From 22485254425f4ce6c237afa87d1efba30a8dd15d Mon Sep 17 00:00:00 2001 From: cheetah Date: Mon, 29 Mar 2021 20:25:21 +0000 Subject: [PATCH] rx dummychain works --- config.json | 13 +++++------ index.js | 2 +- package.json | 4 +++- types/ConnectorRegistry.js | 7 +++++- types/DeviceRegistry.js | 6 ++++++ types/MessageManager.js | 6 ++++++ types/connectors/DummyConnector.js | 21 ++++++++++-------- types/connectors/LoRaWANConnector.js | 27 +++++++++++++++++++++++ types/devices/BirdySlim.js | 32 ++++++++++++++++++++++++++++ types/devices/Device.js | 1 + 10 files changed, 101 insertions(+), 18 deletions(-) diff --git a/config.json b/config.json index 11aad62..295b6a4 100644 --- a/config.json +++ b/config.json @@ -15,7 +15,10 @@ "duplexTimeout": 30 }, "lorawan": { - "enabled": false + "enabled": true, + "mqttserver": "mqtt://eu1.cloud.thethings.network:1883", + "username": "", + "password": "" }, "dapnet": { "enabled": false @@ -24,11 +27,9 @@ "pagers": { "birdyslim": { "enabled": true, - "formatRecvAck": "|5||S||V||G||D||C|>A", - "formatReadAck": "|5||S||V||G||D||C|>B", - "formatOperAck": "|5||S||V||G||D||C|$OP", - "formatStatus": "|S||V||G||D||C|", - "formatSOS": "|S||V||G||D||C|" + "rxchain": { + "lorawan": true + } } } } \ No newline at end of file diff --git a/index.js b/index.js index fa873f8..0776131 100644 --- a/index.js +++ b/index.js @@ -15,7 +15,7 @@ if (!!config.connectors.lorawan && config.connectors.lorawan.enabled === true) { types.ConnectorRegistry.register(new types.Connectors.LoRaWANConnector(connection)) } if (!!config.connectors.dapnet && config.connectors.dapnet.enabled === true) { - types.ConnectorRegistry.register(new types.Connectors.DAPNETConnector()) + types.ConnectorRegistry.register(new types.Connectors.DAPNETConnector(connection)) } types.ConnectorRegistry.register(new types.Connectors.DummyConnector()) diff --git a/package.json b/package.json index 2c1a455..6521277 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,10 @@ "@supercharge/strings": "^1.18.0", "amqp-connection-manager": "^3.2.2", "amqplib": "^0.7.0", + "async-mqtt": "^2.6.1", "body-parser": "^1.19.0", "express": "^4.17.1", - "md5": "^2.3.0" + "md5": "^2.3.0", + "mqtt": "^4.2.6" } } diff --git a/types/ConnectorRegistry.js b/types/ConnectorRegistry.js index c406cb0..8e0e582 100644 --- a/types/ConnectorRegistry.js +++ b/types/ConnectorRegistry.js @@ -1,11 +1,13 @@ const events = require('events') const md5 = require('md5') +const DeviceRegistry = require("./DeviceRegistry") class ConnectorRegistry { constructor() { this.Connectors = {} this.events = new events.EventEmitter() this.events.on('ping', (x) => console.log('connector event "ping" from', x)) + this.events.on('response', this.receive.bind(this)) } register(connector) { this.Connectors[ connector.name ] = connector @@ -35,7 +37,10 @@ class ConnectorRegistry { //W.I.P - receive(id, data) { + async receive(data, connector) { + for (let device of DeviceRegistry.getDevices()) { + if (await device.tryReceive(data, connector) === true) { break; } + } } } const registry = new ConnectorRegistry() diff --git a/types/DeviceRegistry.js b/types/DeviceRegistry.js index 8aa6a19..9c04d07 100644 --- a/types/DeviceRegistry.js +++ b/types/DeviceRegistry.js @@ -5,6 +5,12 @@ class DeviceRegistry { register(device) { this.Devices[ device.name ] = device } + getDevices() { + return Object.values(this.Devices) + } + /*tryReceive(deviceName, data) { + return this.Devices[ deviceName ].tryReceive(data) + }*/ } const registry = new DeviceRegistry() module.exports = registry \ No newline at end of file diff --git a/types/MessageManager.js b/types/MessageManager.js index 1868890..afc1576 100644 --- a/types/MessageManager.js +++ b/types/MessageManager.js @@ -50,6 +50,12 @@ class MessageManager { else this.DeliverOneWay(msgId) } + attachMetadata(msgId, metadata) { + if (!this.messages[ msgId ]._routerData.metadata) { + this.messages[ msgId ]._routerData.metadata = [] + } + this.messages[ msgId ]._routerData.metadata.push(metadata) + } _clearEventHandlers4MsgID(msgId) { ConnectorRegistry.events.removeAllListeners(`msg:status:${ msgId }:delivered`) ConnectorRegistry.events.removeAllListeners(`msg:status:${ msgId }:failed`) diff --git a/types/connectors/DummyConnector.js b/types/connectors/DummyConnector.js index 422cb8e..f1a6aaf 100644 --- a/types/connectors/DummyConnector.js +++ b/types/connectors/DummyConnector.js @@ -1,6 +1,7 @@ const Connector = require("./Connector") const md5 = require('md5') +const config = require('../../config.json') class DummyConnector extends Connector { constructor (amqpConnMngr) { super(amqpConnMngr) @@ -13,16 +14,18 @@ class DummyConnector extends Connector { // set Routed this.connectorRegistry.reportState(msg, UUID, 'routed') await new Promise((res)=>setTimeout(res,6e3)) - // Pager Configuration Response Format "|5||S||V||G||D||C" - let virtGPS = "+001.38207+43.7717105" - let virtSerial = "1337" - let virtRSSI = "22" - let virtDate = "01/01/2024" - let virtBattery = 0x28.toString(16) - this.connectorRegistry.events.emit('response', `${ msgId }|${ virtSerial }|${ virtBattery }|${ virtGPS }|${ virtDate }|${ virtRSSI }`) + this.connectorRegistry.events.emit('response', { //reconstruct the response coming from a lorawan connector + type: 'ack', + ack: 'recv', + rssi: 22, + msgid: msgId, + f_port: 1, + date: new Date(), + device_id: 'dummy' + }) // this will happen somewhere else, down the response processing chain - this.connectorRegistry.events.emit(`msg:status:${ msgId }:delivered`) - this.connectorRegistry.reportDelivered(msg, UUID) // cheating lol + //this.connectorRegistry.events.emit(`msg:status:${ msgId }:delivered`) + //this.connectorRegistry.reportDelivered(msg, UUID) // cheating lol } async transmitMessage(msg, params) { // lets pretend to be a Birdy Slim const UUID = this.name+':'+md5(JSON.stringify([ this.name, ...params ])) // uuid=name+hash of name+args diff --git a/types/connectors/LoRaWANConnector.js b/types/connectors/LoRaWANConnector.js index 18fc6af..6080f5f 100644 --- a/types/connectors/LoRaWANConnector.js +++ b/types/connectors/LoRaWANConnector.js @@ -1,4 +1,5 @@ const Connector = require("./Connector") +const config = require('../../config.json') class LoRaWANConnector extends Connector { // this is optimized for only receiving LoRa uplink Messages (from Birdy Pagers) @@ -7,6 +8,32 @@ class LoRaWANConnector extends Connector { super(amqpConnMngr) this.name = "lorawan" this.duplexCapable = true + const MQTT = require('async-mqtt') + this.client = MQTT.connect(config.connectors.lorawan.mqttserver, { + username: config.connectors.lorawan.username, + password: config.connectors.lorawan.password, + }) + this.client.on('error', (x) => console.error) + this.client.on('connect', this.onMQTTConnect.bind(this)) + this.client.on('message', this.onMQTTMessage.bind(this)) + } + async onMQTTConnect() { + await this.client.subscribe(`v3/${ config.connectors.lorawan.username }/devices/#`) + console.log('[lorawan] subscribed') + } + async onMQTTMessage(topic, message) { + //if (topic.indexOf('/up') > -1) return + const json = JSON.parse(Buffer.from(message).toString('utf-8')) + console.log(topic, json) + if (!!json.uplink_message) { + this.connectorRegistry.events.emit('response', { + ...json.uplink_message.decoded_payload, + port: json.uplink_message.f_port, + date: new Date(json.received_at), + device_id: json.end_device_ids.device_id, + metadata: json, + }) + } } } module.exports = LoRaWANConnector \ No newline at end of file diff --git a/types/devices/BirdySlim.js b/types/devices/BirdySlim.js index 8b0d9bc..200cda4 100644 --- a/types/devices/BirdySlim.js +++ b/types/devices/BirdySlim.js @@ -1,6 +1,7 @@ const MessageManager = require("../MessageManager") const PagerDevice = require("./Device") const Str = require('@supercharge/strings') +const config = require('../../config.json') // Birdy Slim (IoT) Device class BirdySlim extends PagerDevice { @@ -8,6 +9,21 @@ class BirdySlim extends PagerDevice { super() this.duplex = true this.name = "birdyslim" + /*this.birdyParamMapper = { + //'A': ['beaconIDinstant'], // It is the ID of current localisation beacon. + //'B': ['beaconIDstored'], // It is the ID of the last localisation beacon seen by the BIRDY + 'C': ['rssi', 2], // It is the POCSAG carrier received level (in dBm) transmitted by the POCSAG emitter and received by the pager. + //'D': ['date'], // Timestamp in seconds from 01/01/2014. + //'E': ['beaconRoundIDstored'], // It is the ID of the last round beacon seen by the pager + 'G': ['gps', (1+3+1+5)+(1+2+1+5)+2], // Longitude and latitude in decimal degrees and last acquisition time in minutes. + 'I': ['identityRIC'], // BIRDY first RIC code + 'N': ['messageNumber', 5], // To display message number message must begin with ***Mxxx*** where xxx is the message number. + 'S': ['serial', 13], // BIRDY serial number + //'T': ['receivedRIC'], // Message receipt RIC code + 'V': ['batteryVoltage', 2], // BIRDY battery voltage in HEX + //'X': ['lowBattBeacon'], // It is the ID of a beacon with a low battery voltage + '5': ['msgId', 5], // It is to recall first 5 characters of received message in an acknowledgement. + }*/ } RandID() { return `B${ Str.random(4) }` @@ -17,5 +33,21 @@ class BirdySlim extends PagerDevice { await MessageManager.BindMsg(msg) msg.payload = msg.type === 'duplex' ? `${ msg.id }${ msg.payload }` : msg.payload // only if duplex wanted we add the id } + async tryReceive(data, connector) { + console.log(data) + if (typeof(data) === 'object' && !!data.type) { + switch (data.type) { + case 'ack': + if (data.ack === 'recv') { + require('../ConnectorRegistry').reportDelivered({ id: data.msgid }, `lorawan:${ data.device_id }`) // cheating lol + require('../MessageManager').attachMetadata(data.msgid, data) + } + break; + } + return true + } + return false + // config.pagers.birdyslim.formatRecvAck + } } module.exports = BirdySlim \ No newline at end of file diff --git a/types/devices/Device.js b/types/devices/Device.js index b031d01..c2d1d85 100644 --- a/types/devices/Device.js +++ b/types/devices/Device.js @@ -4,6 +4,7 @@ class PagerDevice { this.name = "_base" } async formatTX(msg) { } + async tryReceive(data, connector) { } RandID() { } } module.exports = PagerDevice \ No newline at end of file