From 91c7adfd2d8aa476e8f0edaabd378374b3698cc2 Mon Sep 17 00:00:00 2001 From: Foy Date: Tue, 30 Dec 2025 10:30:35 +0800 Subject: [PATCH 1/8] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=8F=AF?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=9A=84=E9=96=80=E4=BD=8D=E6=84=9F=E6=87=89?= =?UTF-8?q?=E5=99=A8=20(Door=20Sensor)=20=E6=94=AF=E6=8C=81=20=20=20=20=20?= =?UTF-8?q?2=20=20=20=20=203=20=E5=AF=A6=E4=BD=9C=E5=85=A7=E5=AE=B9?= =?UTF-8?q?=EF=BC=9A=20=20=20=20=204=20-=20=E5=BE=8C=E7=AB=AF=20(C++)?= =?UTF-8?q?=EF=BC=9A=20=20=20=20=205=20=20=20=20=20-=20=E5=9C=A8=20`misc?= =?UTF-8?q?=5Fconfig=5Ft`=20=E9=85=8D=E7=BD=AE=E7=B5=90=E6=A7=8B=E4=B8=AD?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20`doorSensorPin`=20=E6=AC=84=E4=BD=8D?= =?UTF-8?q?=EF=BC=88=E9=A0=90=E8=A8=AD=E7=82=BA=20GPIO=2032=EF=BC=89?= =?UTF-8?q?=E3=80=82=20=20=20=20=206=20=20=20=20=20-=20=E5=9C=A8=20`LockMe?= =?UTF-8?q?chanismService`=20=E4=B8=AD=E5=8A=A0=E5=85=A5=20`CurrentDoorSta?= =?UTF-8?q?te`=20=E7=89=B9=E5=BE=B5=20(Characteristic)=E3=80=82=20=20=20?= =?UTF-8?q?=20=207=20=20=20=20=20-=20=E9=87=8D=E5=AF=AB=20`LockMechanismSe?= =?UTF-8?q?rvice::loop()`=20=E4=BB=A5=E8=BC=AA=E8=A9=A2=20GPIO=20=E7=8B=80?= =?UTF-8?q?=E6=85=8B=EF=BC=8C=E6=94=AF=E6=8F=B4=E5=8D=B3=E6=99=82=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E9=96=80=E4=BD=8D=E8=87=B3=20HomeKit=E3=80=82=20=20?= =?UTF-8?q?=20=20=208=20=20=20=20=20-=20=E9=82=8F=E8=BC=AF=E5=AF=A6?= =?UTF-8?q?=E4=BD=9C=EF=BC=9AGPIO=20LOW=20=E7=82=BA=E9=97=9C=E9=96=80=20(S?= =?UTF-8?q?ecured)=EF=BC=8CHIGH=20=E7=82=BA=E9=96=8B=E9=96=80=20(Unsecured?= =?UTF-8?q?)=E3=80=82=20=20=20=20=209=20=20=20=20=20-=20=E7=A2=BA=E4=BF=9D?= =?UTF-8?q?=20`doorSensorPin`=20=E5=8F=AF=E9=80=8F=E9=81=8E=20`ConfigManag?= =?UTF-8?q?er`=20=E6=8C=81=E4=B9=85=E5=8C=96=E5=84=B2=E5=AD=98=E6=96=BC=20?= =?UTF-8?q?NVS=E3=80=82=20=20=20=2010=20=20=20=2011=20-=20=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=20(Web=20UI)=EF=BC=9A=20=20=20=2012=20=20=20=20=20-?= =?UTF-8?q?=20=E5=9C=A8=20`api.ts`=20=E4=B8=AD=E6=9B=B4=E6=96=B0=20`MiscCo?= =?UTF-8?q?nfig`=20=E7=9A=84=E9=A1=9E=E5=9E=8B=E5=AE=9A=E7=BE=A9=E3=80=82?= =?UTF-8?q?=20=20=20=2013=20=20=20=20=20-=20=E5=9C=A8=E3=80=8C=E7=B3=BB?= =?UTF-8?q?=E7=B5=B1=E8=A8=AD=E5=AE=9A=20(System=20Settings)=E3=80=8D?= =?UTF-8?q?=E5=8D=80=E5=A1=8A=E6=96=B0=E5=A2=9E=E3=80=8CDoor=20Sensor=20GP?= =?UTF-8?q?IO=20Pin=E3=80=8D=E8=BC=B8=E5=85=A5=E6=AC=84=E4=BD=8D=E3=80=82?= =?UTF-8?q?=20=20=20=2014=20=20=20=20=20-=20=E9=87=8D=E6=96=B0=E7=B7=A8?= =?UTF-8?q?=E8=AD=AF=E5=89=8D=E7=AB=AF=E9=9D=9C=E6=85=8B=E8=B3=87=E6=BA=90?= =?UTF-8?q?=E4=B8=A6=E5=9F=B7=E8=A1=8C=E6=AA=94=E6=A1=88=E5=A3=93=E7=B8=AE?= =?UTF-8?q?=E5=84=AA=E5=8C=96=EF=BC=88=E9=A0=90=E5=A3=93=E7=B8=AE=E4=BB=A5?= =?UTF-8?q?=E7=AF=80=E7=9C=81=20Flash=20=E7=A9=BA=E9=96=93=EF=BC=89?= =?UTF-8?q?=E3=80=82=20=20=20=2015=20=20=20=2016=20-=20=E7=A1=AC=E9=AB=94?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=EF=BC=9A=20=20=20=2017=20=20=20=20=20-=20?= =?UTF-8?q?=E9=A0=90=E8=A8=AD=E4=BD=BF=E7=94=A8=20GPIO=2032=20=E4=BD=9C?= =?UTF-8?q?=E7=82=BA=E6=84=9F=E6=87=89=E5=99=A8=E8=BC=B8=E5=85=A5=EF=BC=8C?= =?UTF-8?q?=E4=B8=A6=E5=95=9F=E7=94=A8=E5=85=A7=E9=83=A8=E4=B8=8A=E6=8B=89?= =?UTF-8?q?=E9=9B=BB=E9=98=BB=20(INPUT=5FPULLUP)=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/Frontend_function.md | 21 +++++++++++++++++++++ data/src/lib/components/AppMisc.svelte | 15 +++++++++++++++ data/src/lib/types/api.ts | 2 ++ main/ConfigManager.cpp | 1 + main/ConfigManager_function.md | 17 +++++++++++++++++ main/HKServices.cpp | 19 ++++++++++++++++++- main/HardwareManager_function.md | 18 ++++++++++++++++++ main/HomeKitLock.cpp | 2 +- main/LockManager_function.md | 21 +++++++++++++++++++++ main/MqttManager_function.md | 18 ++++++++++++++++++ main/NfcManager_function.md | 20 ++++++++++++++++++++ main/ReaderDataManager_function.md | 19 +++++++++++++++++++ main/WebServerManager_function.md | 20 ++++++++++++++++++++ main/include/HomeKitLock.hpp | 6 +++++- main/include/config.hpp | 1 + 15 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 data/Frontend_function.md create mode 100644 main/ConfigManager_function.md create mode 100644 main/HardwareManager_function.md create mode 100644 main/LockManager_function.md create mode 100644 main/MqttManager_function.md create mode 100644 main/NfcManager_function.md create mode 100644 main/ReaderDataManager_function.md create mode 100644 main/WebServerManager_function.md diff --git a/data/Frontend_function.md b/data/Frontend_function.md new file mode 100644 index 00000000..babc2c20 --- /dev/null +++ b/data/Frontend_function.md @@ -0,0 +1,21 @@ +# Frontend Module + +## Description +The Frontend is a Single Page Application (SPA) built with Svelte and Vite. It provides a modern, responsive user interface for configuring and controlling the HomeKey-ESP32 device. + +## Key Responsibilities +- **User Interface**: Displays the current lock state, logs, and configuration forms. +- **API Interaction**: Communicates with the `WebServerManager` via REST APIs to fetch and save settings. +- **Real-time Updates**: Connects via WebSocket to display live logs and instant state changes. +- **HomeKey Management**: Provides a UI to view provisioned HomeKey issuers and manage reader settings. + +## Dependencies +- **Svelte**: The UI framework. +- **Vite**: The build tool. +- **Tailwind CSS** (likely): For styling. +- **Backend API**: Depends on the endpoints provided by `WebServerManager`. + +## Key Files +- `data/src/` (Source code) +- `data/package.json` (Dependencies) +- `data/vite.config.ts` (Build configuration) diff --git a/data/src/lib/components/AppMisc.svelte b/data/src/lib/components/AppMisc.svelte index 35c0c982..8b79fb98 100644 --- a/data/src/lib/components/AppMisc.svelte +++ b/data/src/lib/components/AppMisc.svelte @@ -41,6 +41,7 @@ ethSpiConfig: [20, -1, -1, -1, -1, -1, -1], controlPin: 26, hsStatusPin: 2, + doorSensorPin: 32, }, ); let ethConfig = $state( @@ -598,6 +599,20 @@ class="input input-bordered w-full" /> +
+ + + +
diff --git a/data/src/lib/types/api.ts b/data/src/lib/types/api.ts index d3f4a130..7ec3c794 100644 --- a/data/src/lib/types/api.ts +++ b/data/src/lib/types/api.ts @@ -97,6 +97,8 @@ export interface MiscConfig { controlPin: number; /** GPIO pin for HomeSpan status indicator */ hsStatusPin: number; + /** GPIO pin for Door Sensor */ + doorSensorPin: number; /** Enable web authentication */ webAuthEnabled: boolean; /** Web interface username */ diff --git a/main/ConfigManager.cpp b/main/ConfigManager.cpp index 89a851b9..e6590840 100644 --- a/main/ConfigManager.cpp +++ b/main/ConfigManager.cpp @@ -110,6 +110,7 @@ ConfigManager::ConfigManager() : m_isInitialized(false) { {"webPassword", &m_miscConfig.webPassword}, {"nfcGpioPins", &m_miscConfig.nfcGpioPins}, {"nfcPinsPreset", &m_miscConfig.nfcPinsPreset}, + {"doorSensorPin", &m_miscConfig.doorSensorPin}, {"btrLowStatusThreshold", &m_miscConfig.btrLowStatusThreshold}, {"proxBatEnabled", &m_miscConfig.proxBatEnabled}, {"ethernetEnabled", &m_miscConfig.ethernetEnabled}, diff --git a/main/ConfigManager_function.md b/main/ConfigManager_function.md new file mode 100644 index 00000000..24f11d3c --- /dev/null +++ b/main/ConfigManager_function.md @@ -0,0 +1,17 @@ +# ConfigManager Module + +## Description +The `ConfigManager` is responsible for persistent storage of general device settings. It uses the ESP32's Non-Volatile Storage (NVS) to save configuration across reboots. + +## Key Responsibilities +- **Settings Storage**: Saves and loads WiFi credentials, hostname, MQTT settings, and hardware pin configurations. +- **Serialization**: Converts configuration structures to/from JSON or binary formats for storage and API exchange. +- **Defaults**: Provides default values for all settings to ensure the device can boot in a known state. + +## Dependencies +- **NVS Flash**: The underlying storage mechanism. +- **cJSON**: Used for serializing config data for the Web API. + +## Key Files +- `main/ConfigManager.cpp` +- `main/include/ConfigManager.hpp` diff --git a/main/HKServices.cpp b/main/HKServices.cpp index 52ae7cba..731a6614 100644 --- a/main/HKServices.cpp +++ b/main/HKServices.cpp @@ -96,10 +96,15 @@ HomeKitLock::LockManagementService::LockManagementService() { * @param bridge HomeKit bridge instance whose characteristic pointers will be set to the newly created characteristics. * @param lockManager Lock manager providing current and target lock state values and the HOMEKIT source identifier. */ -HomeKitLock::LockMechanismService::LockMechanismService(HomeKitLock& bridge, LockManager& lockManager) : m_lockManager(lockManager) { +HomeKitLock::LockMechanismService::LockMechanismService(HomeKitLock& bridge, LockManager& lockManager, const espConfig::misc_config_t& config) : m_lockManager(lockManager) { espp::EventManager::get().add_publisher("lock/overrideState", "LockMechanismService"); espp::EventManager::get().add_publisher("lock/targetStateChanged", "LockMechanismService"); ESP_LOGI(HomeKitLock::TAG, "Configuring LockMechanism"); + + m_doorSensorPin = config.doorSensorPin; + m_doorState = new Characteristic::CurrentDoorState(1); // Default Closed + pinMode(m_doorSensorPin, INPUT_PULLUP); + m_lockCurrentState = bridge.m_lockCurrentState = new Characteristic::LockCurrentState(m_lockManager.getCurrentState(), true); m_lockTargetState = bridge.m_lockTargetState = new Characteristic::LockTargetState(m_lockManager.getTargetState(), true); EventLockState s{ @@ -134,6 +139,18 @@ boolean HomeKitLock::LockMechanismService::update() { return true; } +void HomeKitLock::LockMechanismService::loop() { + int currentState = digitalRead(m_doorSensorPin); + if (currentState != m_lastDoorState) { + m_lastDoorState = currentState; + if (currentState == LOW) { + m_doorState->setVal(1); // Closed + } else { + m_doorState->setVal(0); // Open + } + } +} + /** * @brief Configure NFC Access service and register its characteristics and event publisher. * diff --git a/main/HardwareManager_function.md b/main/HardwareManager_function.md new file mode 100644 index 00000000..2420a571 --- /dev/null +++ b/main/HardwareManager_function.md @@ -0,0 +1,18 @@ +# HardwareManager Module + +## Description +The `HardwareManager` serves as the Hardware Abstraction Layer (HAL). It translates logical commands from the application into physical electrical signals to control the lock mechanism, LEDs, and buzzer. + +## Key Responsibilities +- **GPIO Control**: Manages the input/output pins for the relay/solenoid, LEDs, and buttons. +- **Feedback**: Controls the buzzer and LED patterns to provide user feedback (e.g., success beep, error flash). +- **Button Handling**: Debounces and interprets physical button presses to trigger local lock/unlock actions. +- **Battery Monitoring**: (If implemented) Reads battery voltage and reports status. + +## Dependencies +- **espp::EventManager**: Subscribes to `lock/action` events to trigger physical hardware. +- **ConfigManager**: Reads hardware configuration (pin mappings, signal logic levels). + +## Key Files +- `main/HardwareManager.cpp` +- `main/include/HardwareManager.hpp` diff --git a/main/HomeKitLock.cpp b/main/HomeKitLock.cpp index 2f86edb6..4d56fd82 100644 --- a/main/HomeKitLock.cpp +++ b/main/HomeKitLock.cpp @@ -228,7 +228,7 @@ void HomeKitLock::begin() { new Service::HAPProtocolInformation(); new Characteristic::Version(); new LockManagementService(); - new LockMechanismService(*this, m_lockManager); + new LockMechanismService(*this, m_lockManager, miscConfig); new NFCAccessService(m_readerDataManager); if(miscConfig.proxBatEnabled) { new PhysicalLockBatteryService(*this); diff --git a/main/LockManager_function.md b/main/LockManager_function.md new file mode 100644 index 00000000..8b18aa77 --- /dev/null +++ b/main/LockManager_function.md @@ -0,0 +1,21 @@ +# LockManager Module + +## Description +The `LockManager` is the central brain of the application. It implements an event-driven state machine that orchestrates the behavior of the smart lock. It decouples the logical state of the lock from the various control interfaces (HomeKit, MQTT, Web, NFC). + +## Key Responsibilities +- **State Management**: Maintains the current state of the lock (Locked, Unlocked, Jammed, etc.) and the target state. +- **Event Orchestration**: Subscribes to input events from protocol adapters (HomeKit, MQTT, NFC) and publishes action events to the HardwareManager. +- **Auto-Lock**: Manages the auto-lock timer to automatically secure the door after a set duration. +- **Synchronization**: Ensures that state changes triggered by one source (e.g., NFC) are reflected across all other interfaces (e.g., HomeKit, MQTT). + +## Dependencies +- **espp::EventManager**: Used to publish state changes and subscribe to command events. +- **HardwareManager**: Receives action commands (open/close) from the LockManager. +- **ConfigManager**: Provides settings for features like auto-lock duration. + +## Key Files +- `main/LockManager.cpp` +- `main/include/LockManager.hpp` +- `main/HomeKitLock.cpp` (Acts as the HomeKit protocol adapter) +- `main/include/HomeKitLock.hpp` diff --git a/main/MqttManager_function.md b/main/MqttManager_function.md new file mode 100644 index 00000000..0167092d --- /dev/null +++ b/main/MqttManager_function.md @@ -0,0 +1,18 @@ +# MqttManager Module + +## Description +The `MqttManager` provides integration with MQTT brokers, primarily to support Home Assistant. It acts as a bridge, translating internal application events into MQTT messages and vice versa. + +## Key Responsibilities +- **Connection Management**: Maintains the connection to the MQTT broker and handles reconnections. +- **Home Assistant Discovery**: Automatically publishes discovery payloads so Home Assistant can detect the lock without manual configuration. +- **State Reporting**: Publishes the current lock state, battery level, and other sensors to MQTT topics. +- **Command Handling**: Subscribes to command topics to allow remote control of the lock via MQTT. + +## Dependencies +- **espp::EventManager**: Subscribes to state changes and publishes commands. +- **ConfigManager**: Retrieves broker URL, credentials, and topic prefixes. + +## Key Files +- `main/MqttManager.cpp` +- `main/include/MqttManager.hpp` diff --git a/main/NfcManager_function.md b/main/NfcManager_function.md new file mode 100644 index 00000000..4c187998 --- /dev/null +++ b/main/NfcManager_function.md @@ -0,0 +1,20 @@ +# NfcManager Module + +## Description +The `NfcManager` handles all interactions with the PN532 NFC controller. It is responsible for detecting NFC tags, executing the Apple HomeKey authentication protocol, and reporting successful authentications to the system. + +## Key Responsibilities +- **Hardware Driver**: Manages the SPI/I2C communication with the PN532 chip. +- **Polling Loop**: Continuously scans for NFC cards or smartphones. +- **HomeKey Authentication**: When a compatible device is detected, it orchestrates the fast auth or standard auth flow using the `HK-HomeKit-Lib`. +- **Legacy Support**: Can optionally read standard Mifare tags for legacy access control. + +## Dependencies +- **HK-HomeKit-Lib**: Provides the cryptographic logic for HomeKey. +- **ReaderDataManager**: Retrieves the cryptographic keys and issuer data required for authentication. +- **espp::EventManager**: Publishes `nfc/auth` events upon successful entry. + +## Key Files +- `main/NfcManager.cpp` +- `main/include/NfcManager.hpp` +- `components/PN532/` (Driver library) diff --git a/main/ReaderDataManager_function.md b/main/ReaderDataManager_function.md new file mode 100644 index 00000000..8154e4e4 --- /dev/null +++ b/main/ReaderDataManager_function.md @@ -0,0 +1,19 @@ +# ReaderDataManager Module + +## Description +The `ReaderDataManager` is a specialized storage module for Apple HomeKey data. Unlike the general `ConfigManager`, it handles sensitive cryptographic material and dynamic provisioning data required for the HomeKey protocol. + +## Key Responsibilities +- **Secure Storage**: Manages the storage of the Reader Private Key, Reader ID, and Group ID. +- **Issuer Management**: Stores the public keys and permissions of trusted HomeKit controllers (Issuers). +- **Endpoint Management**: Manages the endpoint configurations that define how the lock appears to iOS devices (e.g., color, name). +- **Lifecycle Management**: Handles the creation, update, and deletion of HomeKey credentials during the pairing and unpairing process. + +## Dependencies +- **NVS Flash**: Stores the data persistently. +- **msgpack**: Uses MessagePack for efficient binary serialization of the complex HomeKey data structures. +- **HomeKey.h**: Defines the `readerData_t` structure. + +## Key Files +- `main/ReaderDataManager.cpp` (implied, or implemented in `main.cpp` or similar if not present as standalone cpp, but header exists) +- `main/include/ReaderDataManager.hpp` diff --git a/main/WebServerManager_function.md b/main/WebServerManager_function.md new file mode 100644 index 00000000..fc7f8cdd --- /dev/null +++ b/main/WebServerManager_function.md @@ -0,0 +1,20 @@ +# WebServerManager Module + +## Description +The `WebServerManager` hosts the local web interface and API. It serves the Svelte-based frontend and provides REST/WebSocket endpoints for configuration and real-time control. + +## Key Responsibilities +- **Static File Serving**: Serves the compiled HTML/JS/CSS assets of the frontend from the filesystem. +- **REST API**: Provides endpoints for updating settings (`/api/config`), managing HomeKey data, and performing OTA updates. +- **Real-time Communication**: Uses WebSockets to stream log data and lock state updates to the browser. +- **Authentication**: (If enabled) Enforces basic authentication to protect the interface. + +## Dependencies +- **esp_http_server**: The underlying HTTP server library. +- **ConfigManager**: Read/Write configuration via API. +- **ReaderDataManager**: Read/Write HomeKey data via API. +- **MqttManager**: To allow configuration of MQTT settings. + +## Key Files +- `main/WebServerManager.cpp` +- `main/include/WebServerManager.hpp` diff --git a/main/include/HomeKitLock.hpp b/main/include/HomeKitLock.hpp index c174aebf..859856fd 100644 --- a/main/include/HomeKitLock.hpp +++ b/main/include/HomeKitLock.hpp @@ -58,8 +58,12 @@ class HomeKitLock { LockManager& m_lockManager; SpanCharacteristic* m_lockTargetState; SpanCharacteristic* m_lockCurrentState; - LockMechanismService(HomeKitLock& bridge, LockManager& lockManager); + SpanCharacteristic* m_doorState; + int m_doorSensorPin = 32; + int m_lastDoorState = -1; + LockMechanismService(HomeKitLock& bridge, LockManager& lockManager, const espConfig::misc_config_t& config); boolean update() override; + void loop() override; }; struct NFCAccessService : Service::NFCAccess { ReaderDataManager& m_readerDataManager; diff --git a/main/include/config.hpp b/main/include/config.hpp index f9d994e4..d53ed050 100644 --- a/main/include/config.hpp +++ b/main/include/config.hpp @@ -125,6 +125,7 @@ namespace espConfig std::string webPassword = WEB_AUTH_PASSWORD; uint8_t nfcPinsPreset = 255; std::array nfcGpioPins{SS_PIN, SCK_PIN, MISO_PIN, MOSI_PIN}; + uint8_t doorSensorPin = 32; uint8_t btrLowStatusThreshold = BTR_PROX_BAT_LOW_THRESHOLD; bool proxBatEnabled = BTR_PROX_BAT_ENABLED; bool ethernetEnabled = ETH_ENABLED; From f38e02a649be8e42f9820f6e09eaa06e0dda23b4 Mon Sep 17 00:00:00 2001 From: Foy Date: Tue, 30 Dec 2025 10:32:33 +0800 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=8F=AF?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=9A=84=E9=96=80=E4=BD=8D=E6=84=9F=E6=87=89?= =?UTF-8?q?=E5=99=A8=20(Door=20Sensor)=20=E6=94=AF=E6=8C=81=20=20=20=20=20?= =?UTF-8?q?2=20=20=20=20=203=20=E5=AF=A6=E4=BD=9C=E5=85=A7=E5=AE=B9?= =?UTF-8?q?=EF=BC=9A=20=20=20=20=204=20-=20=E5=BE=8C=E7=AB=AF=20(C++)?= =?UTF-8?q?=EF=BC=9A=20=20=20=20=205=20=20=20=20=20-=20=E5=9C=A8=20`misc?= =?UTF-8?q?=5Fconfig=5Ft`=20=E9=85=8D=E7=BD=AE=E7=B5=90=E6=A7=8B=E4=B8=AD?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20`doorSensorPin`=20=E6=AC=84=E4=BD=8D?= =?UTF-8?q?=EF=BC=88=E9=A0=90=E8=A8=AD=E7=82=BA=20GPIO=2032=EF=BC=89?= =?UTF-8?q?=E3=80=82=20=20=20=20=206=20=20=20=20=20-=20=E5=9C=A8=20`LockMe?= =?UTF-8?q?chanismService`=20=E4=B8=AD=E5=8A=A0=E5=85=A5=20`CurrentDoorSta?= =?UTF-8?q?te`=20=E7=89=B9=E5=BE=B5=20(Characteristic)=E3=80=82=20=20=20?= =?UTF-8?q?=20=207=20=20=20=20=20-=20=E9=87=8D=E5=AF=AB=20`LockMechanismSe?= =?UTF-8?q?rvice::loop()`=20=E4=BB=A5=E8=BC=AA=E8=A9=A2=20GPIO=20=E7=8B=80?= =?UTF-8?q?=E6=85=8B=EF=BC=8C=E6=94=AF=E6=8F=B4=E5=8D=B3=E6=99=82=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E9=96=80=E4=BD=8D=E8=87=B3=20HomeKit=E3=80=82=20=20?= =?UTF-8?q?=20=20=208=20=20=20=20=20-=20=E9=82=8F=E8=BC=AF=E5=AF=A6?= =?UTF-8?q?=E4=BD=9C=EF=BC=9AGPIO=20LOW=20=E7=82=BA=E9=97=9C=E9=96=80=20(S?= =?UTF-8?q?ecured)=EF=BC=8CHIGH=20=E7=82=BA=E9=96=8B=E9=96=80=20(Unsecured?= =?UTF-8?q?)=E3=80=82=20=20=20=20=209=20=20=20=20=20-=20=E7=A2=BA=E4=BF=9D?= =?UTF-8?q?=20`doorSensorPin`=20=E5=8F=AF=E9=80=8F=E9=81=8E=20`ConfigManag?= =?UTF-8?q?er`=20=E6=8C=81=E4=B9=85=E5=8C=96=E5=84=B2=E5=AD=98=E6=96=BC=20?= =?UTF-8?q?NVS=E3=80=82=20=20=20=2010=20=20=20=2011=20-=20=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=20(Web=20UI)=EF=BC=9A=20=20=20=2012=20=20=20=20=20-?= =?UTF-8?q?=20=E5=9C=A8=20`api.ts`=20=E4=B8=AD=E6=9B=B4=E6=96=B0=20`MiscCo?= =?UTF-8?q?nfig`=20=E7=9A=84=E9=A1=9E=E5=9E=8B=E5=AE=9A=E7=BE=A9=E3=80=82?= =?UTF-8?q?=20=20=20=2013=20=20=20=20=20-=20=E5=9C=A8=E3=80=8C=E7=B3=BB?= =?UTF-8?q?=E7=B5=B1=E8=A8=AD=E5=AE=9A=20(System=20Settings)=E3=80=8D?= =?UTF-8?q?=E5=8D=80=E5=A1=8A=E6=96=B0=E5=A2=9E=E3=80=8CDoor=20Sensor=20GP?= =?UTF-8?q?IO=20Pin=E3=80=8D=E8=BC=B8=E5=85=A5=E6=AC=84=E4=BD=8D=E3=80=82?= =?UTF-8?q?=20=20=20=2014=20=20=20=20=20-=20=E9=87=8D=E6=96=B0=E7=B7=A8?= =?UTF-8?q?=E8=AD=AF=E5=89=8D=E7=AB=AF=E9=9D=9C=E6=85=8B=E8=B3=87=E6=BA=90?= =?UTF-8?q?=E4=B8=A6=E5=9F=B7=E8=A1=8C=E6=AA=94=E6=A1=88=E5=A3=93=E7=B8=AE?= =?UTF-8?q?=E5=84=AA=E5=8C=96=EF=BC=88=E9=A0=90=E5=A3=93=E7=B8=AE=E4=BB=A5?= =?UTF-8?q?=E7=AF=80=E7=9C=81=20Flash=20=E7=A9=BA=E9=96=93=EF=BC=89?= =?UTF-8?q?=E3=80=82=20=20=20=2015=20=20=20=2016=20-=20=E7=A1=AC=E9=AB=94?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=EF=BC=9A=20=20=20=2017=20=20=20=20=20-=20?= =?UTF-8?q?=E9=A0=90=E8=A8=AD=E4=BD=BF=E7=94=A8=20GPIO=2032=20=E4=BD=9C?= =?UTF-8?q?=E7=82=BA=E6=84=9F=E6=87=89=E5=99=A8=E8=BC=B8=E5=85=A5=EF=BC=8C?= =?UTF-8?q?=E4=B8=A6=E5=95=9F=E7=94=A8=E5=85=A7=E9=83=A8=E4=B8=8A=E6=8B=89?= =?UTF-8?q?=E9=9B=BB=E9=98=BB=20(INPUT=5FPULLUP)=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/HK-HomeKit-Lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/HK-HomeKit-Lib b/components/HK-HomeKit-Lib index a6b34a74..8805e172 160000 --- a/components/HK-HomeKit-Lib +++ b/components/HK-HomeKit-Lib @@ -1 +1 @@ -Subproject commit a6b34a74bb2094fc40fd735917d6a92971b8444c +Subproject commit 8805e1728ce4f733fb4db87544fe234cfa8e0bbf From f81e092df3cc7d8cfc82547eae14c70001201cc5 Mon Sep 17 00:00:00 2001 From: Foy Date: Tue, 30 Dec 2025 14:54:10 +0800 Subject: [PATCH 3/8] add new ui to config Door Sensor --- data/src/lib/components/AppMisc.svelte | 32 +++++++++++++++++++++++++- data/src/lib/types/api.ts | 2 ++ dependencies.lock | 4 ++-- main/CMakeLists.txt | 6 ++++- main/ConfigManager.cpp | 6 ++--- main/HKServices.cpp | 13 +++++------ main/NfcManager.cpp | 2 +- main/WebServerManager.cpp | 1 - main/include/HomeKitLock.hpp | 1 + main/include/config.hpp | 5 ++-- main/main.cpp | 5 ++++ sdkconfig.defaults | 1 + 12 files changed, 60 insertions(+), 18 deletions(-) diff --git a/data/src/lib/components/AppMisc.svelte b/data/src/lib/components/AppMisc.svelte index 8b79fb98..6a63978a 100644 --- a/data/src/lib/components/AppMisc.svelte +++ b/data/src/lib/components/AppMisc.svelte @@ -42,6 +42,7 @@ controlPin: 26, hsStatusPin: 2, doorSensorPin: 32, + doorSensorInvert: false, }, ); let ethConfig = $state( @@ -599,11 +600,20 @@ class="input input-bordered w-full" /> + + + +
+ +
+ Door Sensor +
+
+
+ + +
diff --git a/data/src/lib/types/api.ts b/data/src/lib/types/api.ts index 7ec3c794..8a0e1516 100644 --- a/data/src/lib/types/api.ts +++ b/data/src/lib/types/api.ts @@ -99,6 +99,8 @@ export interface MiscConfig { hsStatusPin: number; /** GPIO pin for Door Sensor */ doorSensorPin: number; + /** Invert Door Sensor logic (true: HIGH=Closed, false: LOW=Closed) */ + doorSensorInvert: boolean; /** Enable web authentication */ webAuthEnabled: boolean; /** Web interface username */ diff --git a/dependencies.lock b/dependencies.lock index e4e66301..bbbde0cd 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -495,7 +495,7 @@ dependencies: idf: source: type: idf - version: 5.5.1 + version: 5.3.2 joltwallet/littlefs: component_hash: 1808d73e99168f6f3c26dd31799a248484762b3a320ec4962dec11a145f4277f dependencies: @@ -516,5 +516,5 @@ direct_dependencies: - idf - joltwallet/littlefs manifest_hash: 8905cecd4b0c6f7dfceebc1552dd0fde86b0c3a0f17aed702e8d30cdad24af13 -target: esp32c6 +target: esp32 version: 2.0.0 diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 09660fda..bc604bf5 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -8,7 +8,11 @@ if(NOT DEFINED ENV{CI}) add_custom_target(webui WORKING_DIRECTORY ${COMPONENT_DIR}/../data COMMAND bun run build - COMMAND bash -c "find build -regex '.*\\.\\(html\\.gz\\|css\\|br\\|js\\|json\\.gz\\)' -delete" + COMMAND find build -name "*.html.gz" -delete + COMMAND find build -name "*.css" -delete + COMMAND find build -name "*.br" -delete + COMMAND find build -name "*.js" -delete + COMMAND find build -name "*.json.gz" -delete VERBATIM ) littlefs_create_partition_image(spiffs ../data/build FLASH_IN_PROJECT DEPENDS webui) diff --git a/main/ConfigManager.cpp b/main/ConfigManager.cpp index e6590840..8e06914c 100644 --- a/main/ConfigManager.cpp +++ b/main/ConfigManager.cpp @@ -195,7 +195,7 @@ bool ConfigManager::begin() { nvs_stats_t nvs_stats; nvs_get_stats(NULL, &nvs_stats); - ESP_LOGI(TAG,"Count: UsedEntries = (%lu), FreeEntries = (%lu), AvailableEntries = (%lu), AllEntries = (%lu)\n", + ESP_LOGI(TAG,"Count: UsedEntries = (%zu), FreeEntries = (%zu), AvailableEntries = (%zu), AllEntries = (%zu)\n", nvs_stats.used_entries, nvs_stats.free_entries, nvs_stats.available_entries, nvs_stats.total_entries); m_isInitialized = true; @@ -573,7 +573,7 @@ void ConfigManager::deserialize(msgpack_object obj, std::string type) { break; } default: - ESP_LOGW(TAG, "DON'T KNOW THIS ONE! - %s (%d) = %d", key.c_str(), v.val.type, v.val.via.u64); + ESP_LOGW(TAG, "DON'T KNOW THIS ONE! - %s (%d) = %llu", key.c_str(), (int)v.val.type, v.val.via.u64); } } }, m_configMap[type][key]); @@ -1078,7 +1078,7 @@ bool ConfigManager::deserializeFromJson(const std::string& json_string) { } } }, configMap.at(key)); - } else ESP_LOGW(TAG, "Key '%s' could not be found!"); + } else ESP_LOGW(TAG, "Key '%s' could not be found!", key.c_str()); item = item->next; } diff --git a/main/HKServices.cpp b/main/HKServices.cpp index 731a6614..4f1ebe03 100644 --- a/main/HKServices.cpp +++ b/main/HKServices.cpp @@ -100,11 +100,12 @@ HomeKitLock::LockMechanismService::LockMechanismService(HomeKitLock& bridge, Loc espp::EventManager::get().add_publisher("lock/overrideState", "LockMechanismService"); espp::EventManager::get().add_publisher("lock/targetStateChanged", "LockMechanismService"); ESP_LOGI(HomeKitLock::TAG, "Configuring LockMechanism"); - + m_doorSensorPin = config.doorSensorPin; + m_doorSensorInvert = config.doorSensorInvert; m_doorState = new Characteristic::CurrentDoorState(1); // Default Closed pinMode(m_doorSensorPin, INPUT_PULLUP); - + m_lockCurrentState = bridge.m_lockCurrentState = new Characteristic::LockCurrentState(m_lockManager.getCurrentState(), true); m_lockTargetState = bridge.m_lockTargetState = new Characteristic::LockTargetState(m_lockManager.getTargetState(), true); EventLockState s{ @@ -143,11 +144,9 @@ void HomeKitLock::LockMechanismService::loop() { int currentState = digitalRead(m_doorSensorPin); if (currentState != m_lastDoorState) { m_lastDoorState = currentState; - if (currentState == LOW) { - m_doorState->setVal(1); // Closed - } else { - m_doorState->setVal(0); // Open - } + // Apply invert logic: if inverted, swap the interpretation + bool isClosed = m_doorSensorInvert ? (currentState == HIGH) : (currentState == LOW); + m_doorState->setVal(isClosed ? 1 : 0); // 1 = Closed, 0 = Open } } diff --git a/main/NfcManager.cpp b/main/NfcManager.cpp index 03319ebc..e798e756 100644 --- a/main/NfcManager.cpp +++ b/main/NfcManager.cpp @@ -105,7 +105,7 @@ bool NfcManager::initializeReader() { m_nfc->stop(); return false; } - ESP_LOGI(TAG, "Found chip PN5%x, Firmware ver. %d.%d", (versiondata >> 24) & 0xFF, (versiondata >> 16) & 0xFF, (versiondata >> 8) & 0xFF); + ESP_LOGI(TAG, "Found chip PN5%x, Firmware ver. %u.%u", (unsigned int)((versiondata >> 24) & 0xFF), (unsigned int)((versiondata >> 16) & 0xFF), (unsigned int)((versiondata >> 8) & 0xFF)); m_nfc->SAMConfig(); m_nfc->setRFField(0x02, 0x01); m_nfc->setPassiveActivationRetries(0); diff --git a/main/WebServerManager.cpp b/main/WebServerManager.cpp index a91a96c9..56afbe37 100644 --- a/main/WebServerManager.cpp +++ b/main/WebServerManager.cpp @@ -14,7 +14,6 @@ #include "esp_heap_caps.h" #include "esp_http_server.h" #include "esp_log.h" -#include "esp_log_level.h" #include "esp_task_wdt.h" #include "eth_structs.hpp" #include "eventStructs.hpp" diff --git a/main/include/HomeKitLock.hpp b/main/include/HomeKitLock.hpp index 859856fd..68cad01a 100644 --- a/main/include/HomeKitLock.hpp +++ b/main/include/HomeKitLock.hpp @@ -60,6 +60,7 @@ class HomeKitLock { SpanCharacteristic* m_lockCurrentState; SpanCharacteristic* m_doorState; int m_doorSensorPin = 32; + bool m_doorSensorInvert = false; int m_lastDoorState = -1; LockMechanismService(HomeKitLock& bridge, LockManager& lockManager, const espConfig::misc_config_t& config); boolean update() override; diff --git a/main/include/config.hpp b/main/include/config.hpp index d53ed050..432d3344 100644 --- a/main/include/config.hpp +++ b/main/include/config.hpp @@ -4,7 +4,7 @@ #include #include #include "defaults.h" -#include "esp_log_level.h" +#include "esp_log.h" #include "fmt/format.h" #include "esp_mac.h" @@ -126,6 +126,7 @@ namespace espConfig uint8_t nfcPinsPreset = 255; std::array nfcGpioPins{SS_PIN, SCK_PIN, MISO_PIN, MOSI_PIN}; uint8_t doorSensorPin = 32; + bool doorSensorInvert = false; uint8_t btrLowStatusThreshold = BTR_PROX_BAT_LOW_THRESHOLD; bool proxBatEnabled = BTR_PROX_BAT_ENABLED; bool ethernetEnabled = ETH_ENABLED; @@ -133,7 +134,7 @@ namespace espConfig uint8_t ethPhyType = ETH_PHY_TYPE; std::array ethRmiiConfig = {ETH_RMII_CONF_PHY_ADDR, ETH_RMII_CONF_MDC_PIN, ETH_RMII_CONF_MDIO_PIN, ETH_RMII_CONF_POWER_PIN, ETH_RMII_CONF_RMII_CLOCK_MODE}; std::array ethSpiConfig = {ETH_SPI_CONF_SPI_FREQ_MHZ, ETH_SPI_CONF_PIN_CS, ETH_SPI_CONF_PIN_IRQ, ETH_SPI_CONF_PIN_RST, ETH_SPI_CONF_PIN_SCK, ETH_SPI_CONF_PIN_MISO, ETH_SPI_CONF_PIN_MOSI}; - uint8_t logLevel = ESP_LOG_ERROR; + uint8_t logLevel = ESP_LOG_INFO; }; struct actions_config_t { enum colorMap diff --git a/main/main.cpp b/main/main.cpp index af1f3f2c..f8fdab8a 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1,5 +1,10 @@ #include +#include #define FMT_HEADER_ONLY + +extern "C" void flockfile(FILE* file) {} +extern "C" void funlockfile(FILE* file) {} + #include "config.hpp" #include "HomeKitLock.hpp" #include "LockManager.hpp" diff --git a/sdkconfig.defaults b/sdkconfig.defaults index c2d9443e..c27d6a20 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -91,3 +91,4 @@ CONFIG_ESP_RMAKER_FACTORY_NAMESPACE="" CONFIG_ESP_RMAKER_DEF_TIMEZONE="" CONFIG_ESP_RMAKER_SNTP_SERVER_NAME="" CONFIG_HTTPD_WS_SUPPORT=y +CONFIG_HTTPD_MAX_REQ_HDR_LEN=4096 From 55466ecf328d8321d415d879d0ac23cf569cb083 Mon Sep 17 00:00:00 2001 From: Foy Date: Tue, 30 Dec 2025 15:06:54 +0800 Subject: [PATCH 4/8] fix bug The doorSensorPin is added to the config map, but doorSensorInvert is missing. This means the invert setting won't be persisted to NVS or properly serialized/deserialized, causing the setting to be lost on device reboot. --- main/ConfigManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/main/ConfigManager.cpp b/main/ConfigManager.cpp index 8e06914c..ec47ccf7 100644 --- a/main/ConfigManager.cpp +++ b/main/ConfigManager.cpp @@ -111,6 +111,7 @@ ConfigManager::ConfigManager() : m_isInitialized(false) { {"nfcGpioPins", &m_miscConfig.nfcGpioPins}, {"nfcPinsPreset", &m_miscConfig.nfcPinsPreset}, {"doorSensorPin", &m_miscConfig.doorSensorPin}, + {"doorSensorInvert", &m_miscConfig.doorSensorInvert}, {"btrLowStatusThreshold", &m_miscConfig.btrLowStatusThreshold}, {"proxBatEnabled", &m_miscConfig.proxBatEnabled}, {"ethernetEnabled", &m_miscConfig.ethernetEnabled}, From d128720e42046573496a6fe209b1c6b916c0cf7a Mon Sep 17 00:00:00 2001 From: Foy Date: Fri, 2 Jan 2026 09:51:26 +0800 Subject: [PATCH 5/8] refactor: move door sensor logic to HardwareManager and cleanup - Relocate door sensor GPIO interaction to HardwareManager as requested. - Implement 50ms debouncing for door sensor state changes. - Remove unrelated documentation files added in previous commits. - Refactor LockMechanismService to use HardwareManager for state updates. - Organize Door Sensor settings within the System Settings UI section. --- components/HK-HomeKit-Lib | 2 +- data/Frontend_function.md | 21 ------------------ main/ConfigManager_function.md | 17 --------------- main/HKServices.cpp | 14 ++++-------- main/HardwareManager.cpp | 34 ++++++++++++++++++++++++++++-- main/HardwareManager_function.md | 18 ---------------- main/HomeKitLock.cpp | 5 +++-- main/LockManager_function.md | 21 ------------------ main/MqttManager_function.md | 18 ---------------- main/NfcManager_function.md | 20 ------------------ main/ReaderDataManager_function.md | 19 ----------------- main/WebServerManager_function.md | 20 ------------------ main/include/HardwareManager.hpp | 16 ++++++++++++-- main/include/HomeKitLock.hpp | 11 +++++----- main/main.cpp | 4 ++-- 15 files changed, 62 insertions(+), 178 deletions(-) delete mode 100644 data/Frontend_function.md delete mode 100644 main/ConfigManager_function.md delete mode 100644 main/HardwareManager_function.md delete mode 100644 main/LockManager_function.md delete mode 100644 main/MqttManager_function.md delete mode 100644 main/NfcManager_function.md delete mode 100644 main/ReaderDataManager_function.md delete mode 100644 main/WebServerManager_function.md diff --git a/components/HK-HomeKit-Lib b/components/HK-HomeKit-Lib index 8805e172..a6b34a74 160000 --- a/components/HK-HomeKit-Lib +++ b/components/HK-HomeKit-Lib @@ -1 +1 @@ -Subproject commit 8805e1728ce4f733fb4db87544fe234cfa8e0bbf +Subproject commit a6b34a74bb2094fc40fd735917d6a92971b8444c diff --git a/data/Frontend_function.md b/data/Frontend_function.md deleted file mode 100644 index babc2c20..00000000 --- a/data/Frontend_function.md +++ /dev/null @@ -1,21 +0,0 @@ -# Frontend Module - -## Description -The Frontend is a Single Page Application (SPA) built with Svelte and Vite. It provides a modern, responsive user interface for configuring and controlling the HomeKey-ESP32 device. - -## Key Responsibilities -- **User Interface**: Displays the current lock state, logs, and configuration forms. -- **API Interaction**: Communicates with the `WebServerManager` via REST APIs to fetch and save settings. -- **Real-time Updates**: Connects via WebSocket to display live logs and instant state changes. -- **HomeKey Management**: Provides a UI to view provisioned HomeKey issuers and manage reader settings. - -## Dependencies -- **Svelte**: The UI framework. -- **Vite**: The build tool. -- **Tailwind CSS** (likely): For styling. -- **Backend API**: Depends on the endpoints provided by `WebServerManager`. - -## Key Files -- `data/src/` (Source code) -- `data/package.json` (Dependencies) -- `data/vite.config.ts` (Build configuration) diff --git a/main/ConfigManager_function.md b/main/ConfigManager_function.md deleted file mode 100644 index 24f11d3c..00000000 --- a/main/ConfigManager_function.md +++ /dev/null @@ -1,17 +0,0 @@ -# ConfigManager Module - -## Description -The `ConfigManager` is responsible for persistent storage of general device settings. It uses the ESP32's Non-Volatile Storage (NVS) to save configuration across reboots. - -## Key Responsibilities -- **Settings Storage**: Saves and loads WiFi credentials, hostname, MQTT settings, and hardware pin configurations. -- **Serialization**: Converts configuration structures to/from JSON or binary formats for storage and API exchange. -- **Defaults**: Provides default values for all settings to ensure the device can boot in a known state. - -## Dependencies -- **NVS Flash**: The underlying storage mechanism. -- **cJSON**: Used for serializing config data for the Web API. - -## Key Files -- `main/ConfigManager.cpp` -- `main/include/ConfigManager.hpp` diff --git a/main/HKServices.cpp b/main/HKServices.cpp index 4f1ebe03..eb2c2658 100644 --- a/main/HKServices.cpp +++ b/main/HKServices.cpp @@ -96,15 +96,12 @@ HomeKitLock::LockManagementService::LockManagementService() { * @param bridge HomeKit bridge instance whose characteristic pointers will be set to the newly created characteristics. * @param lockManager Lock manager providing current and target lock state values and the HOMEKIT source identifier. */ -HomeKitLock::LockMechanismService::LockMechanismService(HomeKitLock& bridge, LockManager& lockManager, const espConfig::misc_config_t& config) : m_lockManager(lockManager) { +HomeKitLock::LockMechanismService::LockMechanismService(HomeKitLock& bridge, LockManager& lockManager, HardwareManager& hardwareManager) : m_lockManager(lockManager), m_hardwareManager(hardwareManager) { espp::EventManager::get().add_publisher("lock/overrideState", "LockMechanismService"); espp::EventManager::get().add_publisher("lock/targetStateChanged", "LockMechanismService"); ESP_LOGI(HomeKitLock::TAG, "Configuring LockMechanism"); - m_doorSensorPin = config.doorSensorPin; - m_doorSensorInvert = config.doorSensorInvert; m_doorState = new Characteristic::CurrentDoorState(1); // Default Closed - pinMode(m_doorSensorPin, INPUT_PULLUP); m_lockCurrentState = bridge.m_lockCurrentState = new Characteristic::LockCurrentState(m_lockManager.getCurrentState(), true); m_lockTargetState = bridge.m_lockTargetState = new Characteristic::LockTargetState(m_lockManager.getTargetState(), true); @@ -141,12 +138,9 @@ boolean HomeKitLock::LockMechanismService::update() { } void HomeKitLock::LockMechanismService::loop() { - int currentState = digitalRead(m_doorSensorPin); - if (currentState != m_lastDoorState) { - m_lastDoorState = currentState; - // Apply invert logic: if inverted, swap the interpretation - bool isClosed = m_doorSensorInvert ? (currentState == HIGH) : (currentState == LOW); - m_doorState->setVal(isClosed ? 1 : 0); // 1 = Closed, 0 = Open + int doorState = m_hardwareManager.checkDoorSensor(); + if (doorState != -1) { + m_doorState->setVal(doorState); } } diff --git a/main/HardwareManager.cpp b/main/HardwareManager.cpp index d142d267..d8136a3b 100644 --- a/main/HardwareManager.cpp +++ b/main/HardwareManager.cpp @@ -27,8 +27,9 @@ const std::array pixelTypeMap = { "RGB", "RBG", "BRG", "BGR", "G * @param miscConfig Configuration values controlling GPIO pins, NeoPixel type/behavior, and * timing used by the HardwareManager. */ -HardwareManager::HardwareManager(const espConfig::actions_config_t& miscConfig) - : m_miscConfig(miscConfig), +HardwareManager::HardwareManager(const espConfig::misc_config_t& sysConfig, const espConfig::actions_config_t& miscConfig) + : m_sysConfig(sysConfig), + m_miscConfig(miscConfig), m_feedbackTaskHandle(nullptr), m_feedbackQueue(nullptr), m_lockControlTaskHandle(nullptr), @@ -137,6 +138,10 @@ void HardwareManager::begin() { gpio_isr_handler_add((gpio_num_t)m_miscConfig.hkAltActionInitPin, initiator_isr_handler, (void*) this); } + if (m_sysConfig.doorSensorPin != 255) { + pinMode(m_sysConfig.doorSensorPin, INPUT_PULLUP); + } + // --- Initialize NeoPixel --- if (m_miscConfig.nfcNeopixelPin != 255) { size_t pixelTypeIndex = m_miscConfig.neoPixelType; @@ -233,6 +238,31 @@ void HardwareManager::setLockOutput(int state) { } } +/** + * @brief Checks the door sensor state with debouncing. + * @return 1 for Closed, 0 for Open, -1 for no change/invalid. + */ +int HardwareManager::checkDoorSensor() { + if (m_sysConfig.doorSensorPin == 255) return -1; + + int currentState = digitalRead(m_sysConfig.doorSensorPin); + + if (currentState != m_lastRawDoorState) { + m_lastDoorChangeTime = esp_timer_get_time() / 1000; + m_lastRawDoorState = currentState; + } + + if (((esp_timer_get_time() / 1000) - m_lastDoorChangeTime) > DEBOUNCE_DELAY) { + if (currentState != m_lastDoorState) { + m_lastDoorState = currentState; + // Apply invert logic: if inverted, swap the interpretation + bool isClosed = m_sysConfig.doorSensorInvert ? (currentState == HIGH) : (currentState == LOW); + return isClosed ? 1 : 0; + } + } + return -1; +} + /** * @brief Enqueue a success feedback event for the feedback task to process. * diff --git a/main/HardwareManager_function.md b/main/HardwareManager_function.md deleted file mode 100644 index 2420a571..00000000 --- a/main/HardwareManager_function.md +++ /dev/null @@ -1,18 +0,0 @@ -# HardwareManager Module - -## Description -The `HardwareManager` serves as the Hardware Abstraction Layer (HAL). It translates logical commands from the application into physical electrical signals to control the lock mechanism, LEDs, and buzzer. - -## Key Responsibilities -- **GPIO Control**: Manages the input/output pins for the relay/solenoid, LEDs, and buttons. -- **Feedback**: Controls the buzzer and LED patterns to provide user feedback (e.g., success beep, error flash). -- **Button Handling**: Debounces and interprets physical button presses to trigger local lock/unlock actions. -- **Battery Monitoring**: (If implemented) Reads battery voltage and reports status. - -## Dependencies -- **espp::EventManager**: Subscribes to `lock/action` events to trigger physical hardware. -- **ConfigManager**: Reads hardware configuration (pin mappings, signal logic levels). - -## Key Files -- `main/HardwareManager.cpp` -- `main/include/HardwareManager.hpp` diff --git a/main/HomeKitLock.cpp b/main/HomeKitLock.cpp index 4d56fd82..52c5f318 100644 --- a/main/HomeKitLock.cpp +++ b/main/HomeKitLock.cpp @@ -30,10 +30,11 @@ static HomeKitLock* s_instance = nullptr; * @param configManager Reference to the ConfigManager used for configuration access. * @param readerDataManager Reference to the ReaderDataManager used to manage reader/issuer data. */ -HomeKitLock::HomeKitLock(std::function &conn_cb, LockManager& lockManager, ConfigManager& configManager, ReaderDataManager& readerDataManager) +HomeKitLock::HomeKitLock(std::function &conn_cb, LockManager& lockManager, ConfigManager& configManager, ReaderDataManager& readerDataManager, HardwareManager& hardwareManager) : m_lockManager(lockManager), m_configManager(configManager), m_readerDataManager(readerDataManager), + m_hardwareManager(hardwareManager), conn_cb(conn_cb) { if (s_instance != nullptr) { ESP_LOGE(TAG, "ERROR: More than one instance of HomeKitBridge created!"); @@ -228,7 +229,7 @@ void HomeKitLock::begin() { new Service::HAPProtocolInformation(); new Characteristic::Version(); new LockManagementService(); - new LockMechanismService(*this, m_lockManager, miscConfig); + new LockMechanismService(*this, m_lockManager, m_hardwareManager); new NFCAccessService(m_readerDataManager); if(miscConfig.proxBatEnabled) { new PhysicalLockBatteryService(*this); diff --git a/main/LockManager_function.md b/main/LockManager_function.md deleted file mode 100644 index 8b18aa77..00000000 --- a/main/LockManager_function.md +++ /dev/null @@ -1,21 +0,0 @@ -# LockManager Module - -## Description -The `LockManager` is the central brain of the application. It implements an event-driven state machine that orchestrates the behavior of the smart lock. It decouples the logical state of the lock from the various control interfaces (HomeKit, MQTT, Web, NFC). - -## Key Responsibilities -- **State Management**: Maintains the current state of the lock (Locked, Unlocked, Jammed, etc.) and the target state. -- **Event Orchestration**: Subscribes to input events from protocol adapters (HomeKit, MQTT, NFC) and publishes action events to the HardwareManager. -- **Auto-Lock**: Manages the auto-lock timer to automatically secure the door after a set duration. -- **Synchronization**: Ensures that state changes triggered by one source (e.g., NFC) are reflected across all other interfaces (e.g., HomeKit, MQTT). - -## Dependencies -- **espp::EventManager**: Used to publish state changes and subscribe to command events. -- **HardwareManager**: Receives action commands (open/close) from the LockManager. -- **ConfigManager**: Provides settings for features like auto-lock duration. - -## Key Files -- `main/LockManager.cpp` -- `main/include/LockManager.hpp` -- `main/HomeKitLock.cpp` (Acts as the HomeKit protocol adapter) -- `main/include/HomeKitLock.hpp` diff --git a/main/MqttManager_function.md b/main/MqttManager_function.md deleted file mode 100644 index 0167092d..00000000 --- a/main/MqttManager_function.md +++ /dev/null @@ -1,18 +0,0 @@ -# MqttManager Module - -## Description -The `MqttManager` provides integration with MQTT brokers, primarily to support Home Assistant. It acts as a bridge, translating internal application events into MQTT messages and vice versa. - -## Key Responsibilities -- **Connection Management**: Maintains the connection to the MQTT broker and handles reconnections. -- **Home Assistant Discovery**: Automatically publishes discovery payloads so Home Assistant can detect the lock without manual configuration. -- **State Reporting**: Publishes the current lock state, battery level, and other sensors to MQTT topics. -- **Command Handling**: Subscribes to command topics to allow remote control of the lock via MQTT. - -## Dependencies -- **espp::EventManager**: Subscribes to state changes and publishes commands. -- **ConfigManager**: Retrieves broker URL, credentials, and topic prefixes. - -## Key Files -- `main/MqttManager.cpp` -- `main/include/MqttManager.hpp` diff --git a/main/NfcManager_function.md b/main/NfcManager_function.md deleted file mode 100644 index 4c187998..00000000 --- a/main/NfcManager_function.md +++ /dev/null @@ -1,20 +0,0 @@ -# NfcManager Module - -## Description -The `NfcManager` handles all interactions with the PN532 NFC controller. It is responsible for detecting NFC tags, executing the Apple HomeKey authentication protocol, and reporting successful authentications to the system. - -## Key Responsibilities -- **Hardware Driver**: Manages the SPI/I2C communication with the PN532 chip. -- **Polling Loop**: Continuously scans for NFC cards or smartphones. -- **HomeKey Authentication**: When a compatible device is detected, it orchestrates the fast auth or standard auth flow using the `HK-HomeKit-Lib`. -- **Legacy Support**: Can optionally read standard Mifare tags for legacy access control. - -## Dependencies -- **HK-HomeKit-Lib**: Provides the cryptographic logic for HomeKey. -- **ReaderDataManager**: Retrieves the cryptographic keys and issuer data required for authentication. -- **espp::EventManager**: Publishes `nfc/auth` events upon successful entry. - -## Key Files -- `main/NfcManager.cpp` -- `main/include/NfcManager.hpp` -- `components/PN532/` (Driver library) diff --git a/main/ReaderDataManager_function.md b/main/ReaderDataManager_function.md deleted file mode 100644 index 8154e4e4..00000000 --- a/main/ReaderDataManager_function.md +++ /dev/null @@ -1,19 +0,0 @@ -# ReaderDataManager Module - -## Description -The `ReaderDataManager` is a specialized storage module for Apple HomeKey data. Unlike the general `ConfigManager`, it handles sensitive cryptographic material and dynamic provisioning data required for the HomeKey protocol. - -## Key Responsibilities -- **Secure Storage**: Manages the storage of the Reader Private Key, Reader ID, and Group ID. -- **Issuer Management**: Stores the public keys and permissions of trusted HomeKit controllers (Issuers). -- **Endpoint Management**: Manages the endpoint configurations that define how the lock appears to iOS devices (e.g., color, name). -- **Lifecycle Management**: Handles the creation, update, and deletion of HomeKey credentials during the pairing and unpairing process. - -## Dependencies -- **NVS Flash**: Stores the data persistently. -- **msgpack**: Uses MessagePack for efficient binary serialization of the complex HomeKey data structures. -- **HomeKey.h**: Defines the `readerData_t` structure. - -## Key Files -- `main/ReaderDataManager.cpp` (implied, or implemented in `main.cpp` or similar if not present as standalone cpp, but header exists) -- `main/include/ReaderDataManager.hpp` diff --git a/main/WebServerManager_function.md b/main/WebServerManager_function.md deleted file mode 100644 index fc7f8cdd..00000000 --- a/main/WebServerManager_function.md +++ /dev/null @@ -1,20 +0,0 @@ -# WebServerManager Module - -## Description -The `WebServerManager` hosts the local web interface and API. It serves the Svelte-based frontend and provides REST/WebSocket endpoints for configuration and real-time control. - -## Key Responsibilities -- **Static File Serving**: Serves the compiled HTML/JS/CSS assets of the frontend from the filesystem. -- **REST API**: Provides endpoints for updating settings (`/api/config`), managing HomeKey data, and performing OTA updates. -- **Real-time Communication**: Uses WebSockets to stream log data and lock state updates to the browser. -- **Authentication**: (If enabled) Enforces basic authentication to protect the interface. - -## Dependencies -- **esp_http_server**: The underlying HTTP server library. -- **ConfigManager**: Read/Write configuration via API. -- **ReaderDataManager**: Read/Write HomeKey data via API. -- **MqttManager**: To allow configuration of MQTT settings. - -## Key Files -- `main/WebServerManager.cpp` -- `main/include/WebServerManager.hpp` diff --git a/main/include/HardwareManager.hpp b/main/include/HardwareManager.hpp index ad2e1c78..b40e8ac2 100644 --- a/main/include/HardwareManager.hpp +++ b/main/include/HardwareManager.hpp @@ -7,7 +7,7 @@ class ConfigManager; class Pixel; -namespace espConfig { struct actions_config_t; } +namespace espConfig { struct actions_config_t; struct misc_config_t; } /** * @class HardwareManager @@ -23,7 +23,7 @@ class HardwareManager { * @brief Constructs the HardwareManager. * @param configManager Reference to the application configuration manager. */ - HardwareManager(const espConfig::actions_config_t &); + HardwareManager(const espConfig::misc_config_t &, const espConfig::actions_config_t &); /** * @brief Initializes all hardware pins and starts background tasks for feedback. @@ -36,6 +36,12 @@ class HardwareManager { */ void setLockOutput(int state); + /** + * @brief Checks the door sensor state with debouncing. + * @return 1 for Closed, 0 for Open, -1 for no change/invalid. + */ + int checkDoorSensor(); + /** * @brief Triggers a non-blocking visual/audible signal for a successful action. */ @@ -92,10 +98,16 @@ class HardwareManager { static void handleTimer(void *instance); // --- Member Variables --- + const espConfig::misc_config_t& m_sysConfig; const espConfig::actions_config_t& m_miscConfig; Pixel* m_pixel = nullptr; + int m_lastDoorState = -1; + int m_lastRawDoorState = -1; + uint32_t m_lastDoorChangeTime = 0; + static const uint32_t DEBOUNCE_DELAY = 50; + esp_timer_handle_t m_gpioSuccessTimer; esp_timer_handle_t m_gpioFailTimer; esp_timer_handle_t m_tagEventTimer; diff --git a/main/include/HomeKitLock.hpp b/main/include/HomeKitLock.hpp index 68cad01a..72679d24 100644 --- a/main/include/HomeKitLock.hpp +++ b/main/include/HomeKitLock.hpp @@ -16,11 +16,12 @@ namespace Service class LockManager; class ConfigManager; class ReaderDataManager; +class HardwareManager; namespace espConfig { struct misc_config_t; }; class HomeKitLock { public: - HomeKitLock(std::function &conn_cb, LockManager& lockManager, ConfigManager& configManager, ReaderDataManager& readerDataManager); + HomeKitLock(std::function &conn_cb, LockManager& lockManager, ConfigManager& configManager, ReaderDataManager& readerDataManager, HardwareManager& hardwareManager); void begin(); void updateLockState(int currentState, int targetState); void updateBatteryStatus(uint8_t batteryLevel, bool isLow); @@ -34,6 +35,7 @@ class HomeKitLock { LockManager& m_lockManager; ConfigManager& m_configManager; ReaderDataManager& m_readerDataManager; + HardwareManager& m_hardwareManager; std::function &conn_cb; @@ -56,13 +58,12 @@ class HomeKitLock { }; struct LockMechanismService : Service::LockMechanism { LockManager& m_lockManager; + HardwareManager& m_hardwareManager; SpanCharacteristic* m_lockTargetState; SpanCharacteristic* m_lockCurrentState; SpanCharacteristic* m_doorState; - int m_doorSensorPin = 32; - bool m_doorSensorInvert = false; - int m_lastDoorState = -1; - LockMechanismService(HomeKitLock& bridge, LockManager& lockManager, const espConfig::misc_config_t& config); + + LockMechanismService(HomeKitLock& bridge, LockManager& lockManager, HardwareManager& hardwareManager); boolean update() override; void loop() override; }; diff --git a/main/main.cpp b/main/main.cpp index f8fdab8a..e2c8ef31 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -63,10 +63,10 @@ void setup() { esp_log_level_set("*", static_cast(configManager->getConfig().logLevel)); webServerManager = new WebServerManager(*configManager, *readerDataManager); distributor.add_sinker(std::make_shared(webServerManager)); - hardwareManager = new HardwareManager(configManager->getConfig()); + hardwareManager = new HardwareManager(configManager->getConfig(), configManager->getConfig()); lockManager = new LockManager(configManager->getConfig(), configManager->getConfig()); mqttManager = new MqttManager(*configManager); - homekitLock = new HomeKitLock(lambda, *lockManager, *configManager, *readerDataManager); + homekitLock = new HomeKitLock(lambda, *lockManager, *configManager, *readerDataManager, *hardwareManager); espConfig::misc_config_t miscConfig = configManager->getConfig(); static const char* TAG = "Main"; if(miscConfig.nfcPinsPreset != 255){ From 5df2781db5a74abee753943bebf585333571acee Mon Sep 17 00:00:00 2001 From: Foy Date: Fri, 2 Jan 2026 10:28:41 +0800 Subject: [PATCH 6/8] fix doorSensorPin input is missing min and max attributes that are present on other GPIO pin inputs in this file. This could allow invalid GPIO values. --- data/src/lib/components/AppMisc.svelte | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/src/lib/components/AppMisc.svelte b/data/src/lib/components/AppMisc.svelte index 6a63978a..30302ff4 100644 --- a/data/src/lib/components/AppMisc.svelte +++ b/data/src/lib/components/AppMisc.svelte @@ -620,6 +620,8 @@ type="number" bind:value={miscConfig.doorSensorPin} placeholder="32" + min="0" + max="255" class="input input-bordered w-full" /> From a487b451377ad2d6ac0745f48db692844fbe6c94 Mon Sep 17 00:00:00 2001 From: Foy Date: Fri, 9 Jan 2026 09:16:01 +0800 Subject: [PATCH 7/8] Fix Expose m_doorState to the bridge for proper HomeKit registration. --- main/HKServices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/HKServices.cpp b/main/HKServices.cpp index 74579a86..9dc712a4 100644 --- a/main/HKServices.cpp +++ b/main/HKServices.cpp @@ -102,7 +102,7 @@ HomeKitLock::LockMechanismService::LockMechanismService(HomeKitLock& bridge, Loc espp::EventManager::get().add_publisher("lock/targetStateChanged", "LockMechanismService"); ESP_LOGI(HomeKitLock::TAG, "Configuring LockMechanism"); - m_doorState = new Characteristic::CurrentDoorState(1); // Default Closed + m_doorState = brodge.m_doorState = new Characteristic::CurrentDoorState(1); //default Closed m_lockCurrentState = bridge.m_lockCurrentState = new Characteristic::LockCurrentState(m_lockManager.getCurrentState(), true); m_lockTargetState = bridge.m_lockTargetState = new Characteristic::LockTargetState(m_lockManager.getTargetState(), true); From b962c525d628d7853c61fe2c6c6a8bb7c468387b Mon Sep 17 00:00:00 2001 From: Foy Date: Fri, 16 Jan 2026 10:11:12 +0800 Subject: [PATCH 8/8] add HomeSpan thread synchronization and fix variable naming - Wrap setVal() calls with homeSpanPAUSE()/homeSpanRESUME() to prevent race conditions with HomeSpan event processing - Fix incorrect variable naming in HKServices.cpp 105 --- main/HKServices.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main/HKServices.cpp b/main/HKServices.cpp index 9dc712a4..d780f0b1 100644 --- a/main/HKServices.cpp +++ b/main/HKServices.cpp @@ -102,7 +102,7 @@ HomeKitLock::LockMechanismService::LockMechanismService(HomeKitLock& bridge, Loc espp::EventManager::get().add_publisher("lock/targetStateChanged", "LockMechanismService"); ESP_LOGI(HomeKitLock::TAG, "Configuring LockMechanism"); - m_doorState = brodge.m_doorState = new Characteristic::CurrentDoorState(1); //default Closed + m_doorState = bridge.m_doorState = new Characteristic::CurrentDoorState(1); //default Closed m_lockCurrentState = bridge.m_lockCurrentState = new Characteristic::LockCurrentState(m_lockManager.getCurrentState(), true); m_lockTargetState = bridge.m_lockTargetState = new Characteristic::LockTargetState(m_lockManager.getTargetState(), true); @@ -141,7 +141,9 @@ boolean HomeKitLock::LockMechanismService::update() { void HomeKitLock::LockMechanismService::loop() { int doorState = m_hardwareManager.checkDoorSensor(); if (doorState != -1) { + homeSpanPAUSE(); m_doorState->setVal(doorState); + homeSpanRESUME(); } }