48
48
# This will be populated if we have the config file
49
49
# url format: mqtt[s]://[<username>[:<password>]@]<host>[:<port>]/<topic_root>
50
50
MQTT_URL = None
51
+ MQTT_TOPIC_ROOT = ''
52
+ MQTT_CLIENT = None
51
53
MQTT_CONFIG_FILE = '/etc/sbot/mqtt.conf'
52
54
53
55
@@ -156,6 +158,15 @@ def set_status(self, value: LedStatus) -> None:
156
158
GPIO .output (self .LEDs .STATUS_GREEN , GPIO .HIGH if value .value [1 ] else GPIO .LOW )
157
159
GPIO .output (self .LEDs .STATUS_BLUE , GPIO .HIGH if value .value [2 ] else GPIO .LOW )
158
160
161
+ # Also send the status over MQTT
162
+ if MQTT_CLIENT is not None :
163
+ MQTT_CLIENT .publish (
164
+ f'{ MQTT_TOPIC_ROOT } /state' ,
165
+ json .dumps ({"state" : value .name }),
166
+ qos = 1 ,
167
+ retain = True ,
168
+ )
169
+
159
170
160
171
LED_CONTROLLER = LEDController ()
161
172
@@ -238,6 +249,7 @@ def __init__(self, mountpoint_path: str) -> None:
238
249
self ._setup_logging (mountpoint_path )
239
250
LED_CONTROLLER .set_code (True )
240
251
LED_CONTROLLER .set_status (LedStatus .Running )
252
+
241
253
env = dict (os .environ )
242
254
env ["SBOT_METADATA_PATH" ] = MOUNTPOINT_DIR
243
255
if MQTT_URL is not None :
@@ -270,7 +282,6 @@ def cleanup(self) -> None:
270
282
except subprocess .TimeoutExpired :
271
283
# The process did not exit after 5 seconds, so kill it.
272
284
self ._send_signal (signal .SIGKILL )
273
- self ._set_leds ()
274
285
275
286
def close (self ) -> None :
276
287
self .cleanup ()
@@ -289,8 +300,10 @@ def _watch_process(self) -> None:
289
300
self .process .wait ()
290
301
if self .process .returncode != 0 :
291
302
USERCODE_LOGGER .warning (f"Process exited with code { self .process .returncode } " )
303
+ LED_CONTROLLER .set_status (LedStatus .Crashed )
292
304
else :
293
305
USERCODE_LOGGER .info ("Your code finished successfully." )
306
+ LED_CONTROLLER .set_status (LedStatus .Finished )
294
307
295
308
process_lifetime = time .time () - self .process_start_time
296
309
@@ -328,12 +341,6 @@ def _log_output(self, pipe: IO[str]) -> None:
328
341
USERCODE_LOGGER .log (USERCODE_LEVEL , line .rstrip ('\n ' ))
329
342
LOGGER .info ('Process output finished' )
330
343
331
- def _set_leds (self ) -> None :
332
- if self .process .returncode == 0 :
333
- LED_CONTROLLER .set_status (LedStatus .Finished )
334
- else :
335
- LED_CONTROLLER .set_status (LedStatus .Crashed )
336
-
337
344
def _rotate_old_logs (self , log_dir : str ) -> None :
338
345
"""
339
346
Add a suffix to the old log file, if it exists.
@@ -460,7 +467,7 @@ def read_mqtt_config_file() -> MQTTVariables | None:
460
467
461
468
462
469
def setup_usercode_logging () -> None :
463
- global REL_TIME_FILTER
470
+ global REL_TIME_FILTER , MQTT_CLIENT , MQTT_TOPIC_ROOT
464
471
REL_TIME_FILTER = RelativeTimeFilter ()
465
472
USERCODE_LOGGER .addFilter (REL_TIME_FILTER )
466
473
USERCODE_LOGGER .setLevel (logging .DEBUG )
@@ -481,6 +488,8 @@ def setup_usercode_logging() -> None:
481
488
connected_callback = lambda : LED_CONTROLLER .set_wifi (True ),
482
489
disconnected_callback = lambda : LED_CONTROLLER .set_wifi (False ),
483
490
)
491
+ MQTT_CLIENT = handler .mqtt
492
+ MQTT_TOPIC_ROOT = mqtt_config .topic_prefix
484
493
485
494
handler .setLevel (logging .INFO )
486
495
handler .setFormatter (TieredFormatter (
@@ -501,6 +510,8 @@ def main():
501
510
registry = AutorunProcessRegistry ()
502
511
503
512
LED_CONTROLLER .mark_start ()
513
+ LED_CONTROLLER .set_status (LedStatus .NoUSB )
514
+
504
515
# Initial pass (in case an autorun FS is already mounted)
505
516
registry .update_filesystems (fstab_reader .read ())
506
517
0 commit comments