added emessage api
parent
c950dba5a5
commit
3bce300c70
@ -1,49 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
## Bash Library for sending out Pages and/or getting their State
|
|
||||||
# dependencies: curl, jq
|
|
||||||
|
|
||||||
# echo "Bericht" | send_page "http://127.0.0.1:3000" "duplex" "birdyslim" "dapnet=dl-all#DXxxx"
|
|
||||||
send_page() {
|
|
||||||
text=$(cat -)
|
|
||||||
endpoint=$1
|
|
||||||
msgType=$2
|
|
||||||
deviceType=$3
|
|
||||||
argArr=("$@")
|
|
||||||
connectorJSON=$(for arg in "${argArr[@]}"; do echo $arg; done | jq -Rcs '{array:split("\n")|.[3:-1]|map(split("=")|[(.[0]),.[1]]?)}.array')
|
|
||||||
echo $connectorJSON |\
|
|
||||||
jq -c --arg t "$msgType" --arg d "$deviceType" --arg p "$text" '{type:$t, routing: {connectors:.,device:$d}, payload:$p}' |\
|
|
||||||
curl -s -XPOST -H "Content-type: application/json" "$endpoint/api/message/advanced" -d @- |\
|
|
||||||
jq -r .
|
|
||||||
}
|
|
||||||
msg_status() {
|
|
||||||
endpoint=$1
|
|
||||||
msgid=$2
|
|
||||||
curl -s "$endpoint/api/message/status/$msgid" |\
|
|
||||||
jq -r ._routerData
|
|
||||||
}
|
|
||||||
is_msg_recv() {
|
|
||||||
msg_status $* | jq .recvAck | grep -q "true"
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
is_msg_read() {
|
|
||||||
msg_status $* | jq .readAck | grep -q "true"
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
is_msg_resp() {
|
|
||||||
msg_status $* | jq .response | grep -vq "false"
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
|
|
||||||
ENDPOINT="http://127.0.0.1:3000"
|
|
||||||
#echo "Test" | send_page "$ENDPOINT" "duplex" "birdyslim" "pocsag=133701D" "test=123"
|
|
||||||
msgid=$(echo "Test" | send_page "$ENDPOINT" "duplex" "birdyslim" "pocsag=133701D" "test=123")
|
|
||||||
#msgid="Bznka"
|
|
||||||
msg_status "$ENDPOINT" "$msgid"
|
|
||||||
|
|
||||||
|
|
||||||
if is_msg_recv "$ENDPOINT" "$msgid"; then
|
|
||||||
echo "message is recv"
|
|
||||||
fi
|
|
||||||
if is_msg_read "$ENDPOINT" "$msgid"; then
|
|
||||||
echo "message is read"
|
|
||||||
fi
|
|
@ -0,0 +1,142 @@
|
|||||||
|
const Connector = require("./Connector")
|
||||||
|
const config = require('../../config.json')
|
||||||
|
const md5 = require('md5')
|
||||||
|
const axios = require('axios')
|
||||||
|
// [ "ecityruf", "123456789" ]
|
||||||
|
class eCityrufConnector extends Connector {
|
||||||
|
constructor (amqpConnMngr) {
|
||||||
|
super(amqpConnMngr)
|
||||||
|
this.name = "emessage"
|
||||||
|
this.duplexCapable = true
|
||||||
|
this.supportBOSkrypt = true
|
||||||
|
}
|
||||||
|
async transmitMessage(msg, params) {
|
||||||
|
const UUID = this.name+':'+md5(JSON.stringify([this.name,...params]))
|
||||||
|
const target = params[0]
|
||||||
|
if (target.split('#').length !== 2) throw 'No valid eMessage Parameter <serviceName#identifier>'
|
||||||
|
const serviceName = target.split('#')[ 0 ], identifier = target.split('#')[ 1 ]
|
||||||
|
// eCityruf#8907737
|
||||||
|
|
||||||
|
let jwtToken = '', msgTrackID = ''
|
||||||
|
// login
|
||||||
|
axios.post('https://api.emessage.de/auth/login', {
|
||||||
|
username: config.connectors.emessage.username,
|
||||||
|
password: config.connectors.emessage.password
|
||||||
|
})
|
||||||
|
.then((loginReq) => { // extract jwt
|
||||||
|
if (loginReq.data.apiStatusCode != 200) { throw loginReq }
|
||||||
|
jwtToken = loginReq.data.data.jwt
|
||||||
|
return jwtToken
|
||||||
|
})
|
||||||
|
.then(() => { // send Message Request
|
||||||
|
return axios.post('https://api.emessage.de/rs/eSendMessages', {
|
||||||
|
messageText: msg.payload,
|
||||||
|
recipients: [{ serviceName, identifier }]
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${ jwtToken }`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then((sndMessageReq) => { // extract tracking ID from response
|
||||||
|
if (sndMessageReq.data.apiStatusCode != 200) { throw sndMessageReq }
|
||||||
|
this.connectorRegistry.reportState(msg, UUID, 'routed') // since we queued the message, we shall mark it was routed
|
||||||
|
msgTrackID = sndMessageReq.data.data.trackingId
|
||||||
|
console.log('TRACKING ID', msgTrackID)
|
||||||
|
return msgTrackID
|
||||||
|
})
|
||||||
|
/*.then((_) => { // extract tracking ID from response
|
||||||
|
this.connectorRegistry.reportState(msg, UUID, 'routed')
|
||||||
|
msgTrackID = '04872f70-9029-11ec-b877-e5935093b691'
|
||||||
|
return msgTrackID
|
||||||
|
})*/
|
||||||
|
.then(async () => { // check for response til duplexTimeout
|
||||||
|
const delaySeconds = (timeout) => new Promise(r=>setTimeout(r, timeout * 1e3))
|
||||||
|
const checkDelivery = async () => {
|
||||||
|
try {
|
||||||
|
let res = await axios.get('https://api.emessage.de/rs/eGetMessages/External/' + msgTrackID, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${ jwtToken }`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
let deliveryState = res.data.data.recipients[ 0 ].status[ 0 ].answer
|
||||||
|
if (deliveryState == 'INTRANSIT') this.connectorRegistry.reportState(msg, UUID, 'transit')
|
||||||
|
if (deliveryState == 'SENT') this.connectorRegistry.reportState(msg, UUID, 'sent')
|
||||||
|
if (deliveryState == 'RECEIVED' || +deliveryState > 0) {
|
||||||
|
this.connectorRegistry.reportDelivered(msg, UUID)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
console.log(JSON.stringify(res.data.data))
|
||||||
|
//this.connectorRegistry.reportState(msg, UUID, deliveryState)
|
||||||
|
|
||||||
|
return false
|
||||||
|
//if (res.data.data.recipients.filter(rec=>))
|
||||||
|
} catch (e) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const checkResponse = async () => {
|
||||||
|
try {
|
||||||
|
let res = await axios.get('https://api.emessage.de/rs/eGetMessages/External/' + msgTrackID, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${ jwtToken }`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
let status = res.data.data.recipients[ 0 ].status[ 0 ]
|
||||||
|
//if (deliveryState == 'INTRANSIT') this.connectorRegistry.reportState(msg, UUID, 'transit')
|
||||||
|
/*if (deliveryState == 'RECEIVED' || +deliveryState > 0) {
|
||||||
|
this.connectorRegistry.reportDelivered(msg, UUID)
|
||||||
|
return true
|
||||||
|
}*/
|
||||||
|
if (+status.answerNo == 1 && +status.answer > -1 ) {
|
||||||
|
//this.connectorRegistry.response(msg, status.answer)
|
||||||
|
require('../MessageManager').markMessageRead(msg.id)
|
||||||
|
require('../MessageManager').respondToMessage(msg.id, +status.answer)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
//if (res.data.data.recipients.filter(rec=>))
|
||||||
|
} catch (e) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deliveryProcess = new Promise(async (res, rej) => {
|
||||||
|
const { startInterval, duplexTimeout } = config.connectors.emessage
|
||||||
|
let nextDelay = startInterval + 0
|
||||||
|
do {
|
||||||
|
let resultCheck = await checkDelivery()
|
||||||
|
if (resultCheck == true) return res()
|
||||||
|
await delaySeconds(nextDelay)
|
||||||
|
nextDelay *= 2 // wait 2x longer than before
|
||||||
|
} while (nextDelay <= duplexTimeout)
|
||||||
|
return rej()
|
||||||
|
})
|
||||||
|
const responseProcess = new Promise(async (res, rej) => {
|
||||||
|
const { startInterval, responseTimeout } = config.connectors.emessage
|
||||||
|
let nextDelay = startInterval + 0
|
||||||
|
do {
|
||||||
|
let resultCheck = await checkResponse()
|
||||||
|
if (resultCheck == true) return res()
|
||||||
|
await delaySeconds(nextDelay)
|
||||||
|
nextDelay *= 2 // wait 2x longer than before
|
||||||
|
} while (nextDelay <= responseTimeout)
|
||||||
|
return rej()
|
||||||
|
})
|
||||||
|
return Promise.race([
|
||||||
|
new Promise((res, rej) => { // exit pattern after duplexTimeout
|
||||||
|
setTimeout(rej, config.connectors.emessage.duplexTimeout * 1e3)
|
||||||
|
}),
|
||||||
|
deliveryProcess.then(responseProcess)
|
||||||
|
])
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err)
|
||||||
|
this.connectorRegistry.reportFail(msg, UUID)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = eCityrufConnector
|
@ -0,0 +1,92 @@
|
|||||||
|
const MessageManager = require("../MessageManager")
|
||||||
|
const PagerDevice = require("./Device")
|
||||||
|
const Str = require('@supercharge/strings')
|
||||||
|
const config = require('../../config.json')
|
||||||
|
|
||||||
|
// Birdy Slim (IoT) Device
|
||||||
|
class EMessage2Ways extends PagerDevice {
|
||||||
|
constructor () {
|
||||||
|
super()
|
||||||
|
this.duplex = true
|
||||||
|
this.supportBOSkrypt = false
|
||||||
|
this.name = "emessage2WayS"
|
||||||
|
}
|
||||||
|
RandID() {
|
||||||
|
return `E${ Str.random(8) }`
|
||||||
|
}
|
||||||
|
async formatTX(msg) {
|
||||||
|
msg.id = this.RandID()
|
||||||
|
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) {
|
||||||
|
if (typeof(data) === 'object' && !!data.type) {
|
||||||
|
const stateSet = {
|
||||||
|
lastSeen: data.date
|
||||||
|
}
|
||||||
|
// If we have a Battery Measurement or other Power Events, we should store it
|
||||||
|
if (!!data.battery) stateSet.battery = data.battery/1e1
|
||||||
|
if (data.hasOwnProperty('isCharging')) stateSet.isCharging = data.isCharging
|
||||||
|
if (data.hasOwnProperty('poweredOn')) stateSet.poweredOn = data.poweredOn
|
||||||
|
|
||||||
|
// the same if we have an rssi measurement
|
||||||
|
if (!!data.rssi) stateSet.rssi = data.rssi
|
||||||
|
// and if we have the 3 components of a GPS Block
|
||||||
|
if (!!data.latitude && !!data.longitude && !!data.lastGPSAcquisition) stateSet.gps = {
|
||||||
|
lastGPSAcquisition: data.lastGPSAcquisition,
|
||||||
|
latitude: data.latitude,
|
||||||
|
longitude: data.longitude,
|
||||||
|
}
|
||||||
|
stateSet.lastLoRaPacket = data.metadata
|
||||||
|
console.log(data, stateSet)
|
||||||
|
/*if (!!data.metadata && !!data.metadata.uplink_message.rx_metadata) {
|
||||||
|
const rx_metadata = data.metadata.uplink_message.rx_metadata
|
||||||
|
|
||||||
|
}*/
|
||||||
|
|
||||||
|
switch (data.type) {
|
||||||
|
case 'ack': {
|
||||||
|
switch (data.ack) {
|
||||||
|
case 'recv':
|
||||||
|
require('../ConnectorRegistry').reportDelivered({ id: data.msgid }, `lorawan:${ data.device_id }`)
|
||||||
|
break;
|
||||||
|
case 'read':
|
||||||
|
require('../MessageManager').markMessageRead(data.msgid)
|
||||||
|
break;
|
||||||
|
case 'operational':
|
||||||
|
require('../MessageManager').respondToMessage(data.msgid, data.operationalData)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// If we have had a Ack. Event, we should store some Metadata about it too
|
||||||
|
require('../MessageManager').attachMetadata(data.msgid, {
|
||||||
|
ack: data.ack,
|
||||||
|
rssi: data.rssi,
|
||||||
|
date: data.date,
|
||||||
|
metadata: data.metadata,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'sos':
|
||||||
|
stateSet.sos = {
|
||||||
|
sos: data.sos,
|
||||||
|
date: data.date,
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'status':
|
||||||
|
case 'cannedMessage':
|
||||||
|
case 'low_battery':
|
||||||
|
case 'power':
|
||||||
|
case 'battery':
|
||||||
|
case 'sos':
|
||||||
|
case 'gps':
|
||||||
|
require('../DeviceRegistry').deviceEvent(this.name, data.device_id, data)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
require('../DeviceRegistry').stateSet(this.name, data.device_id, stateSet)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = EMessage2Ways
|
@ -1,6 +1,7 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
GenericPager: require("./GenericPager"),
|
GenericPager: require("./GenericPager"),
|
||||||
BirdySlim: require("./BirdySlim"),
|
BirdySlim: require("./BirdySlim"),
|
||||||
|
EMessage2Ways: require("./EMessage2Ways"),
|
||||||
Skyper: require("./Skyper"),
|
Skyper: require("./Skyper"),
|
||||||
Device: require("./Device"),
|
Device: require("./Device"),
|
||||||
}
|
}
|
Loading…
Reference in New Issue