Skip to content

Commit b771c87

Browse files
authored
Merge pull request #190 from AccelerationConsortium/copilot/fix-189
Add aside section showing Python alternative to MicroPython for device communication and update non-MicroPython notebook
2 parents c6e70be + 4ffc8ea commit b771c87

File tree

4 files changed

+108
-32
lines changed

4 files changed

+108
-32
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,4 @@ docs/courses/hello-world/micropython/mqtt_as.py
6060
docs/courses/hello-world/images/43577_2023_498_Fig1_HTML.webp
6161
docs/courses/hello-world/scratch.py
6262
docs/courses/hello-world/results.csv
63+
docs/courses/hello-world/deployment.zip

docs/courses/hello-world/1.4.1-onboard-led-temp.ipynb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,17 @@
179179
" plt.show() # Show the plot"
180180
]
181181
},
182+
{
183+
"cell_type": "markdown",
184+
"metadata": {},
185+
"source": [
186+
"## Aside: Using Python instead of MicroPython for device communication\n",
187+
"\n",
188+
"This notebook demonstrates communication with a microcontroller running MicroPython (such as a Raspberry Pi Pico W). However, if you were using a device that supports full Python (e.g., a Raspberry Pi Zero 2W running a complete operating system instead of being restricted to MicroPython), you could use the `paho-mqtt` Python library directly on the device itself. \n",
189+
"\n",
190+
"For an example of how to implement the device-side MQTT communication using Python instead of MicroPython, see the [non-MicroPython device version notebook](./1.4.2-non-micropython-device-version.ipynb). This approach can be useful when working with more powerful hardware that can run a full operating system and Python environment."
191+
]
192+
},
182193
{
183194
"cell_type": "markdown",
184195
"metadata": {},

docs/courses/hello-world/1.4.2-non-micropython-device-version.ipynb

Lines changed: 96 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
{
1818
"cell_type": "markdown",
1919
"source": [
20-
"# 1.4.2 Non-MicroPython Device Version"
20+
"# 1.4.2 Non-MicroPython Device Version\n",
21+
"\n",
22+
"[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/AccelerationConsortium/ac-microcourses/blob/main/docs/courses/hello-world/1.4.2-non-micropython-device-version.ipynb)"
2123
],
2224
"metadata": {
2325
"id": "JSeeBF7SvENI"
@@ -26,7 +28,11 @@
2628
{
2729
"cell_type": "markdown",
2830
"source": [
29-
"This notebook serves as a replacement of [hardware/software communication notebook](./1.4-hardware-software-communication) if you were running on a device that supports Python (e.g., Raspberry Pi 5, Linux, Windows, MacOS, etc.) where you can install the `paho-mqtt` Python library (as opposed to using the `mqtt_as` MicroPython library on a Pico W). This notebook can also be used directly with [the companion notebook](./1.4.1-onboard-led-temp.ipynb). Note that these examples do not consider the possibility of having multiple devices or sending simultaneous requests, for simplicity. However, in [`self-driving-lab-demo`](https://self-driving-lab-demo.readthedocs.io/en/latest/), this is distinguished by passing an `experiment_id` back and forth, which is incorporated into the module assignment."
31+
"This notebook serves as an alternative to the [hardware/software communication notebook](./1.4-hardware-software-communication.ipynb) for devices that support full Python rather than MicroPython. If you're using hardware that can run a complete operating system (e.g., Raspberry Pi 4/5, Linux, Windows, macOS, etc.), you can install the `paho-mqtt` Python library directly instead of using the `mqtt_as` MicroPython library.\n",
32+
"\n",
33+
"This approach is particularly useful when you have more powerful hardware that isn't restricted to MicroPython's limitations. This notebook can be used alongside [the companion notebook](./1.4.1-onboard-led-temp.ipynb) for a complete MQTT communication setup.\n",
34+
"\n",
35+
"**Note:** These examples don't consider multiple devices or simultaneous requests for simplicity. For more advanced scenarios with experiment tracking, see the [`self-driving-lab-demo`](https://self-driving-lab-demo.readthedocs.io/en/latest/) which uses `experiment_id` for distinguishing between different operations."
3036
],
3137
"metadata": {
3238
"id": "oJIRtUZTuDQZ"
@@ -35,8 +41,8 @@
3541
{
3642
"cell_type": "code",
3743
"source": [
38-
"# only install paho-mqtt if we are running in colab\n",
39-
"# matplotlib only for visualization\n",
44+
"# Install required packages\n",
45+
"# Only install paho-mqtt if we are running in Colab\n",
4046
"import sys\n",
4147
"IN_COLAB = 'google.colab' in sys.modules\n",
4248
"if IN_COLAB:\n",
@@ -60,6 +66,23 @@
6066
}
6167
]
6268
},
69+
{
70+
"cell_type": "markdown",
71+
"source": [
72+
"## MQTT Device Simulation\n",
73+
"\n",
74+
"The code below simulates an MQTT device that can receive LED control commands and send temperature sensor data. Before running this code, make sure to:\n",
75+
"\n",
76+
"1. **Replace the credentials** (currently showing public test credentials) with your own HiveMQ Cloud credentials if desired\n",
77+
"2. **Set your unique device ID** in the `COURSE_ID` variable\n",
78+
"3. **Ensure your device ID matches** what you're using in the companion notebook\n",
79+
"\n",
80+
"> **_CAUTION:_** The credentials shown below are public test credentials for educational purposes only. In production environments, never hardcode credentials directly in your code or expose them in plain text. Instead, use environment variables, secure configuration files, or cloud secret management services."
81+
],
82+
"metadata": {
83+
"id": "mqttSetupNote"
84+
}
85+
},
6386
{
6487
"cell_type": "code",
6588
"execution_count": 10,
@@ -113,90 +136,131 @@
113136
"\n",
114137
"# Replace with your actual HiveMQ Cloud credentials and device ID\n",
115138
"# (or import from your own my_secrets.py)\n",
116-
"HIVEMQ_HOST = \"248cc294c37642359297f75b7b023374.s2.eu.hivemq.cloud\"\n",
117-
"HIVEMQ_USERNAME = \"sgbaird\"\n",
118-
"HIVEMQ_PASSWORD = \"D.Pq5gYtejYbU#L\"\n",
119-
"COURSE_ID = \"<your_id_here>\" # Make sure this matches your Colab script!\n",
139+
"HIVEMQ_HOST = \"248cc294c37642359297f75b7b023374.s2.eu.hivemq.cloud\" # Replace with your HiveMQ host\n",
140+
"HIVEMQ_USERNAME = \"sgbaird\" # Replace with your username\n",
141+
"HIVEMQ_PASSWORD = \"D.Pq5gYtejYbU#L\" # Replace with your password\n",
142+
"COURSE_ID = \"<your_id_here>\" # Make sure this matches your companion notebook!\n",
120143
"\n",
121144
"command_topic = f\"{COURSE_ID}/onboard_led\"\n",
122145
"sensor_data_topic = f\"{COURSE_ID}/onboard_temp\"\n",
123146
"\n",
124-
"# Simulate LED on/off\n",
125-
"led_state = False # we will set this as a global var later, to emulate a hardware state\n",
147+
"# Simulate LED state (in real hardware, this would be the actual LED)\n",
148+
"led_state = False\n",
126149
"\n",
127150
"\n",
128151
"def read_temperature():\n",
129-
" # for demonstration\n",
152+
" \"\"\"Simulate temperature reading (replace with actual sensor code).\"\"\"\n",
130153
" return round(25 + random.uniform(-2.0, 2.0), 1)\n",
131154
"\n",
132-
"# The callback for when the client receives a CONNACK response from the server.\n",
133155
"def on_connect(client, userdata, flags, rc, properties=None):\n",
156+
" \"\"\"Callback for when the client receives a CONNACK response from the server.\"\"\"\n",
134157
" if rc == 0:\n",
158+
" print(\"Connected to MQTT broker\")\n",
135159
" # Subscribing in on_connect() means that if we lose the connection and\n",
136160
" # reconnect then subscriptions will be renewed.\n",
137161
" client.subscribe(command_topic, qos=1)\n",
162+
" print(f\"Subscribed to command topic: {command_topic}\")\n",
138163
" else:\n",
139164
" print(f\"Failed to connect. Return code={rc}\")\n",
140165
"\n",
141166
"def on_message(client, userdata, msg):\n",
142-
" # we permit a global var for sake of demo'ing pretend hardware\n",
143-
" # normally the \"state\" would be kept by the device itself (hence one would remove the following line)\n",
167+
" \"\"\"Handle incoming MQTT messages.\"\"\"\n",
168+
" # Global variable for LED state simulation\n",
169+
" # In real hardware, the state would be maintained by the device\n",
144170
" global led_state\n",
171+
" \n",
145172
" try:\n",
146173
" payload_str = msg.payload.decode().strip().lower()\n",
147174
" print(f\"Received command on {msg.topic}: {payload_str}\")\n",
148175
"\n",
149176
" if msg.topic == command_topic:\n",
150-
" if msg == \"on\":\n",
177+
" # Process LED commands\n",
178+
" if payload_str == \"on\":\n",
151179
" led_state = True\n",
152-
" elif msg == \"off\":\n",
180+
" elif payload_str == \"off\":\n",
153181
" led_state = False\n",
154-
" elif msg == \"toggle\":\n",
182+
" elif payload_str == \"toggle\":\n",
155183
" led_state = not led_state\n",
156184
" else:\n",
157185
" print(f\"Unknown command: {payload_str}\")\n",
186+
" \n",
158187
" print(f\"LED state: {led_state}\")\n",
188+
" \n",
189+
" # Send temperature reading as response\n",
159190
" temperature = read_temperature()\n",
160-
" payload = f\"{temperature}\"\n",
161-
" client.publish(sensor_data_topic, payload, qos=1)\n",
191+
" client.publish(sensor_data_topic, str(temperature), qos=1)\n",
192+
" print(f\"Published temperature: {temperature}°C\")\n",
193+
" \n",
162194
" except Exception as exc:\n",
163-
" print(\"Exception in on_message:\", exc)\n",
195+
" print(f\"Exception in on_message: {exc}\")\n",
164196
"\n",
165197
"print(\"Setting up MQTT Client\")\n",
166198
"client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, protocol=mqtt.MQTTv5)\n",
167199
"\n",
168-
"# enable TLS for secure connection\n",
200+
"# Enable TLS for secure connection\n",
169201
"client.tls_set(tls_version=mqtt.ssl.PROTOCOL_TLS_CLIENT)\n",
170-
"# set username and password\n",
202+
"\n",
203+
"# Set username and password\n",
171204
"client.username_pw_set(HIVEMQ_USERNAME, HIVEMQ_PASSWORD)\n",
172-
"# connect to HiveMQ Cloud on port 8883\n",
173-
"port = 8883\n",
174-
"client.connect(HIVEMQ_HOST, port)\n",
175-
"print(\"Connected to MQTT Client\")\n",
176-
"client.subscribe(sensor_data_topic, qos=2)\n",
177205
"\n",
178206
"# Attach callbacks\n",
179207
"client.on_connect = on_connect\n",
180208
"client.on_message = on_message\n",
181209
"\n",
210+
"# Connect to HiveMQ Cloud on port 8883\n",
211+
"port = 8883\n",
212+
"print(f\"Connecting to {HIVEMQ_HOST}:{port}...\")\n",
213+
"client.connect(HIVEMQ_HOST, port)\n",
214+
"\n",
182215
"# Start the MQTT network loop in a separate thread\n",
183216
"client.loop_start()\n",
184217
"print(\"Waiting for commands...\")\n",
218+
"print(f\"Send commands to topic: {command_topic}\")\n",
219+
"print(f\"Temperature data will be published to: {sensor_data_topic}\")\n",
185220
"\n",
186221
"start_time = time.time()\n",
187222
"try:\n",
188223
" # Keep the script running to handle incoming messages\n",
189224
" while True:\n",
190225
" elapsed = round(time.time() - start_time)\n",
191-
" print(f\"Running... Elapsed: {elapsed}s\")\n",
192-
" time.sleep(5)\n",
226+
" if elapsed % 10 == 0: # Print status every 10 seconds\n",
227+
" print(f\"Running... Elapsed: {elapsed}s\")\n",
228+
" time.sleep(1)\n",
193229
"except KeyboardInterrupt:\n",
194-
" print(\"Interrupted by user.\")\n",
230+
" print(\"\\nInterrupted by user.\")\n",
195231
"finally:\n",
196232
" # Gracefully stop\n",
233+
" print(\"Disconnecting...\")\n",
197234
" client.loop_stop()\n",
198-
" client.disconnect()\n"
199-
]
235+
" client.disconnect()\n",
236+
" print(\"Disconnected.\")"
237+
],
238+
"metadata": {
239+
"id": "mqttDeviceCode"
240+
},
241+
"execution_count": null,
242+
"outputs": []
243+
},
244+
{
245+
"cell_type": "markdown",
246+
"source": [
247+
"## Usage Instructions\n",
248+
"\n",
249+
"1. **Configure credentials**: Replace the placeholder values for `HIVEMQ_HOST`, `HIVEMQ_USERNAME`, `HIVEMQ_PASSWORD`, and `COURSE_ID` with your actual values\n",
250+
"2. **Run the device simulation**: Execute the code cell above to start the MQTT device simulation\n",
251+
"3. **Send commands**: Use the companion notebook to send LED commands (`\"on\"`, `\"off\"`, or `\"toggle\"`) to the command topic\n",
252+
"4. **Monitor responses**: The device will respond with temperature readings on the sensor data topic\n",
253+
"\n",
254+
"**Valid LED commands:**\n",
255+
"- `\"on\"` - Turn LED on\n",
256+
"- `\"off\"` - Turn LED off \n",
257+
"- `\"toggle\"` - Switch LED state\n",
258+
"\n",
259+
"The device simulation will continue running until you interrupt it (Ctrl+C in terminal or stop the cell in Jupyter/Colab)."
260+
],
261+
"metadata": {
262+
"id": "usageInstructions"
263+
}
200264
}
201265
]
202266
}
-3.63 MB
Binary file not shown.

0 commit comments

Comments
 (0)