sgbaird commited on
Commit
9d57020
1 Parent(s): 2af30d4

split singleton (major fix!), use form, add experiment_id checking, min upper y bound, better messages

Browse files
Files changed (1) hide show
  1. app.py +83 -72
app.py CHANGED
@@ -7,6 +7,10 @@ import matplotlib.pyplot as plt
7
  import numpy as np
8
  from matplotlib.patches import Rectangle
9
 
 
 
 
 
10
  # Initialize Streamlit app
11
  st.title("Light-mixing Control Panel")
12
 
@@ -20,65 +24,65 @@ You may also be interested in the Acceleration Consortium's ["Hello World" micro
20
  """
21
  )
22
 
23
- # MQTT Configuration
24
- HIVEMQ_HOST = st.text_input(
25
- "Enter your HiveMQ host:",
26
- "248cc294c37642359297f75b7b023374.s2.eu.hivemq.cloud",
27
- type="password",
28
- )
29
- HIVEMQ_USERNAME = st.text_input("Enter your HiveMQ username:", "sgbaird")
30
- HIVEMQ_PASSWORD = st.text_input(
31
- "Enter your HiveMQ password:", "D.Pq5gYtejYbU#L", type="password"
32
- )
33
- PORT = st.number_input(
34
- "Enter the port number:", min_value=1, max_value=65535, value=8883
35
- )
36
 
37
- # User input for the Pico ID
38
- PICO_ID = st.text_input("Enter your Pico ID:", "test", type="password")
39
 
40
- command_topic = f"sdl-demo/picow/{PICO_ID}/GPIO/28/"
41
- sensor_data_topic = f"sdl-demo/picow/{PICO_ID}/as7341/"
 
 
 
 
 
 
 
 
 
 
 
42
 
43
- max_power = 0.35
44
- max_value = round(max_power * 255)
45
 
46
- # Information about the maximum power reduction
47
- st.info(
48
- f"The upper limit for RGB power levels has been set to {max_value} instead of 255. NeoPixels are bright 😎"
49
- )
50
 
51
- # Sliders for RGB values
52
- R = st.slider("Select the Red value:", min_value=0, max_value=max_value, value=0)
53
- G = st.slider("Select the Green value:", min_value=0, max_value=max_value, value=0)
54
- B = st.slider("Select the Blue value:", min_value=0, max_value=max_value, value=0)
55
 
56
- # # Initialize session state for messages and lock state
57
- if "messages" not in st.session_state:
58
- st.session_state.messages = []
59
 
60
- # if "locked" not in st.session_state:
61
- # st.session_state.locked = False
62
 
63
- # if "command_history" not in st.session_state:
64
- # st.session_state.command_history = []
65
- # if "sensor_data_history" not in st.session_state:
66
- # st.session_state.sensor_data_history = []
 
67
 
68
- # Queue to hold sensor data
69
  sensor_data_queue = queue.Queue()
70
 
71
 
72
  # Singleton: https://docs.streamlit.io/develop/api-reference/caching-and-state/st.cache_resource
73
  @st.cache_resource
74
- def get_paho_client(
75
- sensor_data_topic, hostname, username, password=None, port=8883, tls=True
76
- ):
 
 
77
 
78
- client = mqtt.Client(
79
- mqtt.CallbackAPIVersion.VERSION2, protocol=mqtt.MQTTv5
80
- ) # create new instance
81
 
 
 
 
 
82
  def on_message(client, userdata, msg):
83
  sensor_data_queue.put(json.loads(msg.payload))
84
 
@@ -90,8 +94,6 @@ def get_paho_client(
90
  client.on_connect = on_connect
91
  client.on_message = on_message
92
 
93
- if tls:
94
- client.tls_set(tls_version=mqtt.ssl.PROTOCOL_TLS_CLIENT)
95
  client.username_pw_set(username, password)
96
  client.connect(hostname, port)
97
  client.loop_start() # Use a non-blocking loop
@@ -99,7 +101,7 @@ def get_paho_client(
99
  return client
100
 
101
 
102
- def send_and_receive(client, command_topic, msg, queue_timeout=60):
103
  print("Sending command...")
104
  result = client.publish(command_topic, json.dumps(msg), qos=2)
105
  result.wait_for_publish() # Ensure the message is sent
@@ -109,13 +111,6 @@ def send_and_receive(client, command_topic, msg, queue_timeout=60):
109
  else:
110
  print(f"Failed to send command: {result.rc}")
111
 
112
- try:
113
- sensor_data = sensor_data_queue.get(True, queue_timeout)
114
- return sensor_data
115
- except queue.Empty:
116
- st.error("No sensor data received within the timeout period.")
117
- return None
118
-
119
 
120
  # Helper function to plot discrete spectral sensor data
121
  def plot_spectra(sensor_data):
@@ -140,7 +135,8 @@ def plot_spectra(sensor_data):
140
 
141
  # Adding rectangles for color bar effect
142
  dense_wavelengths = np.linspace(wavelengths.min(), wavelengths.max(), num_points)
143
- rect_height = max(intensities) * 0.02 # Height of the rectangles
 
144
 
145
  for dw in dense_wavelengths:
146
  rect = Rectangle(
@@ -169,8 +165,8 @@ def plot_spectra(sensor_data):
169
  # Adjust limits and labels with larger font size
170
  ax.set_xlim(wavelengths.min() - 10, wavelengths.max() + 10)
171
  ax.set_ylim(
172
- 0, max(intensities) + 15
173
- ) # Ensure the lower y limit is 0 and add buffer
174
  ax.set_xticks(wavelengths)
175
  ax.set_xlabel("Wavelength (nm)", fontsize=14)
176
  ax.set_ylabel("Intensity", fontsize=14)
@@ -181,33 +177,48 @@ def plot_spectra(sensor_data):
181
 
182
 
183
  # Publish button
184
- # if st.button("Send RGB Command", disabled=st.session_state.locked):
185
- if st.button("Send RGB Command"):
186
  if not PICO_ID or not HIVEMQ_HOST or not HIVEMQ_USERNAME or not HIVEMQ_PASSWORD:
187
  st.error("Please enter all required fields.")
188
  else:
189
- # st.session_state.locked = True
190
- st.info("Please wait while the command is sent...")
 
191
 
192
- client = get_paho_client(
 
 
 
193
  sensor_data_topic,
194
  HIVEMQ_HOST,
195
  HIVEMQ_USERNAME,
196
  password=HIVEMQ_PASSWORD,
197
  port=int(PORT),
198
- tls=True,
199
  )
200
 
201
- command_msg = {"R": R, "G": G, "B": B}
202
- sensor_data = send_and_receive(
203
- client, command_topic, command_msg, queue_timeout=15
204
- )
 
 
205
 
206
- # st.session_state.locked = False
207
 
208
- print("Waiting for sensor data...")
 
209
 
210
- if sensor_data:
211
- st.success("Command sent successfully!")
212
- plot_spectra(sensor_data)
213
- st.write("Sensor Data Received:", sensor_data)
 
 
 
 
 
 
 
 
 
 
 
7
  import numpy as np
8
  from matplotlib.patches import Rectangle
9
 
10
+ import secrets
11
+
12
+ from time import time
13
+
14
  # Initialize Streamlit app
15
  st.title("Light-mixing Control Panel")
16
 
 
24
  """
25
  )
26
 
27
+ max_power = 0.35
28
+ max_value = round(max_power * 255)
 
 
 
 
 
 
 
 
 
 
 
29
 
30
+ with st.form("mqtt_form"):
 
31
 
32
+ # MQTT Configuration
33
+ HIVEMQ_HOST = st.text_input(
34
+ "Enter your HiveMQ host:",
35
+ "248cc294c37642359297f75b7b023374.s2.eu.hivemq.cloud",
36
+ type="password",
37
+ )
38
+ HIVEMQ_USERNAME = st.text_input("Enter your HiveMQ username:", "sgbaird")
39
+ HIVEMQ_PASSWORD = st.text_input(
40
+ "Enter your HiveMQ password:", "D.Pq5gYtejYbU#L", type="password"
41
+ )
42
+ PORT = st.number_input(
43
+ "Enter the port number:", min_value=1, max_value=65535, value=8883
44
+ )
45
 
46
+ # User input for the Pico ID
47
+ PICO_ID = st.text_input("Enter your Pico ID:", "test", type="password")
48
 
49
+ # Information about the maximum power reduction
50
+ st.info(
51
+ f"The upper limit for RGB power levels has been set to {max_value} instead of 255. NeoPixels are bright 😎"
52
+ )
53
 
54
+ # Sliders for RGB values
55
+ R = st.slider("Select the Red value:", min_value=0, max_value=max_value, value=0)
56
+ G = st.slider("Select the Green value:", min_value=0, max_value=max_value, value=0)
57
+ B = st.slider("Select the Blue value:", min_value=0, max_value=max_value, value=0)
58
 
59
+ submit_button = st.form_submit_button(label="Send RGB Command")
 
 
60
 
61
+ command_topic = f"sdl-demo/picow/{PICO_ID}/GPIO/28/"
62
+ sensor_data_topic = f"sdl-demo/picow/{PICO_ID}/as7341/"
63
 
64
+ # random session id to keep track of the session and filter out old data
65
+ experiment_id = secrets.token_hex(4) # 4 bytes = 8 characters
66
+ sensor_data_file = f"sensor_data-{experiment_id}.json"
67
+
68
+ # TODO: Session ID using st.session_state to have history of commands and sensor data
69
 
 
70
  sensor_data_queue = queue.Queue()
71
 
72
 
73
  # Singleton: https://docs.streamlit.io/develop/api-reference/caching-and-state/st.cache_resource
74
  @st.cache_resource
75
+ def create_paho_client(tls=True):
76
+ client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, protocol=mqtt.MQTTv5)
77
+ if tls:
78
+ client.tls_set(tls_version=mqtt.ssl.PROTOCOL_TLS_CLIENT)
79
+ return client
80
 
 
 
 
81
 
82
+ # Define setup separately since sensor_data is dynamic
83
+ def setup_paho_client(
84
+ client, sensor_data_topic, hostname, username, password=None, port=8883
85
+ ):
86
  def on_message(client, userdata, msg):
87
  sensor_data_queue.put(json.loads(msg.payload))
88
 
 
94
  client.on_connect = on_connect
95
  client.on_message = on_message
96
 
 
 
97
  client.username_pw_set(username, password)
98
  client.connect(hostname, port)
99
  client.loop_start() # Use a non-blocking loop
 
101
  return client
102
 
103
 
104
+ def send_command(client, command_topic, msg):
105
  print("Sending command...")
106
  result = client.publish(command_topic, json.dumps(msg), qos=2)
107
  result.wait_for_publish() # Ensure the message is sent
 
111
  else:
112
  print(f"Failed to send command: {result.rc}")
113
 
 
 
 
 
 
 
 
114
 
115
  # Helper function to plot discrete spectral sensor data
116
  def plot_spectra(sensor_data):
 
135
 
136
  # Adding rectangles for color bar effect
137
  dense_wavelengths = np.linspace(wavelengths.min(), wavelengths.max(), num_points)
138
+ # rect_height = max(intensities) * 0.02 # Height of the rectangles
139
+ rect_height = 300
140
 
141
  for dw in dense_wavelengths:
142
  rect = Rectangle(
 
165
  # Adjust limits and labels with larger font size
166
  ax.set_xlim(wavelengths.min() - 10, wavelengths.max() + 10)
167
  ax.set_ylim(
168
+ 0, max(30000, max(intensities) + 15)
169
+ ) # Ensure the lower y limit is 0 and add buffer with a minimum upper limit of 30000
170
  ax.set_xticks(wavelengths)
171
  ax.set_xlabel("Wavelength (nm)", fontsize=14)
172
  ax.set_ylabel("Intensity", fontsize=14)
 
177
 
178
 
179
  # Publish button
180
+ if submit_button:
 
181
  if not PICO_ID or not HIVEMQ_HOST or not HIVEMQ_USERNAME or not HIVEMQ_PASSWORD:
182
  st.error("Please enter all required fields.")
183
  else:
184
+ st.info(
185
+ f"Please wait while the command {R, G, B} for experiment {experiment_id} is sent..."
186
+ )
187
 
188
+ client = create_paho_client(tls=True)
189
+
190
+ client = setup_paho_client(
191
+ client,
192
  sensor_data_topic,
193
  HIVEMQ_HOST,
194
  HIVEMQ_USERNAME,
195
  password=HIVEMQ_PASSWORD,
196
  port=int(PORT),
 
197
  )
198
 
199
+ command_msg = {"R": R, "G": G, "B": B, "_experiment_id": experiment_id}
200
+
201
+ session_timeout = time() + 60
202
+ send_command(client, command_topic, command_msg)
203
+
204
+ while True and time() < session_timeout:
205
 
206
+ sensor_data = sensor_data_queue.get(True, timeout=15)
207
 
208
+ input_message = sensor_data["_input_message"]
209
+ received_experiment_id = input_message["_experiment_id"]
210
 
211
+ if sensor_data and received_experiment_id == experiment_id:
212
+ R1 = input_message["R"]
213
+ G1 = input_message["G"]
214
+ B1 = input_message["B"]
215
+ st.success(
216
+ f"Command {R1, G1, B1} for experiment {experiment_id} sent successfully!"
217
+ )
218
+ plot_spectra(sensor_data)
219
+ st.write("Sensor Data Received:", sensor_data)
220
+ break
221
+ else:
222
+ st.warning(
223
+ f"Received data for experiment {received_experiment_id} instead of {experiment_id}. Retrying..."
224
+ )