initial work for rak wisnode trackit

This commit is contained in:
Tobias Brunner 2023-06-02 20:36:23 +02:00
parent 0115bab9dd
commit b5057347f6
Signed by: tobru
SSH Key Fingerprint: SHA256:kywVhvCA+MIxL6eBgoQa+BfC/ROJqcfD2bpy1PR6Ebk
3 changed files with 247 additions and 2 deletions

3
.gitignore vendored
View File

@ -1,2 +1 @@
.env
.env2
.env*

170
rak2171.py Normal file
View File

@ -0,0 +1,170 @@
import paho.mqtt.client as mqtt
import json
import os
import logging
import signal
import requests
from datetime import datetime
from dotenv import find_dotenv, load_dotenv
from pprint import pprint
load_dotenv(find_dotenv(filename=".env_rak2171"))
SRC_MQTT_HOST = os.getenv("SRC_MQTT_HOST")
SRC_MQTT_USER = os.getenv("SRC_MQTT_USER")
SRC_MQTT_PASS = os.getenv("SRC_MQTT_PASS")
DST_MQTT_HOST = os.getenv("DST_MQTT_HOST")
DST_MQTT_USER = os.getenv("DST_MQTT_USER")
DST_MQTT_PASS = os.getenv("DST_MQTT_PASS")
DST_TRACCAR_URL = os.getenv("DST_TRACCAR_URL")
PUSHOVER_TOKEN = os.getenv("PUSHOVER_TOKEN")
PUSHOVER_USER_KEY = os.getenv("PUSHOVER_USER_KEY")
VERSION = "v1.0"
OT_TOPIC_PREFIX = "owntracks/things/"
def on_connect_ttn(client, userdata, flags, rc):
logging.info("connected to ttn %s - %s", SRC_MQTT_HOST, str(rc))
client.subscribe("v3/+/devices/+/up")
def on_connect_ot(client, userdata, flags, rc):
logging.info("connected to ot %s - %s", DST_MQTT_HOST, str(rc))
def on_publish_ot(client, userdata, rc):
logging.info("published data to ot")
def on_log(client, userdata, level, buf):
logging_level = mqtt.LOGGING_LEVEL[level]
logging.log(logging_level, buf)
# logging.info("got a log message level %s: %s", level, str(buf))
# The callback for when a PUBLISH message is received from the server.
def on_message_ttn(client, userdata, msg):
data = json.loads(msg.payload)
device_id = data["end_device_ids"]["device_id"]
logging.info(
"message from ttn received for %s via %s",
device_id,
data["uplink_message"]["network_ids"]["cluster_id"],
)
# retrieve info about gateway
# gtw_id = data["uplink_message"]["rx_metadata"][0]["gateway_ids"]["gateway_id"]
# for gtw in data["uplink_message"]["rx_metadata"]:
# pprint(gtw)
# gtw_id += data["uplink_message"]["rx_metadata"][gtw]["gateway_ids"]["gateway_id"]
# logging.info("received via gw %s", gtw_id)
# the decoded data
fix = data["uplink_message"]["decoded_payload"].get("fix", 0)
sos = data["uplink_message"]["decoded_payload"].get("sos", 0)
alarm = data["uplink_message"]["decoded_payload"].get("alarm", 0)
if fix == 1:
logging.info("got payload with a fix")
ot_data = json.dumps(
{
"_type": "location",
"acc": data["uplink_message"]["decoded_payload"].get("acc", 0),
"lat": data["uplink_message"]["decoded_payload"].get("lat", 0.0),
"lon": data["uplink_message"]["decoded_payload"].get("lng", 0.0),
"batt": data["uplink_message"]["decoded_payload"].get("batt", 0),
"t": "p",
"tid": device_id,
"tst": data["uplink_message"]["decoded_payload"].get("time", 0),
"conn": "m",
}
)
# publish to owntracks via MQTT
logging.info(
"publishing data to owntracks via mqtt to topic %s",
OT_TOPIC_PREFIX + device_id,
)
client_ot.publish(
OT_TOPIC_PREFIX + device_id, payload=ot_data, retain=True, qos=1
)
# send to traccar
# logging.info("publishing data to traccar")
# traccar_url = f"{DST_TRACCAR_URL}/?id={device_id}&lat={latitude}&lon={longitude}&timestamp={timestamp}&hdop={hdop}&altitude={altitude}&speed=0"
# requests.get(traccar_url)
elif sos == 1:
logging.info("got payload with a sos")
requests.post(
"https://api.pushover.net/1/messages.json",
data={
"token": PUSHOVER_TOKEN,
"user": PUSHOVER_USER_KEY,
"message": f"SOS from {device_id}",
},
)
elif alarm == 1:
logging.info("got payload with an alarm")
else:
logging.info("no usable payload - skipping")
def shutdown():
logging.info("disconnecting from mqtt")
client_ot.disconnect()
client_ot.loop_stop()
client_ttn.disconnect()
client_ttn.loop_stop()
def handleSIGTERM(signalNumber, frame):
logging.info("got SIGTERM")
shutdown()
return
if __name__ == "__main__":
signal.signal(signal.SIGTERM, handleSIGTERM)
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S %Z",
)
logging.info("Starting ioteer rak2171. " + VERSION)
# Prepare MQTT for The Things Network
client_ttn = mqtt.Client()
client_ttn.enable_logger()
client_ttn.on_connect = on_connect_ttn
client_ttn.on_message = on_message_ttn
client_ttn.on_log = on_log
client_ttn.username_pw_set(SRC_MQTT_USER, SRC_MQTT_PASS)
client_ttn.tls_set()
client_ttn.connect(SRC_MQTT_HOST, 8883, 60)
# Prepare MQTT for OwnTracks
ot_lwt = json.dumps(
{
"_type": "lwt",
"tst": int(datetime.timestamp(datetime.now())),
}
)
client_ot = mqtt.Client()
client_ot.enable_logger()
client_ot.on_connect = on_connect_ot
client_ot.on_publish = on_publish_ot
client_ot.on_log = on_log
client_ot.username_pw_set(DST_MQTT_USER, DST_MQTT_PASS)
client_ot.tls_set()
# todo: this is wrong
# client_ot.will_set(OT_TOPIC_PREFIX + device_id, payload=ot_lwt, qos=1, retain=True)
client_ot.connect(DST_MQTT_HOST, 8883, 60)
try:
# Connect to MQTT and react to messages
client_ot.loop_start()
client_ttn.loop_forever()
except KeyboardInterrupt:
shutdown()
logging.info("tschuess")

76
ttnscripts/rak2171.js Normal file
View File

@ -0,0 +1,76 @@
// For TTN and Datacake
function Decoder(bytes, fPort) {
return Decode(fPort, bytes);
}
// For Chirpstack
function Decode(fPort, bytes) {
var decoded = {};
// Adjust time zone only in older RAK2171 firmware versions!
// adjust time zone, here Asia/Manila = +8H
var my_time_zone = 0;
// (8 * 60 * 60);
decoded.num = bytes[1];
decoded.app_id = (bytes[2] << 24) | (bytes[3] << 16) | (bytes[4] << 8) | bytes[5];
decoded.dev_id = (bytes[6] << 24) | (bytes[7] << 16) | (bytes[8] << 8) | bytes[9];
switch (bytes[0]) {
case 0xCA: // No Location fix
decoded.acc = 0;
decoded.fix = 0;
decoded.batt = bytes[10];
decoded.time = ((bytes[11] << 24) | (bytes[12] << 16) | (bytes[13] << 8) | bytes[14]);
// adjust time zone
decoded.time = decoded.time + my_time_zone;
var dev_date = new Date(decoded.time * 1000);
decoded.time_stamp = dev_date.getHours() + ":" + dev_date.getMinutes();
decoded.date_stamp = dev_date.getDate() + "." + (dev_date.getMonth() + 1) + "." + dev_date.getFullYear();
decoded.stat = bytes[15] & 0x03;
decoded.gps = bytes[15] & 0x0C;
break;
case 0xCB: // Location fix
decoded.fix = 1;
decoded.batt = bytes[20];
decoded.time = ((bytes[21] << 24) | (bytes[22] << 16) | (bytes[23] << 8) | bytes[24]);
// adjust time zone
decoded.time = decoded.time + my_time_zone;
var dev_date = new Date(decoded.time * 1000);
decoded.time_stamp = dev_date.getHours() + ":" + dev_date.getMinutes();
decoded.date_stamp = dev_date.getDate() + "." + (dev_date.getMonth() + 1) + "." + dev_date.getFullYear();
decoded.stat = bytes[25] & 0x03;
decoded.gps = bytes[25] & 0x0C;
decoded.lng = (((bytes[10] << 24) | (bytes[11] << 16) | (bytes[12] << 8) | bytes[13]) * 0.000001).toFixed(6);
decoded.lat = (((bytes[14] << 24) | (bytes[15] << 16) | (bytes[16] << 8) | bytes[17]) * 0.000001).toFixed(6);
decoded.acc = bytes[18];
decoded.gps_start = bytes[19];
decoded.location = "(" + decoded.latitude + "," + decoded.longitude + ")";
break;
case 0xCC: // SOS
decoded.sos = 1;
decoded.lng = (((bytes[10] << 24) | (bytes[11] << 16) | (bytes[12] << 8) | bytes[13]) * 0.000001).toFixed(6);
decoded.lat = (((bytes[14] << 24) | (bytes[15] << 16) | (bytes[16] << 8) | bytes[17]) * 0.000001).toFixed(6);
if (bytes.length > 18) {
var i;
for (i = 18; i < 28; i++) {
decoded.name += bytes[i].toString();
}
for (i = 28; i < 40; i++) {
decoded.country += bytes[i].toString();
}
for (i = 39; i < 50; i++) {
decoded.phone += bytes[i].toString();
}
}
decoded.location = "(" + decoded.latitude + "," + decoded.longitude + ")";
break;
case 0xCD:
decoded.sos = 0;
break;
case 0xCE:
decoded.alarm = 0x01;
decoded.alarm_lvl = bytes[10];
break;
}
return decoded;
}