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
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())
|
|
|