Blame view

lib/modem.js 10.1 KB
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
1
2
3
  'use strict';
  
  const INTERVAL_BEETWEN_SIGNAL_STRENGTH_MS = 60000;
fb3911e43   Adhidarma Hadiwinoto   Typo max age
4
  const MAX_LAST_DATA_AGE_MS = 3 * 60 * 1000;
956ce5804   Adhidarma Hadiwinoto   Minors
5
6
7
  const REGEX_WAIT_FOR_OK_OR_ERROR = /
  (?:OK|ERROR)\r
  /;
35ba3f574   Adhidarma Hadiwinoto   Proteksi kalo mod...
8

5a00ec06f   Adhidarma Hadiwinoto   DEBUG signalStrength
9
  const moment = require('moment');
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
10
11
  const SerialPort = require('serialport');
  const ParserReadline = require('@serialport/parser-readline');
2db546a87   Adhidarma Hadiwinoto   Regex parser
12
13
14
  // const ParserDelimiter = require('@serialport/parser-delimiter');
  
  const ParserRegex = require('@serialport/parser-regex');
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
15
16
17
  
  const config = require('komodo-sdk/config');
  const logger = require('komodo-sdk/logger');
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
18

cba7eef40   Adhidarma Hadiwinoto   Separate locks fu...
19
  const mutex = require('./mutex');
67af4245e   Adhidarma Hadiwinoto   Refactor util men...
20
  const common = require('./common');
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
21
  const sms = require('./sms');
7355ad895   Adhidarma Hadiwinoto   Network information
22
  const dbCops = require('./db-cops');
5ae543453   Adhidarma Hadiwinoto   Report via HTTP
23
  const reportSender = require('./report-sender');
9ad3c8d30   Adhidarma Hadiwinoto   MSISDN db
24
  const msisdn = require('./msisdn');
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
25

bc541e414   Adhidarma Hadiwinoto   modemInfo
26
  const modemInfo = {
209ea177a   Adhidarma Hadiwinoto   modemInfo.device
27
      device: config.modem.device,
c428dcf05   Adhidarma Hadiwinoto   More information ...
28
29
      manufacturer: null,
      model: null,
3ec3e9eb3   Adhidarma Hadiwinoto   HTTP command serv...
30
      imei: null,
bc541e414   Adhidarma Hadiwinoto   modemInfo
31
      imsi: null,
9ad3c8d30   Adhidarma Hadiwinoto   MSISDN db
32
      msisdn: null,
7355ad895   Adhidarma Hadiwinoto   Network information
33
34
35
      cops: null,
      networkId: null,
      networkName: null,
bc541e414   Adhidarma Hadiwinoto   modemInfo
36
      signalStrength: null,
5a00ec06f   Adhidarma Hadiwinoto   DEBUG signalStrength
37
38
      signalStrengthTs: null,
      signalStrengthTsReadable: null,
bc541e414   Adhidarma Hadiwinoto   modemInfo
39
  };
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
40

35ba3f574   Adhidarma Hadiwinoto   Proteksi kalo mod...
41
42
43
  let lastTs = new Date();
  
  const port = new SerialPort(config.modem.device, { baudRate: 115200 }, (err) => {
24c0e1ac1   Adhidarma Hadiwinoto   Perbaikan deteksi...
44
      if (err) {
18586efc2   Adhidarma Hadiwinoto   More detail on te...
45
          logger.warn(`Error opening modem. ${err}. Terminating modem ${config.modem.device}.`);
24c0e1ac1   Adhidarma Hadiwinoto   Perbaikan deteksi...
46
47
          process.exit(1);
      }
35ba3f574   Adhidarma Hadiwinoto   Proteksi kalo mod...
48
  });
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
49
50
  
  const parserReadLine = new ParserReadline();
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
51

2db546a87   Adhidarma Hadiwinoto   Regex parser
52
  const parserWaitForOK = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
53
54
55
  parserWaitForOK.on('data', () => {
      mutex.releaseLockWaitForCommand();
  });
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
56
57
58
59
60
61
62
63
64
65
66
  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   Adhidarma Hadiwinoto   Regex parser
67
  // eslint-disable-next-line no-unused-vars
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
68
  async function writeToPortAndWaitForOK(data) {
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
69
      await mutex.setLockWaitForCommand();
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
70
      const result = await writeToPort(data);
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
71
72
73
  
      await mutex.setLockWaitForCommand();
      mutex.releaseLockWaitForCommand();
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
74
75
76
77
      return result;
  }
  
  async function readSMS(slot) {
2db546a87   Adhidarma Hadiwinoto   Regex parser
78
      const parserCMGR = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
79
      parserCMGR.on('data', (data) => {
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
80
          if (data) {
2db546a87   Adhidarma Hadiwinoto   Regex parser
81
              try {
343164ad5   Adhidarma Hadiwinoto   Repot modem info ...
82
                  reportSender.incomingSMS(sms.extract(data.toString().trim()), modemInfo);
2db546a87   Adhidarma Hadiwinoto   Regex parser
83
84
85
86
87
              } catch (e) {
                  logger.warn(`Exception on reporting new message. ${e.toString()}`, { smsObj: e.smsObj, dataFromModem: data });
  
                  process.exit(0);
              }
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
88
          }
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
89
90
91
          port.unpipe(parserCMGR);
          mutex.releaseLockWaitForCommand();
      });
2db546a87   Adhidarma Hadiwinoto   Regex parser
92
93
      // const parserCMGD = new ParserDelimiter({ delimiter: DELIMITER_WAIT_FOR_OK });
      const parserCMGD = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
94
95
96
      parserCMGD.on('data', () => {
          port.unpipe(parserCMGD);
          mutex.releaseLockWaitForCommand();
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
97
98
99
      });
  
      logger.info(`Reading SMS on slot ${slot}`);
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
100
101
102
103
      await mutex.setLockWaitForCommand();
      port.pipe(parserCMGR);
      await writeToPort(`AT+CMGR=${slot}\r`);
      logger.info(`Finished reading SMS on slot ${slot}`);
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
104
105
  
      logger.info(`Deleting message on slot ${slot}`);
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
106
107
108
      await mutex.setLockWaitForCommand();
      port.pipe(parserCMGD);
      await writeToPort(`AT+CMGD=${slot}\r`);
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
      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   Adhidarma Hadiwinoto   Network information
124
125
126
127
128
129
130
131
132
133
134
135
  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   Adhidarma Hadiwinoto   SMS is ok
136
137
138
  parserReadLine.on('data', (data) => {
      logger.verbose(`* IN: ${data}`);
      if (data) {
35ba3f574   Adhidarma Hadiwinoto   Proteksi kalo mod...
139
          lastTs = new Date();
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
140
          if (data.indexOf('+CSQ: ') === 0) {
5a00ec06f   Adhidarma Hadiwinoto   DEBUG signalStrength
141
142
143
144
145
146
147
              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   Adhidarma Hadiwinoto   SMS is ok
148
149
          } else if (data.indexOf('+CMTI: ') === 0) {
              onIncomingSMS(data);
7355ad895   Adhidarma Hadiwinoto   Network information
150
151
          } else if (data.indexOf('+COPS: ') === 0) {
              onCOPS(data);
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
152
153
154
          }
      }
  });
2db546a87   Adhidarma Hadiwinoto   Regex parser
155
156
  async function simpleSubCommand(cmd, callback) {
      const parser = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
c428dcf05   Adhidarma Hadiwinoto   More information ...
157
158
      parser.on('data', (data) => {
          port.unpipe(parser);
2db546a87   Adhidarma Hadiwinoto   Regex parser
159
          mutex.releaseLockWaitForSubCommand();
c428dcf05   Adhidarma Hadiwinoto   More information ...
160
161
  
          if (data) {
2db546a87   Adhidarma Hadiwinoto   Regex parser
162
              if (callback) callback(null, data.toString().trim());
c428dcf05   Adhidarma Hadiwinoto   More information ...
163
164
          }
      });
2db546a87   Adhidarma Hadiwinoto   Regex parser
165
166
167
168
169
170
171
172
173
174
      return new Promise(async (resolve) => {
          await mutex.setLockWaitForSubCommand();
          port.pipe(parser);
          writeToPort(cmd);
  
          await mutex.setLockWaitForSubCommand();
          mutex.releaseLockWaitForSubCommand();
  
          resolve();
      });
c428dcf05   Adhidarma Hadiwinoto   More information ...
175
  }
c428dcf05   Adhidarma Hadiwinoto   More information ...
176
177
  function readManufacturer() {
      return new Promise((resolve) => {
2db546a87   Adhidarma Hadiwinoto   Regex parser
178
          simpleSubCommand('AT+CGMI\r', (err, result) => {
c428dcf05   Adhidarma Hadiwinoto   More information ...
179
180
181
182
183
184
185
186
187
              modemInfo.manufacturer = result;
              logger.info(`Manufacturer: ${result}`);
              resolve(result);
          });
      });
  }
  
  function readModel() {
      return new Promise((resolve) => {
2db546a87   Adhidarma Hadiwinoto   Regex parser
188
          simpleSubCommand('AT+CGMM\r', (err, result) => {
c428dcf05   Adhidarma Hadiwinoto   More information ...
189
190
191
192
193
194
195
196
197
              modemInfo.model = result;
              logger.info(`Model: ${result}`);
              resolve(result);
          });
      });
  }
  
  function readIMEI() {
      return new Promise((resolve) => {
2db546a87   Adhidarma Hadiwinoto   Regex parser
198
          simpleSubCommand('AT+CGSN\r', (err, result) => {
c428dcf05   Adhidarma Hadiwinoto   More information ...
199
200
201
202
203
204
205
206
207
              modemInfo.imei = result;
              logger.info(`IMEI: ${result}`);
              resolve(result);
          });
      });
  }
  
  function readIMSI() {
      return new Promise((resolve) => {
2db546a87   Adhidarma Hadiwinoto   Regex parser
208
          simpleSubCommand('AT+CIMI\r', (err, result) => {
c428dcf05   Adhidarma Hadiwinoto   More information ...
209
210
              modemInfo.imsi = result;
              logger.info(`IMSI: ${result}`);
9ad3c8d30   Adhidarma Hadiwinoto   MSISDN db
211
212
213
214
215
216
  
              if (result) {
                  modemInfo.msisdn = msisdn[result];
                  if (modemInfo.msisdn) {
                      logger.info(`MSISDN: ${modemInfo.msisdn}`);
                  }
5087dec58   Adhidarma Hadiwinoto   ESLINT
217
              } else {
18586efc2   Adhidarma Hadiwinoto   More detail on te...
218
                  logger.warn(`IMSI not detected. Please insert a sim card to your modem. Terminating  ${config.modem.device}.`);
24c0e1ac1   Adhidarma Hadiwinoto   Perbaikan deteksi...
219
220
                  process.exit(2);
              }
c428dcf05   Adhidarma Hadiwinoto   More information ...
221
222
223
224
              resolve(result);
          });
      });
  }
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
225

2db546a87   Adhidarma Hadiwinoto   Regex parser
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  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   Adhidarma Hadiwinoto   SMS is ok
241
  async function querySignalStrength() {
2db546a87   Adhidarma Hadiwinoto   Regex parser
242
      const parser = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
243
244
245
246
247
248
249
250
251
      parser.on('data', () => {
          port.unpipe(parser);
          mutex.releaseLockWaitForCommand();
      });
  
      if (mutex.tryLockWaitForCommand()) {
          port.pipe(parser);
          await writeToPort('AT+CSQ\r');
      }
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
252
253
254
255
  }
  
  async function registerSignalStrengthBackgroundQuery() {
      logger.info('Registering background signal strength query');
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
256
      querySignalStrength();
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
257
258
      setInterval(() => {
          querySignalStrength();
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
259
      }, config.interval_beetwen_signal_strength_ms || INTERVAL_BEETWEN_SIGNAL_STRENGTH_MS);
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
260
261
262
  }
  
  async function sendSMS(destination, msg) {
3023245c4   Adhidarma Hadiwinoto   Pengamanan tambahan
263
      if (typeof destination !== 'string' || typeof msg !== 'string' || !destination.trim() || !msg.trim()) return;
2db546a87   Adhidarma Hadiwinoto   Regex parser
264
      const parser = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
265
266
267
268
269
270
      parser.on('data', () => {
          port.unpipe(parser);
          mutex.releaseLockWaitForSubCommand();
      });
  
      logger.verbose('Waiting for command lock to send message');
cba7eef40   Adhidarma Hadiwinoto   Separate locks fu...
271
      await mutex.setLockWaitForCommand();
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
272

49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
273
274
275
      logger.info('Sending message', { destination, msg });
  
      const correctedDestination = `+${destination}`.replace(/^0/, '62').replace(/^\++/, '+');
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
276
277
278
279
280
281
282
283
284
285
286
287
288
      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   Adhidarma Hadiwinoto   SMS is ok
289
290
  
      logger.info('Message has been sent');
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
291
292
293
294
      setTimeout(() => {
          logger.verbose('Releasing command lock');
          mutex.releaseLockWaitForCommand();
      }, 2000);
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
295
296
297
  }
  
  function init() {
18586efc2   Adhidarma Hadiwinoto   More detail on te...
298
      setInterval(() => {
35ba3f574   Adhidarma Hadiwinoto   Proteksi kalo mod...
299
          if ((new Date() - lastTs) > MAX_LAST_DATA_AGE_MS) {
18586efc2   Adhidarma Hadiwinoto   More detail on te...
300
              logger.warn(`No data for more than ${MAX_LAST_DATA_AGE_MS} ms. Modem might be unresponsive. Terminating modem ${config.modem.device}.`);
35ba3f574   Adhidarma Hadiwinoto   Proteksi kalo mod...
301
302
303
              process.exit(0);
          }
      }, 30 * 1000);
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
304
      port.on('open', async () => {
2db546a87   Adhidarma Hadiwinoto   Regex parser
305
          await mutex.setLockWaitForCommand();
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
306
307
  
          logger.info('Modem opened');
2db546a87   Adhidarma Hadiwinoto   Regex parser
308
309
          await writeToPort('\r');
          await simpleSubCommand('AT\r');
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
310
311
  
          logger.info('Initializing modem to factory set');
2db546a87   Adhidarma Hadiwinoto   Regex parser
312
          await simpleSubCommand('AT&F\r');
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
313
314
  
          logger.info('Disabling echo');
2db546a87   Adhidarma Hadiwinoto   Regex parser
315
          await simpleSubCommand('ATE0\r');
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
316

2db546a87   Adhidarma Hadiwinoto   Regex parser
317
          await readCOPS();
7355ad895   Adhidarma Hadiwinoto   Network information
318

c428dcf05   Adhidarma Hadiwinoto   More information ...
319
320
321
          await readManufacturer();
          await readModel();
          await readIMEI();
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
322
          await readIMSI();
2253f95a7   Adhidarma Hadiwinoto   config.disable_de...
323
324
          if (!config.disable_delete_inbox_on_startup) {
              logger.info('Deleting existing messages');
2db546a87   Adhidarma Hadiwinoto   Regex parser
325
              await deleteInbox();
2253f95a7   Adhidarma Hadiwinoto   config.disable_de...
326
          }
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
327
          mutex.releaseLockWaitForCommand();
2db546a87   Adhidarma Hadiwinoto   Regex parser
328
          logger.verbose('Init completed');
0bdac2f9c   Adhidarma Hadiwinoto   Bersih kirim sms ...
329

49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
330
          registerSignalStrengthBackgroundQuery();
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
331
332
333
334
      });
  }
  
  init();
bc541e414   Adhidarma Hadiwinoto   modemInfo
335
  exports.modemInfo = modemInfo;
49eaf19a3   Adhidarma Hadiwinoto   SMS is ok
336
  exports.sendSMS = sendSMS;