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
@@ -134,6 +136,15 @@ def set_status(self, value: LedStatus) -> None:
134
136
GPIO .output (self .LEDs .STATUS_GREEN , GPIO .HIGH if value .value [1 ] else GPIO .LOW )
135
137
GPIO .output (self .LEDs .STATUS_BLUE , GPIO .HIGH if value .value [2 ] else GPIO .LOW )
136
138
139
+ # Also send the status over MQTT
140
+ if MQTT_CLIENT is not None :
141
+ MQTT_CLIENT .publish (
142
+ f'{ MQTT_TOPIC_ROOT } /state' ,
143
+ json .dumps ({"state" : value .name }),
144
+ qos = 1 ,
145
+ retain = True ,
146
+ )
147
+
137
148
138
149
LED_CONTROLLER = LEDController ()
139
150
@@ -216,6 +227,7 @@ def __init__(self, mountpoint_path: str) -> None:
216
227
self ._setup_logging (mountpoint_path )
217
228
LED_CONTROLLER .set_code (True )
218
229
LED_CONTROLLER .set_status (LedStatus .Running )
230
+
219
231
env = dict (os .environ )
220
232
env ["SBOT_METADATA_PATH" ] = MOUNTPOINT_DIR
221
233
if MQTT_URL is not None :
@@ -248,7 +260,6 @@ def cleanup(self) -> None:
248
260
except subprocess .TimeoutExpired :
249
261
# The process did not exit after 5 seconds, so kill it.
250
262
self ._send_signal (signal .SIGKILL )
251
- self ._set_leds ()
252
263
253
264
def close (self ) -> None :
254
265
self .cleanup ()
@@ -267,8 +278,10 @@ def _watch_process(self) -> None:
267
278
self .process .wait ()
268
279
if self .process .returncode != 0 :
269
280
USERCODE_LOGGER .warning (f"Process exited with code { self .process .returncode } " )
281
+ LED_CONTROLLER .set_status (LedStatus .Crashed )
270
282
else :
271
283
USERCODE_LOGGER .info ("Your code finished successfully." )
284
+ LED_CONTROLLER .set_status (LedStatus .Finished )
272
285
273
286
process_lifetime = time .time () - self .process_start_time
274
287
@@ -306,12 +319,6 @@ def _log_output(self, pipe: IO[str]) -> None:
306
319
USERCODE_LOGGER .log (USERCODE_LEVEL , line .rstrip ('\n ' ))
307
320
LOGGER .info ('Process output finished' )
308
321
309
- def _set_leds (self ) -> None :
310
- if self .process .returncode == 0 :
311
- LED_CONTROLLER .set_status (LedStatus .Finished )
312
- else :
313
- LED_CONTROLLER .set_status (LedStatus .Crashed )
314
-
315
322
def _rotate_old_logs (self , log_dir : str ) -> None :
316
323
"""
317
324
Add a suffix to the old log file, if it exists.
@@ -438,7 +445,7 @@ def read_mqtt_config_file() -> MQTTVariables | None:
438
445
439
446
440
447
def setup_usercode_logging () -> None :
441
- global REL_TIME_FILTER
448
+ global REL_TIME_FILTER , MQTT_CLIENT , MQTT_TOPIC_ROOT
442
449
REL_TIME_FILTER = RelativeTimeFilter ()
443
450
USERCODE_LOGGER .addFilter (REL_TIME_FILTER )
444
451
USERCODE_LOGGER .setLevel (logging .DEBUG )
@@ -459,6 +466,8 @@ def setup_usercode_logging() -> None:
459
466
connected_callback = lambda : LED_CONTROLLER .set_wifi (True ),
460
467
disconnected_callback = lambda : LED_CONTROLLER .set_wifi (False ),
461
468
)
469
+ MQTT_CLIENT = handler .mqtt
470
+ MQTT_TOPIC_ROOT = mqtt_config .topic_prefix
462
471
463
472
handler .setLevel (logging .INFO )
464
473
handler .setFormatter (TieredFormatter (
@@ -479,6 +488,8 @@ def main():
479
488
registry = AutorunProcessRegistry ()
480
489
481
490
LED_CONTROLLER .mark_start ()
491
+ LED_CONTROLLER .set_status (LedStatus .NoUSB )
492
+
482
493
# Initial pass (in case an autorun FS is already mounted)
483
494
registry .update_filesystems (fstab_reader .read ())
484
495
0 commit comments