Firmware for the ST B-L475E-IOT01A board. The device connects to a 2.4 GHz Wi-Fi network, reads onboard environmental sensors, periodically sends telemetry to an HTTP API behind Traefik, and listens for MQTT Wake-on-LAN commands.
The main use case is to keep a remote server informed that the home network is alive. Because every API call reaches the server through the Livebox public IP, the backend can infer and log the current public IP address without the STM32 needing to know it.
- Initializes the STM32 HAL and board peripherals generated by STM32CubeIDE.
- Connects the ISM43362 Wi-Fi module to a configured 2.4 GHz SSID.
- Reads onboard temperature, humidity, and pressure sensors.
- Applies a configurable temperature offset to compensate for board self-heating.
- Builds a structured JSON payload with telemetry, runtime counters, network metadata, and firmware information.
- Sends the payload with an HTTP
POSTrequest to the configured API endpoint. - Maintains an MQTT connection and subscribes to a Wake-on-LAN command topic.
- Sends a UDP Magic Packet on the local network when it receives the
wakeMQTT command. - Logs boot, Wi-Fi, telemetry, and API status over UART.
- Runs an independent watchdog and self-healing recovery loop so the board can reboot if firmware or Wi-Fi operations get stuck.
Target board:
- ST B-L475E-IOT01A Discovery kit
- STM32L475 MCU
- ISM43362 Wi-Fi module
- HTS221 humidity and temperature sensor
- LPS22HB pressure sensor
This project currently includes BSP drivers for temperature, humidity, and pressure only. The board has additional sensors physically present, but their BSP drivers are not part of this workspace yet.
Application code lives in Core/Inc and Core/Src:
app.c/app.h: high-level application loop, scheduling, counters, and retry behavior.app_config.h: versioned application configuration.app_secrets.h: local Wi-Fi credentials, ignored by Git.app_secrets.example.h: safe template for local secrets.telemetry.c/telemetry.h: sensor initialization and averaged readings.wifi_service.c/wifi_service.h: small wrapper around ST'swifi.hAPI.api_client.c/api_client.h: JSON payload creation and HTTP request sending.mqtt_client.c/mqtt_client.h: minimal MQTT 3.1.1 client forCONNECT,SUBSCRIBE, QoS 1 wake commands, keepalive, and reconnects.wol.c/wol.h: Wake-on-LAN Magic Packet builder and UDP broadcast sender.log.c/log.h: UART logging helpers.system_health.c/system_health.h: reset reason capture, independent watchdog startup, watchdog refresh, and forced MCU reset.main.c: STM32CubeIDE-generated initialization plus calls toApp_Init()andApp_Loop().
Versioned configuration is in Core/Inc/app_config.h.
Important values:
#define APP_DEVICE_ID "stm32-room"
#define APP_FIRMWARE_VERSION "1.3.0"
#define APP_LOCATION "room"
#define APP_API_HOST "iot.mathislambert.fr"
#define APP_API_IP_ADDR {82U, 67U, 120U, 109U}
#define APP_API_PATH "/api/ingest?device=" APP_DEVICE_ID
#define APP_API_PORT 80U
#define APP_MQTT_KEEPALIVE_SECONDS 60U
#define APP_WOL_BROADCAST_PORT 9U
#define APP_SEND_INTERVAL_MS 300000UL
#define APP_SEND_RETRY_INTERVAL_MS 60000UL
#define APP_WIFI_RECOVERY_FAILURE_THRESHOLD 3U
#define APP_SYSTEM_RESET_FAILURE_THRESHOLD 12U
#define APP_TEMPERATURE_OFFSET_C 6.0fThe firmware uses a static API IP address to avoid DNS issues observed with the Wi-Fi module. It still sends the HTTP Host header, so Traefik can route by hostname.
Wi-Fi credentials must be stored locally in:
Core/Inc/app_secrets.h
That file is ignored by Git. Use Core/Inc/app_secrets.example.h as a template:
#ifndef APP_SECRETS_H
#define APP_SECRETS_H
#define APP_WIFI_SSID "your-2.4ghz-ssid"
#define APP_WIFI_PASSWORD "your-wifi-password"
#define APP_MQTT_HOST "your-mqtt-host.example.com"
#define APP_MQTT_IP_ADDR_VALUE_0 192U
#define APP_MQTT_IP_ADDR_VALUE_1 0U
#define APP_MQTT_IP_ADDR_VALUE_2 2U
#define APP_MQTT_IP_ADDR_VALUE_3 10U
#define APP_MQTT_IP_ADDR {192U, 0U, 2U, 10U}
#define APP_MQTT_PORT 1883U
#define APP_MQTT_USERNAME "your-mqtt-username"
#define APP_MQTT_PASSWORD "your-mqtt-password"
#define APP_MQTT_WAKE_TOPIC "your/private/wake/topic"
#define APP_MQTT_STATUS_TOPIC "your/private/status/topic"
#define APP_WOL_PC_MAC {0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U}
#endifDo not commit Core/Inc/app_secrets.h.
APP_WOL_PC_MAC must be replaced with the Ethernet MAC address of the PC to wake. If it stays all zeroes, the firmware will refuse to send the Magic Packet and log an error.
The firmware currently uses MQTT over plain TCP for STM32 compatibility. The public broker should restrict this account with ACLs to the wake and status topics only.
Runtime flow:
- The board connects to Wi-Fi.
- It opens an MQTT TCP connection to
APP_MQTT_HOST:APP_MQTT_PORT. - It authenticates with the configured username and password.
- It subscribes to
APP_MQTT_WAKE_TOPICwith QoS 1. - When it receives payload
wake, it sends a 102-byte Wake-on-LAN Magic Packet to the local/24broadcast address on UDP port9.
Example command from a remote machine:
mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" \
-u "$MQTT_USERNAME" \
-P "$MQTT_PASSWORD" \
-t "$MQTT_WAKE_TOPIC" \
-m wake \
-q 1TLS on 8883 is intentionally not enabled in firmware yet. The local driver has low-level SSL hints, but the public wrapper used by this project only exposes TCP and UDP cleanly. Plain MQTT is the first stable implementation target; MQTTS can be tested later behind a configurable WifiService_OpenSslClient() path.
The firmware sends an HTTP POST request with a structured JSON body compatible with the /api/ingest route from iot-api.
{
"device": {
"id": "stm32-room",
"firmware": "1.3.0",
"location": "room"
},
"runtime": {
"uptime_ms": 6074,
"sequence": 1,
"success_count": 0,
"failure_count": 0,
"wifi_reconnect_count": 1,
"consecutive_failure_count": 0,
"watchdog_enabled": 1,
"reset_reason": "power_on"
},
"network": {
"ssid": "your_wifi_2.4GHz",
"local_ip": "192.168.1.52",
"api_host": "iot.mathislambert.fr",
"api_ip": "82.67.120.109",
"api_port": 80
},
"config": {
"send_interval_ms": 300000,
"retry_interval_ms": 60000,
"temperature_offset_c": 6.0,
"sample_count": 5
},
"sensors": {
"humidity_sensor_id": 188,
"pressure_sensor_id": 177
},
"telemetry": {
"temperature_c": 25.24,
"raw_temperature_c": 31.24,
"humidity_percent": 46.37,
"pressure_hpa": 991.38
}
}Recommended workflow:
- Open the project in STM32CubeIDE.
- Create
Core/Inc/app_secrets.hfromCore/Inc/app_secrets.example.h. - Build the project.
- Flash the board with Run or Debug.
- Open a serial terminal on the ST-LINK COM port at
115200 8N1.
The local command-line build used during development was:
make -C Debug allThe exact make and arm-none-eabi-gcc paths may depend on the STM32CubeIDE installation.
The firmware logs over USART1 at 115200 baud.
Example:
[2] INFO Starting stm32-room
[3] INFO Reset reason=power_on watchdog=enabled
[5] INFO Sensors initialized
[588] INFO WiFi module initialized
[591] INFO Connecting to WiFi SSID "your_wifi_2.4GHz"
[5660] INFO WiFi connected with local IP 192.168.1.52
[5665] INFO Opening MQTT TCP connection to your-mqtt-host.example.com:1883 (192.0.2.10)
[5901] INFO MQTT connected and subscribed
[6074] INFO Telemetry temp=25.24C raw=31.24C hum=46.37% pressure=991.38hPa
[6081] INFO Opening TCP connection to iot.mathislambert.fr:80 (82.67.120.109)
[9247] INFO Sent 339/339 bytes to API
[9496] INFO API response received (255 bytes)
[9588] INFO Telemetry sent successfully
The firmware is designed to keep running unattended:
- The independent watchdog (IWDG) starts early during boot and uses the STM32L4 LSI clock with the maximum practical timeout, about 32 seconds.
- The watchdog is refreshed only from the main application loop. If the firmware blocks inside Wi-Fi, SPI, HAL, a fault handler, or
Error_Handler(), the board resets automatically. - Consecutive failures are tracked and reported in the API payload.
- After
APP_WIFI_RECOVERY_FAILURE_THRESHOLDconsecutive failures, the firmware closes the socket, disconnects Wi-Fi, resets the Wi-Fi module, and reconnects cleanly. - After
APP_SYSTEM_RESET_FAILURE_THRESHOLDconsecutive failures, the firmware requests a full MCU reset withNVIC_SystemReset(). - On boot, reset flags are captured before being cleared, then the reset reason is sent in the next payload.
- The board Wi-Fi module connects to 2.4 GHz networks. A 5 GHz-only SSID will not work.
- HTTPS/TLS on port
443was not reliable with the current Wi-Fi wrapper and module firmware. The working setup uses HTTP on port80and relies on the backend network configuration for exposure and routing. - Build outputs under
Debug/andRelease/are intentionally ignored.