ioteer/rak2171.py

199 lines
6.2 KiB
Python

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.2"
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))
def push_msg(msg, device_id):
requests.post(
"https://api.pushover.net/1/messages.json",
data={
"token": PUSHOVER_TOKEN,
"user": PUSHOVER_USER_KEY,
"message": msg,
"title": f"Nachricht von {device_id}",
},
)
def check_batt(batt, device_id):
msg = f"Batterie von {device_id} ist unter 20%: {batt}%"
if batt <= 20 and batt >= 1:
logging.info(msg)
push_msg(msg=msg, device_id=device_id)
# 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 = []
for gtw in data["uplink_message"]["rx_metadata"]:
gtw_id.append(gtw["gateway_ids"]["gateway_id"])
gws = ",".join(gtw_id)
logging.info(f"received via ttn gateway: {gws}")
# 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)
batt = data["uplink_message"]["decoded_payload"].get("batt", 0)
if fix == 1:
logging.info("got payload with a fix")
latitude = data["uplink_message"]["decoded_payload"].get("lat", 0.0)
longitude = data["uplink_message"]["decoded_payload"].get("lng", 0.0)
timestamp = data["uplink_message"]["decoded_payload"].get("time", 0)
accuracy = data["uplink_message"]["decoded_payload"].get("acc", 0)
battery = data["uplink_message"]["decoded_payload"].get("batt", 0)
ot_data = json.dumps(
{
"_type": "location",
"acc": accuracy,
"lat": latitude,
"lon": longitude,
"batt": battery,
"t": "p",
"tid": device_id,
"tst": timestamp,
"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
)
# check battery
check_batt(batt=batt, device_id=device_id)
# send to traccar
logging.info("publishing data to traccar")
traccar_url = f"{DST_TRACCAR_URL}/?id={device_id}&lat={latitude}&lon={longitude}&timestamp={timestamp}&accuracy={accuracy}&batt={battery}"
requests.get(traccar_url)
# elif sos == 0:
# logging.info("got payload with a sos")
# push_msg(msg=f"Knopf 5 mal gedrückt - deaktiviert", device_id=device_id)
elif sos == 1:
logging.info("got payload with a sos")
push_msg(msg=f"Knopf 5 mal gedrückt - aktiviert", device_id=device_id)
# TODO publish geo:// URL
elif alarm == 1:
logging.info("got payload with an alarm")
else:
logging.info("no usable payload - skipping")
# check battery
check_batt(batt=batt, device_id=device_id)
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")