/
TimerManager.py
151 lines (112 loc) · 4.92 KB
/
TimerManager.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import paho.mqtt.client as mqtt
import stmpy
import logging
from threading import Thread
import json
# TODO: choose proper MQTT broker address
MQTT_BROKER = 'test.mosquitto.org'
MQTT_PORT = 1883
# TODO: choose proper topics for communication
MQTT_TOPIC_INPUT = 'ttm4115/command'
MQTT_TOPIC_OUTPUT = 'ttm4115/answer'
class TimerLogic:
"""
State Machine for a named timer.
This is the support object for a state machine that models a single timer.
"""
def __init__(self, name, duration, component):
self._logger = logging.getLogger(__name__)
self.name = name
self.duration = duration
self.component = component
# TODO: build the transitions
self.stm = stmpy.Machine(name=name, transitions=[t0, t1, t2], obj=self)
# TODO define functions as transition effetcs
class TimerManagerComponent:
"""
The component to manage named timers in a voice assistant.
This component connects to an MQTT broker and listens to commands.
To interact with the component, do the following:
* Connect to the same broker as the component. You find the broker address
in the value of the variable `MQTT_BROKER`.
* Subscribe to the topic in variable `MQTT_TOPIC_OUTPUT`. On this topic, the
component sends its answers.
* Send the messages listed below to the topic in variable `MQTT_TOPIC_INPUT`.
{"command": "new_timer", "name": "spaghetti", "duration":50}
{"command": "status_all_timers"}
{"command": "status_single_timer", "name": "spaghetti"}
"""
def on_connect(self, client, userdata, flags, rc):
# we just log that we are connected
self._logger.debug('MQTT connected to {}'.format(client))
def on_message(self, client, userdata, msg):
"""
Processes incoming MQTT messages.
We assume the payload of all received MQTT messages is an UTF-8 encoded
string, which is formatted as a JSON object. The JSON object contains
a field called `command` which identifies what the message should achieve.
As a reaction to a received message, we can for example do the following:
* create a new state machine instance to handle the incoming messages,
* route the message to an existing state machine session,
* handle the message right here,
* throw the message away.
"""
self._logger.debug('Incoming message to topic {}'.format(msg.topic))
# TODO unwrap JSON-encoded payload
# TODO extract command
# TODO determine what to do
def __init__(self):
"""
Start the component.
## Start of MQTT
We subscribe to the topic(s) the component listens to.
The client is available as variable `self.client` so that subscriptions
may also be changed over time if necessary.
The MQTT client reconnects in case of failures.
## State Machine driver
We create a single state machine driver for STMPY. This should fit
for most components. The driver is available from the variable
`self.driver`. You can use it to send signals into specific state
machines, for instance.
"""
# get the logger object for the component
self._logger = logging.getLogger(__name__)
print('logging under name {}.'.format(__name__))
self._logger.info('Starting Component')
# create a new MQTT client
self._logger.debug('Connecting to MQTT broker {} at port {}'.format(MQTT_BROKER, MQTT_PORT))
self.mqtt_client = mqtt.Client()
# callback methods
self.mqtt_client.on_connect = self.on_connect
self.mqtt_client.on_message = self.on_message
# Connect to the broker
self.mqtt_client.connect(MQTT_BROKER, MQTT_PORT)
# subscribe to proper topic(s) of your choice
self.mqtt_client.subscribe(MQTT_TOPIC_INPUT)
# start the internal loop to process MQTT messages
self.mqtt_client.loop_start()
# we start the stmpy driver, without any state machines for now
self.stm_driver = stmpy.Driver()
self.stm_driver.start(keep_active=True)
self._logger.debug('Component initialization finished')
def stop(self):
"""
Stop the component.
"""
# stop the MQTT client
self.mqtt_client.loop_stop()
# stop the state machine Driver
self.stm_driver.stop()
# logging.DEBUG: Most fine-grained logging, printing everything
# logging.INFO: Only the most important informational log items
# logging.WARN: Show only warnings and errors.
# logging.ERROR: Show only error messages.
debug_level = logging.DEBUG
logger = logging.getLogger(__name__)
logger.setLevel(debug_level)
ch = logging.StreamHandler()
ch.setLevel(debug_level)
formatter = logging.Formatter('%(asctime)s - %(name)-12s - %(levelname)-8s - %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)
t = TimerManagerComponent()