before update
This commit is contained in:
parent
2814584831
commit
7eb1aa78ab
10 changed files with 239 additions and 118 deletions
|
@ -26,7 +26,7 @@
|
|||
},
|
||||
"emPuppettering": {
|
||||
"enabled": true,
|
||||
"duplexTimeout": 360
|
||||
"duplexTimeout": "250"
|
||||
},
|
||||
"emessage": {
|
||||
"enabled": true,
|
||||
|
@ -50,6 +50,10 @@
|
|||
"username": "test",
|
||||
"password": "testsucks",
|
||||
"duplexTimeout": 300
|
||||
},
|
||||
"pnet": {
|
||||
"enabled": true,
|
||||
"duplexTimeout": 10
|
||||
}
|
||||
},
|
||||
"pagers": {
|
||||
|
|
|
@ -325,6 +325,8 @@
|
|||
deviceType: [
|
||||
{ k: 'Generic', v: 'generic' },
|
||||
{ k: 'Birdy Slim (IoT)', v: 'birdyslim' },
|
||||
{ k: 'MXP600', v: 'mxp600' },
|
||||
{ k: 'Generic Tetra', v: 'tetra-generic' },
|
||||
],
|
||||
connectorTypes: [
|
||||
{ k: 'Dummy', v: 'dummy' },
|
||||
|
@ -339,6 +341,8 @@
|
|||
{ k: 'e*2wayS alarmManager', v: 'em-a-twoways' },
|
||||
|
||||
{ k: 'LoRaWAN TTNv3', v: 'lorawan' },
|
||||
|
||||
{ k: 'pNET TETRA', v: 'pnet' },
|
||||
],
|
||||
configData: {
|
||||
boskrypt: {
|
||||
|
|
|
@ -217,6 +217,8 @@ Last LoRaWAN Packet:
|
|||
deviceType: [
|
||||
{k: 'Generic', v: 'generic'},
|
||||
{k: 'Birdy Slim (IoT)', v: 'birdyslim'},
|
||||
{ k: 'MXP600', v: 'mxp600' },
|
||||
{ k: 'Generic Tetra', v: 'tetra-generic' },
|
||||
],
|
||||
connectorTypes: [
|
||||
{k: 'Dummy', v: 'dummy'},
|
||||
|
@ -231,6 +233,8 @@ Last LoRaWAN Packet:
|
|||
{k: 'e*2wayS alarmManager', v: 'em-a-twoways'},
|
||||
|
||||
{k: 'LoRaWAN TTNv3', v: 'lorawan'},
|
||||
|
||||
{ k: 'pNET TETRA', v: 'pnet' },
|
||||
],
|
||||
|
||||
newMSGData: {
|
||||
|
|
6
index.js
6
index.js
|
@ -36,6 +36,9 @@ if (!!config.connectors.emPuppettering && config.connectors.emPuppettering.enabl
|
|||
if (!!config.connectors.ecityruf && config.connectors.pagernetzAT.enabled === true) {
|
||||
types.ConnectorRegistry.register(new types.Connectors.PagernetzConnetorAT(connection))
|
||||
}
|
||||
if (!!config.connectors.ecityruf && config.connectors.pnet.enabled === true) {
|
||||
types.ConnectorRegistry.register(new types.Connectors.pNetConnector())
|
||||
}
|
||||
|
||||
types.ConnectorRegistry.register(new types.Connectors.DummyConnector())
|
||||
|
||||
|
@ -43,6 +46,9 @@ types.DeviceRegistry.register(new types.devices.GenericPager())
|
|||
types.DeviceRegistry.register(new types.devices.BirdySlim())
|
||||
types.DeviceRegistry.register(new types.devices.EMessage2Ways())
|
||||
types.DeviceRegistry.register(new types.devices.Skyper())
|
||||
//new tetra devices
|
||||
types.DeviceRegistry.register(new types.devices.TETRA_Generic())
|
||||
types.DeviceRegistry.register(new types.devices.TETRA_MXP600())
|
||||
|
||||
const express = require('express')
|
||||
const { MessageManager } = require('./types')
|
||||
|
|
|
@ -1,125 +1,125 @@
|
|||
function Decoder(bytes, port) {
|
||||
var data = {}
|
||||
function bytesToString(a) {
|
||||
return a.map(function(x){ return String.fromCharCode(x) }).join('') // because very OLD js parser
|
||||
}
|
||||
switch (port) {
|
||||
case 1: // Technical Received Acknowledgment '|5||C|'
|
||||
// 31 32 33 34 35 20
|
||||
data.type = 'ack'
|
||||
data.ack = 'recv'
|
||||
data.msgid = bytesToString(bytes.splice(0,5))
|
||||
data.rssi = bytes[0]
|
||||
break;
|
||||
case 2: // Read and Operational Acknowledgment 'AA|5|' and Operational '33|5|<CustomByte(s)>'
|
||||
// AA 31 32 33 34 35
|
||||
// operational ack with Payload "test"(maybe you should use a single byte)
|
||||
// 33 31 32 33 34 35 54 65 73 74
|
||||
data.type = 'ack'
|
||||
data.ack = bytes.length == 5 ? 'read' : 'operational'
|
||||
data.msgid = bytesToString(bytes.splice(0,5))
|
||||
if (data.ack === 'operational') {
|
||||
data.operationalData = bytes
|
||||
var data = {}
|
||||
function bytesToString(a) {
|
||||
return a.map(function(x){ return String.fromCharCode(x) }).join('') // because very OLD js parser
|
||||
}
|
||||
switch (port) {
|
||||
case 1: // Technical Received Acknowledgment '|5||C|'
|
||||
// 31 32 33 34 35 20
|
||||
data.type = 'ack'
|
||||
data.ack = 'recv'
|
||||
data.msgid = bytesToString(bytes.splice(0,5))
|
||||
data.rssi = -bytes[0] / 2
|
||||
break;
|
||||
case 2: // Read and Operational Acknowledgment 'AA|5|' and Operational '33|5|<CustomByte(s)>'
|
||||
// AA 31 32 33 34 35
|
||||
// operational ack with Payload "test"(maybe you should use a single byte)
|
||||
// 33 31 32 33 34 35 54 65 73 74
|
||||
data.type = 'ack'
|
||||
data.ack = bytes.length == 5 ? 'read' : 'operational'
|
||||
data.msgid = bytesToString(bytes.splice(0,5))
|
||||
if (data.ack === 'operational') {
|
||||
data.operationalData = bytes
|
||||
}
|
||||
break;
|
||||
case 3: // Status & Canned Messages
|
||||
// Canned Message '01' --- '05', single Hex Number, incrementing
|
||||
// Status '<StatusIncrID>|Z|' or if no CenterSelection '<StatusIncrID>00'
|
||||
|
||||
if (bytes.length == 1) {
|
||||
data.type = 'cannedMessage'
|
||||
data.cannedMessage = bytes[0] * 1
|
||||
} else {
|
||||
data.type = 'status'
|
||||
data.status = bytes[0] * 1
|
||||
data.selection = bytes[1] * 1
|
||||
}
|
||||
break;
|
||||
case 4: // Battery and Power Notifications
|
||||
// Startup 'FF'
|
||||
// Shutdown 'EE'
|
||||
// Low Battery 'FD'
|
||||
// ChargingOn '|V|CC'
|
||||
// ChargingOff'|V|BB'
|
||||
if (bytes.length == 1) {
|
||||
data.type = 'power'
|
||||
if (bytes[0] >= 0xEE) {
|
||||
data.poweredOn = bytes[0]== 0xFF
|
||||
}
|
||||
break;
|
||||
case 3: // Status & Canned Messages
|
||||
// Canned Message '01' --- '05', single Hex Number, incrementing
|
||||
// Status '<StatusIncrID>|Z|' or if no CenterSelection '<StatusIncrID>00'
|
||||
|
||||
if (bytes.length == 1) {
|
||||
data.type = 'cannedMessage'
|
||||
data.cannedMessage = bytes[0] * 1
|
||||
} else {
|
||||
data.type = 'status'
|
||||
data.status = bytes[0] * 1
|
||||
data.selection = bytes[1] * 1
|
||||
if (bytes[0] == 0xFD) {
|
||||
data.type = 'low_battery'
|
||||
}
|
||||
break;
|
||||
case 4: // Battery and Power Notifications
|
||||
// Startup 'FF'
|
||||
// Shutdown 'EE'
|
||||
// Low Battery 'FD'
|
||||
// ChargingOn '|V|CC'
|
||||
// ChargingOff'|V|BB'
|
||||
if (bytes.length == 1) {
|
||||
data.type = 'power'
|
||||
if (bytes[0] >= 0xEE) {
|
||||
data.poweredOn = bytes[0]== 0xFF
|
||||
}
|
||||
if (bytes[0] == 0xFD) {
|
||||
data.type = 'low_battery'
|
||||
}
|
||||
if (bytes[0] <= 0xAA) {
|
||||
data.type = 'battery'
|
||||
data.battery = bytes[0] * 1
|
||||
data.isCharging = false
|
||||
}
|
||||
} else {
|
||||
if (bytes[0] <= 0xAA) {
|
||||
data.type = 'battery'
|
||||
data.battery = bytes[0] * 1
|
||||
data.isCharging = bytes[1] == 0xCC
|
||||
data.isCharging = false
|
||||
}
|
||||
break;
|
||||
case 5: // OTAStatus + LoneWorker/SOS Trigger + GPS Tracking Port '|G|'
|
||||
// GPS Tracking '|G|'
|
||||
//// 00 1E 33 D7 00 4A 2C 31 10
|
||||
// SOS Start 'FF|G|'
|
||||
//// FF 00 1E 33 D7 00 4A 2C 31 10
|
||||
// SOS End 'FE|G|'
|
||||
//// FE 00 1E 33 D7 00 4A 2C 31 10
|
||||
// LoneWorker Lack of movement 'FD|G|'
|
||||
//// FD 00 1E 33 D7 00 4A 2C 31 10
|
||||
// LoneWorker Falldetect 'FC|G|'
|
||||
//// FC 00 1E 33 D7 00 4A 2C 31 10
|
||||
// LoneWorker End 'FB|G|'
|
||||
//// FB 00 1E 33 D7 00 4A 2C 31 10
|
||||
// OTA/PagerStatus 'FA|G||V|'
|
||||
//// FA 00 1E 33 D7 00 4A 2C 31 10 28
|
||||
if (bytes.length !== 9) { // we have more than just the |G| block
|
||||
if (bytes.length === 10) {
|
||||
switch(bytes[0]) {
|
||||
case 0xFF: // SOS Start
|
||||
data.type = 'sos'
|
||||
data.sos = true
|
||||
break;
|
||||
case 0xFE: // SOS End
|
||||
data.type = 'sos'
|
||||
data.sos = false
|
||||
break;
|
||||
case 0xFD: // LoneWorker Lack of movement
|
||||
data.type = 'sos'
|
||||
data.sos = false
|
||||
data.loneworker = 'lackofmovement'
|
||||
break;
|
||||
case 0xFC: // LoneWorker Falldetect
|
||||
data.type = 'sos'
|
||||
data.sos = false
|
||||
data.loneworker = 'falldetect'
|
||||
break;
|
||||
case 0xFB: // LoneWorker End
|
||||
data.type = 'sos'
|
||||
data.sos = false
|
||||
data.loneworker = false
|
||||
break;
|
||||
}
|
||||
bytes.splice(0,1)
|
||||
} else {
|
||||
data.type = 'battery'
|
||||
data.battery = bytes[0] * 1
|
||||
data.isCharging = bytes[1] == 0xCC
|
||||
}
|
||||
break;
|
||||
case 5: // OTAStatus + LoneWorker/SOS Trigger + GPS Tracking Port '|G|'
|
||||
// GPS Tracking '|G|'
|
||||
//// 00 1E 33 D7 00 4A 2C 31 10
|
||||
// SOS Start 'FF|G|'
|
||||
//// FF 00 1E 33 D7 00 4A 2C 31 10
|
||||
// SOS End 'FE|G|'
|
||||
//// FE 00 1E 33 D7 00 4A 2C 31 10
|
||||
// LoneWorker Lack of movement 'FD|G|'
|
||||
//// FD 00 1E 33 D7 00 4A 2C 31 10
|
||||
// LoneWorker Falldetect 'FC|G|'
|
||||
//// FC 00 1E 33 D7 00 4A 2C 31 10
|
||||
// LoneWorker End 'FB|G|'
|
||||
//// FB 00 1E 33 D7 00 4A 2C 31 10
|
||||
// OTA/PagerStatus 'FA|G||V|'
|
||||
//// FA 00 1E 33 D7 00 4A 2C 31 10 28
|
||||
if (bytes.length !== 9) { // we have more than just the |G| block
|
||||
if (bytes.length === 10) {
|
||||
switch(bytes[0]) {
|
||||
case 0xFF: // SOS Start
|
||||
data.type = 'sos'
|
||||
data.sos = true
|
||||
break;
|
||||
case 0xFE: // SOS End
|
||||
data.type = 'sos'
|
||||
data.sos = false
|
||||
break;
|
||||
case 0xFD: // LoneWorker Lack of movement
|
||||
data.type = 'sos'
|
||||
data.sos = false
|
||||
data.loneworker = 'lackofmovement'
|
||||
break;
|
||||
case 0xFC: // LoneWorker Falldetect
|
||||
data.type = 'sos'
|
||||
data.sos = false
|
||||
data.loneworker = 'falldetect'
|
||||
break;
|
||||
case 0xFB: // LoneWorker End
|
||||
data.type = 'sos'
|
||||
data.sos = false
|
||||
data.loneworker = false
|
||||
break;
|
||||
}
|
||||
if (bytes.length === 11) { // OTA PagerStatus
|
||||
data.type = 'ota'
|
||||
data.ota = 'status'
|
||||
data.battery = bytes[10] * 1
|
||||
bytes.splice(0,1)
|
||||
}
|
||||
} else { // we are having a normal gps block only
|
||||
data.type = 'gps'
|
||||
bytes.splice(0,1)
|
||||
}
|
||||
var gpsBlock = bytes.splice(0,9)
|
||||
data.longitude = ((gpsBlock[0]<<24)>>>0) + ((gpsBlock[1]<<16)>>>0) + ((gpsBlock[2]<<8)>>>0) + gpsBlock[3]
|
||||
data.longitude /= 10e4
|
||||
data.latitude = ((gpsBlock[4]<<24)>>>0) + ((gpsBlock[5]<<16)>>>0) + ((gpsBlock[6]<<8)>>>0) + gpsBlock[7]
|
||||
data.latitude /= 10e4
|
||||
data.lastGPSAcquisition = gpsBlock[8]
|
||||
break;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
if (bytes.length === 11) { // OTA PagerStatus
|
||||
data.type = 'ota'
|
||||
data.ota = 'status'
|
||||
data.battery = bytes[10] * 1
|
||||
bytes.splice(0,1)
|
||||
}
|
||||
} else { // we are having a normal gps block only
|
||||
data.type = 'gps'
|
||||
}
|
||||
var gpsBlock = bytes.splice(0,9)
|
||||
data.longitude = ((gpsBlock[0]<<24)>>>0) + ((gpsBlock[1]<<16)>>>0) + ((gpsBlock[2]<<8)>>>0) + gpsBlock[3]
|
||||
data.longitude /= 10e4
|
||||
data.latitude = ((gpsBlock[4]<<24)>>>0) + ((gpsBlock[5]<<16)>>>0) + ((gpsBlock[6]<<8)>>>0) + gpsBlock[7]
|
||||
data.latitude /= 10e4
|
||||
data.lastGPSAcquisition = gpsBlock[8]
|
||||
break;
|
||||
}
|
||||
return data;
|
||||
}
|
|
@ -22,6 +22,7 @@ module.exports = {
|
|||
eMessagePuppeteerConnectorTwoWays,
|
||||
|
||||
PagernetzConnetorAT: require('./PagernetzConnetorAT'),
|
||||
pNetConnector: require('./pNetConnector'),
|
||||
|
||||
LoRaWANConnector: require("./LoRaWANConnector"),
|
||||
POCSAGConnector: require("./POCSAGConnector"),
|
||||
|
|
59
types/connectors/pNetConnector.js
Normal file
59
types/connectors/pNetConnector.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
const Connector = require("./Connector")
|
||||
const config = require('../../config.json')
|
||||
const md5 = require('md5')
|
||||
const axios = require('axios')
|
||||
const { io } = require("socket.io-client")
|
||||
|
||||
|
||||
class pNetConnector extends Connector {
|
||||
constructor (amqpConnMngr) {
|
||||
super(amqpConnMngr)
|
||||
this.name = "pnet"
|
||||
this.duplexCapable = true
|
||||
this.managementSocket = false
|
||||
}
|
||||
async transmitMessage(msg, params) {
|
||||
console.log('pnet socket=',this.managementSocket)
|
||||
if (!this.managementSocket) {
|
||||
console.log('starting pnet socket')
|
||||
this.managementSocket = io("wss://<pnet url>")
|
||||
this.managementSocket.on('smartpager:ingress:event', (evt) => {
|
||||
console.log(evt)
|
||||
//this.connectorRegistry.reportState(msg, evt.UUID, evt.state)
|
||||
if (evt.delivered) this.connectorRegistry.reportDelivered({ id: evt.msgid }, `tetra:${ evt.device_id }`)
|
||||
//require('../MessageManager').markMessageRead(data.msgid)
|
||||
if (evt.response) require('../MessageManager').respondToMessage(evt.msgid, evt.response)
|
||||
})
|
||||
await this.managementSocket.connect()
|
||||
}
|
||||
const UUID = this.name+':'+md5(JSON.stringify([this.name,...params]))
|
||||
if (params.length < 1) return false
|
||||
const target = params[0]
|
||||
if (target.split('#').length !== 2) throw 'No valid pNet Parameter <transmitterGroup#callSign>'
|
||||
const contact = target.split('#')[ 0 ], options = target.split('#')[ 1 ]
|
||||
/*const extraParameters = {
|
||||
auth: {
|
||||
username: config.connectors.dapnet.username,
|
||||
password: config.connectors.dapnet.password
|
||||
}
|
||||
}*/
|
||||
this.managementSocket.emit('smartpager:ingress', {
|
||||
UUID,
|
||||
id: msg.id,
|
||||
text: msg.payload,
|
||||
contact,
|
||||
options,
|
||||
})
|
||||
return true
|
||||
/*return axios.post("https://pnet.cheetah.cat/", dapnetRequest, extraParameters)
|
||||
.then(() => {
|
||||
return true
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err.response.data)
|
||||
this.connectorRegistry.reportFail(msg, UUID)
|
||||
return false
|
||||
})*/
|
||||
}
|
||||
}
|
||||
module.exports = pNetConnector
|
20
types/devices/GenericTetra.js
Normal file
20
types/devices/GenericTetra.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
const MessageManager = require("../MessageManager")
|
||||
const PagerDevice = require("./Device")
|
||||
const Str = require('@supercharge/strings')
|
||||
|
||||
class GenericTetra extends PagerDevice {
|
||||
constructor () {
|
||||
super()
|
||||
this.duplex = true
|
||||
this.name = "tetra-generic"
|
||||
}
|
||||
RandID() {
|
||||
return `TETRA${ Str.random(8) }`
|
||||
}
|
||||
async formatTX(msg) {
|
||||
msg.id = this.RandID()
|
||||
await MessageManager.BindMsg(msg)
|
||||
// return msg
|
||||
}
|
||||
}
|
||||
module.exports = GenericTetra
|
20
types/devices/MXP600.js
Normal file
20
types/devices/MXP600.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
const MessageManager = require("../MessageManager")
|
||||
const PagerDevice = require("./Device")
|
||||
const Str = require('@supercharge/strings')
|
||||
|
||||
class TETRA_MXP600 extends PagerDevice {
|
||||
constructor () {
|
||||
super()
|
||||
this.duplex = true
|
||||
this.name = "mxp600"
|
||||
}
|
||||
RandID() {
|
||||
return `MXP${ Str.random(8) }`
|
||||
}
|
||||
async formatTX(msg) {
|
||||
msg.id = this.RandID()
|
||||
await MessageManager.BindMsg(msg)
|
||||
// return msg
|
||||
}
|
||||
}
|
||||
module.exports = TETRA_MXP600
|
|
@ -3,5 +3,8 @@ module.exports = {
|
|||
BirdySlim: require("./BirdySlim"),
|
||||
EMessage2Ways: require("./EMessage2Ways"),
|
||||
Skyper: require("./Skyper"),
|
||||
TETRA_MXP600: require("./MXP600"),
|
||||
TETRA_Generic: require("./GenericTetra"),
|
||||
|
||||
Device: require("./Device"),
|
||||
}
|
Loading…
Add table
Reference in a new issue