initial work for rak wisnode trackit
This commit is contained in:
parent
0115bab9dd
commit
b5057347f6
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,2 +1 @@
|
|||
.env
|
||||
.env2
|
||||
.env*
|
170
rak2171.py
Normal file
170
rak2171.py
Normal 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}×tamp={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
76
ttnscripts/rak2171.js
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue