{"id":51887885,"url":"https://github.com/saegey/alarm-panel-v2","last_synced_at":"2026-07-25T23:30:31.566Z","repository":{"id":366494501,"uuid":"1222101587","full_name":"saegey/alarm-panel-v2","owner":"saegey","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-22T03:57:32.000Z","size":42,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-22T05:21:26.137Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/saegey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-27T03:31:37.000Z","updated_at":"2026-06-22T03:57:37.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/saegey/alarm-panel-v2","commit_stats":null,"previous_names":["saegey/alarm-panel-v2"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/saegey/alarm-panel-v2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saegey%2Falarm-panel-v2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saegey%2Falarm-panel-v2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saegey%2Falarm-panel-v2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saegey%2Falarm-panel-v2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/saegey","download_url":"https://codeload.github.com/saegey/alarm-panel-v2/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saegey%2Falarm-panel-v2/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35896124,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-25T02:00:06.922Z","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":[],"created_at":"2026-07-25T23:30:30.953Z","updated_at":"2026-07-25T23:30:31.559Z","avatar_url":"https://github.com/saegey.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ESP32 Home Keypad Proof of Concept\n\nPlatformIO project for an `ESP32-WROOM-32` driving an `ILI9341` 240x320 SPI TFT with an `XPT2046` resistive touch controller. The UI is built with `LVGL`, display rendering uses `TFT_eSPI`, and touch input is handled on a separate SPI bus.\n\n## Hardware\n\n### Target MCU\n\n- ESP32-WROOM-32\n- PlatformIO board: `esp32dev`\n- Framework: `Arduino`\n\n### Wiring\n\n| Signal | ESP32 GPIO | Notes |\n| --- | --- | --- |\n| TFT_MOSI / SDI | GPIO13 | Display SPI MOSI |\n| TFT_MISO / SDO | GPIO12 | Display SPI MISO, boot strapping pin |\n| TFT_SCLK / SCK | GPIO14 | Display SPI clock |\n| TFT_CS | GPIO15 | Display chip select |\n| TFT_DC | GPIO2 | Display data/command |\n| TFT_RST | GPIO4 | Display reset |\n| TFT_LED | GPIO21 | Backlight enable |\n| TOUCH_MOSI / T_DIN | GPIO32 | Touch SPI MOSI |\n| TOUCH_MISO / T_OUT | GPIO39 | Touch SPI MISO, input-only is expected |\n| TOUCH_SCLK / T_CLK | GPIO25 | Touch SPI clock |\n| TOUCH_CS | GPIO33 | Touch chip select |\n| TOUCH_IRQ / T_IRQ | GPIO36 | Touch interrupt, input-only is expected |\n| VCC | 3.3V or 5V | Module-dependent |\n| GND | GND | Common ground |\n\n## Notes\n\n- The display is configured for portrait mode `240x320`.\n- `GPIO36` and `GPIO39` are input-only, which is appropriate for `T_IRQ` and `T_OUT`.\n- `GPIO12` is a boot strapping pin on ESP32. If boot issues occur, move display `MISO` off `GPIO12` and update `include/pin_config.h` plus `platformio.ini` build flags.\n- `TFT_eSPI` is configured locally through `platformio.ini` build flags. No global library files need to be edited.\n- Touch calibration values in `include/pin_config.h` are safe starter values and will likely need tuning on real hardware.\n- Runtime secrets are sourced from 1Password and rendered into `include/secrets.h`. That generated file is gitignored and should be treated as a build artifact, not the source of truth.\n- The project uses a custom OTA partition table with no SPIFFS/LittleFS partition so both OTA app slots are larger.\n\n## Project Layout\n\n- `platformio.ini`: PlatformIO environment and TFT_eSPI build-time configuration\n- `include/pin_config.h`: Pin definitions and touch calibration bounds\n- `include/lv_conf.h`: Local LVGL configuration\n- `include/secrets.example.h`: Template showing the generated header shape\n- `include/secrets.h`: Generated local secrets header from 1Password\n- `scripts/render_secrets_header.py`: Generates `include/secrets.h` from 1Password\n- `src/main.cpp`: Hardware setup, LVGL integration, UI, and placeholder actions\n\n## Current UI\n\n- Top row with local time and weather summary\n- `Master` alarm status card\n- `Garage` alarm status card\n- `Garage Door` status card\n- Tap a card to open an action modal\n- Alarm arming uses direct mode buttons\n- Alarm disarm requires PIN entry\n- Garage door modal shows `Open` or `Close` based on current door state\n\n## MQTT Setup\n\nThe project now includes a first-pass WiFi and MQTT client using `PubSubClient`.\n\n## 1Password Schema\n\nCreate a 1Password item named `Alarm Panel` in vault `Homelab` with these fields:\n\n- `wifi_ssid`\n- `wifi_password`\n- `mqtt_host`\n- `mqtt_port`\n- `mqtt_client_id`\n- `mqtt_username`\n- `mqtt_password`\n- `ota_hostname`\n- `ota_password`\n\nCreate or keep a separate `Wokwi CLI` item in the same vault with:\n\n- `credential`\n\nYou can override those default references at runtime with:\n\n- `OP_VAULT`\n- `OP_ITEM`\n- `OP_OTA_HOSTNAME_REF`\n- `OP_OTA_PASSWORD_REF`\n- `OP_WOKWI_TOKEN_REF`\n\nGenerate the local header with:\n\n```bash\npython3 scripts/render_secrets_header.py\n```\n\nCurrent publish topics are:\n\n- `home/keypad/status`\n- `home/keypad/display/set`\n- `weather/kbfi/state`\n- `garage/door/command`\n- `garage/door/state`\n- `alarmo/command`\n- `alarmo/state`\n- `alarmo/garage/state`\n\nCurrent behavior:\n\n- The device connects to WiFi during boot\n- The device attempts an MQTT connection after WiFi is up\n- The top-left clock uses NTP once WiFi is connected\n- The top-right weather label updates from `weather/kbfi/state`\n- The keypad subscribes to `alarmo/state`, `alarmo/garage/state`, and `garage/door/state`\n- The main screen shows master alarm, garage alarm, and garage door status with color dots\n- Alarm arming does not require a PIN\n- Alarm disarm requires a PIN\n- Garage door actions publish `TOGGLE` to `garage/door/command`\n- The display backlight can be controlled over MQTT and wakes on touch\n- The status topic publishes `online` as a retained message on connect\n\n## Display Sleep\n\nThe display backlight can be controlled over MQTT using:\n\n- Topic: `home/keypad/display/set`\n- Payloads: `ON`, `OFF`, `WAKE`, `SLEEP`, `TOGGLE`\n\nBehavior:\n\n- `OFF` or `SLEEP` turns the backlight off\n- `ON` or `WAKE` turns the backlight on\n- `TOGGLE` flips the current backlight state\n- A touch while sleeping wakes the display and does not trigger a UI action\n\n## Build and Upload\n\nRun these commands from the project root:\n\n```bash\njust build\njust flash\npio device monitor\n```\n\n## OTA Updates\n\nThe project includes `ArduinoOTA` so you can update over Wi-Fi after the first USB flash.\n\nConfigure these in the 1Password `Alarm Panel` item:\n\n- `ota_hostname`\n- `ota_password`\n\nAfter the device joins Wi-Fi, it advertises itself as:\n\n- `OTA_HOSTNAME.local`\n\nFirst flash over USB:\n\n```bash\npio run -e esp32dev -t upload\n```\n\nWireless OTA upload:\n\n```bash\njust flash\n```\n\nOverride the OTA upload target explicitly when needed:\n\n```bash\njust flash 192.168.1.123\njust flash alarm-panel.local\n```\n\nNotes:\n\n- The first flash still needs USB.\n- The device must be on Wi-Fi and powered on.\n- `platformio.ini` uses `OTA_PASSWORD` from the environment at upload time.\n- `just flash` reads `ota_password` and `ota_hostname` from 1Password at upload time.\n- If no explicit target is given, `just flash` uploads to `ota_hostname.local`.\n- OTA progress is logged to Serial if a monitor is attached.\n- If mDNS is unreliable on your network, override the upload host:\n\n```bash\njust flash 192.168.1.123\n```\n\n## Wokwi Simulation\n\nThe project includes Wokwi files:\n\n- `diagram.json`\n- `wokwi.toml`\n- `env:esp32dev-wokwi` in `platformio.ini`\n\nBuild for Wokwi:\n\n```bash\njust build\n```\n\nWhen built with `env:esp32dev-wokwi`, firmware automatically uses:\n\n- Wi-Fi SSID: `Wokwi-GUEST`\n- Wi-Fi password: empty\n- MQTT broker: `broker.hivemq.com:1883`\n\nYour normal hardware environments (`esp32dev`, `esp32dev-ota`) continue to use values from `include/secrets.h`.\n\n### MQTT Harness For Wokwi\n\nUse the included helper to mimic Home Assistant-like topic updates and log keypad commands:\n\n```bash\njust harness\n```\n\n`just sim` reads the Wokwi token from `op://Homelab/Wokwi CLI/credential`. Override the reference with `OP_WOKWI_TOKEN_REF` if your item lives elsewhere.\n`just sim` runs the headless Wokwi CLI. It does not open the browser-based visual simulator; it streams serial logs in the terminal and exits after `WOKWI_TIMEOUT_MS` milliseconds. The default is `300000` (5 minutes).\n\nThe harness publishes:\n\n- `weather/kbfi/state` JSON payloads\n- `alarmo/state`\n- `alarmo/garage/state`\n- `garage/door/state`\n\nAnd listens for:\n\n- `alarmo/command`\n- `garage/door/command`\n- `home/keypad/display/set`\n- `home/keypad/status`\n\n## What Happens Today\n\n- The backlight is enabled on `GPIO21`\n- The display is initialized with reset on `GPIO4`\n- Touch is initialized on its own SPI bus\n- LVGL renders a simple proof-of-concept keypad screen\n- Button presses log to Serial\n\n## Touch Calibration\n\nIf touches land in the wrong place, adjust the touch settings in `include/pin_config.h`.\n\nOrientation flags:\n\n- `TOUCH_SWAP_XY`\n- `TOUCH_INVERT_X`\n- `TOUCH_INVERT_Y`\n\nEdge alignment values:\n\n- `TOUCH_RAW_MIN_X`\n- `TOUCH_RAW_MAX_X`\n- `TOUCH_RAW_MIN_Y`\n- `TOUCH_RAW_MAX_Y`\n\nRecommended process:\n\n1. Upload the firmware and open `pio device monitor`\n2. Touch near the top-left, top-right, bottom-left, and bottom-right corners\n3. Watch the `[TOUCH] raw=(...) mapped=(...)` logs\n4. If the touch moves along the wrong axis, change `TOUCH_SWAP_XY`\n5. If the touch is mirrored left/right or up/down, change the corresponding invert flag\n6. If the touch reaches the right area but is offset near the edges, tighten the raw min/max values\n\nFor example:\n\n- If pressing higher on the screen makes `mapped.x` change instead of `mapped.y`, flip `TOUCH_SWAP_XY`\n- If pressing the left side triggers the right side, toggle `TOUCH_INVERT_X`\n- If pressing the top triggers the bottom, toggle `TOUCH_INVERT_Y`\n\n## Next Steps\n\n- Add WiFi setup in `setup()` before any MQTT connection logic\n- Add MQTT client initialization after WiFi is connected\n- Replace placeholder publish functions with real MQTT publishes\n- Update `MQTT: disconnected` from actual connection state\n- Add a PIN pad modal or separate screen for arm/disarm workflows\n- Calibrate touch and refine coordinate mapping on the physical device\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaegey%2Falarm-panel-v2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaegey%2Falarm-panel-v2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaegey%2Falarm-panel-v2/lists"}