Blame view
lib/modem.js
9.43 KB
49eaf19a3
|
1 2 3 |
'use strict'; const INTERVAL_BEETWEN_SIGNAL_STRENGTH_MS = 60000; |
2db546a87
|
4 5 6 7 8 9 10 11 12 13 |
// const DELIMITER_WAIT_FOR_OK = ' OK\r '; const REGEX_WAIT_FOR_OK_OR_ERROR = / (?:OK|ERROR)\r /; // const REGEX_WAIT_FOR_OK_OR_ERROR = / OK\r /; |
49eaf19a3
|
14 |
|
5a00ec06f
|
15 |
const moment = require('moment'); |
49eaf19a3
|
16 17 |
const SerialPort = require('serialport'); const ParserReadline = require('@serialport/parser-readline'); |
2db546a87
|
18 19 20 |
// const ParserDelimiter = require('@serialport/parser-delimiter'); const ParserRegex = require('@serialport/parser-regex'); |
49eaf19a3
|
21 22 23 |
const config = require('komodo-sdk/config'); const logger = require('komodo-sdk/logger'); |
49eaf19a3
|
24 |
|
cba7eef40
|
25 |
const mutex = require('./mutex'); |
67af4245e
|
26 |
const common = require('./common'); |
49eaf19a3
|
27 |
const sms = require('./sms'); |
7355ad895
|
28 |
const dbCops = require('./db-cops'); |
5ae543453
|
29 |
const reportSender = require('./report-sender'); |
9ad3c8d30
|
30 |
const msisdn = require('./msisdn'); |
49eaf19a3
|
31 |
|
bc541e414
|
32 |
const modemInfo = { |
c428dcf05
|
33 34 |
manufacturer: null, model: null, |
3ec3e9eb3
|
35 |
imei: null, |
bc541e414
|
36 |
imsi: null, |
9ad3c8d30
|
37 |
msisdn: null, |
7355ad895
|
38 39 40 |
cops: null, networkId: null, networkName: null, |
bc541e414
|
41 |
signalStrength: null, |
5a00ec06f
|
42 43 |
signalStrengthTs: null, signalStrengthTsReadable: null, |
0440fda97
|
44 |
config: config.modem, |
bc541e414
|
45 |
}; |
49eaf19a3
|
46 |
|
49eaf19a3
|
47 48 49 |
const port = new SerialPort(config.modem.device, { baudRate: 115200 }); const parserReadLine = new ParserReadline(); |
0bdac2f9c
|
50 |
|
2db546a87
|
51 |
const parserWaitForOK = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); |
0bdac2f9c
|
52 53 54 |
parserWaitForOK.on('data', () => { mutex.releaseLockWaitForCommand(); }); |
49eaf19a3
|
55 56 57 58 59 60 61 62 63 64 65 |
port.pipe(parserReadLine); function writeToPort(data) { return new Promise((resolve) => { port.write(data, (err, bytesWritten) => { if (err) logger.warn(`ERROR: ${err.toString()}`); logger.verbose(`* OUT: ${data}`); resolve(bytesWritten); }); }); } |
2db546a87
|
66 |
// eslint-disable-next-line no-unused-vars |
49eaf19a3
|
67 |
async function writeToPortAndWaitForOK(data) { |
0bdac2f9c
|
68 |
await mutex.setLockWaitForCommand(); |
49eaf19a3
|
69 |
const result = await writeToPort(data); |
0bdac2f9c
|
70 71 72 |
await mutex.setLockWaitForCommand(); mutex.releaseLockWaitForCommand(); |
49eaf19a3
|
73 74 75 76 |
return result; } async function readSMS(slot) { |
2db546a87
|
77 |
const parserCMGR = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); |
0bdac2f9c
|
78 |
parserCMGR.on('data', (data) => { |
49eaf19a3
|
79 |
if (data) { |
2db546a87
|
80 |
try { |
343164ad5
|
81 |
reportSender.incomingSMS(sms.extract(data.toString().trim()), modemInfo); |
2db546a87
|
82 83 84 85 86 |
} catch (e) { logger.warn(`Exception on reporting new message. ${e.toString()}`, { smsObj: e.smsObj, dataFromModem: data }); process.exit(0); } |
49eaf19a3
|
87 |
} |
0bdac2f9c
|
88 89 90 |
port.unpipe(parserCMGR); mutex.releaseLockWaitForCommand(); }); |
2db546a87
|
91 92 |
// const parserCMGD = new ParserDelimiter({ delimiter: DELIMITER_WAIT_FOR_OK }); const parserCMGD = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); |
0bdac2f9c
|
93 94 95 |
parserCMGD.on('data', () => { port.unpipe(parserCMGD); mutex.releaseLockWaitForCommand(); |
49eaf19a3
|
96 97 98 |
}); logger.info(`Reading SMS on slot ${slot}`); |
0bdac2f9c
|
99 100 101 102 |
await mutex.setLockWaitForCommand(); port.pipe(parserCMGR); await writeToPort(`AT+CMGR=${slot}\r`); logger.info(`Finished reading SMS on slot ${slot}`); |
49eaf19a3
|
103 104 |
logger.info(`Deleting message on slot ${slot}`); |
0bdac2f9c
|
105 106 107 |
await mutex.setLockWaitForCommand(); port.pipe(parserCMGD); await writeToPort(`AT+CMGD=${slot}\r`); |
49eaf19a3
|
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
logger.info('Message processing has completed'); } function onIncomingSMS(data) { const value = common.extractValueFromReadLineData(data); if (!value) return; const chunks = value.split(','); if (!chunks && !chunks[1]) return; const slot = chunks[1]; logger.info(`Incoming SMS on slot ${slot}`); readSMS(slot); } |
7355ad895
|
123 124 125 126 127 128 129 130 131 132 133 134 |
function onCOPS(data) { modemInfo.cops = common.extractValueFromReadLineData(data).trim(); logger.info(`Connected Network: ${modemInfo.cops}`); if (!modemInfo.cops) return; [, , modemInfo.networkId] = modemInfo.cops.split(','); if (modemInfo.networkId) { modemInfo.networkName = dbCops[modemInfo.networkId]; } } |
49eaf19a3
|
135 136 137 138 |
parserReadLine.on('data', (data) => { logger.verbose(`* IN: ${data}`); if (data) { if (data.indexOf('+CSQ: ') === 0) { |
5a00ec06f
|
139 140 141 142 143 144 145 |
const signalStrength = common.extractValueFromReadLineData(data).trim(); if (signalStrength) { modemInfo.signalStrength = signalStrength; modemInfo.signalStrengthTs = new Date(); modemInfo.signalStrengthTsReadable = moment(modemInfo.signalStrengthTs).format('YYYY-MM-DD HH:mm:ss'); logger.info(`Signal strength: ${modemInfo.signalStrength}`); } |
49eaf19a3
|
146 147 |
} else if (data.indexOf('+CMTI: ') === 0) { onIncomingSMS(data); |
7355ad895
|
148 149 |
} else if (data.indexOf('+COPS: ') === 0) { onCOPS(data); |
49eaf19a3
|
150 151 152 |
} } }); |
2db546a87
|
153 154 |
async function simpleSubCommand(cmd, callback) { const parser = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); |
c428dcf05
|
155 156 |
parser.on('data', (data) => { port.unpipe(parser); |
2db546a87
|
157 |
mutex.releaseLockWaitForSubCommand(); |
c428dcf05
|
158 159 |
if (data) { |
2db546a87
|
160 |
if (callback) callback(null, data.toString().trim()); |
c428dcf05
|
161 162 |
} }); |
2db546a87
|
163 164 165 166 167 168 169 170 171 172 |
return new Promise(async (resolve) => { await mutex.setLockWaitForSubCommand(); port.pipe(parser); writeToPort(cmd); await mutex.setLockWaitForSubCommand(); mutex.releaseLockWaitForSubCommand(); resolve(); }); |
c428dcf05
|
173 |
} |
c428dcf05
|
174 175 |
function readManufacturer() { return new Promise((resolve) => { |
2db546a87
|
176 |
simpleSubCommand('AT+CGMI\r', (err, result) => { |
c428dcf05
|
177 178 179 180 181 182 183 184 185 |
modemInfo.manufacturer = result; logger.info(`Manufacturer: ${result}`); resolve(result); }); }); } function readModel() { return new Promise((resolve) => { |
2db546a87
|
186 |
simpleSubCommand('AT+CGMM\r', (err, result) => { |
c428dcf05
|
187 188 189 190 191 192 193 194 195 |
modemInfo.model = result; logger.info(`Model: ${result}`); resolve(result); }); }); } function readIMEI() { return new Promise((resolve) => { |
2db546a87
|
196 |
simpleSubCommand('AT+CGSN\r', (err, result) => { |
c428dcf05
|
197 198 199 200 201 202 203 204 205 |
modemInfo.imei = result; logger.info(`IMEI: ${result}`); resolve(result); }); }); } function readIMSI() { return new Promise((resolve) => { |
2db546a87
|
206 |
simpleSubCommand('AT+CIMI\r', (err, result) => { |
c428dcf05
|
207 208 |
modemInfo.imsi = result; logger.info(`IMSI: ${result}`); |
9ad3c8d30
|
209 210 211 212 213 214 215 |
if (result) { modemInfo.msisdn = msisdn[result]; if (modemInfo.msisdn) { logger.info(`MSISDN: ${modemInfo.msisdn}`); } } |
c428dcf05
|
216 217 218 219 |
resolve(result); }); }); } |
49eaf19a3
|
220 |
|
2db546a87
|
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
function readCOPS() { return new Promise((resolve) => { simpleSubCommand('AT+COPS?\r', (err, result) => { resolve(result); }); }); } function deleteInbox() { return new Promise((resolve) => { simpleSubCommand('AT+CMGD=0,4\r', (err, result) => { resolve(result); }); }); } |
49eaf19a3
|
236 |
async function querySignalStrength() { |
2db546a87
|
237 |
const parser = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); |
0bdac2f9c
|
238 239 240 241 242 243 244 245 246 |
parser.on('data', () => { port.unpipe(parser); mutex.releaseLockWaitForCommand(); }); if (mutex.tryLockWaitForCommand()) { port.pipe(parser); await writeToPort('AT+CSQ\r'); } |
49eaf19a3
|
247 248 249 250 |
} async function registerSignalStrengthBackgroundQuery() { logger.info('Registering background signal strength query'); |
0bdac2f9c
|
251 |
querySignalStrength(); |
49eaf19a3
|
252 253 |
setInterval(() => { querySignalStrength(); |
0bdac2f9c
|
254 |
}, config.interval_beetwen_signal_strength_ms || INTERVAL_BEETWEN_SIGNAL_STRENGTH_MS); |
49eaf19a3
|
255 256 257 |
} async function sendSMS(destination, msg) { |
3023245c4
|
258 |
if (typeof destination !== 'string' || typeof msg !== 'string' || !destination.trim() || !msg.trim()) return; |
2db546a87
|
259 |
const parser = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); |
0bdac2f9c
|
260 261 262 263 264 265 |
parser.on('data', () => { port.unpipe(parser); mutex.releaseLockWaitForSubCommand(); }); logger.verbose('Waiting for command lock to send message'); |
cba7eef40
|
266 |
await mutex.setLockWaitForCommand(); |
0bdac2f9c
|
267 |
|
49eaf19a3
|
268 269 270 |
logger.info('Sending message', { destination, msg }); const correctedDestination = `+${destination}`.replace(/^0/, '62').replace(/^\++/, '+'); |
0bdac2f9c
|
271 272 273 274 275 276 277 278 279 280 281 282 283 |
logger.verbose('Waiting for lock before set to text mode'); await mutex.setLockWaitForSubCommand(); port.pipe(parser); await writeToPort('AT+CMGF=1\r'); logger.verbose('Waiting for lock before writing message'); await mutex.setLockWaitForSubCommand(); port.pipe(parser); await writeToPort(`AT+CMGS="${correctedDestination}" ${msg}${Buffer.from([0x1A])}`); await mutex.setLockWaitForSubCommand(); mutex.releaseLockWaitForSubCommand(); |
49eaf19a3
|
284 285 |
logger.info('Message has been sent'); |
0bdac2f9c
|
286 287 288 289 |
setTimeout(() => { logger.verbose('Releasing command lock'); mutex.releaseLockWaitForCommand(); }, 2000); |
49eaf19a3
|
290 291 292 293 |
} function init() { port.on('open', async () => { |
2db546a87
|
294 |
await mutex.setLockWaitForCommand(); |
49eaf19a3
|
295 296 |
logger.info('Modem opened'); |
2db546a87
|
297 298 |
await writeToPort('\r'); await simpleSubCommand('AT\r'); |
49eaf19a3
|
299 300 |
logger.info('Initializing modem to factory set'); |
2db546a87
|
301 |
await simpleSubCommand('AT&F\r'); |
49eaf19a3
|
302 303 |
logger.info('Disabling echo'); |
2db546a87
|
304 |
await simpleSubCommand('ATE0\r'); |
49eaf19a3
|
305 |
|
2db546a87
|
306 |
await readCOPS(); |
7355ad895
|
307 |
|
c428dcf05
|
308 309 310 |
await readManufacturer(); await readModel(); await readIMEI(); |
49eaf19a3
|
311 |
await readIMSI(); |
2253f95a7
|
312 313 |
if (!config.disable_delete_inbox_on_startup) { logger.info('Deleting existing messages'); |
2db546a87
|
314 |
await deleteInbox(); |
2253f95a7
|
315 |
} |
0bdac2f9c
|
316 |
mutex.releaseLockWaitForCommand(); |
2db546a87
|
317 |
logger.verbose('Init completed'); |
0bdac2f9c
|
318 |
|
49eaf19a3
|
319 |
registerSignalStrengthBackgroundQuery(); |
49eaf19a3
|
320 321 322 323 |
}); } init(); |
bc541e414
|
324 |
exports.modemInfo = modemInfo; |
49eaf19a3
|
325 |
exports.sendSMS = sendSMS; |