2024-10-28 16:45:30 +00:00
|
|
|
import paho.mqtt.client as mqtt
|
2024-10-28 20:33:14 +00:00
|
|
|
import asyncio
|
2024-10-28 16:45:30 +00:00
|
|
|
import secrets
|
2024-10-28 22:32:02 +00:00
|
|
|
import data
|
|
|
|
from random import randrange
|
2024-10-28 16:45:30 +00:00
|
|
|
|
|
|
|
|
2024-10-28 22:32:02 +00:00
|
|
|
state = {}
|
|
|
|
rules = data.rules
|
2024-10-28 20:33:14 +00:00
|
|
|
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
|
2024-10-28 16:45:30 +00:00
|
|
|
|
2024-10-31 16:45:52 +00:00
|
|
|
async def do_a_gesture(gesture, topic):
|
2024-10-28 22:32:02 +00:00
|
|
|
state = False
|
2024-10-31 16:45:52 +00:00
|
|
|
delay = gesture["delay"]
|
|
|
|
for i in range(randrange(gesture["range"][0],gesture["range"][1])):
|
2024-10-28 22:32:02 +00:00
|
|
|
await asyncio.sleep(delay)
|
2024-10-31 16:45:52 +00:00
|
|
|
delay = delay * gesture["multiplier"]
|
2024-10-28 22:32:02 +00:00
|
|
|
if state:
|
2024-10-31 16:45:52 +00:00
|
|
|
publish("gesture" + topic, gesture["on"])
|
2024-10-28 22:32:02 +00:00
|
|
|
state = False
|
|
|
|
else:
|
2024-10-31 16:45:52 +00:00
|
|
|
publish("gesture" + topic, gesture["off"])
|
2024-10-28 22:32:02 +00:00
|
|
|
state = True
|
|
|
|
|
2024-10-31 16:45:52 +00:00
|
|
|
publish("main/gesture" + topic, 0)
|
2024-10-28 22:32:02 +00:00
|
|
|
|
|
|
|
|
2024-10-28 16:45:30 +00:00
|
|
|
def on_connect(client, userdata, flags, reason_code, properties):
|
|
|
|
print(f"Connected with result code {reason_code}")
|
|
|
|
client.subscribe("main/#")
|
2024-10-28 20:33:14 +00:00
|
|
|
|
2024-10-31 16:45:52 +00:00
|
|
|
async def publish_later(rule, transformTopic):
|
2024-10-28 22:32:02 +00:00
|
|
|
print(f"publish_later: Processing message with doTopic {rule['doTopic']} after {rule['delay']} seconds delay")
|
|
|
|
await asyncio.sleep(rule['delay'])
|
|
|
|
del rule['doingDelay']
|
|
|
|
publish(rule['doTopic'], rule['doMessage'])
|
2024-10-31 16:45:52 +00:00
|
|
|
publish(transformTopic, 1)
|
2024-10-28 16:45:30 +00:00
|
|
|
|
|
|
|
def publish(topic, msg):
|
2024-10-28 22:32:02 +00:00
|
|
|
print(f"publish {topic} {msg}")
|
2024-10-28 16:45:30 +00:00
|
|
|
result = mqttc.publish(topic, msg)
|
|
|
|
|
|
|
|
status = result[0]
|
|
|
|
|
|
|
|
if not status == 0:
|
|
|
|
print(f"Failed to send message to topic {topic}")
|
|
|
|
|
|
|
|
def check_against_rules(msg):
|
|
|
|
if msg.topic in rules:
|
2024-10-28 22:32:02 +00:00
|
|
|
print(f"Found {len(rules[msg.topic])} rules on this topic"),
|
|
|
|
|
|
|
|
willReset = False
|
2024-10-28 16:45:30 +00:00
|
|
|
|
2024-10-28 22:32:02 +00:00
|
|
|
for rule in rules[msg.topic]:
|
|
|
|
print(f"Rule: when the count is > {rule['count']}. Current = {state[msg.topic]['count'][msg.payload]} on payload {msg.payload}"),
|
|
|
|
|
|
|
|
if (state[msg.topic]['count'][msg.payload] >= rule['count'] or rule['count'] == False) and msg.payload == rule['state']:
|
2024-10-31 16:45:52 +00:00
|
|
|
print(f"transform topic is {transformTopic}")
|
2024-10-28 16:45:30 +00:00
|
|
|
if(rule['reset']):
|
2024-10-28 22:32:02 +00:00
|
|
|
willReset = True
|
2024-10-28 16:45:30 +00:00
|
|
|
if rule['delay']:
|
2024-10-28 22:32:02 +00:00
|
|
|
if not 'doingDelay' in rule:
|
|
|
|
rule['doingDelay'] = True
|
2024-10-31 16:45:52 +00:00
|
|
|
asyncio.run_coroutine_threadsafe(publish_later(rule, transformTopic), loop)
|
2024-10-28 22:32:02 +00:00
|
|
|
else:
|
|
|
|
print('not scheduling')
|
2024-10-28 16:45:30 +00:00
|
|
|
else:
|
2024-10-31 16:45:52 +00:00
|
|
|
publish(transformTopic, 1)
|
2024-10-28 16:45:30 +00:00
|
|
|
publish(rule['doTopic'], rule['doMessage'])
|
2024-10-28 22:32:02 +00:00
|
|
|
|
|
|
|
if willReset:
|
|
|
|
state[msg.topic]['count'][msg.payload] = 0
|
|
|
|
|
2024-10-28 16:45:30 +00:00
|
|
|
else:
|
2024-10-28 20:33:14 +00:00
|
|
|
print("... ... i have no rules for this topic")
|
|
|
|
|
2024-10-28 16:45:30 +00:00
|
|
|
# The callback for when a PUBLISH message is received from the server.
|
|
|
|
def on_message(client, userdata, msg):
|
2024-10-28 22:32:02 +00:00
|
|
|
print("on message")
|
2024-10-28 16:45:30 +00:00
|
|
|
if msg.retain:
|
|
|
|
return False
|
|
|
|
else:
|
2024-10-28 22:32:02 +00:00
|
|
|
msg.payload = str(msg.payload.decode("utf-8"))
|
|
|
|
|
|
|
|
if len(msg.payload) > 140:
|
|
|
|
print("way to long of a message, not gonna store that")
|
|
|
|
return False
|
|
|
|
|
|
|
|
if msg.topic not in state:
|
|
|
|
state[msg.topic] = {'count': {}}
|
|
|
|
|
|
|
|
state[msg.topic]['count'].setdefault(msg.payload, 0)
|
|
|
|
state[msg.topic]['count'][msg.payload] += 1
|
2024-10-31 16:45:52 +00:00
|
|
|
|
|
|
|
# check if the message has a gesture
|
|
|
|
if "gesture" in msg.topic:
|
|
|
|
if msg.payload.strip() in data.gestures:
|
|
|
|
asyncio.run_coroutine_threadsafe(do_a_gesture(data.gestures[msg.payload], msg.topic.removeprefix('main/gesture')), loop)
|
|
|
|
|
|
|
|
else:
|
|
|
|
check_against_rules(msg)
|
2024-10-28 16:45:30 +00:00
|
|
|
|
2024-10-28 20:33:14 +00:00
|
|
|
async def main():
|
|
|
|
global loop
|
|
|
|
loop = asyncio.get_running_loop() # Store the main event loop
|
2024-10-28 16:45:30 +00:00
|
|
|
|
2024-10-28 20:33:14 +00:00
|
|
|
mqttc.on_connect = on_connect
|
|
|
|
mqttc.on_message = on_message
|
2024-10-28 16:45:30 +00:00
|
|
|
|
2024-10-28 20:33:14 +00:00
|
|
|
mqttc.username_pw_set(secrets.mqtt_username, secrets.mqtt_password)
|
|
|
|
print("connect to klank.school")
|
|
|
|
mqttc.connect("mqtt.klank.school", 7000, 60)
|
2024-10-28 16:45:30 +00:00
|
|
|
|
2024-10-28 20:33:14 +00:00
|
|
|
# Start the MQTT loop in a background thread
|
|
|
|
mqttc.loop_start()
|
2024-10-28 22:32:02 +00:00
|
|
|
|
2024-10-28 20:33:14 +00:00
|
|
|
# Keep the asyncio event loop running
|
|
|
|
await asyncio.Event().wait()
|
2024-10-28 16:45:30 +00:00
|
|
|
|
2024-10-28 20:33:14 +00:00
|
|
|
# Run the main function
|
|
|
|
asyncio.run(main())
|