diff --git a/assets/img/authors/daniel-paul.webp b/assets/img/authors/daniel-paul.webp new file mode 100644 index 000000000..dcdf85574 Binary files /dev/null and b/assets/img/authors/daniel-paul.webp differ diff --git a/content/authors/daniel-paul/_index.md b/content/authors/daniel-paul/_index.md new file mode 100644 index 000000000..a71ecedff --- /dev/null +++ b/content/authors/daniel-paul/_index.md @@ -0,0 +1,3 @@ +--- +title: Daniel Paul +--- diff --git a/content/workshops/micropython-jupyter-notebooks-in-browser/_index.md b/content/workshops/micropython-jupyter-notebooks-in-browser/_index.md new file mode 100644 index 000000000..6f38d41ef --- /dev/null +++ b/content/workshops/micropython-jupyter-notebooks-in-browser/_index.md @@ -0,0 +1,81 @@ +--- +title: "MicroPython Jupyter Notebooks in the Browser with ESP32-C3-DevKit-RUST-2" +date: 2025-10-17 +showAuthor: false +series: ["WS00M"] +series_order: 1 +tags: ["Workshop", "MicroPython", "Jupyter", "Browser"] +authors: + - "daniel-paul" +showTableOfContents: false +showAuthor: false +summary: "In this workshop, you will learn how to program Espressif SoCs directly in your browser using MicroPython and Jupyter notebooks. We will primarily be using ESP32-C3-DevKit-RUST-2 development board. In the process, we will cover LED control, wireless communication, sensors, and MQTT." +--- + +Welcome to the workshop on MicroPython Jupyter Notebooks in the browser! In this session, you will see how modern web technologies enable direct hardware programming without the need to install local development tools. You'll learn how to flash firmware, execute code interactively, and build IoT applications using only a browser and a USB connection. + +## About the workshop + +This workshop covers both basic and advanced MicroPython programming for ESP32-C3-DevKit-RUST-2 development board through hands-on assignments: + + + +- **Setup** - Flash MicroPython firmware and understand the development environment +- **Assignment 1: Blink** -- Control addressable LED +- **Assignment 2: Button Input** -- Read button presses and create interactive responses +- **Assignment 3: ESP-NOW Communication** -- Implement wireless Morse code communication between two ESP32-C3-DevKit-RUST-2 development boards +- **Assignment 4: IMU Sensor and MQTT Communication** -- Read orientation data from an IMU and publish it to MQTT broker + + +## Prerequisites + +### Hardware + +- A computer running Windows, macOS or Linux +- ESP32-C3-DevKit-RUST-2 board (Provided by us) +- USB-C cable (data + power) compatible with the board + +### Software + +- Chromium-based browser (Google Chrome, Microsoft Edge, Opera, Brave, Vivaldi) +- [Mosquitto](https://mosquitto.org/download/) client (Optional) + +### Effort + +{{< alert icon="mug-hot">}} +**Estimated time: 120 min** +{{< /alert >}} + +## Workshop + +Without further ado, let's dive into the exciting world of ESP microcontrollers and MicroPython! Please follow along as we explore the capabilities of this powerful platform. + +* [Introduction and Setup](introduction-and-setup/) +* [Assignment 1 - Blink](assignment-1/) +* [Assignment 2 - Button Input](assignment-2/) +* [Assignment 3 - ESP-NOW Communication](assignment-3/) +* [Assignment 4 - IMU Sensor and MQTT Communication](assignment-4/) + +## Conclusion + +You've learned to program ESP32-C3-DevKit-RUST-2 development board using browser-based Jupyter notebooks, covering: + +- MicroPython firmware flashing and interactive development +- GPIO control for LEDs and button input +- ESP-NOW wireless communication protocol +- IMU sensor data acquisition and processing +- MQTT protocol for IoT messaging + +These skills form the foundation for building sophisticated IoT applications. The browser-based approach eliminates toolchain complexity while maintaining full access to MicroPython's capabilities. + +## FAQ +- I have been prompted to select a kernel in Jupyter Notebook. Which one should I use? + - Select `Embedded Kernel`. +- How do I connect my device to the Jupyter notebook? + - Click on the ESP Control Panel, click `Connect` and select your device. +- Which of the devices is my ESP board? + - The ESP board usually appears as `USB JTAG`. +- I cannot connect to a different Jupyter notebook. + - Disconnect from the previous notebook and connect the new one. +- The notebook isn’t running my code, what should I do + - In the ESP Control Panel, click `Disconnect device`, then reopen the notebook and connect again. diff --git a/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-1/index.md b/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-1/index.md new file mode 100644 index 000000000..7ad7cb806 --- /dev/null +++ b/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-1/index.md @@ -0,0 +1,119 @@ +--- +title: "Assignment 1: Blink - Control the addressable LED" +date: 2025-10-17T00:00:00+01:00 +showTableOfContents: true +series: ["WS00M"] +series_order : 2 +showAuthor: false +--- + +In this assignment you will initialize and control the onboard addressable LED in three different ways. + +## Understanding addressable LEDs + +WS2812 are individually addressable RGB LEDs. Each LED can display any color by mixing red, green, and blue values (0-255 each). The ESP32-C3-DevKit-RUST-2 board has one addressable LED on GPIO 2. + +Work through the following tasks in your Assignment 1 Jupyter notebook: + +## Task 1: Initialize the addressable LED +In this task, you’ll set up the addressable LED so your code can communicate with it. The `neopixel.NeoPixel(machine.Pin(2), 1)` line tells the chip which pin the LED is connected to (GPIO 2) and how many LEDs are being controlled (1 in this case). + +```python +neopixel_led = neopixel.NeoPixel(machine.Pin(2), 1) +``` + +## Task 2: Set the Solid Colors + +Here, you’ll write helper functions to change the LED’s color. +The `set_color()` function lets you set any RGB color by adjusting red, green, and blue brightness values from 0–255. +The `clear_led()` function turns the LED off. +You’ll then test the LED by cycling through a few example colors. + + +```python +def set_color(r, g, b): + """Set the addressable LED to a specific RGB color""" + neopixel_led[0] = (r, g, b) + neopixel_led.write() + +def clear_led(): + """Turn off the LED""" + set_color(0, 0, 0) + + +# Try different colors +set_color(255, 0, 0) # Red +time.sleep(1) +set_color(0, 255, 0) # Green +time.sleep(1) +set_color(0, 0, 255) # Blue +time.sleep(1) +set_color(255, 255, 0) # Yellow +time.sleep(1) +clear_led() +``` + +## Task 3: Rainbow cycle effect + +This task adds a simple animation. +You’ll create a rainbow_cycle() function that loops through a list of predefined colors — red, orange, yellow, green, blue, indigo, and violet — so the LED smoothly transitions through the rainbow spectrum. + +```python +def rainbow_cycle(): + """Cycle through rainbow colors""" + colors = [ + (255, 0, 0), # Red + (255, 127, 0), # Orange + (255, 255, 0), # Yellow + (0, 255, 0), # Green + (0, 0, 255), # Blue + (75, 0, 130), # Indigo + (148, 0, 211) # Violet + ] + + for color in colors: + set_color(*color) + time.sleep(0.3) + clear_led() + +rainbow_cycle() +``` + +## Task 4: Breathing Effect + +Now you’ll create a more dynamic lighting effect. +The breathing_effect() function gradually fades the LED in and out using brightness scaling, giving a “breathing” glow. +You can adjust the color, duration, and smoothness by changing the parameters. + +```python +def breathing_effect(r, g, b, duration=2, steps=50): + """ + Create a breathing effect with the specified color + """ + step_delay = duration / (steps * 2) + + # Fade in + for i in range(steps): + brightness = i / steps + set_color(int(r * brightness), int(g * brightness), int(b * brightness)) + time.sleep(step_delay) + + # Fade out + for i in range(steps, 0, -1): + brightness = i / steps + set_color(int(r * brightness), int(g * brightness), int(b * brightness)) + time.sleep(step_delay) + + clear_led() + +breathing_effect(0, 100, 255) +``` + +#### Next step + +{{< alert iconColor="#df8e1d" cardColor="#edcea3">}} +Click on the ESP Control Panel and `Disconnect device` the device from the Jupyter notebook. +{{< /alert >}} + + +> Next step: [Assignment 2](../assignment-2/). diff --git a/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-2/index.md b/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-2/index.md new file mode 100644 index 000000000..6c2b3ff74 --- /dev/null +++ b/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-2/index.md @@ -0,0 +1,116 @@ +--- +title: "Assignment 2: Button Input" +date: 2025-10-17T00:00:00+01:00 +showTableOfContents: true +series: ["WS00M"] +series_order : 3 +showAuthor: false +--- + +Navigate to `workshops/2025-10-17` directory and open Assignment 2 in the MicroPython Jupyter Notebook browser interface. + +If prompted with selecting kernel, select `Embedded Kernel`, click on the ESP Control Panel and connect your device. + +In this assignment, you will learn to read button inputs and generate interactive responses with LEDs. + +{{< alert icon="circle-info" cardColor="#b3e0f2" iconColor="#04a5e5">}} +You will be configuring a `boot` button located on Pin 9. +{{< /alert >}} + +## Understanding Pull-up Resistors + +On the ESP32-C3-DevKit-RUST-2 board, pressing the **boot** button connects pin 9 to ground. When the button is not pressed, the pin is left floating, which leads to an undefined logic level. Pull-up resistors ensure that the pin maintains a defined logic high level when the button is released. + +In summary: +* Button not pressed: GPIO reads HIGH (1) thanks to pull-up resistor. +* Button pressed: GPIO reads LOW (0) because the pin is connected to ground. + +The ESP32-C3-DevKit-RUST-2 has internal pull-up resistors that can be enabled in software. + +## Task 1: Configure button + +In this task, you’ll initialize the onboard button so your program can read its state. +The pin is configured as an input (`machine.Pin.IN`) with an internal pull-up resistor (`machine.Pin.PULL_UP`). + + +```python +button = machine.Pin(9, machine.Pin.IN, machine.Pin.PULL_UP) +``` + +## Task 2: Simple Button Press Detection + +Here you’ll write a function that waits until the button is pressed. +The loop continuously checks the pin’s value — when it changes from HIGH to LOW, the program detects a press and prints a message. + +```python +def wait_for_button_press(): + """Wait until button is pressed""" + while button.value() == 1: + time.sleep(0.05) + print("Button pressed!") +``` + +Now you’ll make the LED respond to button input. +Each time the button is pressed, the LED toggles between ON and OFF. +A small delay is added to handle “debouncing” — preventing multiple rapid triggers from one press. + +{{< alert icon="circle-info" cardColor="#b3e0f2" iconColor="#04a5e5">}} +“Bouncing” happens when you press a button and instead of sending a single clean signal, it wiggles a little and makes the system think you pressed it many times really fast. Debouncing is just a way to make the system listen to only one press, no matter how wobbly the button is.” +{{< /alert >}} + + +## Task 3: Toggle LED on Button Press + +```python +led_state = False + +while True: + if button.value() == 0: # Button pressed + led_state = not led_state + if led_state: + set_color(255, 0, 0) + else: + clear_led() + + # Wait for button release (debounce) + while button.value() == 0: + time.sleep(0.05) + time.sleep(0.1) # Additional debounce delay +``` + +## Task 4: Measure Press duration + +In this task, you’ll measure how long the button is held down. +The program records the start time when pressed and calculates the total duration once released. + +```python +def measure_press_duration(): + """Measure how long the button is held down""" + start = time.ticks_ms() + while button.value() == 0: + time.sleep(0.05) + duration = time.ticks_diff(time.ticks_ms(), start) / 1000.0 + return duration + +wait_for_button_press() +duration = measure_press_duration() +print(f"Button held for {duration:.2f} seconds") +``` + +## Bonus Challenge + +Create a visual feedback based on duration. + +Change LED color based on how long the button is pressed: +- Short press (< 1s): Blue +- Medium press (1-3s): Yellow +- Long press (> 3s): Red + + +#### Next step + +{{< alert iconColor="#df8e1d" cardColor="#edcea3">}} +Click on the ESP Control Panel and `Disconnect device` the device from the Jupyter notebook. +{{< /alert >}} + +> Next step: [Assignment 3](../assignment-3). diff --git a/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-3-receiver/index.md b/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-3-receiver/index.md new file mode 100644 index 000000000..3f9eae214 --- /dev/null +++ b/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-3-receiver/index.md @@ -0,0 +1,123 @@ +--- +title: "Assignment 3: ESP-NOW Communication - Receiver" +date: 2025-10-17T00:00:00+01:00 +showTableOfContents: true +series: ["WS00M"] +series_order : 4 +showAuthor: false +--- + +Navigate to `workshops/2025-10-17` directory and open Assignment 3 - Receiver in the MicroPython Jupyter Notebook browser interface. + +If prompted with selecting kernel, select `Embedded Kernel`, click on the ESP Control Panel and connect your device. + +In this assignment, you will be to receive Morse code sent by the sender and display it on an LED. To do this, you will need to initialize the ESP-NOW communication protocol and set up a callback function to handle incoming messages. The sender will need your MAC address to send the Morse code. You can obtain it by initializing your station interface and running `print(sta.config('mac'))` (see [Task 1](#task-1-initialize-receiver)) + +## Task 1: Initialize Receiver + +In this task, you’ll set up the chip as a Wi-Fi station and retrieve its MAC address. +This MAC address will be used by the sender device to target your board when sending data. + +```python +# Setup Wi-Fi and ESP-NOW +sta = network.WLAN(network.STA_IF) +sta.active(True) + +# Get and print MAC address +print("My MAC address:", sta.config('mac')) +``` + +## Task 2: Initialize addressable LED + +Here you’ll set up the addressable LED to visualize incoming Morse code signals. + +```python +# Setup addressable LED +neopixel_led = neopixel.NeoPixel(machine.Pin(2), 1) +``` + +## Task 3: Initialize ESP-NOW + +Now you’ll initialize the ESP-NOW communication protocol, which allows direct device-to-device messaging without Wi-Fi networking. +You’ll also define timing constants that control how long each LED flash lasts. + +```python +# Initialize ESP-NOW +e = espnow.ESPNow() +e.active(True) + +# Timing constants +DOT_TIME = 0.2 # Green LED duration +DASH_TIME = 0.6 # Red LED duration +PAUSE = 0.2 # Gap after symbol +``` + +## Task 4: LED Display Functions + +In this task, you’ll implement helper functions to show Morse code visually. +Dots will flash green for a short time, dashes will flash red for longer, and each symbol will include a short pause after it. + +```python +def set_color(r, g, b): + """Set the addressable LED to a specific RGB color""" + neopixel_led[0] = (r, g, b) + neopixel_led.write() + +def clear_led(): + """Turn off the addressable LED""" + set_color(0, 0, 0) + +def blink_dot(): + """Display dot: green LED""" + set_color(0, 255, 0) + time.sleep(DOT_TIME) + clear_led() + +def blink_dash(): + """Display dash: red LED""" + set_color(255, 0, 0) + time.sleep(DASH_TIME) + clear_led() + +def blink_morse_symbol(symbol): + """ + Display the received Morse symbol with appropriate color and timing. + Includes pause after each symbol. + """ + if symbol == ".": + blink_dot() + elif symbol == "-": + blink_dash() + +``` + +## Task 5: Receive Morse Code + +Finally, you’ll write the main loop that waits for incoming ESP-NOW messages. +Each received symbol (dot or dash) is decoded, printed, and displayed on the LED. + +```python +print("Morse Code Receiver ready...") +print("Dot = Green LED, Dash = Red LED") + +while True: + host, msg = e.recv(0) # Non-blocking receive + if msg: + symbol = msg.decode() + print("Received:", symbol) + blink_morse_symbol(symbol) + + time.sleep(PAUSE) +``` + +## Bonus Challenge + +Extend the receiver to decode complete Morse code letters and display them. You can use a dictionary mapping Morse patterns (e.g., ".-" → "A") to actual text output. + +#### Next step + +{{< alert iconColor="#df8e1d" cardColor="#edcea3">}} +Click on the ESP Control Panel and `Disconnect device` the device from the Jupyter notebook. +{{< /alert >}} + +> Next step: [Assignment 4](../assignment-4/). diff --git a/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-3-sender/index.md b/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-3-sender/index.md new file mode 100644 index 000000000..f2a5e1b2f --- /dev/null +++ b/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-3-sender/index.md @@ -0,0 +1,111 @@ +--- +title: "Assignment 3: ESP-NOW Communication - Sender" +date: 2025-10-17T00:00:00+01:00 +showTableOfContents: true +series: ["WS00M"] +series_order : 4 +showAuthor: false +--- + +Navigate to `workshops/2025-10-17` directory and open Assignment 3 - Sender in the MicroPython Jupyter Notebook browser interface. + +If prompted with selecting kernel, select `Embedded Kernel`, click on the ESP Control Panel and connect your device. + +In this assignment, you will send Morse code to the receiver based on the length of the button presses. Ask your partner for their MAC address and replace `` with it in your code. They can get this information by initializing station interface and running `print(sta.config('mac'))` (see [here](../assignment-3-receiver#task-1-initialize-receiver)) + +## Task 1: Initialize ESP-NOW + +Set up your ESP32 as a Wi-Fi station and initialize ESP-NOW communication. +Add your partner’s MAC address as a peer so you can send Morse code directly to their board. + +```python +# Create Wi-Fi station interface +sta = network.WLAN(network.STA_IF) +sta.active(True) + +# Initialize ESP-NOW +e = espnow.ESPNow() +e.active(True) + +# MAC address of receiver (replace receiver's MAC!) +peer_mac = b'' + +# Try to delete any existing peer +try: + e.del_peer(peer_mac) +except OSError: + pass + +e.add_peer(peer_mac) +``` + +## Task 2: Implement Morse Detection + +Here you’ll configure the button and define functions to detect how long it’s pressed. +Short presses will be interpreted as dots, long presses as dashes. +Debouncing ensures that tiny accidental presses are ignored. + +```python +# Button configuration +button = machine.Pin(9, machine.Pin.IN, machine.Pin.PULL_UP) + +DOT_THRESHOLD = 0.3 # seconds +DEBOUNCE = 0.05 + +def wait_for_button_press(): + """Wait until button is pressed""" + while button.value() == 1: + time.sleep(0.05) + +def measure_press_duration(): + """Measure how long the button is held down""" + start = time.ticks_ms() + while button.value() == 0: + time.sleep(0.05) + duration = time.ticks_diff(time.ticks_ms(), start) / 1000.0 + return duration + +def determine_morse_symbol(duration): + """Determine if press was dot or dash""" + if duration < DEBOUNCE: + return None + symbol = '.' if duration < DOT_THRESHOLD else '-' + return symbol + +def send_morse_symbol(symbol): + """Send morse symbol via ESP-NOW""" + print("Sending:", symbol) + e.send(peer_mac, symbol.encode()) +``` + +Finally, you’ll write the main loop that waits for button presses, detects the duration, determines the Morse symbol, and sends it to the receiver. +The program prints each symbol for confirmation. + +## Task 3: Send Morse Symbols + +```python +print("Morse Code Sender Ready!") +print("Press button: short = dot (.), long = dash (-)") +print("Press the stop button on the toolbar to terminate the while loop.") + +while True: + # Wait for button press + wait_for_button_press() + + # Measure duration + duration = measure_press_duration() + + # Determine symbol + symbol = determine_morse_symbol(duration) + if symbol: + # Send symbol via ESP-NOW + send_morse_symbol(symbol) +``` + +#### Next step + +{{< alert iconColor="#df8e1d" cardColor="#edcea3">}} +Click on the ESP Control Panel and `Disconnect device` the device from the Jupyter notebook. +{{< /alert >}} + +> Next step: [Assignment 4](../assignment-4/). diff --git a/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-3/index.md b/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-3/index.md new file mode 100644 index 000000000..133647087 --- /dev/null +++ b/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-3/index.md @@ -0,0 +1,35 @@ +--- +title: "Assignment 3: ESP-NOW Communication" +date: 2025-10-17T00:00:00+01:00 +showTableOfContents: true +series: ["WS00M"] +series_order : 4 +showAuthor: false +--- + +In this assignment, you will implement wireless Morse code communication between two ESP32-C3-DevKit-RUST-2 development boards using ESP-NOW protocol. + +You’ll need to work with a partner: one of you will implement the Sender and the other will implement the Receiver. + +## Understanding ESP-NOW + +ESP-NOW is a connectionless communication protocol developed by Espressif that enables direct, low-power communication between ESP devices (ESP8266, ESP32, ESP32-S and ESP32-C series of SoCs) without requiring Wi-Fi router infrastructure. Key features: + +- **Low latency**: ~10ms typical +- **No router required**: Direct device-to-device communication +- **Long range**: Up to 200m line-of-sight (depending on environment) +- **Multiple peers**: Can communicate with up to 20 peers + +## Project Morse Code Sender and Receiver + +You'll build one of two devices: a sender that transmits Morse code or a receiver that displays the Morse code on an LED. + +**Morse Code Timing**: + +- **Dot**: Short press (< 0.3 seconds) +- **Dash**: Long press (≥ 0.3 seconds) + +Pick one of the following roles and proceed with your assignment: + +- **Sender**: [Assignment 3 - Sender](../assignment-3-sender/). +- **Receiver**: [Assignment 3 - Receiver](../assignment-3-receiver/). diff --git a/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-4/index.md b/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-4/index.md new file mode 100644 index 000000000..efcf63871 --- /dev/null +++ b/content/workshops/micropython-jupyter-notebooks-in-browser/assignment-4/index.md @@ -0,0 +1,159 @@ +--- +title: "Assignment 4: IMU Sensor and MQTT Communication" +date: 2025-10-17T00:00:00+01:00 +showTableOfContents: true +series: ["WS00M"] +series_order : 5 + +--- + +Navigate to `workshops/2025-10-17` directory and open Assignment 4 in the MicroPython Jupyter Notebook browser interface. + +If prompted with selecting kernel, select `Embedded Kernel`, click on the ESP Control Panel and connect your device. + +In this assignment you will read orientation data from an ICM42670 IMU sensor and publish it to an MQTT broker. + +## Understanding IMU Sensors +An Inertial Measurement Unit (IMU) combines: + +- **Accelerometer**: Measures linear acceleration (including gravity) +- **Gyroscope**: Measures rotational velocity +- **Temperature sensor**: Measures device temperature + +The ICM42670 is a 6-axis IMU (3-axis accelerometer + 3-axis gyroscope). + +For more information about IMU sensors, visit the [wiki page](https://en.wikipedia.org/wiki/Inertial_measurement_unit). + +## Understanding MQTT +MQTT (Message Queuing Telemetry Transport) is a lightweight publish-subscribe messaging protocol ideal for IoT: + +- **Broker**: Central server that routes messages +- **Topics**: Hierarchical message channels (e.g., sensors/imu/orientation) +- **QoS**: Quality of Service levels (0, 1, or 2) + +For more information about MQTT, visit the [wiki page](https://en.wikipedia.org/wiki/MQTT). + + +## Subscribing to MQTT Topic + +To subscribe to a topic, you will have two options: + +### HiveMQ Online MQTT Client + +- Navigate to [HiveMQ](https://www.hivemq.com/demos/websocket-client/) and connect to the broker `test.mosquitto.org` on port `8081`. +- Under `Subscriptions` click on the `Add New Topic Subscription`, enter `esp32/orientation` and click on `Subscribe` + +### Mosquitto Client + +- Subscribe to the topic: + - On **Linux** or **MacOS** run command `mosquitto_sub -h test.mosquitto.org -t "esp32/orientation"` in your terminal to subscribe to the topic + - On **Windows** you will need to add mosquitto to your `PATH` environment variable or navigate to the path where the executable is located (usually `C:\Program Files\mosquitto\`) and run `mosquitto_sub.exe -h test.mosquitto.org -t "esp32/orientation"` + +## Task 1: Connect to Wi-Fi + +In this task, you’ll connect the ESP32 to your Wi-Fi network so it can communicate with the MQTT broker. +The code waits until the connection is established and prints the network configuration. + +```python +SSID = "" +PASSWORD = "" + +sta = network.WLAN(network.STA_IF) +sta.active(True) +sta.connect(SSID, PASSWORD) + +while not sta.isconnected(): + time.sleep(1) + print("Connecting to Wi-Fi...") + +print("Connected to Wi-Fi") +print(f"Network config: {sta.ifconfig()}") +``` + +## Task 2: Initialize MQTT + +Here you’ll create an MQTT client and connect it to a broker. +You’ll publish orientation messages to the topic "esp32/orientation". + +```python +BROKER = "test.mosquitto.org" +TOPIC = b"esp32/orientation" + +client = MQTTClient("esp32client", BROKER) +client.connect() +print("Connected to MQTT broker") +``` + +## Task 3: Initialize IMU + +In this task, you’ll set up the ICM42670 IMU over I2C. +You’ll configure the accelerometer and gyroscope full-scale range, data rate, and power mode for accurate measurements. + +```python +i2c = I2C(0, scl=Pin(8), sda=Pin(7), freq=400000) + +# Create IMU instance +imu = ICM42670(i2c) + +# Configure sensor +imu.configure( + gyro_fs=GyroFS.FS_500DPS, + gyro_odr=ODR.ODR_100_HZ, + accel_fs=AccelFS.FS_4G, + accel_odr=ODR.ODR_100_HZ +) + +# Enable sensors +imu.set_accel_power_mode(PowerMode.LOW_NOISE) +imu.set_gyro_power_mode(PowerMode.LOW_NOISE) +``` + +## Task 4: Read Orientation and Publish + +Finally, you’ll read accelerometer and gyroscope data, compute orientation using a complementary filter, interpret the device’s tilt, and publish it to MQTT. +The main loop prints the orientation locally and continuously sends updates to the broker. + +```python +def publish_orientation(): + """Read orientation and publish to MQTT""" + + while True: + # Read sensor data + data = imu.get_all_data() + accel = (data['accel']['x'], data['accel']['y'], data['accel']['z']) + gyro = (data['gyro']['x'], data['gyro']['y'], data['gyro']['z']) + + # Calculate orientation using complementary filter + angles = imu.complementary_filter(accel, gyro) + roll = angles['roll'] + pitch = angles['pitch'] + + # Interpret orientation + if abs(pitch) < 20 and abs(roll) < 20: + position = "Flat" + elif pitch > 30: + position = "Tilted Forward" + elif pitch < -30: + position = "Tilted Backward" + elif roll > 30: + position = "Tilted Right" + elif roll < -30: + position = "Tilted Left" + else: + position = "Diagonal" + + # Create message + message = f"Roll: {roll:.1f}°, Pitch: {pitch:.1f}° -> {position}" + print(message) + + # Publish to MQTT + client.publish(TOPIC, position.encode()) + + time.sleep(0.5) + +publish_orientation() +``` + +#### Next step + +> Congratulations! Proceed to the [Conclusion](../#conclusion). diff --git a/content/workshops/micropython-jupyter-notebooks-in-browser/featured.webp b/content/workshops/micropython-jupyter-notebooks-in-browser/featured.webp new file mode 100644 index 000000000..4b503613d Binary files /dev/null and b/content/workshops/micropython-jupyter-notebooks-in-browser/featured.webp differ diff --git a/content/workshops/micropython-jupyter-notebooks-in-browser/introduction-and-setup/index.md b/content/workshops/micropython-jupyter-notebooks-in-browser/introduction-and-setup/index.md new file mode 100644 index 000000000..710c98650 --- /dev/null +++ b/content/workshops/micropython-jupyter-notebooks-in-browser/introduction-and-setup/index.md @@ -0,0 +1,60 @@ +--- +title: "Introduction and Setup" +date: 2025-10-17T00:00:00+01:00 +showTableOfContents: false +series: ["WS00M"] +series_order : 1 +showAuthor: false +--- + +## Introduction + +As it has already been announced, this workshop will be using MicroPython and Jupyter Notebooks. Let's quickly introduce them. + +### MicroPython + +MicroPython is a lean implementation of Python 3 optimized for microcontrollers. It provides an interactive REPL (Read-Eval-Print Loop) and supports most Python standard library features, making embedded development accessible to Python programmers. + +### Jupyter Notebook + +Jupyter Notebook is a web-based interactive computing environment that allows you to create documents that contain live code, and narrative text. It is composed from a kernel, which is a program that executes the code, and a frontend, which is a user interface that allows you to interact with the kernel. + +The code is composed of cells, which can be executed independently or sequentially, either by clicking on the cell and pressing the run button or using a keyboard shortcut `Shift + Enter`. If the code executes a `while True` loop, it can be interrupted by clicking on the stop button in the toolbar. + +### Why MicroPython Jupyter Notebooks in the Browser? +Traditional embedded development requires installing toolchains, IDEs, and drivers. Browser-based Jupyter notebooks eliminate this setup by leveraging the WebSerial API, which allows web applications to communicate directly with serial devices. This approach offers several advantages: + +- **Zero installation**: No local toolchain required +- **Interactive development**: Execute code cells individually and see immediate results +- **Educational value**: Clear separation of concepts into notebook cells +- **Cross-platform**: Works identically on Windows, macOS, and Linux +- **Version control friendly**: Notebooks can be easily shared and versioned + +### How It Works +The browser connects to your ESP32-C3-DevKit-RUST-2 development board via USB using the WebSerial API. Jupyter notebooks send Python code to the MicroPython REPL running on the device. The device executes the code and returns output, which displays in the notebook interface. + +### Related documentation + +- [MicroPython Documentation](https://docs.micropython.org/en/latest/) +- [ESP32 MicroPython Guide](https://docs.micropython.org/en/latest/esp32/quickref.html) +- [ESP-NOW Protocol](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html) +- [ESP-NOW in MicroPython](https://docs.micropython.org/en/latest/library/espnow.html) + +## Setup + +Let's start by flashing MicroPython firmware. + +### Flashing MicroPython Firmware + +1. Connect your ESP32-C3-DevKit-RUST-2 development board to your computer via USB cable +2. [Open MicroPython Jupyter Notebook](https://espressif.github.io/jupyter-lite-micropython/lab/index.html) in your chromium based browser +3. Open the sidebar folder, navigate to `workshops/2025-10-17/Assignment 1.ipynb` and open the notebook +4. When prompted with selecting kernel, select `Embedded Kernel` +5. On the ESP Control Panel select `Connect device` and → `ESP32C3 (USB JTAG)` +6. On the same ESP Control Panel select `Flash Device` and `Flash Selected Firmware` - this will flash MicroPython to your device + +Your device is now ready to run MicroPython code. + +#### Next step + +> Next step: [Assignment 1](../assignment-1) diff --git a/data/authors/daniel-paul.json b/data/authors/daniel-paul.json new file mode 100644 index 000000000..a4ec62c17 --- /dev/null +++ b/data/authors/daniel-paul.json @@ -0,0 +1,11 @@ +{ + "name": "Daniel Paul", + "image": "img/authors/daniel-paul.webp", + "bio": "Espressif Systems", + "social": [ + { + "github": "https://github.com/xdanielpaul", + "discord": "https://discord.com/users/336468170170826764" + } + ] +}