Commit 3023245c4f75f2ffc9ab3fbb7b8d89012d165108

Authored by Adhidarma Hadiwinoto
1 parent edb8b6e81d
Exists in master

Pengamanan tambahan

Showing 2 changed files with 3 additions and 1 deletions Inline Diff

1 'use strict'; 1 'use strict';
2 2
3 const INTERVAL_BEETWEN_SIGNAL_STRENGTH_MS = 60000; 3 const INTERVAL_BEETWEN_SIGNAL_STRENGTH_MS = 60000;
4 const DELIMITER_WAIT_FOR_OK = '\nOK\r\n'; 4 const DELIMITER_WAIT_FOR_OK = '\nOK\r\n';
5 5
6 const SerialPort = require('serialport'); 6 const SerialPort = require('serialport');
7 const ParserReadline = require('@serialport/parser-readline'); 7 const ParserReadline = require('@serialport/parser-readline');
8 const ParserDelimiter = require('@serialport/parser-delimiter'); 8 const ParserDelimiter = require('@serialport/parser-delimiter');
9 9
10 const config = require('komodo-sdk/config'); 10 const config = require('komodo-sdk/config');
11 const logger = require('komodo-sdk/logger'); 11 const logger = require('komodo-sdk/logger');
12 12
13 const mutex = require('./mutex'); 13 const mutex = require('./mutex');
14 const common = require('./common'); 14 const common = require('./common');
15 const sms = require('./sms'); 15 const sms = require('./sms');
16 const dbCops = require('./db-cops'); 16 const dbCops = require('./db-cops');
17 const reportSender = require('./report-sender'); 17 const reportSender = require('./report-sender');
18 18
19 const modemInfo = { 19 const modemInfo = {
20 manufacturer: null, 20 manufacturer: null,
21 model: null, 21 model: null,
22 imei: null, 22 imei: null,
23 imsi: null, 23 imsi: null,
24 cops: null, 24 cops: null,
25 networkId: null, 25 networkId: null,
26 networkName: null, 26 networkName: null,
27 signalStrength: null, 27 signalStrength: null,
28 config: config.modem, 28 config: config.modem,
29 }; 29 };
30 30
31 const port = new SerialPort(config.modem.device, { baudRate: 115200 }); 31 const port = new SerialPort(config.modem.device, { baudRate: 115200 });
32 32
33 const parserReadLine = new ParserReadline(); 33 const parserReadLine = new ParserReadline();
34 const parserWaitForOK = new ParserDelimiter({ delimiter: DELIMITER_WAIT_FOR_OK }); 34 const parserWaitForOK = new ParserDelimiter({ delimiter: DELIMITER_WAIT_FOR_OK });
35 port.pipe(parserReadLine); 35 port.pipe(parserReadLine);
36 36
37 function writeToPort(data) { 37 function writeToPort(data) {
38 return new Promise((resolve) => { 38 return new Promise((resolve) => {
39 port.write(data, (err, bytesWritten) => { 39 port.write(data, (err, bytesWritten) => {
40 if (err) logger.warn(`ERROR: ${err.toString()}`); 40 if (err) logger.warn(`ERROR: ${err.toString()}`);
41 logger.verbose(`* OUT: ${data}`); 41 logger.verbose(`* OUT: ${data}`);
42 resolve(bytesWritten); 42 resolve(bytesWritten);
43 }); 43 });
44 }); 44 });
45 } 45 }
46 46
47 async function writeToPortAndWaitForOK(data) { 47 async function writeToPortAndWaitForOK(data) {
48 await mutex.setLockWaitForOK(); 48 await mutex.setLockWaitForOK();
49 const result = await writeToPort(data); 49 const result = await writeToPort(data);
50 await mutex.setLockWaitForOK(); 50 await mutex.setLockWaitForOK();
51 mutex.releaseLockWaitForOK(); 51 mutex.releaseLockWaitForOK();
52 return result; 52 return result;
53 } 53 }
54 54
55 async function readSMS(slot) { 55 async function readSMS(slot) {
56 const parser = new ParserDelimiter({ delimiter: DELIMITER_WAIT_FOR_OK }); 56 const parser = new ParserDelimiter({ delimiter: DELIMITER_WAIT_FOR_OK });
57 parser.on('data', async (data) => { 57 parser.on('data', async (data) => {
58 if (data) { 58 if (data) {
59 reportSender.incomingSMS(sms.extract(data.toString().trim())); 59 reportSender.incomingSMS(sms.extract(data.toString().trim()));
60 } 60 }
61 mutex.releaseLockWaitForOK(); 61 mutex.releaseLockWaitForOK();
62 }); 62 });
63 63
64 logger.info(`Reading SMS on slot ${slot}`); 64 logger.info(`Reading SMS on slot ${slot}`);
65 port.pipe(parser); 65 port.pipe(parser);
66 await writeToPortAndWaitForOK(`AT+CMGR=${slot}\r`); 66 await writeToPortAndWaitForOK(`AT+CMGR=${slot}\r`);
67 port.unpipe(parser); 67 port.unpipe(parser);
68 logger.verbose(`Finished reading SMS on slot ${slot}`); 68 logger.verbose(`Finished reading SMS on slot ${slot}`);
69 69
70 logger.info(`Deleting message on slot ${slot}`); 70 logger.info(`Deleting message on slot ${slot}`);
71 port.pipe(parserWaitForOK); 71 port.pipe(parserWaitForOK);
72 await writeToPortAndWaitForOK(`AT+CMGD=${slot}\r`); 72 await writeToPortAndWaitForOK(`AT+CMGD=${slot}\r`);
73 port.unpipe(parserWaitForOK); 73 port.unpipe(parserWaitForOK);
74 74
75 logger.info('Message processing has completed'); 75 logger.info('Message processing has completed');
76 } 76 }
77 77
78 function onIncomingSMS(data) { 78 function onIncomingSMS(data) {
79 const value = common.extractValueFromReadLineData(data); 79 const value = common.extractValueFromReadLineData(data);
80 if (!value) return; 80 if (!value) return;
81 81
82 const chunks = value.split(','); 82 const chunks = value.split(',');
83 if (!chunks && !chunks[1]) return; 83 if (!chunks && !chunks[1]) return;
84 84
85 const slot = chunks[1]; 85 const slot = chunks[1];
86 86
87 logger.info(`Incoming SMS on slot ${slot}`); 87 logger.info(`Incoming SMS on slot ${slot}`);
88 readSMS(slot); 88 readSMS(slot);
89 } 89 }
90 90
91 function onCOPS(data) { 91 function onCOPS(data) {
92 modemInfo.cops = common.extractValueFromReadLineData(data).trim(); 92 modemInfo.cops = common.extractValueFromReadLineData(data).trim();
93 logger.info(`Connected Network: ${modemInfo.cops}`); 93 logger.info(`Connected Network: ${modemInfo.cops}`);
94 94
95 if (!modemInfo.cops) return; 95 if (!modemInfo.cops) return;
96 96
97 [, , modemInfo.networkId] = modemInfo.cops.split(','); 97 [, , modemInfo.networkId] = modemInfo.cops.split(',');
98 98
99 if (modemInfo.networkId) { 99 if (modemInfo.networkId) {
100 modemInfo.networkName = dbCops[modemInfo.networkId]; 100 modemInfo.networkName = dbCops[modemInfo.networkId];
101 } 101 }
102 } 102 }
103 103
104 parserReadLine.on('data', (data) => { 104 parserReadLine.on('data', (data) => {
105 logger.verbose(`* IN: ${data}`); 105 logger.verbose(`* IN: ${data}`);
106 if (data) { 106 if (data) {
107 if (data.indexOf('+CSQ: ') === 0) { 107 if (data.indexOf('+CSQ: ') === 0) {
108 modemInfo.signalStrength = common.extractValueFromReadLineData(data).trim(); 108 modemInfo.signalStrength = common.extractValueFromReadLineData(data).trim();
109 logger.info(`Signal strength: ${modemInfo.signalStrength}`); 109 logger.info(`Signal strength: ${modemInfo.signalStrength}`);
110 } else if (data.indexOf('+CMTI: ') === 0) { 110 } else if (data.indexOf('+CMTI: ') === 0) {
111 onIncomingSMS(data); 111 onIncomingSMS(data);
112 } else if (data.indexOf('+COPS: ') === 0) { 112 } else if (data.indexOf('+COPS: ') === 0) {
113 onCOPS(data); 113 onCOPS(data);
114 } 114 }
115 } 115 }
116 }); 116 });
117 117
118 parserWaitForOK.on('data', () => { 118 parserWaitForOK.on('data', () => {
119 mutex.releaseLockWaitForOK(); 119 mutex.releaseLockWaitForOK();
120 }); 120 });
121 121
122 function simpleCommand(cmd, callback) { 122 function simpleCommand(cmd, callback) {
123 const parser = new ParserDelimiter({ delimiter: DELIMITER_WAIT_FOR_OK }); 123 const parser = new ParserDelimiter({ delimiter: DELIMITER_WAIT_FOR_OK });
124 parser.on('data', (data) => { 124 parser.on('data', (data) => {
125 port.unpipe(parser); 125 port.unpipe(parser);
126 mutex.releaseLockWaitForOK(); 126 mutex.releaseLockWaitForOK();
127 127
128 if (data) { 128 if (data) {
129 callback(null, data.toString().trim()); 129 callback(null, data.toString().trim());
130 } 130 }
131 }); 131 });
132 132
133 port.pipe(parser); 133 port.pipe(parser);
134 writeToPortAndWaitForOK(cmd); 134 writeToPortAndWaitForOK(cmd);
135 } 135 }
136 136
137 function readManufacturer() { 137 function readManufacturer() {
138 return new Promise((resolve) => { 138 return new Promise((resolve) => {
139 simpleCommand('AT+CGMI\r', (err, result) => { 139 simpleCommand('AT+CGMI\r', (err, result) => {
140 modemInfo.manufacturer = result; 140 modemInfo.manufacturer = result;
141 logger.info(`Manufacturer: ${result}`); 141 logger.info(`Manufacturer: ${result}`);
142 resolve(result); 142 resolve(result);
143 }); 143 });
144 }); 144 });
145 } 145 }
146 146
147 function readModel() { 147 function readModel() {
148 return new Promise((resolve) => { 148 return new Promise((resolve) => {
149 simpleCommand('AT+CGMM\r', (err, result) => { 149 simpleCommand('AT+CGMM\r', (err, result) => {
150 modemInfo.model = result; 150 modemInfo.model = result;
151 logger.info(`Model: ${result}`); 151 logger.info(`Model: ${result}`);
152 resolve(result); 152 resolve(result);
153 }); 153 });
154 }); 154 });
155 } 155 }
156 156
157 function readIMEI() { 157 function readIMEI() {
158 return new Promise((resolve) => { 158 return new Promise((resolve) => {
159 simpleCommand('AT+CGSN\r', (err, result) => { 159 simpleCommand('AT+CGSN\r', (err, result) => {
160 modemInfo.imei = result; 160 modemInfo.imei = result;
161 logger.info(`IMEI: ${result}`); 161 logger.info(`IMEI: ${result}`);
162 resolve(result); 162 resolve(result);
163 }); 163 });
164 }); 164 });
165 } 165 }
166 166
167 function readIMSI() { 167 function readIMSI() {
168 return new Promise((resolve) => { 168 return new Promise((resolve) => {
169 simpleCommand('AT+CIMI\r', (err, result) => { 169 simpleCommand('AT+CIMI\r', (err, result) => {
170 modemInfo.imsi = result; 170 modemInfo.imsi = result;
171 logger.info(`IMSI: ${result}`); 171 logger.info(`IMSI: ${result}`);
172 resolve(result); 172 resolve(result);
173 }); 173 });
174 }); 174 });
175 } 175 }
176 176
177 async function querySignalStrength() { 177 async function querySignalStrength() {
178 port.pipe(parserWaitForOK); 178 port.pipe(parserWaitForOK);
179 await writeToPortAndWaitForOK('AT+CSQ\r'); 179 await writeToPortAndWaitForOK('AT+CSQ\r');
180 port.unpipe(parserWaitForOK); 180 port.unpipe(parserWaitForOK);
181 } 181 }
182 182
183 async function registerSignalStrengthBackgroundQuery() { 183 async function registerSignalStrengthBackgroundQuery() {
184 logger.info('Registering background signal strength query'); 184 logger.info('Registering background signal strength query');
185 185
186 setInterval(() => { 186 setInterval(() => {
187 querySignalStrength(); 187 querySignalStrength();
188 }, INTERVAL_BEETWEN_SIGNAL_STRENGTH_MS); 188 }, INTERVAL_BEETWEN_SIGNAL_STRENGTH_MS);
189 } 189 }
190 190
191 async function sendSMS(destination, msg) { 191 async function sendSMS(destination, msg) {
192 if (typeof destination !== 'string' || typeof msg !== 'string' || !destination.trim() || !msg.trim()) return;
193
192 await mutex.setLockWaitForCommand(); 194 await mutex.setLockWaitForCommand();
193 logger.info('Sending message', { destination, msg }); 195 logger.info('Sending message', { destination, msg });
194 196
195 const correctedDestination = `+${destination}`.replace(/^0/, '62').replace(/^\++/, '+'); 197 const correctedDestination = `+${destination}`.replace(/^0/, '62').replace(/^\++/, '+');
196 198
197 port.pipe(parserWaitForOK); 199 port.pipe(parserWaitForOK);
198 await writeToPortAndWaitForOK('AT+CMGF=1\r'); 200 await writeToPortAndWaitForOK('AT+CMGF=1\r');
199 await writeToPortAndWaitForOK(`AT+CMGS="${correctedDestination}"\n${msg}${Buffer.from([0x1A])}`); 201 await writeToPortAndWaitForOK(`AT+CMGS="${correctedDestination}"\n${msg}${Buffer.from([0x1A])}`);
200 port.unpipe(parserWaitForOK); 202 port.unpipe(parserWaitForOK);
201 203
202 logger.info('Message has been sent'); 204 logger.info('Message has been sent');
203 205
204 mutex.releaseLockWaitForCommand(); 206 mutex.releaseLockWaitForCommand();
205 } 207 }
206 208
207 function init() { 209 function init() {
208 port.on('open', async () => { 210 port.on('open', async () => {
209 port.pipe(parserWaitForOK); 211 port.pipe(parserWaitForOK);
210 212
211 logger.info('Modem opened'); 213 logger.info('Modem opened');
212 await writeToPortAndWaitForOK('AT\r'); 214 await writeToPortAndWaitForOK('AT\r');
213 215
214 logger.info('Initializing modem to factory set'); 216 logger.info('Initializing modem to factory set');
215 await writeToPortAndWaitForOK('AT&F\r'); 217 await writeToPortAndWaitForOK('AT&F\r');
216 218
217 logger.info('Disabling echo'); 219 logger.info('Disabling echo');
218 await writeToPortAndWaitForOK('ATE0\r'); 220 await writeToPortAndWaitForOK('ATE0\r');
219 221
220 await writeToPortAndWaitForOK('AT+COPS?\r'); 222 await writeToPortAndWaitForOK('AT+COPS?\r');
221 223
222 logger.info('Querying signal strength'); 224 logger.info('Querying signal strength');
223 await writeToPortAndWaitForOK('AT+CSQ\r'); 225 await writeToPortAndWaitForOK('AT+CSQ\r');
224 226
225 logger.info('Deleting existing messages'); 227 logger.info('Deleting existing messages');
226 // await writeToPortAndWaitForOK('AT+CMGD=0,4\r'); 228 // await writeToPortAndWaitForOK('AT+CMGD=0,4\r');
227 229
228 await readManufacturer(); 230 await readManufacturer();
229 await readModel(); 231 await readModel();
230 await readIMEI(); 232 await readIMEI();
231 await readIMSI(); 233 await readIMSI();
232 234
233 port.unpipe(parserWaitForOK); 235 port.unpipe(parserWaitForOK);
234 236
235 registerSignalStrengthBackgroundQuery(); 237 registerSignalStrengthBackgroundQuery();
236 logger.verbose('Init completed'); 238 logger.verbose('Init completed');
237 }); 239 });
238 } 240 }
239 241
240 init(); 242 init();
241 243
242 exports.modemInfo = modemInfo; 244 exports.modemInfo = modemInfo;
243 exports.sendSMS = sendSMS; 245 exports.sendSMS = sendSMS;
244 246
1 'use strict'; 1 'use strict';
2 2
3 const locks = require('locks'); 3 const locks = require('locks');
4 4
5 const mutexWaitForOK = locks.createMutex(); 5 const mutexWaitForOK = locks.createMutex();
6 const mutexCommand = locks.createMutex(); 6 const mutexCommand = locks.createMutex();
7 7
8 function setLockWaitForOK() { 8 function setLockWaitForOK() {
9 return new Promise((resolve) => { 9 return new Promise((resolve) => {
10 mutexWaitForOK.lock(() => { 10 mutexWaitForOK.lock(() => {
11 resolve(true); 11 resolve(true);
12 }); 12 });
13 }); 13 });
14 } 14 }
15 15
16 function releaseLockWaitForOK() { 16 function releaseLockWaitForOK() {
17 try { 17 try {
18 mutexWaitForOK.unlock(); 18 mutexWaitForOK.unlock();
19 } catch (e) { 19 } catch (e) {
20 // 20 //
21 } 21 }
22 } 22 }
23 23
24 function setLockWaitForCommand() { 24 function setLockWaitForCommand() {
25 return new Promise((resolve) => { 25 return new Promise((resolve) => {
26 mutexCommand.lock(() => { 26 mutexCommand.lock(() => {
27 resolve(true); 27 resolve(true);
28 }); 28 });
29 }); 29 });
30 } 30 }
31 31
32 function releaseLockWaitForCommand() { 32 function releaseLockWaitForCommand() {
33 setTimeout(() => { 33 setTimeout(() => {
34 try { 34 try {
35 mutexCommand.unlock(); 35 mutexCommand.unlock();
36 } catch (e) { 36 } catch (e) {
37 // 37 //
38 } 38 }
39 }, 1500); 39 }, 2000);
40 } 40 }
41 41
42 exports.setLockWaitForOK = setLockWaitForOK; 42 exports.setLockWaitForOK = setLockWaitForOK;
43 exports.releaseLockWaitForOK = releaseLockWaitForOK; 43 exports.releaseLockWaitForOK = releaseLockWaitForOK;
44 44
45 exports.setLockWaitForCommand = setLockWaitForCommand; 45 exports.setLockWaitForCommand = setLockWaitForCommand;
46 exports.releaseLockWaitForCommand = releaseLockWaitForCommand; 46 exports.releaseLockWaitForCommand = releaseLockWaitForCommand;
47 47