I asked for the 4g modem to be installed in the reactor, since a customer has only provided me with 4g sim, when the APN returns and the internet connects, I send the emails but I have an error in sending the SMS.
Does the SMS library also have to be modified in order to manage the new modem?
below the error reported in the offending lines
Code:
function sendsms(number, message)
require('socket')
client = socket.udp()
client:sendto(number .. ' ' .. message, '127.0.0.1', 12535)
end
This script has nothing to do with the SMS sending via modem it simply sends message to the resident script. Post your full resident SMS script and a screenshot from System config > Status > System status > Serial ports.
(31.01.2022, 15:30)admin Wrote: This script has nothing to do with the SMS sending via modem it simply sends message to the resident script. Post your full resident SMS script and a screenshot from System config > Status > System status > Serial ports.
resident sms
Code:
-- init
if not numbers then
require('user.sms')
require('json')
require('socket')
-- allowed numbers, SMS from other numbers will be ignored
numbers = { '3332958126' }
-- port number depends on modem model
comport = 'ttyACM3'
doreset = false -- set to true if USB reset is required before starting any communication
-- if SIM PIN is enabled, uncomment the line below and replace 0000 with SIM PIN
-- pincode = '0000'
-- name end not found, stop
if not pos then
return
end
-- get name part
name = cmd:sub(1 + offset, pos - offset):trim()
if mode == 'W' then
value = cmd:sub(pos + offset):trim()
if #value > 0 then
-- try decoding value
dvalue = json.pdecode(value)
if dvalue ~= nil then
value = dvalue
end
-- send to bus
grp.write(name, value)
end
-- read request
else
obj = grp.find(name)
-- object not known
if not obj then
return
end
-- send read request and wait for an update
obj:read()
os.sleep(1)
-- read new value
value = grp.getvalue(name)
-- got no value
if value == nil then
return
end
-- add object name if specified
if obj.name then
name = string.format('%s (%s)', obj.name, obj.address)
end
message = string.format('Value of %s is %s', name, json.encode(value))
modem:sendsms('+' .. sender, message)
end
end
-- incoming sms handler
handler = function(sms)
--alert('incoming sms: [%s] %s', tostring(sms.sender), tostring(sms.data))
-- sms from known number, call parser
if table.contains(numbers, sms.sender) then
--parser(sms.data, sms.sender)
end
end
-- check local udp server for messages to send
udphandler = function(server)
-- check for local sms to send
local msg = server:receive()
-- got no message
if not msg then
return
end
-- split into number and message
local sep = msg:find(' ')
if not sep then
return
end
--alert('sending sms: ' .. msg)
modem:sendsms(msg:sub(1, sep - 1), msg:sub(sep + 1))
end
end
-- handle data from modem
if modem then
if modem:run() then
udphandler(server)
else
--alert('SMS handler lost connection')
modem:reinit()
end
-- modem init
else
--alert('SMS handler init')
-- open serial port
modem = AT:init('/dev/' .. comport, doreset)
-- init ok
if modem then
-- set sms handler
modem:setsmshandler(handler)
-- send pin if set
if pincode then
modem:send('AT+CPIN=' .. pincode)
modem:read()
end
-- set to pdu mode
modem:send('AT+CMGF=0')
-- enable sms notifications
modem:send('AT+CNMI=1,1,0,0,0')
-- fixup encoding
modem:send('AT+CSCS="GSM"')
-- delete all saved messages
modem:send('AT+CMGD=1,4')
-- local udp server for sending sms
server = socket.udp()
server:setsockname('127.0.0.1', 12535)
server:settimeout(0.1)
--alert('SMS handler started')
-- init failed
else
--alert('SMS USB init failed')
end
end
-- init
if not numbers then
require('user.sms')
require('json')
require('socket')
-- allowed numbers, SMS from other numbers will be ignored
numbers = { '3332958126' }
-- port number depends on modem model
comport = 'ttyACM3'
doreset = false -- set to true if USB reset is required before starting any communication
-- if SIM PIN is enabled, uncomment the line below and replace 0000 with SIM PIN
-- pincode = '0000'
-- name end not found, stop
if not pos then
return
end
-- get name part
name = cmd:sub(1 + offset, pos - offset):trim()
if mode == 'W' then
value = cmd:sub(pos + offset):trim()
if #value > 0 then
-- try decoding value
dvalue = json.pdecode(value)
if dvalue ~= nil then
value = dvalue
end
-- send to bus
grp.write(name, value)
end
-- read request
else
obj = grp.find(name)
-- object not known
if not obj then
return
end
-- send read request and wait for an update
obj:read()
os.sleep(1)
-- read new value
value = grp.getvalue(name)
-- got no value
if value == nil then
return
end
-- add object name if specified
if obj.name then
name = string.format('%s (%s)', obj.name, obj.address)
end
message = string.format('Value of %s is %s', name, json.encode(value))
modem:sendsms('+' .. sender, message)
end
end
-- incoming sms handler
handler = function(sms)
--alert('incoming sms: [%s] %s', tostring(sms.sender), tostring(sms.data))
-- sms from known number, call parser
if table.contains(numbers, sms.sender) then
--parser(sms.data, sms.sender)
end
end
-- check local udp server for messages to send
udphandler = function(server)
-- check for local sms to send
local msg = server:receive()
-- got no message
if not msg then
return
end
-- split into number and message
local sep = msg:find(' ')
if not sep then
return
end
--alert('sending sms: ' .. msg)
modem:sendsms(msg:sub(1, sep - 1), msg:sub(sep + 1))
end
end
-- handle data from modem
if modem then
if modem:run() then
udphandler(server)
else
--alert('SMS handler lost connection')
modem:reinit()
end
-- modem init
else
--alert('SMS handler init')
-- open serial port
modem = AT:init('/dev/' .. comport, doreset)
-- init ok
if modem then
-- set sms handler
modem:setsmshandler(handler)
-- send pin if set
if pincode then
modem:send('AT+CPIN=' .. pincode)
modem:read()
end
-- set to pdu mode
modem:send('AT+CMGF=0')
-- enable sms notifications
modem:send('AT+CNMI=1,1,0,0,0')
-- fixup encoding
modem:send('AT+CSCS="GSM"')
-- delete all saved messages
modem:send('AT+CMGD=1,4')
-- local udp server for sending sms
server = socket.udp()
server:setsockname('127.0.0.1', 12535)
server:settimeout(0.1)
--alert('SMS handler started')
-- init failed
else
--alert('SMS USB init failed')
end
end
return msg
end,
-- decode sender address depending on source type
decodesender = function(sender, ntype)
if ntype == 5 then
return AT.decode7bit(sender)
else
return AT.decodeswapped(sender)
end
end,
-- decode time in sms pdu
decodetime = function(timestamp)
local offset, year, time
time = os.time({
year = year < 70 and (2000 + year) or (1900 + year),
month = tonumber(timestamp:sub(3, 4)),
day = tonumber(timestamp:sub(5, 6)),
hour = tonumber(timestamp:sub(7, 8)),
min = tonumber(timestamp:sub(9, 10)),
sec = tonumber(timestamp:sub(11, 12))
}) or os.time()
return time
end,
-- convert swapped number to normal
decodeswapped = function(data)
local i, nr, len, buf
buf = {}
-- real byte length
len = math.floor(data:len() / 2)
-- read 2 bytes at once
for i = 1, len do
-- convert low byte to number
nr = tonumber(data:sub(i * 2, i * 2))
if nr then
table.insert(buf, tostring(nr))
end
-- convert high byte to number
nr = tonumber(data:sub(i * 2 - 1, i * 2 - 1))
if nr then
table.insert(buf, tostring(nr))
end
end
return table.concat(buf)
end,
-- convert from 7 bit char to 8 bit
from7bit = function(c)
if c < 128 then
return string.char(AT.alphabet[ c + 1 ])
else
return ' '
end
end,
-- converts from 7 bit to 8 bit
decode7bit = function(data, len)
local i, o, byte, prev, curr, mask, buf, res
-- convert to binary string
data = lmcore.hextostr(data, true)
-- init vars
o = 0
prev = 0
buf = {}
for i = 1, data:len() do
byte = data:byte(i, i)
-- get 7 bit data
mask = bit.lshift(1, 7 - o) - 1
-- get current chunk
curr = bit.band(byte, mask)
curr = bit.lshift(curr, o)
curr = bit.bor(curr, prev)
-- save bit chunk
prev = bit.rshift(byte, 7 - o)
-- add to buffer
table.insert(buf, AT.from7bit(curr))
-- every 7th step prev will have a full char
if o == 6 then
table.insert(buf, AT.from7bit(prev))
prev = 0
end
o = (o + 1) % 7
end
-- catch last char in buffer
if prev > 0 then
table.insert(buf, AT.from7bit(prev))
end
-- flatten buffer
res = table.concat(buf)
if len then
res = res:sub(1, len)
end
return res
end
}
function AT:init(dev, reset)
require('serial')
local t = setmetatable({}, { __index = AT })
t.dev = dev
while true do
if t:reinit(30, reset) then
break
else
if reset then
t:reset()
else
return nil
end
end
end
return t
end
function AT:open(timeout)
local port
while true do
if io.exists(self.dev) then
port = serial.open(self.dev)
if port then
break
end
end
if timeout then
timeout = timeout - 1
if timeout <= 0 then
return false
end
end
os.sleep(1)
end
self.port = port
self.buffer = {}
return true
end
function AT:reset()
--alert('modem reset')
os.execute('usbreset /dev/bus/usb/001/001')
end
function AT:reinit(timeout, reset)
local res
if reset then
self:reset()
end
res = self:open(timeout)
self.buffer = {}
return res
end
function AT:close()
if self.port then
self.port:close()
self.port = nil
end
end
-- read single line from port
function AT:read(timeout)
local char, err, timeout, deftimeout, line
-- default timeout is 1 second, converted to 0.1 sec ticks
timeout = tonumber(timeout) or 1
timeout = timeout * 10
deftimeout = timeout
-- read until got one line or timeout occured
while timeout > 0 do
-- read 1 char
char, err = self.port:read(1, 0.1)
-- got data
if char then
-- got LF, end of line
if char == '\n' then
-- convert to string and empty buffer
line = table.concat(self.buffer)
self.buffer = {}
line = line:trim()
-- return only lines with data
if #line > 0 then
return line
-- reset timeout
else
timeout = deftimeout
end
-- ignore CR
elseif char ~= '\r' then
table.insert(self.buffer, char)
end
-- read timeout
elseif err == 'timeout' then
timeout = timeout - 1
-- other error
else
break
end
end
print('error', err)
return nil, err
end
-- blocking read until cmd is received
function AT:readuntil(cmd, timeout)
local line, err
timeout = timeout or 5
while timeout > 0 do
line, err = self:read()
-- read line ok
if line then
if line == cmd or line == 'COMMAND NOT SUPPORT' or line:match('ERROR') then
return line
else
timeout = timeout - 1
err = 'invalid line'
end
-- timeout
elseif err == 'timeout' then
timeout = timeout - 1
-- other error
else
break
end
end
return nil, err
end
-- send command to terminal
function AT:send(cmd)
local res, err = self.port:write(cmd .. '\r\n')
-- write ok, get local echo
if res then
res, err = self:readuntil(cmd)
self:read()
end
return res, err
end
-- main handler
function AT:run()
local res, err, cmd, pos, sms
res, err = self:read()
if err then
return err == 'timeout'
end
-- check for incoming command
if res:sub(1, 1) ~= '+' then
return true
end
pos = res:find(':', 1, true)
if not pos then
return true
end
-- get command type
cmd = res:sub(2, pos - 1)
-- check only for incoming sms
if cmd ~= 'CMTI' then
return
end
-- read from sim
sms = self:incsms(res)
-- sms seems to be valid, pass to handler if specified
if sms and self.smshandler then
self.smshandler(sms)
end
return true
end
-- incoming sms handler
function AT:incsms(res)
local chunks, index, sms
-- get message index from result
chunks = res:split(',')
if #chunks == 2 then
-- get index and read from it
index = tonumber(chunks[ 2 ])
sms = self:readsms(index)
-- delete sms from store
self:deletesms(index)
end
return sms
end
-- delete sms at index
function AT:deletesms(index)
local cmd, res
-- send delete request
cmd = 'AT+CMGD=' .. index
res = self:send(cmd)
return res
end
-- read sms at index
function AT:readsms(index)
local cmd, res, sms
-- send read request
cmd = 'AT+CMGR=' .. index
res = self:send(cmd)
-- no message at then index
if res == 'OK' then
return nil, 'not found'
end
Replace the whole sendsms function with this and check if it works. Also check if you have any messages in Logs.
Code:
function sendsms(number, message)
local client, err = require('socket').udp()
if client then
client:sendto(number .. ' ' .. message, '127.0.0.1', 12535)
client:close()
else
log('failed to created socket: ' .. tostring(err))
end
end
(01.02.2022, 12:18)admin Wrote: Replace the whole sendsms function with this and check if it works. Also check if you have any messages in Logs.
Code:
function sendsms(number, message)
local client, err = require('socket').udp()
if client then
client:sendto(number .. ' ' .. message, '127.0.0.1', 12535)
client:close()
else
log('failed to created socket: ' .. tostring(err))
end
end
You have the same code in the resident script twice, this can lead to errors. You've also commented out all alerts so there's no way of knowing if the script is working or not.
Replace your resident script with this and post what you get in alerts:
Code:
-- init
if not numbers then
require('user.sms')
require('json')
require('socket')
-- allowed numbers, SMS from other numbers will be ignored
numbers = { '3332958126' }
-- port number depends on modem model
comport = 'ttyACM3'
doreset = false -- set to true if USB reset is required before starting any communication
-- if SIM PIN is enabled, uncomment the line below and replace 0000 with SIM PIN
-- pincode = '0000'
-- name end not found, stop
if not pos then
return
end
-- get name part
name = cmd:sub(1 + offset, pos - offset):trim()
if mode == 'W' then
value = cmd:sub(pos + offset):trim()
if #value > 0 then
-- try decoding value
dvalue = json.pdecode(value)
if dvalue ~= nil then
value = dvalue
end
-- send to bus
grp.write(name, value)
end
-- read request
else
obj = grp.find(name)
-- object not known
if not obj then
return
end
-- send read request and wait for an update
obj:read()
os.sleep(1)
-- read new value
value = grp.getvalue(name)
-- got no value
if value == nil then
return
end
-- add object name if specified
if obj.name then
name = string.format('%s (%s)', obj.name, obj.address)
end
message = string.format('Value of %s is %s', name, json.encode(value))
modem:sendsms('+' .. sender, message)
end
end
-- incoming sms handler
handler = function(sms)
--alert('incoming sms: [%s] %s', tostring(sms.sender), tostring(sms.data))
-- sms from known number, call parser
if table.contains(numbers, sms.sender) then
--parser(sms.data, sms.sender)
end
end
-- check local udp server for messages to send
udphandler = function(server)
-- check for local sms to send
local msg = server:receive()
-- got no message
if not msg then
return
end
-- split into number and message
local sep = msg:find(' ')
if not sep then
return
end
alert('sending sms: ' .. msg)
modem:sendsms(msg:sub(1, sep - 1), msg:sub(sep + 1))
end
end
-- handle data from modem
if modem then
if modem:run() then
udphandler(server)
else
alert('SMS handler lost connection')
modem:reinit()
end
-- modem init
else
alert('SMS handler init')
-- open serial port
modem = AT:init('/dev/' .. comport, doreset)
-- init ok
if modem then
-- set sms handler
modem:setsmshandler(handler)
-- send pin if set
if pincode then
modem:send('AT+CPIN=' .. pincode)
modem:read()
end
-- set to pdu mode
modem:send('AT+CMGF=0')
-- enable sms notifications
modem:send('AT+CNMI=1,1,0,0,0')
-- fixup encoding
modem:send('AT+CSCS="GSM"')
-- delete all saved messages
modem:send('AT+CMGD=1,4')
-- local udp server for sending sms
server = socket.udp()
server:setsockname('127.0.0.1', 12535)
server:settimeout(0.1)
alert('SMS handler started')
-- init failed
else
alert('SMS USB init failed')
end
end
(01.02.2022, 13:35)admin Wrote: You have the same code in the resident script twice, this can lead to errors. You've also commented out all alerts so there's no way of knowing if the script is working or not.
Replace your resident script with this and post what you get in alerts:
Code:
-- init
if not numbers then
require('user.sms')
require('json')
require('socket')
-- allowed numbers, SMS from other numbers will be ignored
numbers = { '3332958126' }
-- port number depends on modem model
comport = 'ttyACM3'
doreset = false -- set to true if USB reset is required before starting any communication
-- if SIM PIN is enabled, uncomment the line below and replace 0000 with SIM PIN
-- pincode = '0000'
-- name end not found, stop
if not pos then
return
end
-- get name part
name = cmd:sub(1 + offset, pos - offset):trim()
if mode == 'W' then
value = cmd:sub(pos + offset):trim()
if #value > 0 then
-- try decoding value
dvalue = json.pdecode(value)
if dvalue ~= nil then
value = dvalue
end
-- send to bus
grp.write(name, value)
end
-- read request
else
obj = grp.find(name)
-- object not known
if not obj then
return
end
-- send read request and wait for an update
obj:read()
os.sleep(1)
-- read new value
value = grp.getvalue(name)
-- got no value
if value == nil then
return
end
-- add object name if specified
if obj.name then
name = string.format('%s (%s)', obj.name, obj.address)
end
message = string.format('Value of %s is %s', name, json.encode(value))
modem:sendsms('+' .. sender, message)
end
end
-- incoming sms handler
handler = function(sms)
--alert('incoming sms: [%s] %s', tostring(sms.sender), tostring(sms.data))
-- sms from known number, call parser
if table.contains(numbers, sms.sender) then
--parser(sms.data, sms.sender)
end
end
-- check local udp server for messages to send
udphandler = function(server)
-- check for local sms to send
local msg = server:receive()
-- got no message
if not msg then
return
end
-- split into number and message
local sep = msg:find(' ')
if not sep then
return
end
alert('sending sms: ' .. msg)
modem:sendsms(msg:sub(1, sep - 1), msg:sub(sep + 1))
end
end
-- handle data from modem
if modem then
if modem:run() then
udphandler(server)
else
alert('SMS handler lost connection')
modem:reinit()
end
-- modem init
else
alert('SMS handler init')
-- open serial port
modem = AT:init('/dev/' .. comport, doreset)
-- init ok
if modem then
-- set sms handler
modem:setsmshandler(handler)
-- send pin if set
if pincode then
modem:send('AT+CPIN=' .. pincode)
modem:read()
end
-- set to pdu mode
modem:send('AT+CMGF=0')
-- enable sms notifications
modem:send('AT+CNMI=1,1,0,0,0')
-- fixup encoding
modem:send('AT+CSCS="GSM"')
-- delete all saved messages
modem:send('AT+CMGD=1,4')
-- local udp server for sending sms
server = socket.udp()
server:setsockname('127.0.0.1', 12535)
server:settimeout(0.1)
alert('SMS handler started')
-- init failed
else
alert('SMS USB init failed')
end
end
For the problem of sending sms I solved with your help in 2 reactor out of 3, in the third with the same scripts, if I text the sms calling send it works, while if it is called from the script the alalrme event does not work, while the mails from the same script do
The alalrme event scripts I checked it are like in the reactor it works in, I'm getting lost and I don't know where.
I found the problem, the phone number had a space at the end for which it was not valid, now I try how to remove the spaces before and after, both for the phone number and if I can also for the email address so as to no longer have the problem.
We are having the same problem that Frank68 sending SMS.
The LM was working fine but from one day to the other it stop working. We tried changing the comport, factory reset the LM and even tried it on other LM with no result.
On Alert tab we keep getting SMS USB init failed.
Another thing I find strange is that the serial ports don't show on system status (view image).