162 lines
4.3 KiB
Python
Executable file
162 lines
4.3 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
# Bitlair HobbyBot
|
|
|
|
from time import sleep
|
|
from discord import Intents
|
|
from discord.ext import commands
|
|
from discord_webhook import DiscordWebhook, DiscordEmbed
|
|
import pytz
|
|
import paho.mqtt.client as mqtt
|
|
import paho.mqtt.subscribe as subscribe
|
|
import os
|
|
import sys
|
|
|
|
|
|
mqtt_host = os.getenv("MQTT_HOST")
|
|
if not mqtt_host:
|
|
print("MQTT_HOST unset")
|
|
sys.exit(1)
|
|
|
|
token = os.getenv("DISCORD_TOKEN")
|
|
if not token:
|
|
print("DISCORD_TOKEN unset")
|
|
sys.exit(1)
|
|
|
|
webhook_url = os.getenv("DISCORD_WEBHOOK_URL")
|
|
if not webhook_url:
|
|
print("DISCORD_WEBHOOK_URL unset")
|
|
sys.exit(1)
|
|
|
|
timezone = pytz.timezone("Europe/Amsterdam")
|
|
|
|
# Discord bot stuff
|
|
intents = Intents.default()
|
|
intents.message_content = True
|
|
intents.members = True
|
|
HobbyBot = commands.Bot(command_prefix="!", description="Bitlair Bot", intents=intents)
|
|
|
|
|
|
def mqtt_get_one(topic):
|
|
try:
|
|
msg = subscribe.simple(topic, hostname=mqtt_host, keepalive=10)
|
|
return msg.payload.decode()
|
|
except Exception as err:
|
|
print(err)
|
|
return ""
|
|
|
|
|
|
# Define bot commands
|
|
@HobbyBot.event
|
|
async def on_ready():
|
|
print(f"Logged in as {HobbyBot.user} (ID: {HobbyBot.user.id})")
|
|
|
|
|
|
# !state
|
|
@HobbyBot.command(description="Bitlair Space State")
|
|
async def state(ctx):
|
|
async with ctx.typing():
|
|
spaceState = mqtt_get_one("bitlair/state")
|
|
if spaceState == "open":
|
|
await ctx.send("Bitlair is OPEN! :sunglasses:")
|
|
elif spaceState == "closed":
|
|
await ctx.send("Bitlair is closed :pensive:")
|
|
|
|
|
|
# !co2
|
|
@HobbyBot.command(description="co2 levels")
|
|
async def co2(ctx):
|
|
async with ctx.typing():
|
|
hoofdruimte = mqtt_get_one("bitlair/climate/hoofdruimte_ingang/co2_ppm")
|
|
await ctx.send("Hoofdruimte: %s ppm\n" % hoofdruimte)
|
|
|
|
|
|
# !temp
|
|
@HobbyBot.command(description="Temperature")
|
|
async def temp(ctx):
|
|
async with ctx.typing():
|
|
hoofdruimte = mqtt_get_one("bitlair/climate/hoofdruimte_ingang/temperature_c")
|
|
await ctx.send("Hoofdruimte: %s °C\n" % hoofdruimte)
|
|
|
|
|
|
# !humid
|
|
@HobbyBot.command(description="Humidity")
|
|
async def humid(ctx):
|
|
async with ctx.typing():
|
|
hoofdruimte = mqtt_get_one("bitlair/climate/hoofdruimte_ingang/humidity_pct")
|
|
await ctx.send("Hoofdruimte: %s pct\n" % hoofdruimte)
|
|
|
|
|
|
# !np
|
|
@HobbyBot.command(description="Now Playing")
|
|
async def np(ctx):
|
|
async with ctx.typing():
|
|
await ctx.send("Now playing: Darude - Sandstorm")
|
|
|
|
|
|
# define mqtt client stuff
|
|
#
|
|
# subscribe to topics
|
|
def on_connect(client, userdata, flags, rc):
|
|
client.subscribe("bitlair/alarm")
|
|
client.subscribe("bitlair/state")
|
|
client.subscribe("bitlair/state/djo")
|
|
client.subscribe("bitlair/photos")
|
|
|
|
|
|
def webhook_message(msg):
|
|
webhook = DiscordWebhook(url=webhook_url, rate_limit_retry=True, content=msg)
|
|
webhook.execute()
|
|
|
|
|
|
retained = {
|
|
"bitlair/alarm",
|
|
"bitlair/photos",
|
|
"bitlair/state",
|
|
"bitlair/state/djo",
|
|
}
|
|
|
|
|
|
# post to mqtt discord channel when state changes
|
|
def on_message(client, userdata, msg):
|
|
try:
|
|
topic = msg.topic
|
|
msg = msg.payload.decode()
|
|
|
|
# Retained messages trigger an initial message on connecting. Prevent relaying them to
|
|
# Discord on startup.
|
|
if topic in retained:
|
|
retained.remove(topic)
|
|
return
|
|
|
|
if topic == "bitlair/alarm":
|
|
webhook_message("Alarm: %s" % msg)
|
|
elif topic == "bitlair/state":
|
|
webhook_message("Bitlair is now %s" % msg.upper())
|
|
elif topic == "bitlair/state/djo":
|
|
webhook_message("DJO is now %s" % msg.upper())
|
|
elif topic == "bitlair/photos":
|
|
webhook = DiscordWebhook(url=webhook_url, rate_limit_retry=True)
|
|
embed = DiscordEmbed(title="WIP Cam", color="fc5d1d")
|
|
embed.set_url("https://bitlair.nl/fotos/view/" + msg)
|
|
embed.set_image("https://bitlair.nl/fotos/photos/" + msg)
|
|
webhook.add_embed(embed)
|
|
webhook.execute()
|
|
else:
|
|
return
|
|
sleep(1) # Prevent triggering rate limits.
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
|
|
client = mqtt.Client()
|
|
client.on_connect = on_connect
|
|
client.on_message = on_message
|
|
client.connect(mqtt_host, 1883, 60)
|
|
|
|
# Start mqtt loop and discord bot
|
|
client.loop_start()
|
|
HobbyBot.run(token)
|
|
|
|
# Exit when bot crashes
|
|
client.loop_stop(force=True)
|