Browse Source

initial

master
user 1 year ago
commit
4ae4dc205a
  1. 1
      .gitignore
  2. 33
      bot.py
  3. 39
      map.py
  4. 164
      mqtt.py
  5. 23
      requirements.txt
  6. 15
      secrets.json

1
.gitignore vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
secrets.json

33
bot.py

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
import logging
from telegram import Update
from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
print(update)
print(update.effective_chat.id)
await context.bot.send_message(
chat_id=update.effective_chat.id, text="I'm a bot, please talk to me!"
)
async def location(update: Update, context: ContextTypes.DEFAULT_TYPE):
locs = updates[0]
await context.bot.send_location(
chat_id=update.effective_chat.id, latitude=locs["lat"], longitude=locs["lon"]
)
if __name__ == "__main__":
application = (
ApplicationBuilder()
.token("6215777004:AAHUiOAeAuHAGzuNtGnQSlVUJ56nXUnWUms")
.build()
)
start_handler = CommandHandler("start", start)
location_handler = CommandHandler("location", location)
application.add_handler(start_handler)
application.add_handler(location_handler)
application.run_polling()

39
map.py

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
# https://github.com/flopp/py-staticmaps
import staticmaps
from typing import NamedTuple
class CardMarker(NamedTuple):
lat: float
lon: float
imagefile: str | None
name: str
def make_map_icons(markers: list[CardMarker], path: str):
context = staticmaps.Context()
context.set_tile_provider(staticmaps.tile_provider_OSM)
for m in markers:
pos = staticmaps.create_latlng(m.lat, m.lon)
if m.imagefile is not None:
context.add_object(staticmaps.ImageMarker(pos, m.imagefile, 0, 0))
else:
context.add_object(staticmaps.Marker(pos, color=staticmaps.GREEN, size=12))
# render anti-aliased png (this only works if pycairo is installed)
image = context.render_cairo(500, 500)
image.write_to_png(path + ".png")
def make_map_icon(lat: float, long: float, path: str):
context = staticmaps.Context()
context.set_tile_provider(staticmaps.tile_provider_OSM)
frankfurt = staticmaps.create_latlng(lat, long)
context.add_object(staticmaps.Marker(frankfurt, color=staticmaps.GREEN, size=12))
# render anti-aliased png (this only works if pycairo is installed)
image = context.render_cairo(500, 500)
image.write_to_png(path + ".png")

164
mqtt.py

@ -0,0 +1,164 @@ @@ -0,0 +1,164 @@
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())

23
requirements.txt

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
anyio==3.6.2
appdirs==1.4.4
certifi==2022.12.7
charset-normalizer==3.1.0
future==0.18.3
geographiclib==2.0
h11==0.14.0
httpcore==0.16.3
httpx==0.23.3
idna==3.4
paho-mqtt==1.6.1
Pillow==9.5.0
py-staticmaps==0.4.0
pycairo==1.23.0
python-slugify==8.0.1
python-telegram-bot==20.2
requests==2.29.0
rfc3986==1.5.0
s2sphere==0.2.5
sniffio==1.3.0
svgwrite==1.4.3
text-unidecode==1.3
urllib3==1.26.15

15
secrets.json

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
{
"config": {
"update_interval_seconds": 30
},
"telegram": {
"bot_token": "",
"update_chat_id": 0
},
"owntracks": {
"broker": "",
"port": 8883,
"username": "",
"password": ""
}
}
Loading…
Cancel
Save