Repository navigation
Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
# IoT ESP32 FreeRTOS Project This project is an ESP32-based IoT application using PlatformIO and FreeRTOS. It is designed for modular task management, including uptime tracking, button input, and light control. The codebase is structured for clarity, maintainability, and easy extension. PlatformIO streamlines the setup of the ESP32 development environment, making it efficient and accessible for rapid prototyping and deployment. ## Features - Modular FreeRTOS tasks for uptime and network management - Configurable PWM lights with brightness control and synchronized updates - Debounced button callbacks through Espressif's button component - Clean separation of application logic and hardware abstraction - Easy integration of new features via the `lib/` directory - Example plans and deprecated code for reference ## Directory Structure | Directory/File | Description | | --------------- | -------------------------------------------------------- | | .github/ | GitHub configuration files | | .gitignore | Git ignore rules | | .pio/ | PlatformIO build files | | .vscode/ | VS Code configuration | | graveyard/ | Deprecated code for reference | | include/ | Project header files | | lib/ | Project-specific libraries (uptime, button, light, etc.) | | plan.excalidraw | Project plan (Excalidraw format) | | platformio.ini | PlatformIO configuration | | README | Project documentation (this file) | | sdkconfig | ESP32 SDK configuration | | src/ | Main application source code | | test/ | PlatformIO Test Runner and tests | ## Build & Upload Instructions 1. Install [PlatformIO](https://platformio.org/) and [VS Code](https://code.visualstudio.com/). 2. Open the project folder in VS Code. 3. Use PlatformIO commands to build and upload firmware to your ESP32 device: - Build: `PlatformIO: Build` - Upload: `PlatformIO: Upload` ## Wokwi Simulator 1. Install the [Wokwi for VS Code](https://marketplace.visualstudio.com/items?itemName=wokwi.wokwi-vscode) extension. 2. If a license is requested, open the Command Palette (`Cmd+Shift+P` on macOS), run `Wokwi: Request a new License`, and complete activation in your browser. 3. Run `PlatformIO: Build` before starting the simulator. Alternatively, build with `~/.platformio/penv/bin/pio run -e esp32dev` on macOS. 4. Open the Command Palette and run `Wokwi: Start Simulator`. 5. Press and release either simulated button to toggle its matching LED. Both LEDs start off. Application and uptime messages appear in the serial terminal. `wokwi.toml` loads `.pio/build/esp32dev/firmware.bin` and its matching ELF file. The environment is named `esp32dev`, but targets the ESP32-S3-DevKitC-1. `diagram.json` uses that board with active-low buttons on GPIO 7 and GPIO 16, and active-high LEDs on GPIO 4 and GPIO 5 through 220-ohm resistors. The firmware enables internal button pull-ups, so external pull-ups are not needed. Rebuild and restart the simulator after changing the firmware. Wi-Fi is initialized, but the current startup does not start station mode or provisioning. A Wi-Fi connection is not expected when testing the buttons and LEDs. ## Buttons and Lights Button and light handling has three layers: - `lib/button`: Reusable `button_create()` / `button_delete()` API with opaque handles, configuration, press/release events, and callbacks. Its implementation wraps [espressif/button](https://components.espressif.com/components/espressif/button); the public header exposes no backend types. It has no light or board dependencies. - `lib/light`: Reusable create/delete, set/get, atomic toggle, and brightness API with opaque handles. Its LEDC backend generates independent PWM outputs without a polling task. Each light has its own mutex; wiring, light count, and application actions stay outside the library. - `lib/light_patterns`: Repeating fade, flash, and SOS effects scheduled by a worker task per light. It owns effect timing and cancellation through the light API. - `src/board.h`: GPIO assignments and active levels for this board's buttons and lights. - `src/controls.c`: Creates the lights and buttons and maps their events to application actions. GPIO 7 and GPIO 16 are active-low inputs with internal pull-ups, controlling active-high lights on GPIO 4 and GPIO 5 respectively. Every debounced release toggles the corresponding light, including releases after long presses. `main.c` calls `controls_init()`, which creates the lights in the off state before creating buttons. Repeated initialization is ignored; failures clean up buttons before lights and return an error. The IDF Component Manager downloads the backend during the build. The backend supplies polling, debouncing, and default gesture timing through its timer task. Callbacks should be short and nonblocking; create/delete buttons from a serialized application lifecycle, never inside a callback. `light_create()` takes a GPIO, active level, initial state, and brightness percentage. An omitted/zero initial brightness defaults to 100%. Use `light_set()` to apply a state, `light_get()` to read its logical state, and `light_toggle()` to invert it atomically. `light_delete()` turns the light off, resets the GPIO, and clears the handle. Each GPIO must have a single owner, and deletion must be serialized with all users of that light. Brightness uses a linear PWM duty from 0 to 100%. `light_set_brightness(light, 40)` turns the light on at 40%; `light_get_brightness()` reports its current percentage (zero when off). Setting brightness to zero or switching off preserves the last nonzero brightness, which is restored when switched on again. The buttons keep their existing toggle behavior, and initially turn the lights on at 100%. The backend reserves low-speed LEDC timer 0 at 5 kHz with 10-bit resolution. It allocates one free channel per light, rejects duplicate GPIOs, and releases channels on deletion. The shared timer remains configured for reuse. Other PWM consumers must avoid this timer and the light library's allocated channels. PWM updates run in task context under a mutex; do not call the light API from an ISR. A future potentiometer belongs in a separate analog-input component. Application code can map its ADC readings to 0–100 and call `light_set_brightness()` on the target light. The light library does not need to know about the knob. The knob's GPIO, ADC handling, and filtering can be added when the hardware is chosen. ## Light Patterns After `controls_init()`, application code can start an effect without waiting for the effect to finish: ```c const light_pattern_options_t sos = { .kind = LIGHT_PATTERN_SOS, .brightness_percent = 60, .interval_ms = 250, }; ESP_ERROR_CHECK(controls_start_pattern(CONTROLS_LIGHT_ONE, &sos)); // Later, cancel the effect and leave its current output unchanged. ESP_ERROR_CHECK(controls_stop_pattern(CONTROLS_LIGHT_ONE)); ``` `LIGHT_PATTERN_FADE` repeatedly ramps from zero to peak brightness and back; `interval_ms` sets the duration of each ramp. `LIGHT_PATTERN_FLASH` uses that interval for each on/off phase. `LIGHT_PATTERN_SOS` uses it as the dot duration, with dashes three times as long, standard letter gaps, and a seven-dot message gap. Zero settings select 100% brightness and 1000 ms fade ramps or 250 ms flash/SOS intervals. Explicit intervals must be at least 20 ms. Each controller updates approximately every 20 ms while running and sleeps while idle. Effects repeat until stopped or replaced. A failed PWM update stops the effect and logs the error. Pressing a button cancels its light's effect before toggling the current on/off state. Effects are idle at startup. For another project, create a controller with `light_pattern_create(light, &pattern)` and use `light_pattern_start()` / `light_pattern_stop()` directly. Create only one controller per light. Stop it before manual brightness changes, and delete it with `light_pattern_delete()` before deleting its light. Worker creation/deletion belongs in application lifecycle code; start/stop may be called from task callbacks. ## License This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. --- For questions or contributions, please open an issue or pull request.