Commit 4a065542a06cb41dff7e3c8a87b4c557ec0b4510
1 parent
7f4bf40722
Exists in
master
another debug
Showing 1 changed file with 1 additions and 0 deletions Inline Diff
lib/modem/index.js
1 | "use strict"; | 1 | "use strict"; |
2 | 2 | ||
3 | const fs = require('fs'); | 3 | const fs = require('fs'); |
4 | const EventEmitter = require('events'); | 4 | const EventEmitter = require('events'); |
5 | const os = require('os'); | 5 | const os = require('os'); |
6 | 6 | ||
7 | const moment = require('moment'); | 7 | const moment = require('moment'); |
8 | 8 | ||
9 | const SerialPort = require('serialport'); | 9 | const SerialPort = require('serialport'); |
10 | const Readline = require('@serialport/parser-readline'); | 10 | const Readline = require('@serialport/parser-readline'); |
11 | const Delimiter = require('@serialport/parser-delimiter'); | 11 | const Delimiter = require('@serialport/parser-delimiter'); |
12 | const jsesc = require('jsesc'); | 12 | const jsesc = require('jsesc'); |
13 | 13 | ||
14 | const logger = require('komodo-sdk/logger'); | 14 | const logger = require('komodo-sdk/logger'); |
15 | 15 | ||
16 | const smsParser = require('./sms-parser'); | 16 | const smsParser = require('./sms-parser'); |
17 | 17 | ||
18 | const SIGNAL_STRENGTH_INTERVAL_MS = 60 * 1000; | 18 | const SIGNAL_STRENGTH_INTERVAL_MS = 60 * 1000; |
19 | 19 | ||
20 | fs.existsSync('logs/') || fs.mkdirSync('logs/'); | 20 | fs.existsSync('logs/') || fs.mkdirSync('logs/'); |
21 | const debugLogWriter = process.env.KOMODO_DEBUG_MODEM ? fs.createWriteStream('logs/log-debug-modem.txt', { flags: 'a' }) : null; | 21 | const debugLogWriter = process.env.KOMODO_DEBUG_MODEM ? fs.createWriteStream('logs/log-debug-modem.txt', { flags: 'a' }) : null; |
22 | 22 | ||
23 | function debugLog(msg) { | 23 | function debugLog(msg) { |
24 | if (debugLogWriter) { | 24 | if (debugLogWriter) { |
25 | debugLogWriter.write(msg + os.EOL); | 25 | debugLogWriter.write(msg + os.EOL); |
26 | } | 26 | } |
27 | } | 27 | } |
28 | 28 | ||
29 | 29 | ||
30 | class Modem extends EventEmitter { | 30 | class Modem extends EventEmitter { |
31 | constructor(portName) { | 31 | constructor(portName) { |
32 | super(); | 32 | super(); |
33 | this.portName = portName; | 33 | this.portName = portName; |
34 | } | 34 | } |
35 | 35 | ||
36 | open(cb) { | 36 | open(cb) { |
37 | const self = this; | 37 | const self = this; |
38 | 38 | ||
39 | debugLog('MODEM: opening ' + this.portName); | 39 | debugLog('MODEM: opening ' + this.portName); |
40 | this.port = new SerialPort(this.portName); | 40 | this.port = new SerialPort(this.portName); |
41 | 41 | ||
42 | this.port.on('error', function(err) { | 42 | this.port.on('error', function(err) { |
43 | debugLog('MODEM: error opening ' + this.portName); | ||
43 | if (cb) cb(err); | 44 | if (cb) cb(err); |
44 | }); | 45 | }); |
45 | 46 | ||
46 | this.port.on('open', function() { | 47 | this.port.on('open', function() { |
47 | self.resetModem(function() { | 48 | self.resetModem(function() { |
48 | self.getIMSI(function() { | 49 | self.getIMSI(function() { |
49 | self.emit('open'); | 50 | self.emit('open'); |
50 | self.getSignalStrength(cb); | 51 | self.getSignalStrength(cb); |
51 | 52 | ||
52 | setInterval(function() { | 53 | setInterval(function() { |
53 | self.getSignalStrength(); | 54 | self.getSignalStrength(); |
54 | }, SIGNAL_STRENGTH_INTERVAL_MS) | 55 | }, SIGNAL_STRENGTH_INTERVAL_MS) |
55 | 56 | ||
56 | }) | 57 | }) |
57 | }); | 58 | }); |
58 | 59 | ||
59 | }); | 60 | }); |
60 | 61 | ||
61 | 62 | ||
62 | } | 63 | } |
63 | 64 | ||
64 | resetParserToDefault() { | 65 | resetParserToDefault() { |
65 | const self = this; | 66 | const self = this; |
66 | //this.port.unpipe(this.parser); | 67 | //this.port.unpipe(this.parser); |
67 | if (this.parser) { this.port.unpipe(this.parser)}; | 68 | if (this.parser) { this.port.unpipe(this.parser)}; |
68 | this.parser = this.port.pipe(new Readline()); | 69 | this.parser = this.port.pipe(new Readline()); |
69 | 70 | ||
70 | this.parser.on('data', function(data) { | 71 | this.parser.on('data', function(data) { |
71 | if (!data) return; | 72 | if (!data) return; |
72 | 73 | ||
73 | debugLog('PARSER-DEFAULT: ' + data); | 74 | debugLog('PARSER-DEFAULT: ' + data); |
74 | 75 | ||
75 | if (data.indexOf('+CMTI:') === 0) { | 76 | if (data.indexOf('+CMTI:') === 0) { |
76 | self.onSMS(data); | 77 | self.onSMS(data); |
77 | } | 78 | } |
78 | else if (data.indexOf('+CUSD:') === 0) { | 79 | else if (data.indexOf('+CUSD:') === 0) { |
79 | self.onUSSDResponse(data); | 80 | self.onUSSDResponse(data); |
80 | } | 81 | } |
81 | if (data.indexOf('+CSQ:') === 0) { | 82 | if (data.indexOf('+CSQ:') === 0) { |
82 | debugLog('*** Got CSQ signal strength response'); | 83 | debugLog('*** Got CSQ signal strength response'); |
83 | self.onSignalStrength(data); | 84 | self.onSignalStrength(data); |
84 | } | 85 | } |
85 | 86 | ||
86 | }); | 87 | }); |
87 | } | 88 | } |
88 | 89 | ||
89 | _write(...args) { | 90 | _write(...args) { |
90 | debugLog('COMMAND: ' + args[0]); | 91 | debugLog('COMMAND: ' + args[0]); |
91 | this.port.write(...args); | 92 | this.port.write(...args); |
92 | this.port.drain(); | 93 | this.port.drain(); |
93 | } | 94 | } |
94 | 95 | ||
95 | write(data) { | 96 | write(data) { |
96 | debugLog('COMMAND: ' + data); | 97 | debugLog('COMMAND: ' + data); |
97 | this.port.write(data); | 98 | this.port.write(data); |
98 | this.port.drain(); | 99 | this.port.drain(); |
99 | } | 100 | } |
100 | 101 | ||
101 | getPort() { | 102 | getPort() { |
102 | return this.port; | 103 | return this.port; |
103 | } | 104 | } |
104 | 105 | ||
105 | onUSSDResponse(data) { | 106 | onUSSDResponse(data) { |
106 | debugLog('USSD-RESPONSE: ' + data); | 107 | debugLog('USSD-RESPONSE: ' + data); |
107 | this.emit('ussd response', data); | 108 | this.emit('ussd response', data); |
108 | } | 109 | } |
109 | 110 | ||
110 | onSMS(data) { | 111 | onSMS(data) { |
111 | const self = this; | 112 | const self = this; |
112 | const port = this.port; | 113 | const port = this.port; |
113 | 114 | ||
114 | const matches = data.match(/,(\d+)\s*$/); | 115 | const matches = data.match(/,(\d+)\s*$/); |
115 | if (!matches || matches.length < 2) { | 116 | if (!matches || matches.length < 2) { |
116 | return; | 117 | return; |
117 | } | 118 | } |
118 | 119 | ||
119 | const slot = matches[1]; | 120 | const slot = matches[1]; |
120 | //console.log('*** Ada SMS masuk di slot ' + slot); | 121 | //console.log('*** Ada SMS masuk di slot ' + slot); |
121 | 122 | ||
122 | if (!slot) { | 123 | if (!slot) { |
123 | debugLog('*** Gagal deteksi slot sms') | 124 | debugLog('*** Gagal deteksi slot sms') |
124 | return; | 125 | return; |
125 | } | 126 | } |
126 | 127 | ||
127 | if (this.parser) { this.port.unpipe(this.parser)}; | 128 | if (this.parser) { this.port.unpipe(this.parser)}; |
128 | const parser = this.port.pipe(new Delimiter({ delimiter: '\r\nOK\r\n' })) | 129 | const parser = this.port.pipe(new Delimiter({ delimiter: '\r\nOK\r\n' })) |
129 | 130 | ||
130 | parser.on('data', function(data) { | 131 | parser.on('data', function(data) { |
131 | self.parseSMS(data); | 132 | self.parseSMS(data); |
132 | self.port.unpipe(parser); | 133 | self.port.unpipe(parser); |
133 | self.resetParserToDefault(); | 134 | self.resetParserToDefault(); |
134 | 135 | ||
135 | self.write('AT+CMGD=' + slot + '\r'); | 136 | self.write('AT+CMGD=' + slot + '\r'); |
136 | }) | 137 | }) |
137 | 138 | ||
138 | this.write('AT+CMGR=' + slot + '\r'); | 139 | this.write('AT+CMGR=' + slot + '\r'); |
139 | } | 140 | } |
140 | 141 | ||
141 | parseSMS(data) { | 142 | parseSMS(data) { |
142 | data = data.toString().trim(); | 143 | data = data.toString().trim(); |
143 | //debugLog(jsesc(data, {wrap: true})); | 144 | //debugLog(jsesc(data, {wrap: true})); |
144 | debugLog('SMS-READ: ' + data); | 145 | debugLog('SMS-READ: ' + data); |
145 | const sms = smsParser.parseModemResponse(data); | 146 | const sms = smsParser.parseModemResponse(data); |
146 | this.emit('incoming sms', sms); | 147 | this.emit('incoming sms', sms); |
147 | } | 148 | } |
148 | 149 | ||
149 | resetModem(cb) { | 150 | resetModem(cb) { |
150 | const self = this; | 151 | const self = this; |
151 | 152 | ||
152 | if (this.parser) { this.port.unpipe(this.parser)}; | 153 | if (this.parser) { this.port.unpipe(this.parser)}; |
153 | const parser = this.port.pipe(new Delimiter({ delimiter: '\nOK\r\n' })); | 154 | const parser = this.port.pipe(new Delimiter({ delimiter: '\nOK\r\n' })); |
154 | 155 | ||
155 | parser.on('data', function(data) { | 156 | parser.on('data', function(data) { |
156 | const value = data.toString().replace(/^\s+/, '').replace(/\s+$/, ''); | 157 | const value = data.toString().replace(/^\s+/, '').replace(/\s+$/, ''); |
157 | 158 | ||
158 | debugLog('PARSER-RESETMODEM: modem reseted'); | 159 | debugLog('PARSER-RESETMODEM: modem reseted'); |
159 | 160 | ||
160 | self.port.unpipe(parser); | 161 | self.port.unpipe(parser); |
161 | self.resetParserToDefault(); | 162 | self.resetParserToDefault(); |
162 | 163 | ||
163 | if (cb) { | 164 | if (cb) { |
164 | cb(null, value); | 165 | cb(null, value); |
165 | } | 166 | } |
166 | }) | 167 | }) |
167 | 168 | ||
168 | this.write('AT &F Z E0\r'); | 169 | this.write('AT &F Z E0\r'); |
169 | } | 170 | } |
170 | 171 | ||
171 | getIMSI(cb) { | 172 | getIMSI(cb) { |
172 | const self = this; | 173 | const self = this; |
173 | const port = this.port; | 174 | const port = this.port; |
174 | 175 | ||
175 | if (this.parser) { this.port.unpipe(this.parser)}; | 176 | if (this.parser) { this.port.unpipe(this.parser)}; |
176 | const parser = this.port.pipe(new Delimiter({ delimiter: '\r\nOK\r\n' })) | 177 | const parser = this.port.pipe(new Delimiter({ delimiter: '\r\nOK\r\n' })) |
177 | 178 | ||
178 | parser.on('data', function(data) { | 179 | parser.on('data', function(data) { |
179 | self.imsi = data.toString().replace(/^\s+/, '').replace(/\s+$/, ''); | 180 | self.imsi = data.toString().replace(/^\s+/, '').replace(/\s+$/, ''); |
180 | debugLog('PARSER-IMSI: ' + self.imsi); | 181 | debugLog('PARSER-IMSI: ' + self.imsi); |
181 | 182 | ||
182 | self.port.unpipe(parser); | 183 | self.port.unpipe(parser); |
183 | self.resetParserToDefault(); | 184 | self.resetParserToDefault(); |
184 | 185 | ||
185 | self.emit('imsi', self.imsi); | 186 | self.emit('imsi', self.imsi); |
186 | 187 | ||
187 | if (cb) { | 188 | if (cb) { |
188 | cb(null, self.imsi); | 189 | cb(null, self.imsi); |
189 | } | 190 | } |
190 | }) | 191 | }) |
191 | 192 | ||
192 | this.write('AT+CIMI\r'); | 193 | this.write('AT+CIMI\r'); |
193 | } | 194 | } |
194 | 195 | ||
195 | getCOPS(cb) { | 196 | getCOPS(cb) { |
196 | const self = this; | 197 | const self = this; |
197 | 198 | ||
198 | /* | 199 | /* |
199 | const parser = this.port.pipe(new Delimiter({ delimiter: '\r\nOK\r\n' })) | 200 | const parser = this.port.pipe(new Delimiter({ delimiter: '\r\nOK\r\n' })) |
200 | 201 | ||
201 | parser.on('data', function(data) { | 202 | parser.on('data', function(data) { |
202 | const value = data.toString().replace(/^\s+/, '').replace(/\s+$/, ''); | 203 | const value = data.toString().replace(/^\s+/, '').replace(/\s+$/, ''); |
203 | debugLog('PARSER-COPS: ' + value); | 204 | debugLog('PARSER-COPS: ' + value); |
204 | self.port.unpipe(parser); | 205 | self.port.unpipe(parser); |
205 | if (cb) { | 206 | if (cb) { |
206 | cb(null, value); | 207 | cb(null, value); |
207 | } | 208 | } |
208 | }) | 209 | }) |
209 | */ | 210 | */ |
210 | 211 | ||
211 | //console.log('MODEM: sending AT+COPS?'); | 212 | //console.log('MODEM: sending AT+COPS?'); |
212 | this.write('AT+COPS?\r'); | 213 | this.write('AT+COPS?\r'); |
213 | } | 214 | } |
214 | 215 | ||
215 | sendUSSD(cmd, cb) { | 216 | sendUSSD(cmd, cb) { |
216 | const self = this; | 217 | const self = this; |
217 | const port = this.port; | 218 | const port = this.port; |
218 | 219 | ||
219 | //console.log('MODEM: ' + moment().format('HH:mm:ss') + ' *** Sending USSD command ' + cmd); | 220 | //console.log('MODEM: ' + moment().format('HH:mm:ss') + ' *** Sending USSD command ' + cmd); |
220 | this.write('AT+CUSD=1,"' + cmd + '",15\r'); | 221 | this.write('AT+CUSD=1,"' + cmd + '",15\r'); |
221 | } | 222 | } |
222 | 223 | ||
223 | onSignalStrength(data) { | 224 | onSignalStrength(data) { |
224 | if (typeof data !== 'string') { | 225 | if (typeof data !== 'string') { |
225 | debugLog('*** onSignalStrength data is not a string'); | 226 | debugLog('*** onSignalStrength data is not a string'); |
226 | return; | 227 | return; |
227 | } | 228 | } |
228 | const matches = data.match(/: (\d+),/); | 229 | const matches = data.match(/: (\d+),/); |
229 | if (matches.length < 2) return; | 230 | if (matches.length < 2) return; |
230 | 231 | ||
231 | this.emit('signal strength', Number(matches[1])); | 232 | this.emit('signal strength', Number(matches[1])); |
232 | } | 233 | } |
233 | 234 | ||
234 | getSignalStrength(cb) { | 235 | getSignalStrength(cb) { |
235 | this.write('AT+CSQ\r'); | 236 | this.write('AT+CSQ\r'); |
236 | 237 | ||
237 | if (cb) { cb() }; | 238 | if (cb) { cb() }; |
238 | } | 239 | } |
239 | } | 240 | } |
240 | 241 | ||
241 | module.exports = Modem; | 242 | module.exports = Modem; |
242 | 243 |