{"id":25167109,"url":"https://github.com/ajcasagrande/bird-iot-platform","last_synced_at":"2026-05-01T22:32:01.781Z","repository":{"id":274374199,"uuid":"922611394","full_name":"ajcasagrande/bird-iot-platform","owner":"ajcasagrande","description":"Complete IoT platform for ESP32 devices using ESP-IDF","archived":false,"fork":false,"pushed_at":"2025-02-08T01:36:39.000Z","size":10098,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-03T17:53:01.958Z","etag":null,"topics":["arduino","arduino-esp32","embedded","esp-idf","esp32","espressif","freertos","garage-door-opener","home-automation","internet-of-things","iot","kconfig","microcontroller","mqtt","neopixel","oled","sensors","smarthome","websockets"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ajcasagrande.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-26T17:05:25.000Z","updated_at":"2025-02-08T01:36:43.000Z","dependencies_parsed_at":"2025-04-03T17:54:23.258Z","dependency_job_id":null,"html_url":"https://github.com/ajcasagrande/bird-iot-platform","commit_stats":null,"previous_names":["ajcasagrande/bird-iot-platform"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ajcasagrande/bird-iot-platform","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajcasagrande%2Fbird-iot-platform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajcasagrande%2Fbird-iot-platform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajcasagrande%2Fbird-iot-platform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajcasagrande%2Fbird-iot-platform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ajcasagrande","download_url":"https://codeload.github.com/ajcasagrande/bird-iot-platform/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajcasagrande%2Fbird-iot-platform/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32515837,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","arduino-esp32","embedded","esp-idf","esp32","espressif","freertos","garage-door-opener","home-automation","internet-of-things","iot","kconfig","microcontroller","mqtt","neopixel","oled","sensors","smarthome","websockets"],"created_at":"2025-02-09T06:18:50.544Z","updated_at":"2026-05-01T22:32:01.759Z","avatar_url":"https://github.com/ajcasagrande.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Bird-IoT Platform\n\nWelcome to the **Bird-IoT Platform**! This project is designed to run on ESP32-based devices with a highly modular approach. It provides a system of **plugins** (each derived from a common interface) and a **task** system that allows easy scheduling and concurrency.\n\n\u003e **Note:** This project is not seeing any regular updates.\n\u003e The intent of this repo is to share the concepts and code within.\n\n\u003e **Note:** Be sure to configure your authorization headers. Look for _TODO__ in the codebase\n\n---\n\n## Table of Contents\n\n- [Getting Started](#getting-started)\n- [Architecture Overview](#architecture-overview)\n- [Plugin System](#plugin-system)\n- [Task System](#task-system)\n- [Supported Plugins and Features](#supported-plugins-and-features)\n\n\n---\n\n## Getting Started\n\nGet the Docker Image\n```shell\ndocker pull ajcasagrande/bird-iot:esp-idf-v4.0.2\n```\n\nBuild a binary for the `ttgo-display` project\n```shell\n./docker-make.sh env=ttgo-display\n```\n\n## Architecture Overview\n\nThe Bird-IoT Platform is built around a central `IotApp` singleton that:\n\n- Manages **device profiles** (GPIO pin assignments, hardware specifics).\n- Initializes **core services** (NVS, Wi-Fi, MQTT, safe mode, etc.).\n- Registers **plugins** (each plugin is a self-contained module providing some feature or driver).\n- Coordinates **tasks** (each plugin can schedule its own asynchronous task, e.g. for polling hardware or performing repeated actions).\n\n**Key Points**:\n\n- **Safe Mode**: The platform supports a “safe mode” that can limit or bypass certain features if too many failed boots occur.\n- **Profiles**: A JSON or struct-based system describes board-specific pins (e.g., SDA, SCL, servo pins, etc.).\n- **Startup Flow**:\n  1. System initializes\n  2. NVS is set up\n  3. Boot counters are incremented\n  4. Wi-Fi and MQTT connect\n  5. Plugins are **setup** (configure) and then **start** (run)\n  6. Tasks begin periodic or event-driven execution\n\n---\n\n## Plugin System\n\n**`IotPlugin`** is the base class. Each plugin:\n\n- Has a **name** (e.g. `\"Console Plugin\"`).\n- Implements any of these optional lifecycle hooks:\n  - `bool setup()` — configure, allocate resources, and do any required initialization.\n  - `bool start()` — start actual execution (e.g. begin tasks, open sockets, etc.).\n  - `void onWifiConnected()` / `onWifiDisconnected()`\n  - `void onMqttConnected()` / `onMqttDisconnected()`\n  - `bool handleMqttMessage(const char *topic, int id, const char *cmd, const JsonDocument\u0026 json)`\n  - `bool handleCommand(const std::string \u0026cmd)` — for console or remote command handling.\n  - `void addFramesAndOverlays()` — for UI-based plugins that draw on a display (OLED, TFT, etc.).\n\n**Plugin Registration**:\n\n- Plugins are registered in `IotApp` via `App.registerPlugin(...)`.\n- Once registered, they will be automatically `setup()` and `start()` in the platform’s initialization sequence.\n- A plugin can also register or spawn its own tasks for scheduling repeated or event-driven actions.\n\n---\n\n## Task System\n\nMost plugins rely on **`TaskClass`** (or `Task\u003cT\u003e` templated class) to schedule:\n\n- **Periodic tasks** with intervals (e.g. 1 second).\n- **Single-shot tasks** that run once after an initial delay.\n- **Paused/resume** functionality.\n- Pinning to a specific ESP32 core (`coreId`).\n- Exact timing vs. yield-based timing.\n\n**Key APIs** in `TaskClass`:\n\n- `configure(interval, stackSize, priority, coreId, useExactTiming, allowDuringOTA, initialDelay)`\n- `start() / pause() / resume() / remove()`\n- `_executeIfAllowed()` — an internal guard to skip runs if paused or in an OTA update.\n\nAny plugin can:\n\n1. Subclass `TaskClass` (or use `Task\u003cPluginType\u003e`) to create a periodic job.\n2. Start the task inside `setup()` or `start()`.\n3. Implement the `execute()` routine that is called each time the task fires.\n\n---\n\n## Supported Plugins and Features\n\nBelow is a summary of all major plugins/features discovered in this project. Many are **conditioned** by `#if CONFIG_ENABLE_...` macros in `sdkconfig` or Kconfig defaults.\n\n\u003e **Note**: Not all plugins must be enabled at once. Each plugin can be individually toggled via build config to keep firmware lean.\n\n### Console Plugin\n\n- **Macro**: `CONFIG_ENABLE_CONSOLE_PLUGIN`\n- **Description**: Provides a **serial console** interface (via UART). It integrates with [linenoise](https://github.com/esp8266/Arduino/tree/master/tools/linenoise) for command history, completion, etc.\n- **Features**:\n  - Supports live command input on serial\n  - Basic console commands (`help`, `meminfo`, etc.)\n  - Ties into the `CommandPlugin` for additional commands\n\n### Command Plugin\n\n- **Macro**: `CONFIG_ENABLE_COMMANDS_PLUGIN`\n- **Description**: Allows execution of text-based **commands** from multiple sources (serial console, websockets, MQTT messages, etc.).\n- **Features**:\n  - Provides a unified `handleCommand(const std::string\u0026)`.\n  - Built-in commands: `help`, `tasks`, `heap`, `ip`, `vcc`, `reset`, `version`, and more.\n  - Simplifies creating new commands in a centralized place.\n\n### Button Plugin\n\n- **Macro**: `CONFIG_ENABLE_BUTTON_PLUGIN`\n- **Description**: Manages **button inputs** (GPIO pins). Each button is an instance of `IotButton`.\n- **Features**:\n  - Schedules a background task to handle debouncing or event polling\n  - Allows hooking custom callbacks on button press\n\n### SecureOTA Plugin\n\n- **Macro**: `CONFIG_ENABLE_SECURE_OTA_PLUGIN`\n- **Description**: Handles **firmware over-the-air** updates, with optional:\n  - HTTPS downloads\n  - MD5 or SHA256 checks\n  - **Rollback** support and verification\n- **Workflow**:\n  - On receiving an MQTT message with OTA details, it suspends non-critical tasks, downloads new firmware, and if successful, reboots into the new image.\n\n### Camera Server Plugin\n\n- **Macro**: `CONFIG_ENABLE_CAMERA_SERVER_PLUGIN`\n- **Description**: Sets up a minimal **HTTP server** that can serve camera frames or respond to a basic route (`/`).\n\n### HTTPS Server Plugin\n\n- **Macro**: `CONFIG_ENABLE_HTTPS_SERVER_PLUGIN`\n- **Description**: Embedded **HTTPS** server built on [httpsserver library](https://github.com/fhessel/esp32_https_server).\n- **Features**:\n  - Creates a self-signed certificate\n  - Serves static or dynamic content over TLS\n  - Example handler for root `/` endpoint\n\n### BLE Beacon Plugin\n\n- **Macro**: `CONFIG_ENABLE_BLE_BEACON`\n- **Description**: Configures an **iBeacon** on the ESP32 that broadcasts a custom UUID, major/minor, etc.\n- **Features**:\n  - Use `btStart()` internally\n  - Advertise indefinite iBeacon data\n  - Optionally releases BT Classic memory\n\n### BLE Keyboard Plugin\n\n- **Macro**: `CONFIG_ENABLE_BLE_KEYBOARD_PLUGIN`\n- **Description**: Emulates a **BLE HID keyboard** that can send key presses (including media keys).\n- **Features**:\n  - Uses NimBLE or Bluedroid under the hood\n  - `sendKey()`, `sendMediaKey()` for controlling remote devices from MQTT commands\n  - Pairing/bonding optional\n\n### NimBLE Plugin\n\n- **Macro**: `CONFIG_ENABLE_NIMBLE_PLUGIN`\n- **Description**: Enables the **NimBLE** stack for BLE operations (lightweight alternative to Classic).\n- **Features**:\n  - Creates a basic iBeacon advertisement\n  - Hooks into the standard NimBLE host tasks\n\n### MDNS Plugin\n\n- **Macro**: `CONFIG_ENABLE_MDNS_PLUGIN`\n- **Description**: Registers an **mDNS** service so the device can be discovered locally via `deviceid.local`.\n- **Features**:\n  - Optionally includes additional mDNS service TXT records (version, environment, etc.)\n\n### OLED Display Plugin\n\n- **Macro**: `CONFIG_ENABLE_I2C_OLED_DISPLAY_PLUGIN`\n- **Description**: Manages a **SSD1306/SH1106** or similar small OLED display over I2C.\n- **Features**:\n  - Uses `OLEDDisplayUi` for frames and overlays\n  - Automatic progress bar for e.g. OTA\n  - `addFramesAndOverlays()` allows each plugin to draw a portion of the UI\n\n### SPI Display Plugin\n\n- **Macro**: `CONFIG_ENABLE_SPI_DISPLAY_PLUGIN`\n- **Description**: Uses **spilcd** driver for ST7789 or similar SPI-based LCD.\n- **Features**:\n  - Screen saver example\n  - Optional backbuffer\n  - Rotation settings\n\n### TFT Display Plugin\n\n- **Macro**: `CONFIG_ENABLE_TFT_DISPLAY`\n- **Description**: Manages a **TFT_eSPI**-driven display (e.g. ILI9341, ST7735, ST7789).\n- **Features**:\n  - Basic UI overlays, progress bars, screen saver\n  - Adjust backlight brightness\n  - Rotation toggles\n\n### Garage Plugin\n\n- **Macro**: `CONFIG_ENABLE_GARAGE_PLUGIN`\n- **Description**: Simple **garage door** opener plugin using a relay or GPIO toggle.\n- **Features**:\n  - MQTT command to `toggle` or `double_toggle`\n  - Delays to simulate relay press\n\n### GPS Plugin\n\n- **Macro**: `CONFIG_ENABLE_GPS_PLUGIN`\n- **Description**: Reads data from an attached **GPS** (e.g. UART NMEA).\n- **Features**:\n  - Uses `TinyGPS++`\n  - Maintains average speed, max speed, satellite info\n  - Can draw overlays on TFT display\n\n### Hobbywing Task Plugin\n\n- **Macro**: `CONFIG_ENABLE_HOBBYWING_TASK_PLUGIN`\n- **Description**: Interacts with a **Hobbywing** ESC or car ESC over a UART or TTL signal.\n- **Features**:\n  - Captures raw data frames from ESC\n  - Example logging of data (RPM, voltage, etc.)\n\n### IR Plugin\n\n- **Macro**: `CONFIG_ENABLE_IR_PLUGIN`\n- **Description**: Transmits **38kHz IR** signals for devices (e.g. TVs or AC).\n- **Features**:\n  - `send_nec()` and `send_lg_ac()` examples\n  - Mark/space approach at 38kHz using raw GPIO toggling\n\n### RF Raw Plugin\n\n- **Macro**: `CONFIG_ENABLE_RF_RAW_PLUGIN`\n- **Description**: Captures raw edges from an **RF** receiver pin, logs timing for further decode.\n- **Features**:\n  - Attaches interrupt\n  - Collects microsecond-level timing for analysis\n\n### RF Sniffer Plugin\n\n- **Macro**: `CONFIG_ENABLE_RF_SNIFFER_PLUGIN`\n- **Description**: Uses a 433/315MHz receiving library to decode pulses into recognizable codes (like “RC Switch” style codes).\n- **Features**:\n  - Publishes discovered codes via MQTT\n  - Optional raw capturing\n\n### RF Transmit Plugin\n\n- **Macro**: `CONFIG_ENABLE_RF_TRANSMIT_PLUGIN`\n- **Description**: Transmits 433/315MHz codes (like RC Switch).\n- **Features**:\n  - MQTT command to send a code with a given bit length, pulse length, protocol, sync factors\n\n### Hunter Fan Plugin\n\n- **Macro**: `CONFIG_ENABLE_HUNTER_FAN_PLUGIN`\n- **Description**: Sends **Hunter Fan**-style remote codes via a certain timing pattern on a GPIO.\n- **Features**:\n  - Supports a specific pulse logic for older Hunter fans\n\n### Acurite Sensor Plugin\n\n- **Macro**: `CONFIG_ENABLE_ACURITE_SENSOR_PLUGIN`\n- **Description**: Work in progress to decode **Acurite temperature/humidity** sensor signals in the 433MHz band.\n\n### Servo Input Plugin\n\n- **Macro**: `CONFIG_ENABLE_SERVO_INPUT_PLUGIN`\n- **Description**: Uses **RMT** to read servo pulses from an RC receiver.\n- **Features**:\n  - Multiple channels\n  - Each channel has a `duty()` or pulse width in microseconds\n  - Notifies changes via a background task\n\n### NTP Plugin\n\n- **Macro**: `CONFIG_ENABLE_SNTP_PLUGIN`\n- **Description**: Synchronizes system time via **NTP** servers.\n- **Features**:\n  - Automatic updates after Wi-Fi is connected\n  - Timezone support, time sync callback\n  - Can show a time overlay on TFT or OLED\n\n### SPIFFS Plugin\n\n- **Macro**: `CONFIG_ENABLE_SPIFFS_PLUGIN`\n- **Description**: Initializes **SPIFFS** filesystem.\n- **Features**:\n  - Formats on failure (if needed)\n  - Logs total/used space\n\n### Secure Websocket Plugin\n\n- **Macro**: `CONFIG_ENABLE_SECURE_WEBSOCKET_PLUGIN`\n- **Description**: Creates an **HTTPS** server with **websocket** capability on port 443, using a certificate/key stored in the firmware.\n- **Features**:\n  - 2-way TLS\n  - Real-time data over wss\n\n### WebSocketCommand Plugin\n\n- **Macro**: `CONFIG_ENABLE_WEBSOCKET_COMMAND_PLUGIN`\n- **Description**: Allows receiving console-like **commands** over a websocket (usually on some port).\n- **Features**:\n  - Forwards lines to the `CommandPlugin::handleCommand()`\n\n### WebSocketServer Plugin\n\n- **Macro**: `CONFIG_ENABLE_WEBSOCKET_SERVER_PLUGIN`\n- **Description**: Similar to above, but might run on a simpler or different port (e.g. `81` or `8081`).\n- **Features**:\n  - Echo or dispatch commands\n  - Maintains a map of connected clients\n\n### WebsocketClient Plugin\n\n- **Macro**: `CONFIG_ENABLE_WEBSOCKET_CLIENT_PLUGIN`\n- **Description**: Connects to a remote **wss** server from the device as a **client**.\n- **Features**:\n  - Periodic keepalive\n  - Data exchange in real-time\n\n### ConnectionStats Plugin\n\n- **Macro**: `CONFIG_ENABLE_CONNECTION_STATS_PLUGIN`\n- **Description**: Tracks **Wi-Fi** and **MQTT** connect/disconnect events:\n  - Number of drops\n  - Time of last connect\n  - Optionally logs or publishes stats\n\n### RSSI Plugin\n\n- **Macro**: `CONFIG_ENABLE_RSSI_STATS_PLUGIN`\n- **Description**: Periodically polls Wi-Fi **RSSI** (signal strength).\n- **Features**:\n  - Publishes min / max / average RSSI after a configurable interval\n  - Optional logs\n\n### WifiScan Plugin\n\n- **Macro**: `CONFIG_ENABLE_WIFI_SCAN_PLUGIN`\n- **Description**: Scans for **nearby APs** either on each channel or a single channel, then publishes results over MQTT.\n- **Features**:\n  - Passive scanning\n  - Displays SSID, RSSI, channel, auth mode\n\n### Example Basic Plugin\n\n- **Macro**: `CONFIG_ENABLE_EXAMPLE_BASIC_PLUGIN`\n- **Description**: A minimal plugin example with basic `setup()`/`start()` stubs.\n\n### Example Task Plugin\n\n- **Macro**: `CONFIG_ENABLE_EXAMPLE_TASK_PLUGIN`\n- **Description**: Demonstrates scheduling an internal `TaskClass` to run periodically.\n\n### Example Sensor Plugin\n\n- **Macro**: `CONFIG_ENABLE_EXAMPLE_SENSOR_PLUGIN`\n- **Description**: Illustrates a sensor plugin pattern with periodic polling and publishing (two tasks):\n  - `pollTask`\n  - `publishTask`\n\n---\n\n## Closing Notes\n\nThis platform is highly modular. Each plugin can be toggled on/off via build flags (`CONFIG_ENABLE_*`).  \nMost plugins use their own `TaskClass` for concurrency.  \nTo add a new feature:\n\n1. Subclass `IotPlugin`.\n2. Implement `setup()`, `start()`, and any relevant hooks.\n3. Optionally create a `Task\u003cYourPlugin\u003e` for periodic or event-based logic.\n4. Register the plugin with `App.registerPlugin(new YourPlugin());`.\n\n## Old README.md\n\nComplete IoT platform for the ESP32 using ESP-IDF and FreeRTOS.\n\n## Supported Devices\n- IR\n- RF 433mhz / 315mhz\n- Hunter Fan Remote\n- Temp / Humidity\n- LG Portable AC\n- Garage Opener\n- Door Sensor (Reed Switch) x2\n\n\n## Setup\n### Install ESP-IDF\n```shell\nmkdir -p ~/esp\ncd ~/esp\ngit clone --recurse-submodules --branch v4.0.2 git@github.com:espressif/esp-idf.git\ncd esp-idf\n./install.sh\n```\n\n\n## Wiring\n### Notes\n- `D0` appears to control an on board RED led on the NodeMCU boards\n- `D4` controls the very bright blue light on the ESP-12E module\n\n\n### Reed Switch\nPlug one wire into `GND` and the other wire into a GPIO pin. `D0` and `D4` are some known working GPIO pins, however not all GPIO pins will work. Typically the reed switches I have are normally open switches, but this can be confirmed by running the software and checking.\n\n### i2c\n- Not all GPIO pins are good for i2c. Some known good ones are `D1`, `D2`, `D3`, `D4`, `D5`, `D6`.\n- Auto detection is supported, just setup the `SDA_PIN` and `SCL_PIN`\n\n### Relay\nWire into the Normally Open Pins which is the middle pin and the pin not connected by a white line. First and second pins if looking from the front.\n\n### LCD Character Display\n- Auto detect using i2c\n\n### RF433 Receiver\n- Connect GND, VCC to 5v (Vin), and the Digital Output pin to `D2` on the nodemcu.\n  - From left to right it is:\n  - `GND, D2, __, Vin, ................. __, __, __, (optional antenna)`\n\n## Development\n### Make targets\n- Create a new basic plugin\n  `make create-plugin name=\u003c...\u003e folder=\u003c...\u003e`\n- Create a new Task plugin\n  `make create-task-plugin name=\u003c...\u003e folder=\u003c...\u003e`\n\nNote: `name` _should include_ the suffix of Plugin or whatever.\nNote: `folder` is the sub-folder within plugins folder the plugin is to be put.\n\n#### Docker\n```shell\n./docker-make.sh\n```\n\n### Serial\n```shell\nmake udev-rules\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fajcasagrande%2Fbird-iot-platform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fajcasagrande%2Fbird-iot-platform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fajcasagrande%2Fbird-iot-platform/lists"}