modem-commands
Version:
Allows you to use your GSM modems on node. It offers a very simple API
584 lines (541 loc) • 18.3 kB
JavaScript
let SerialPort = require('serialport')
let pdu = require('pdu')
let EventEmitter = require('events').EventEmitter
const Modem = function() {
let modem = new EventEmitter()
let data = ''
let resultData = {}
let timeouts = {}
let returnResult = false
modem.queue = []
modem.jobID = 1
modem.isLocked = false
modem.isOpened = false
modem.close = function(callback) {
if (callback == undefined) {
return new Promise((resolve, reject) => {
modem.close((error, result) => {
if (error) {
reject(error)
} else {
resolve(result)
}
})
})
}
modem.port.close(error => {
if (error) {
callback(error)
} else {
callback(null, {
status: 'success',
request: 'diconnectModem',
data: {
comName: modem.port.path,
status: 'Offline'
}
})
}
})
}
modem.open = function(device, options, callback) {
if (callback == undefined) {
return new Promise((resolve, reject) => {
modem.open((error, result) => {
if (error) {
reject(error)
} else {
resolve(result)
}
})
})
}
if (options) options['parser'] = SerialPort.parsers.raw
modem.port = SerialPort(device, options, (error) => {
let result = {status: 'success', request: 'connectModem', data: {modem: modem.port.path,status: 'Online'}}
if (error) {
callback(error)
} else {
modem.emit('open', result)
callback(null, result)
}
})
modem.port.on('open', function() {
modem.isOpened = true
modem.port.on('data', modem.dataReceived.bind(this))
})
modem.port.on('close', function() {
modem.emit('close', {
modem: modem.port.path
})
modem.isOpened = false
})
modem.port.on('error', function() {
modem.emit('error', {
modem: modem.port.path
})
modem.isOpened = false
})
}
modem.dataReceived = function(buffer) {
data += buffer.toString()
let parts = data.split('\r\n')
data = parts.pop()
parts.forEach(function(part) {
let newparts = []
newparts = part.split('\r')
newparts = part.split('\n')
newparts.forEach(function(newpart) {
let pduTest = /[0-9A-Fa-f]{6}/g
if (newpart.substr(0, 6) == '+CMTI:') { // New Message Indicatpr with SIM Card ID, After Recieving Read The DMessage From the SIM Card
newpart = newpart.split(',')
modem.ReadSMSByID(newpart[1], function(res) {})
}
if (modem.queue.length) {
if (modem.queue[0] && (modem.queue[0]['status'] == 'sendSMS')) { // If SMS is currently Sending Emit currently sending SMS
modem.emit('onSendingMessage', {
status: 'Sending SMS',
request: 'sendingSMS',
data: {
messageId: modem.queue[0]['messageID'],
message: modem.queue[0]['message'],
recipient: modem.queue[0]['recipient'],
response: 'Message Currently Sending'
}
})
modem.queue[0]['status'] = 'Sending SMS'
}
if (modem.queue[0] && (modem.queue[0]['command'] == `AT+CPMS='SM'`)) { // Query SIM Card Space Available
if (newpart.trim().substr(0, 6) === '+CPMS:') {
modem.parseSIMCardResponse(newpart, function(result) {
resultData = result
})
}
if ((newpart == ">" || newpart == 'OK') && resultData) {
returnResult = true
}
} else if (modem.queue[0] && (modem.queue[0]['command'] == 'AT+CMGD=1,4')) { // Delete All Data from SIM Card
if (newpart == 'OK') {
resultData = {
status: 'success',
request: 'deleteAllSimMessages',
data: 'success'
}
returnResult = true
}
} else if (modem.queue[0] && (modem.queue[0]['command'] == 'ATZ')) { // Query Modem AT to initialize
resultData = {
status: 'success',
request: 'modemInitialized',
data: 'Modem Successfully Initialized'
}
if ((newpart == ">" || newpart =="> " || newpart == 'OK') && resultData) {
returnResult = true
}
}else if (modem.queue[0] && (modem.queue[0]['command'] == 'AT+CSQ')) { // Query Modem AT to initialize
if(newpart.substr(0, 5)=='+CSQ:'){
var signal = newpart.split(' ');
signal = signal[1].split(',')
resultData = {
status: 'success',
request: 'getNetworkSignal',
data: {'signalQuality':signal[0]}
}
}
if ((newpart == ">" || newpart =="> " || newpart == 'OK') && resultData) {
returnResult = true
}else if(newpart == "ERROR"){
resultData = {
status: 'ERROR',
request: 'getNetworkSignal',
data: 'Cant Get Signal'
}
}
}else if (modem.queue[0] && (modem.queue[0]['command'] == 'AT+CGSN')) { // Query Modem AT to initialize
var isSerial = /^\d+$/.test(newpart);
if(isSerial){
resultData = {
status: 'success',
request: 'getModemSerial',
data: {'modemSerial':newpart}
}
}
if ((newpart == ">" || newpart =="> " || newpart == 'OK') && resultData) {
returnResult = true
}else if(newpart == 'ERROR'){
resultData = {
status: 'ERROR',
request: 'getModemSerial',
data: 'Cant Get Modem Seial Number'
}
returnResult = true
}
} else if (modem.queue[0] && (modem.queue[0]['command'] == 'AT+CMGF=0') || (modem.queue[0]['command'] == 'AT+CMGF=1')) { // PDU Mode for Modem .. Default PDU Mode to accomodate Long SMS
if (modem.queue[0]['command'].substr(8, 8) == '0') {
resultData = {
status: 'success',
request: 'modemMode',
data: 'PDU_Mode'
}
} else if (modem.queue[0]['command'].substr(8, 8) == '1') {
resultData = {
status: 'success',
request: 'modemMode',
data: 'SMS_Mode'
}
}
if ((newpart == ">" || newpart == 'OK') && resultData) {
returnResult = true
}
} else if (modem.queue[0] && (modem.queue[0]['command'].substr(0, 7) == 'AT+CMGS=' || pduTest.test(modem.queue[0]['command']))) { // Sending of Message if with response ok.. Then Message was sent successfully.. If Error then Message Sending Failed
resultData = {
status: 'success',
request: 'SendSMS',
data: {
messageId: modem.queue[0]['messageID'],
message: modem.queue[0]['message'],
recipient: modem.queue[0]['recipient'],
response: 'Message Successfully Sent'
}
}
if ((newpart == ">" || newpart == 'OK') && resultData) {
returnResult = true
}else if(newpart=='ERROR'){
resultData = {
status: 'Fail',
request: 'SendSMS',
data: {
messageId: modem.queue[0]['messageID'],
message: modem.queue[0]['message'],
recipient: modem.queue[0]['recipient'],
response: 'Message Failed'
}
}
returnResult = true
}
} else if (modem.queue[0] && (modem.queue[0]['command'].substr(0, 7) == 'AT+CMGR')) { // Get New Message From SIM Card
let re = /[0-9A-Fa-f]{6}/g
if (re.test(newpart)) {
let newMessage = pdu.parse(newpart)
resultData = {
sender: newMessage.sender,
timeSent: newMessage.time
}
var message = {
'seneder': newMessage.sender || null,
'message': newMessage.text || null,
'dateTimeSent': newMessage.time || null,
'dateTimeReceived': new Date(),
'header': {
'encoding': newMessage.encodinh || null,
'smsc': newMessage.smsc || null,
'smscType': newMessage.smsc_type || null,
'senderType':newMessage.sender_type || null,
'length': (newMessage.udh && newMessage.udh.length) || null,
'iei': (newMessage.udh && newMessage.udh.iei) || null,
'reference_number': (newMessage.udh && newMessage.udh.reference_number) || null,
'parts': (newMessage.udh && newMessage.udh.parts) || null,
'current_part': (newMessage.udh && newMessage.udh.current_part) || null,
}
}
modem.emit('onNewMessageIndicator', resultData)
modem.emit('onNewMessage', message)
}
re.lastIndex = 0 // be sure to reset the index after using .text()
if ((newpart == ">" || newpart == 'OK') && resultData) {
returnResult = true
}
}
let callback;
if (returnResult) { // Expected Result was ok or with error call back function that asked for the data or emit to listener, Execute next Command if any or Execute Next Command if TIME Out and modem did not respond
returnResult = false
if (modem.queue[0] && modem.queue[0]['callback']) {
callback = modem.queue[0]['callback']
} else {
callback = null
}
modem.queue[0]['end_time'] = new Date()
clearTimeout(timeouts[modem.queue[0].id])
modem.release()
if (callback) {
callback(resultData)
}
resultData = null
modem.executeNext()
}
}
})
})
}
modem.ReadSMSByID = function(id, callback) {
if (callback == undefined) {
return new Promise((resolve, reject) => {
modem.ReadSMSByID((error, result) => {
if (error) {
reject(error)
} else {
resolve(result)
}
})
})
}
modem.executeCommand(`AT+CMGR=${id}`, function(data) {}, true)
}
modem.checkSIMMemory = function(callback, priority) {
if (callback == undefined) {
return new Promise((resolve, reject) => {
modem.checkSIMMemory((error, result) => {
if (error) {
reject(error)
} else {
resolve(result)
}
})
})
}
if (priority == null) priority = false
modem.executeCommand(`AT+CPMS='` + `SM'`, function(data) {
callback(data)
}, priority)
}
modem.initializeModem = function(callback, priority) {
if (callback == undefined) {
return new Promise((resolve, reject) => {
modem.initializeModem((error, result) => {
if (error) {
reject(error)
} else {
resolve(result)
}
})
})
}
if (priority == null) priority = false
modem.executeCommand('ATZ', function(data) {
callback(data)
}, false, 30000)
}
modem.modemMode = function(callback, priority, timeout, mode) {
modemMode = '0'
if (priority == null) priority = true
if (timeout == 'PDU' || timeout == 'SMS') {
mode == timeout
}
if (priority == 'PDU' || priority == 'SMS') {
mode = priority
}
if (mode == 'PDU' || mode == 'SMS') {
if (mode == 'PDU') {
modemMode = '0'
} else if (mode = 'SMS') {
modemMode = '1'
}
modem.executeCommand(`AT+CMGF=${modemMode}`, function(data) {
callback(data)
}, false, 30000)
} else {
callback({
status: 'Fail',
request: 'modemMode',
data: 'Modem Failed to Changed Mode'
})
}
}
modem.makeid = function(numOfCharacters) {
let text = ''
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
for (let i = 0; i < numOfCharacters; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length))
return text
}
modem.sendSMS = function(number, message, callback, priority) {
try {
if (number && message) {
let messageID = modem.makeid(25)
let pduMessage = pdu.generate({
text: message,
receiver: number,
encoding: '16bit'
})
modem.executeCommand(`AT+CMGS=${(pduMessage.toString().length/2)-1}`, function(data) {}, false, 100);
modem.executeCommand(`${pduMessage.toString()}`+'\x1a', function(data) {
var channel = ''
if(data.status == "Fail"){
channel = 'onMessageSendingFailed'
}else{
channel = 'onMessageSent'
}
var result = {
status: data.status,
request: data.request,
Data: {
messageId: data.data.messageId,
message: data.data.message,
recipient: data.data.recipient,
response: data.data.response
}
}
modem.emit(channel, result)
callback(result)
}, false, 30000,messageID, message, number);
callback({
status: 'Success',
request: 'sendSMS',
Data: {
messageId: messageID,
response: 'Successfully Sent to Message Queue'
}
})
} else {
callback({
status: 'Error',
request: 'sendSMS',
error: 'Missing Arguments'
})
}
} catch (error) {
callback({
status: 'Error',
request: 'sendSMS',
error: error
})
}
}
modem.deleteAllSimMessages = function(callback, priority, timeout) {
if (priority == null) priority = false
modem.executeCommand('AT+CMGD=1,4', function(data) {
callback(data)
}, priority, timeout)
}
modem.saveOwnNumber = function(number, callback, priority, timeout) {
if (priority == null) priority = false
// modem.executeCommand(`AT+CPBS="ON"`, function(data) {
// callback(data)
// }, priority, timeout)
// modem.executeCommand(`AT+CPBW=?`, function(data) {
// callback(data)
// }, priority, timeout)
// modem.executeCommand(`AT+CPBR=1`, function(data) {
// callback(data)
// }, priority, timeout)
//
// modem.executeCommand(`+CPBW=1,"18589898844",129,"Jane Smith"`, function(data) {
// callback(data)
// }, priority, timeout)
}
modem.getModemSerial = function(callback, priority, timeout) {
if (priority == null) priority = false
modem.executeCommand('AT+CGSN', function(data) {
callback(data)
}, priority, timeout)
}
modem.getNetworkSignal = function(callback, priority, timeout) {
if (priority == null) priority = false
modem.executeCommand('AT+CSQ', function(data) {
callback(data)
}, priority, timeout)
}
modem.listOpenPorts = function(callback) {
if (callback === undefined) {
return new Promise((resolve, reject) => {
modem.listOpenPorts((error, results) => {
if (error) {
resolve(error)
} else {
reject(results)
}
})
})
}
SerialPort.list((error, results) => {
if (error) {
callback(error)
} else {
callback(null, results)
}
})
}
modem.release = function() {
this.data = '' //Empty the result buffer.
this.isLocked = false //release the modem for next command.
this.queue.shift() //Remove current item from queue.
}
modem.executeCommand = function(command, c, priority, timeout, messageID, message, recipient) {
if (!this.isOpened) {
this.emit('close')
return
}
let item = new EventEmitter()
if (messageID) {
item.messageID = messageID
item.message = message
item.recipient = recipient
item.status = 'sendSMS'
}
item.command = command
item.callback = c
item.add_time = new Date()
item.id = ++this.jobID
item.timeout = timeout
if (item.timeout == undefined) //Default timeout it 60 seconds. Send false to disable timeouts.
item.timeout = 60000
if (priority) {
// this.queue.unshift(item)
if (this.queue.length > 1) {
this.queue.splice(2, 0, item)
} else {
this.queue.push(item)
}
} else {
this.queue.push(item)
}
this.emit('job', item)
process.nextTick(this.executeNext.bind(this))
return item
}
modem.executeNext = function() {
if (!this.isOpened) {
this.emit('close')
return
}
//Wait Modem is in use...
if (this.isLocked)
return
let item = this.queue[0]
if (!item) {
this.emit('idle')
return //Queue is empty.
}
this.data = ''
this.isLocked = true
item.execute_time = new Date()
item.emit('start')
if (item.timeout)
timeouts[item.id] = setTimeout(function() {
item.emit('timeout')
this.release()
this.executeNext()
}.bind(this), item.timeout)
modem.port.write(item['command'] + '\r')
}
/////////// Functions ////////////////////////////////
modem.parseSIMCardResponse = function(newpart, callback) {
let simCardCheck = {
used: '',
totalSpace: ''
}
newpart = (newpart.split(' '))
newpart = (newpart[1].split(','))
simCardCheck.used = newpart[0]
simCardCheck.totalSpace = newpart[1]
callback({
status: 'success',
request: 'checkSIMMemory',
data: simCardCheck
})
}
return modem
}
module.exports = {
Modem
}