diff --git a/index.js b/index.js index 5463af4..4065208 100644 --- a/index.js +++ b/index.js @@ -25,4 +25,6 @@ global.KOMODO_LOG_LABEL = (typeof config.name === 'string' && config.name.trim() : `KOMODO-MODEM@${path.basename(config.modem.device).replace('tty', '').toUpperCase()}`; require('./lib/http-command-server'); -require('./lib/modem'); + +// require('./lib/modem'); +require('./lib/bootstrap'); diff --git a/lib/bootstrap.js b/lib/bootstrap.js index 045e531..c8fd9d0 100644 --- a/lib/bootstrap.js +++ b/lib/bootstrap.js @@ -1,9 +1,12 @@ /** * Modul modem bootstrap - * @module bootstrap + * @module * @since 2019-09-25 */ +const DEFAULT_BAUDRATE = 115200; + +const fs = require('fs'); const SerialPort = require('serialport'); const config = require('komodo-sdk/config'); @@ -11,14 +14,32 @@ const logger = require('komodo-sdk/logger'); const parsers = require('./serialport-parsers'); const modemCommands = require('./modem-commands'); +const ussdCodes = require('./modem-commands/ussd-codes'); + const modemInfo = require('./modem-info'); +const registerModem = require('./register-modem'); + +logger.info('Bootstraping modem'); -const port = new SerialPort(config.modem.device, { baudRate: 115200 }, async (err) => { +if (!fs.existsSync(config.modem.device)) { + logger.error(`Modem not found on ${config.modem.device}. Terminating.`); + process.exit(1); +} + +const port = new SerialPort(config.modem.device, { + baudRate: (config.modem && config.modem.options && config.modem.options.baudRate) + || DEFAULT_BAUDRATE, +}, async (err) => { if (err) { logger.warn(`Error opening modem. ${err}. Terminating modem ${config.modem.device}.`); process.exit(1); } + global.MODEM_PORT = port; + parsers.setPort(port); + // modemCommands.setPort(port); + port.pipe(parsers.parserReadline); + await modemCommands.writeToPortAndWaitForOkOrError(`${modemCommands.CTRLZ}AT&FE0\r`); await modemCommands.initATCommands(); await modemCommands.queryManufacturer(); @@ -27,6 +48,22 @@ const port = new SerialPort(config.modem.device, { baudRate: 115200 }, async (er await modemCommands.queryCOPSAndSignalQuality(); logger.info('Modem state', modemInfo); + registerModem(); + + if (config.debug_sms_destination_on_start) { + await modemCommands.sendSMS(config.debug_sms_destination_on_start, + `${config.name} (${modemInfo.imsi || 'UNKNOWN'}) started on ${new Date()}`); + } + + if (config.debug_ussd_code_on_start) { + const ussdResponse = await modemCommands.executeUSSD(config.debug_ussd_code_on_start, 2); + logger.info('USSD RESPONSE', { command: config.debug_ussd_code_on_start, ussdResponse }); + } + + if ((modemInfo.networkName && modemInfo.networkName === 'TELKOMSEL') || config.bootstrap_tsel_sms_quota_check) { + const ussdResponse = await modemCommands.executeUSSD(ussdCodes.TSEL_SMS_QUOTA_CHECK, 1); + logger.info('USSD RESPONSE', { command: config.debug_ussd_code_on_start, ussdResponse }); + } setInterval(async () => { await modemCommands.initATCommands(); @@ -35,10 +72,6 @@ const port = new SerialPort(config.modem.device, { baudRate: 115200 }, async (er await modemCommands.queryIMEIAndIMSI(); await modemCommands.queryCOPSAndSignalQuality(); logger.info('Modem state', modemInfo); + registerModem(); }, config.interval_beetwen_signal_strength_ms || 30000); }); - -global.MODEM_PORT = port; -parsers.setPort(port); -modemCommands.setPort(port); -port.pipe(parsers.parserReadline); diff --git a/lib/http-command-server/router-sms.js b/lib/http-command-server/router-sms.js index 00e8c32..4585d0b 100644 --- a/lib/http-command-server/router-sms.js +++ b/lib/http-command-server/router-sms.js @@ -2,7 +2,8 @@ const express = require('express'); -const modem = require('../modem'); +// const modem = require('../modem'); +const modem = require('../modem-commands'); const router = express.Router(); module.exports = router; diff --git a/lib/modem-commands/index.js b/lib/modem-commands/index.js index 293d291..e765d30 100644 --- a/lib/modem-commands/index.js +++ b/lib/modem-commands/index.js @@ -301,7 +301,7 @@ function sendSMS(destination, msg) { logger.verbose('SMS sent callback called', { data }); if (data.indexOf('ERROR') >= 0 || data.indexOf('+CMS ERROR') >= 0 || data.indexOf('+CMGS') >= 0) { - logger.verbose('SMS sent'); + logger.info('SMS sent', { data }); parsers.setSmsSentCallback(null); mutex.unlock(MUTEX_COMMAND, 'sendSMS'); resolve(data.indexOf('ERROR') >= 0 ? null : data.toString().trim()); @@ -321,7 +321,7 @@ function sendSMS(destination, msg) { } const correctedDestination = `+${destination.replace(/^0/, '62')}`.replace(/^\++/, '+'); - logger.verbose(`Sending sms to ${correctedDestination}`, { msg }); + logger.info(`Sending sms to ${correctedDestination}`, { msg, length: msg.length }); await this.writeToPortAndWaitForOkOrError('AT+CMGF=0\r', MUTEX_SUBCOMMAND); diff --git a/lib/modem-commands/ussd-codes.js b/lib/modem-commands/ussd-codes.js new file mode 100644 index 0000000..d331913 --- /dev/null +++ b/lib/modem-commands/ussd-codes.js @@ -0,0 +1 @@ +exports.TSEL_SMS_QUOTA_CHECK = '*888*2*2*4#'; diff --git a/lib/modem.js b/lib/modem.js index 97bd969..d36e877 100644 --- a/lib/modem.js +++ b/lib/modem.js @@ -5,6 +5,7 @@ * * @module * @deprecated going to move to module:bootstrap + * @see module:bootstrap */ const DEFAULT_SLEEP_AFTER_SEND_SMS_MS = 2000; @@ -13,6 +14,7 @@ const MAX_LAST_DATA_AGE_MS = 3 * 60 * 1000; const REGEX_WAIT_FOR_OK_OR_ERROR = /\n(?:OK|ERROR)\r/; // const REGEX_WAIT_FOR_OK_OR_ERROR_USSD = /\n(?:OK|ERROR)\r/; +const path = require('path'); const moment = require('moment'); const SerialPort = require('serialport'); const ParserReadline = require('@serialport/parser-readline'); @@ -23,6 +25,11 @@ const ParserRegex = require('@serialport/parser-regex'); const config = require('komodo-sdk/config'); const logger = require('komodo-sdk/logger'); +// const stack = new Error().stack; +logger.warn(`'${path.basename(__filename, '.js')}' is DEPRECATED, please use 'modem-commands'!`); +// eslint-disable-next-line no-console +console.trace(`'${path.basename(__filename, '.js')}' is DEPRECATED, please use 'modem-commands'!`); + const mutex = require('./mutex'); const common = require('./common'); const sms = require('./sms'); @@ -30,20 +37,7 @@ const dbCops = require('./db-cops'); const reportSender = require('./report-sender'); const registerModem = require('./register-modem'); -const modemInfo = { - device: config.modem.device, - manufacturer: null, - model: null, - imei: null, - imsi: null, - msisdn: null, - cops: null, - networkId: null, - networkName: null, - signalStrength: null, - signalStrengthTs: null, - signalStrengthTsReadable: null, -}; +const modemInfo = require('./modem-info'); let lastTs = new Date(); diff --git a/lib/register-modem.js b/lib/register-modem.js index d58c0d8..dda773c 100644 --- a/lib/register-modem.js +++ b/lib/register-modem.js @@ -8,6 +8,8 @@ const locks = require('locks'); const config = require('komodo-sdk/config'); const logger = require('komodo-sdk/logger'); +const modemInfo = require('./modem-info'); + const mutex = locks.createMutex(); function reportUrl() { @@ -19,7 +21,7 @@ function reportUrl() { return `${baseUrl}/modems/set`; } -function sender(modemInfo) { +function sender() { if (mutex.tryLock()) { const requestOptions = { url: reportUrl(), diff --git a/lib/report-sender2.js b/lib/report-sender2.js new file mode 100644 index 0000000..e50d3ea --- /dev/null +++ b/lib/report-sender2.js @@ -0,0 +1,45 @@ +const request = require('request'); + +const config = require('komodo-sdk/config'); +const logger = require('komodo-sdk/logger'); +const modemInfo = require('./modem-info'); + +function incomingSMS(ts, from, msg) { + if (!ts || !from || !msg + || !config || !config.report_url || !config.report_url.incoming_sms) return; + + const requestOptions = { + url: config.report_url.incoming_sms, + qs: { + ts, + // status: message.metadata.status, + number: from, + msg, + modem: config.name, + modem_imsi: modemInfo.imsi, + modem_msisdn: modemInfo.msisdn, + modem_device: config.modem.device, + modem_network_id: modemInfo.networkId, + modem_network_name: modemInfo.networkName, + modem_signal_strength: modemInfo.signalStrength, + uptime: Math.floor(process.uptime()), + report_port: config.http_command_server.listen_port, + report_apikey: config.http_command_server.apikey, + report_path_sms: '/sms', + }, + }; + + logger.info('Sending report via HTTP', requestOptions); + request(requestOptions, (err, res, body) => { + if (err) { + logger.warn(`Error sending report via HTTP. ${err.toString()}`); + return; + } + + if (res.statusCode !== 200) { + logger.warn(`Error sending report via HTTP. Server respond with HTTP status code ${res.statusCode}`, { http_status_code: res.statusCode, body }); + } + }); +} + +exports.incomingSMS = incomingSMS; diff --git a/lib/serialport-parsers.js b/lib/serialport-parsers.js index 719ccae..5f5a5a4 100644 --- a/lib/serialport-parsers.js +++ b/lib/serialport-parsers.js @@ -11,6 +11,7 @@ const logger = require('komodo-sdk/logger'); const dbCops = require('./db-cops'); const modemInfo = require('./modem-info'); +const reportSender = require('./report-sender2'); let port; @@ -88,7 +89,7 @@ function onPduDeliver(data, parsedData) { const ts = new Date(parsedData.getScts().getIsoString()); logger.verbose('PDU processed', { ts, from, msg }); - return { from, msg }; + return { ts, from, msg }; } function onCOPS(data) { @@ -149,7 +150,13 @@ parserReadline.on('data', (data) => { if (pduParsed && pduParsed.constructor.name === 'Deliver' && pduParsed.getData().getSize()) { const pduType = pduParsed.getType(); logger.verbose('Got a PDU SMS-DELIVER', { pduType }); - onPduDeliver(data, pduParsed); + const parsedData = onPduDeliver(data, pduParsed); + + if (parsedData.ts && parsedData.from && parsedData.msg) { + reportSender.incomingSMS(parsedData.ts, parsedData.from, parsedData.msg); + } else { + logger.warn('Got a PDU SMS-DELIVER but failed on parsing PDU message'); + } } else if (data.toString().trim() === 'ERROR') { if (typeof smsSentCallback === 'function') smsSentCallback(data.toString()); } else if (isResultCodeIs(data, 'CSQ')) { diff --git a/modem-tester.js b/modem-tester.js index bf9bb00..ebba906 100644 --- a/modem-tester.js +++ b/modem-tester.js @@ -33,13 +33,14 @@ const port = new SerialPort(config.modem.device, { baudRate: 115200 }, async (er await modemCommands.queryCOPSAndSignalQuality(); logger.info('Modem state', modemInfo); - // await modemCommands.sendSMS('628128364883', `coba pakai pdu ${new Date()}`); - // await modemCommands.sendSMS('+6282210008543', `coba pakai pdu ${new Date()}`); - // await modemCommands.sendSMS('6281809903333', `coba pakai pdu ${new Date()}`); - await modemCommands.sendSMS('999', `coba pakai pdu ${new Date()}`); + if (config.debug_sms_destination_on_start) { + await modemCommands.sendSMS(config.debug_sms_destination_on_start, `${modemInfo.imsi || 'UNKNOWN'}: coba pakai pdu ${new Date()}`); + } - // const ussdResponse = await modemCommands.executeUSSD('*888#', 2); - // logger.info('USSD RESPONSE', { ussdResponse }); + if (config.debug_ussd_code_on_start) { + const ussdResponse = await modemCommands.executeUSSD(config.debug_ussd_code_on_start, 2); + logger.info('USSD RESPONSE', { command: config.debug_ussd_code_on_start, ussdResponse }); + } setInterval(async () => { await modemCommands.initATCommands(); @@ -53,7 +54,7 @@ const port = new SerialPort(config.modem.device, { baudRate: 115200 }, async (er global.MODEM_PORT = port; parsers.setPort(port); -modemCommands.setPort(port); +// modemCommands.setPort(port); if (config && config.modem_tester && config.modem_tester.parser === 'regex') { logger.info('Using parserWaitForOkOrError'); diff --git a/package.json b/package.json index b18a827..47e4bf6 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "test": "mocha", - "postversion": "git push && git push --tags" + "postversion": "git push && git push --tags", + "jsdoc": "./generate-jsdoc.sh" }, "repository": { "type": "git",