From 75e003ba1c63a9403d3fe5f20545b900a64b1f89 Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Wed, 14 Jul 2021 19:04:35 +0200
Subject: [PATCH] allow reconnection to mqtt broker

- also rearranged coordinator controls, and fixed topic filtering
---
 main.py  | 91 ++++++++++++++++++++++++++++++++++++--------------------
 utils.py |  9 ++++--
 2 files changed, 65 insertions(+), 35 deletions(-)

diff --git a/main.py b/main.py
index 6902331..2ceea6b 100644
--- a/main.py
+++ b/main.py
@@ -29,9 +29,6 @@ max_topic = utils.MaxTopicLength()
 # buffer for mqtt log
 message_queue = queue.Queue()
 
-# remember how often clear button was pressed (to only trigger clearing once)
-last_clear_n_clicks = 0
-
 # button-id: (topic, payload)
 commands = {
     'send-place-a-model': ('place-a/model', '1'),
@@ -137,6 +134,28 @@ app.layout = html.Div([
     ], className='row', style={'display': 'none'}),
     # dcc.Markdown("---"),
     html.Div([  # Row for commands
+        html.Div([  # Column for commands of place b
+            html.H3("Coordinator"),
+        # html.Div([  # Row for commands coordinator
+            html.Button('Model', id='send-coordinator-model', style=button_style_normal),
+            html.Button('Model (Details)', id='send-coordinator-model-details', style=button_style_normal),
+            html.Button('Exit', id='send-coordinator-exit', style=button_style_exit),
+        # ], className='row'),
+        # html.Div([  # Row for commands up
+            html.Button('Robot Control A Up', id='send-place-a-robot-ctrl-up', style=button_style_normal),
+            html.Button('Robot Control B Up', id='send-place-b-robot-ctrl-up', style=button_style_normal),
+            html.Button('RAG A Up', id='send-place-a-rag-up', style=button_style_normal),
+            html.Button('RAG B Up', id='send-place-b-rag-up', style=button_style_normal),
+            html.Button('Dummy Up', id='send-dummy-up', style=button_style_normal),
+        # ], className='row'),
+        # html.Div([  # Row for commands ready
+            html.Button('Robot Control A Ready', id='send-place-a-robot-ctrl-ready', style=button_style_normal),
+            html.Button('Robot Control B Ready', id='send-place-b-robot-ctrl-ready', style=button_style_normal),
+            html.Button('RAG A Ready', id='send-place-a-rag-ready', style=button_style_normal),
+            html.Button('RAG B Ready', id='send-place-b-rag-ready', style=button_style_normal),
+            html.Button('Dummy Ready', id='send-dummy-ready', style=button_style_normal),
+        # ], className='row'),
+        ], className="four columns"),
         html.Div([  # Column for commands of place a
             html.H3("Commands Place A"),
             html.Button('Model', id='send-place-a-model', style=button_style_normal),
@@ -145,7 +164,7 @@ app.layout = html.Div([
             html.Button('Exit', id='send-place-a-exit', style=button_style_exit),
             html.Button('obj-Red -> Red', id='send-place-a-demo-objRed-red', style=button_style_normal),
             html.Button('obj-Red -> Blue', id='send-place-a-demo-objRed-blue', style=button_style_normal),
-        ], className="six columns"),
+        ], className="four columns"),
         html.Div([  # Column for commands of place b
             html.H3("Commands Place B"),
             html.Button('Model', id='send-place-b-model', style=button_style_normal),
@@ -153,26 +172,7 @@ app.layout = html.Div([
             html.Button('Rewind', id='send-place-b-rewind', style=button_style_normal),
             html.Button('Exit', id='send-place-b-exit', style=button_style_exit),
             html.Button('obj-Red -> Red', id='send-place-b-demo-objRed-red', style=button_style_normal),
-        ], className="six columns"),
-    ], className='row'),
-    html.Div([  # Row for commands coordinator
-        html.Button('Coordinator Model', id='send-coordinator-model', style=button_style_normal),
-        html.Button('Coordinator Model (Details)', id='send-coordinator-model-details', style=button_style_normal),
-        html.Button('Coordinator Exit', id='send-coordinator-exit', style=button_style_exit),
-    ], className='row'),
-    html.Div([  # Row for commands up
-        html.Button('Robot Control A Up', id='send-place-a-robot-ctrl-up', style=button_style_normal),
-        html.Button('Robot Control B Up', id='send-place-b-robot-ctrl-up', style=button_style_normal),
-        html.Button('RAG A Up', id='send-place-a-rag-up', style=button_style_normal),
-        html.Button('RAG B Up', id='send-place-b-rag-up', style=button_style_normal),
-        html.Button('Dummy Up', id='send-dummy-up', style=button_style_normal),
-    ], className='row'),
-    html.Div([  # Row for commands ready
-        html.Button('Robot Control A Ready', id='send-place-a-robot-ctrl-ready', style=button_style_normal),
-        html.Button('Robot Control B Ready', id='send-place-b-robot-ctrl-ready', style=button_style_normal),
-        html.Button('RAG A Ready', id='send-place-a-rag-ready', style=button_style_normal),
-        html.Button('RAG B Ready', id='send-place-b-rag-ready', style=button_style_normal),
-        html.Button('Dummy Ready', id='send-dummy-ready', style=button_style_normal),
+        ], className="four columns"),
     ], className='row'),
     # dcc.Markdown("---"),
     html.H2("Filtered MQTT Log"),
@@ -201,6 +201,12 @@ app.layout = html.Div([
         value=["Auto-Scroll"],
         labelStyle={"display": "inline-block"},
     ),
+    dcc.Checklist(
+        id="mqtt-connected",
+        options=[{"label": "MQTT connected?", "value": "yes", "disabled": True}],
+        value=[],
+        labelStyle={"display": "inline-block"},
+    ),
     html.Button('Clear log', id='clear-mqtt-log', style=button_style_normal),
     dcc.Markdown("---"),
     html.Div([
@@ -313,6 +319,17 @@ def send_complex(*_):
     return dash.no_update
 
 
+@app.callback(
+    Output('mqtt-connected', 'value'),
+    Input('every-1-second', 'n_intervals'),
+)
+def check_connection(_n_intervals):
+    if not ready_event.is_set():
+        print('.', end='', flush=True)
+        return []
+    return ['yes']
+
+
 @app.callback(
     Output('filtered-mqtt-log', 'value'),
     Output('mqtt-log', 'value'),
@@ -349,9 +366,13 @@ def append_to_mqtt_log(_n_intervals, clear_n_clicks, filter_options, topics_to_f
 
     if trigger_id == 'topics-to-filter':
         filtered_value = ""
+        last_match = True
         for line in value.split('\n'):
-            if utils.topic_match(topics_to_filter, line):
+            if utils.topic_match(topics_to_filter, line, last_match=last_match)[0]:
                 filtered_value += line + '\n'
+                last_match = True
+            else:
+                last_match = False
     else:
         # assume trigger_id == 'every-1-second'
         local_messages = []
@@ -366,12 +387,10 @@ def append_to_mqtt_log(_n_intervals, clear_n_clicks, filter_options, topics_to_f
             if not filtered_value:
                 filtered_value = ""
             for msg in local_messages:
-                timestamp, topic, message = utils.parse_log_msg(msg)
-                topic = topic.replace(chr(65532), '')
-                topic_match = topic in topics_to_filter
+                topic_match, topic = utils.topic_match(topics_to_filter, msg)
                 if topic_match:
                     filtered_value += msg + "\n"
-                if topic not in filter_options:
+                if topic not in (option['label'] for option in filter_options):
                     filter_options.append({'label': topic, 'value': topic})
         else:
             return dash.no_update
@@ -427,8 +446,15 @@ def send_manual(n_clicks, topic, message):
 
 def on_mqtt_connect(_client, _userdata, _flags, _rc, _properties=None):
     # Callback for mqtt client when connected
-    print('Connected at ' + datetime.datetime.now().isoformat())
+    print('\nConnected at ' + datetime.datetime.now().isoformat())
     ready_event.set()
+    mqttc.subscribe(topic='#')
+    threading.Thread(target=publish_test_message).start()
+
+
+def on_mqtt_disconnect(_client, _userdata, _rc):
+    print('Lost connection at ' + datetime.datetime.now().isoformat())
+    ready_event.clear()
 
 
 def on_mqtt_message(_client, _userdata, message):
@@ -463,12 +489,13 @@ def publish_test_message():
 
 
 if __name__ == '__main__':
+    print('Starting web-ros3rag')
     mqttc.on_connect = on_mqtt_connect
+    mqttc.on_disconnect = on_mqtt_disconnect
     mqttc.on_message = on_mqtt_message
+    mqttc.reconnect_delay_set(max_delay=2)
     mqttc.connect_async(MQTT_SERVER)
     mqttc.loop_start()
     if not ready_event.wait(2.0):  # wait 2 seconds
         print('Could not connect to mqtt in time!')
-    mqttc.subscribe(topic='#')
-    threading.Thread(target=publish_test_message).start()
     app.run_server(debug=True)
diff --git a/utils.py b/utils.py
index d4bcf48..b3751da 100644
--- a/utils.py
+++ b/utils.py
@@ -36,11 +36,14 @@ def parse_log_msg(entry: str):
     return entry[1:at_index].strip(), entry[at_index + 1:bracket_index].strip(), entry[bracket_index + 2:]
 
 
-def topic_match(topics_to_filter, msg):
-    timestamp, topic, message = parse_log_msg(msg)
+def topic_match(topics_to_filter, msg, last_match=True):
+    try:
+        timestamp, topic, message = parse_log_msg(msg)
+    except:
+        return last_match, None
     # replacing strange space characters
     topic = topic.replace(chr(65532), '')
-    return topic in topics_to_filter
+    return topic in topics_to_filter, topic
 
 
 def format_scene(scene: cgv_connector_pb2.Scene):
-- 
GitLab