You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

164 lines
4.2 KiB

from paho.mqtt import client as mqtt_client
import ssl
import random
import json
import time
from map import make_map_icon, make_map_icons, CardMarker
import base64
import asyncio
import telegram
conf = {}
with open("secrets.json", "r") as f:
conf = json.loads(f.read())
broker = conf["owntracks"]["broker"]
port = conf["owntracks"]["port"]
client_id = f"python-mqtt-{random.randint(0, 1000)}"
username = conf["owntracks"]["username"]
password = conf["owntracks"]["password"]
BOT_TOKEN = conf["telegram"]["bot_token"]
chat_id = conf["telegram"]["update_chat_id"]
always_update = False
UPDATE_INTERVAL = conf["config"]["update_interval_seconds"]
def get_user_key(topic):
return topic.split("/")[1]
def connect_mqtt():
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to MQTT Broker!")
else:
print("Failed to connect, return code %d\n", rc)
# Set Connecting Client ID
client = mqtt_client.Client(client_id)
client.tls_set(
ca_certs=None,
certfile=None,
keyfile=None,
cert_reqs=ssl.CERT_REQUIRED,
tls_version=ssl.PROTOCOL_TLS,
ciphers=None,
)
client.username_pw_set(username, password)
client.on_connect = on_connect
client.connect(broker, port)
return client
updates = {}
cards = {}
def positions():
return updates
def topic_to_file(topic: str):
return topic.replace("/", "-")
def get_card(message_json: dict):
print(message_json)
user = message_json["user"]
if user in cards:
return CardMarker(
message_json["lat"],
message_json["lon"],
cards[user]["imgfile"],
cards[user]["name"],
)
else:
return CardMarker(message_json["lat"], message_json["lon"], None, topic)
def update(client, userdata, message, message_json):
user = message_json["user"]
map_file = "map"
# make_map_icons([get_card(m) for user, m in updates.items()], map_file)
def update_card(client, userdata, message, message_json):
print(message_json)
user = message_json["user"]
cards[user] = message_json
cards[user]["decoded"] = base64.b64decode(message_json["face"])
cards[user]["imgfile"] = "faces/" + topic_to_file(message.topic)
with open(cards[user]["imgfile"], "wb") as f:
f.write(cards[user]["decoded"])
return
def on_message(client, userdata, message):
print(userdata)
print(message.topic, str(message.payload))
data = json.loads(message.payload)
user = get_user_key(message.topic)
data["user"] = user
if data["_type"] == "location":
if (
always_update
or not user in updates
or updates[user]["created_at"] - data["created_at"] > UPDATE_INTERVAL
):
updates[user] = data
return update(client, userdata, message, updates[user])
if data["_type"] == "card":
update_card(client, userdata, message, data)
def subscribe(client):
topics = [
("owntracks/kait/bramble", 0),
("owntracks/amelia/a71x", 0),
]
for topic, qoi in topics[::-1]:
topics.append((topic + "/info", qoi))
client.subscribe(topics)
client.on_message = on_message
async def main():
client = connect_mqtt()
subscribe(client)
bot = telegram.Bot(BOT_TOKEN)
message = None
last_update = 0
while True:
for i in range(20):
client.loop(timeout=1.0, max_packets=1)
async with bot:
if len(updates) > 0 and time.time() - last_update > UPDATE_INTERVAL:
make_map_icons([get_card(m) for user, m in updates.items()], "map")
last_update = time.time()
locs = updates[list(updates.keys())[0]]
if message is not None:
await message.delete()
with open("map.png", "rb") as f:
message = await bot.send_photo(chat_id, f)
# message = await bot.send_location(
# chat_id=chat_id,
# latitude=locs["lat"],
# longitude=locs["lon"],
# )
client.disconnect()
if __name__ == "__main__":
asyncio.run(main())