Full-Stack IoT Activity Recognition System (STM32 + Android) A developer built a full-stack IoT activity recognition system that classifies walking versus running in real time, combining STM32F407 (RT-Spark) firmware, a Python MQTT listener running a trained Random Forest model, an SQLite database behind a Flask Web API, and a Kotlin Android app that queries the API via the Volley HTTP library. Two hardware faults forced workarounds: the onboard LSM6DSL accelerometer/gyroscope returned persistent HAL_ERROR (NACK) responses across all I2C buses, so the developer added a FreeRTOS synthetic data generator mimicking walking and running waveforms, and the RW007 Wi-Fi module lacked native support for the ISM43362 driver, so a UART-to-MQTT bridge (serial_to_mqtt.py) forwards JSON from the STM32 over USB to a local Mosquitto broker. The full source code for the firmware, Python backend, and Android app is published on GitHub. This project is a complete Full-Stack Internet of Things IoT system designed for real-time human activity recognition Walking vs. Running . By combining embedded C programming, cloud infrastructure, Machine Learning, and Android mobile development, this system demonstrates a true end-to-end IoT pipeline. How It Works The architecture is divided into three main components: Device Firmware: The STM32F407 RT-Spark generates movement data and formats it into a JSON payload. Cloud Backend: A Python MQTT listener receives the data, passes it to a trained Random Forest Machine Learning model, stores the prediction in an SQLite database, and serves it via a Flask Web API. Mobile App: A Kotlin Android app queries the Flask API using the Volley HTTP library and displays the live prediction and historical data. During development, we encountered two major hardware limitations with the provided RT-Spark board that required creative engineering solutions: Challenge 1: Sensor Unresponsiveness. The onboard LSM6DSL accelerometer/gyroscope returned persistent HAL ERROR NACK responses across all I2C buses. Solution: We verified the hardware fault using a custom bare-metal I2C diagnostic script. To ensure the pipeline could still be tested, we implemented a synthetic data generator in FreeRTOS that mimics realistic walking/running waveforms. - Solution: We verified the hardware fault using a custom bare-metal I2C diagnostic script. To ensure the pipeline could still be tested, we implemented a synthetic data generator in FreeRTOS that mimics realistic walking/running waveforms. - Challenge 1: Sensor Unresponsiveness. The onboard LSM6DSL accelerometer/gyroscope returned persistent HAL ERROR NACK responses across all I2C buses. Solution: We verified the hardware fault using a custom bare-metal I2C diagnostic script. To ensure the pipeline could still be tested, we implemented a synthetic data generator in FreeRTOS that mimics realistic walking/running waveforms. Challenge 2: Wi-Fi Incompatibility. The board utilizes an RW007 Wi-Fi module, which lacks native support for the ISM43362 driver required by the lab. Solution: We developed a custom UART-to-MQTT bridge . The STM32 sends JSON data via USB, and a Python script serial to mqtt.py acts as a gateway, publishing the data to the local Mosquitto broker. - Solution: We developed a custom UART-to-MQTT bridge . The STM32 sends JSON data via USB, and a Python script serial to mqtt.py acts as a gateway, publishing the data to the local Mosquitto broker. - Challenge 2: Wi-Fi Incompatibility. The board utilizes an RW007 Wi-Fi module, which lacks native support for the ISM43362 driver required by the lab. Solution: We developed a custom UART-to-MQTT bridge . The STM32 sends JSON data via USB, and a Python script serial to mqtt.py acts as a gateway, publishing the data to the local Mosquitto broker. The full source code, including the firmware, Python backend, and Android app, is available on GitHub. You can include the flowchart image we made here Backend: Run app.py Flask API and mqtt listener.py ML Classifier . Bridge: Flash the STM32 and run serial to mqtt.py to forward data. App: Build and run the Android app in an emulator to see the live predictions. Read more