Add wired Ethernet detector (LILYGO T-ETH-Lite S3) with PoE/MQTT support#39
Add wired Ethernet detector (LILYGO T-ETH-Lite S3) with PoE/MQTT support#39
Conversation
New WIRED_DETECTOR role: same audio detection pipeline (AudioTask + audio_processor) but alerts directly over W5500 Ethernet/PoE via MQTT, bypassing the LoRa + Gateway path entirely. - Add LILYGO T-ETH-Lite S3 board (W5500 SPI pins + I2S on GPIO 38/39/40) - Add eth_mqtt_task: W5500 init, MQTT connect, HA Discovery, event publish - Kconfig: new board choice, WIRED_DETECTOR role, MQTT menu shared with gateway - CMakeLists: conditional compile for wired role, esp_eth + w5500 deps - idf_component.yml: add espressif/w5500 managed component for IDF 6.x - config_console: wired_cfg NVS namespace for MQTT settings - CI: build + merge_bin + release wired_detector firmware (16MB flash) - CI: merge size report into build workflow, remove standalone size_report.yml - Docs: full coverage across all mkdocs pages Made-with: Cursor
Static IP: Add Kconfig options (ETH_STATIC_IP, ETH_GATEWAY, ETH_NETMASK, ETH_DNS) with NVS override. eth_mqtt_task applies static IP when configured, falls back to DHCP otherwise. Serial console gains show/set for eth_ip, eth_gw, eth_mask, eth_dns keys. Web Flasher: Replace two-card layout with tab-based role selector (Detector / Gateway / Wired Detector). Config panel adapts dynamically to the selected role. Wired detector tab includes MQTT fields and collapsible static IP configuration. Add generateWiredNvsImage() to nvs_gen.js for browser-side NVS patching of wired_cfg namespace. Made-with: Cursor
Cast uint8_t/uint16_t arguments to unsigned for %u format specifiers to satisfy cppcheck's variadic argument type checking. Made-with: Cursor
Firmware Size Report
idf.py size detailsDetector: |
Firmware Size Report
idf.py size detailsDetector: |
- Track link state via ETH_CONNECTED_BIT (cleared on disconnect/IP lost, set on IP acquired) so the task can detect cable unplug/replug - Register IP_EVENT_ETH_LOST_IP handler for DHCP lease expiry - Main loop blocks on wait_for_link() when Ethernet drops instead of silently dropping events - eth_init() failure no longer suspends the task permanently; it polls every 30s for link recovery (cable plugged in late) - MQTT auto-reconnect is handled by esp_mqtt_client internally; on reconnect the handler re-publishes availability + HA discovery Made-with: Cursor
Firmware Size Report
idf.py size detailsDetector: |
- Two-OTA partition table with rollback protection - HTTP server on port 8080 with endpoints: GET /api/info, GET /api/status, POST /api/ota, POST /api/config, POST /api/reboot - Optional Bearer token auth for POST endpoints - Shared detection status between EthMqttTask and HTTP API - OTA rollback confirmation in app_main - Web flasher: add HTTP auth token field for wired detector - Docs: REST API reference, OTA usage examples, FAQ Made-with: Cursor
- Replace memset on float-containing struct with value initialization - Use static_cast instead of C-style cast for malloc Made-with: Cursor
Made-with: Cursor
The conditional PRIV_DEPS append was not propagating include paths correctly in CI despite the condition being true. Move these lightweight standard IDF components to the unconditional list — unused symbols are garbage-collected. Made-with: Cursor
Firmware Size Report
idf.py size detailsDetector: |
Summary
Closes #35
EthMqttTask: W5500 SPI init, DHCP or static IP, MQTT publish, Home Assistant auto-discoveryshow/setcommands for MQTT and static IP configuration via NVSwired_detector(16MB flash), size report covers all three rolesREST API Endpoints
GET/api/infoGET/api/statusPOST/api/otaPOST/api/configPOST/api/rebootOTA example:
Test plan
idf.py buildfor detector, gateway, wired_detectorset eth_ip/set eth_gw+ rebootGET /api/infoandGET /api/statusreturn valid JSONPOST /api/configupdates NVS keys, verified after rebootPOST /api/otauploads firmware, device reboots and runs new version