listeningdaemon/rule-listener/script.py

166 lines
4.9 KiB
Python
Raw Normal View History

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
2024-11-02 17:33:01 +00:00
import random
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-11-03 11:04:27 +00:00
2024-11-02 17:33:01 +00:00
def publish_transform(fromTopic, toTopic):
if fromTopic and toTopic:
ft = fromTopic.removeprefix("main")
tt = toTopic.removeprefix("main")
path = "transform" + ft + tt
publish(path, 1)
2024-11-03 11:04:27 +00:00
async def set_config(topic, payload):
print(f"Set the config for {topic} to {payload}")
data.config[topic] = int(float(payload))
2024-11-02 17:33:01 +00:00
async def do_a_gesture(topic):
print(f"called to do a gesture for {topic}")
2024-11-03 11:04:27 +00:00
tl = data.topics.copy()
tl.remove('main' + topic)
random.shuffle(tl)
tl.insert(0, topic)
tl[0:random.randint(0, len(tl))]
wIndex = random.randint(0, len(tl))
2024-11-02 17:33:01 +00:00
isW = True
while isW:
2024-11-03 11:04:27 +00:00
print("walking")
wIndex += 1
index = wIndex % len(tl)
publish(tl[index], 1)
publish_transform(tl[index - 1], tl[index])
await asyncio.sleep(data.config['delay'])
2024-11-02 17:33:01 +00:00
if index > 0:
2024-11-03 11:04:27 +00:00
publish(tl[index - 1], 0)
print(f"Go off: {tl[index - 1]}")
await asyncio.sleep(data.config['delay'] * 0.8)
2024-11-02 17:33:01 +00:00
2024-11-03 11:04:27 +00:00
if (random.random() > data.config['probability']):
2024-11-02 17:33:01 +00:00
print("finished the walk")
publish("main/gesture" + topic, 0)
isW = False
2024-11-03 11:04:27 +00:00
asyncio.run_coroutine_threadsafe(publish_later("main/gesture" + topic, 1), loop)
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-11-03 11:04:27 +00:00
publish("main/start", 1)
2024-10-28 20:33:14 +00:00
2024-11-02 17:33:01 +00:00
2024-11-03 11:04:27 +00:00
async def publish_later_by(topic, payload, delay):
await asyncio.sleep(delay)
publish(topic, payload)
async def publish_later(rule, msg):
2024-11-02 17:33:01 +00:00
print(
f"publish_later: Processing message with doTopic {rule['doTopic']} after {rule['delay']} seconds delay")
2024-10-28 22:32:02 +00:00
await asyncio.sleep(rule['delay'])
del rule['doingDelay']
publish(rule['doTopic'], rule['doMessage'])
2024-11-03 11:04:27 +00:00
publish_transform(msg.topic, rule['doTopic'])
2024-10-28 16:45:30 +00:00
2024-11-02 17:33:01 +00:00
2024-10-28 16:45:30 +00:00
def publish(topic, msg):
result = mqttc.publish(topic, msg)
status = result[0]
if not status == 0:
print(f"Failed to send message to topic {topic}")
2024-11-02 17:33:01 +00:00
2024-10-28 16:45:30 +00:00
def check_against_rules(msg):
if msg.topic in rules:
2024-11-02 17:33:01 +00:00
print(f"Found {len(rules[msg.topic])} rules on {msg.topic}"),
2024-10-28 22:32:02 +00:00
willReset = False
2024-11-02 17:33:01 +00:00
for rule in rules[msg.topic]:
if (state[msg.topic]['count'][msg.payload] >= rule['count']
or rule['count'] is None) and int(float(msg.payload)) == rule['state']:
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-11-02 17:33:01 +00:00
if 'doingDelay' not in rule:
2024-10-28 22:32:02 +00:00
rule['doingDelay'] = True
2024-11-03 11:04:27 +00:00
asyncio.run_coroutine_threadsafe(publish_later(rule, msg), loop)
2024-11-02 17:33:01 +00:00
else:
2024-10-28 22:32:02 +00:00
print('not scheduling')
2024-10-28 16:45:30 +00:00
else:
2024-11-03 11:04:27 +00:00
publish_transform(msg.topic, rule['doTopic'])
2024-10-28 16:45:30 +00:00
publish(rule['doTopic'], rule['doMessage'])
2024-11-02 17:33:01 +00:00
2024-10-28 22:32:02 +00:00
if willReset:
state[msg.topic]['count'][msg.payload] = 0
2024-11-02 17:33:01 +00:00
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-11-02 17:33:01 +00:00
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):
if msg.retain:
return False
else:
2024-10-28 22:32:02 +00:00
msg.payload = str(msg.payload.decode("utf-8"))
2024-11-02 17:33:01 +00:00
print(f'msg: {msg.payload} topic: {msg.topic}')
2024-10-28 22:32:02 +00:00
if len(msg.payload) > 140:
print("way to long of a message, not gonna store that")
return False
2024-11-02 17:33:01 +00:00
2024-10-28 22:32:02 +00:00
if msg.topic not in state:
state[msg.topic] = {'count': {}}
2024-11-02 17:33:01 +00:00
2024-10-28 22:32:02 +00:00
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:
2024-11-02 17:33:01 +00:00
if msg.payload.strip() != 0:
2024-11-03 11:04:27 +00:00
asyncio.run_coroutine_threadsafe(do_a_gesture(
msg.topic.removeprefix('main/gesture')), loop)
if "config" in msg.topic:
if msg.payload.strip() != 0:
asyncio.run_coroutine_threadsafe(set_config(
msg.topic.removeprefix('main/config'), msg.payload), loop)
2024-10-31 16:45:52 +00:00
else:
check_against_rules(msg)
2024-10-28 16:45:30 +00:00
2024-11-02 17:33:01 +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-11-02 17:33:01 +00:00
# asyncio.run_coroutine_threadsafe(do_a_gesture(data.topics[0].removeprefix('main')), loop)
# # Keep the asyncio event loop running
2024-10-28 20:33:14 +00:00
await asyncio.Event().wait()
2024-10-28 16:45:30 +00:00
2024-10-28 20:33:14 +00:00
# Run the main function
2024-11-02 17:33:01 +00:00
asyncio.run(main())