/HomeKey-ESP32-oldversion

ESP32 HomeKit Lock with support for the HomeKey - outdated version before refactoring

Primary LanguageC++MIT LicenseMIT

HomeKey-ESP32

CI

ESP32 HomeKit Lock with support for the HomeKey

Credit to @kormax for reverse-engineering the Homekey NFC Protocol and publishing a POC and credit to @kupa22 for the research on the HAP side of things, this project was possible thanks to their work. Additionaly, thanks to the Arduino library HomeSpan for being a great library that eased my work on HAP and other things and allowed me to just focus on the homekey functionality.

Disclaimer

Use this at your own risk, i'm not a cryptographic expert, just a hobbyist. Keep in mind that the HomeKey was implemented through reverse-engineering as indicated above so it might be lacking stuff from Apple's specification to which us private individuals do not have access.

While functional, the project is still a work in progress so expect breaking changes as i'm figuring out how everything should fit together and the overrall structure of the code.

Overview

Right now only the PN532 is supported as the NFC module, however, beware of cheap clones espcially clones of Elechouse's as it will cause issues, i recommend the Elechouse PN532 NFC Module V3 just make sure to buy from a trusted vendor.

  • It integrates with HomeAssistant's Tags and can be used to create automations based on a person(issuer) or device(endpoint).
  • Lock State is published and controlled via MQTT through user-defined topics
  • Any NFC Target that's not identified as homekey will skip the flow and publishes the UID, ATQA and SAK on the same Authentication MQTT topic
  • It is not made for battery-powered applications (yet)
  • Designed for a board with an ESP32 chip and 4MB Flash size

Goal of the project is to make it easy to add the homekey functionality to locks that don't support it or to anything for that matter :) .

Wiring

The current implementation is using SPI for communication.

Pins are the default Arduino pins for SPI which should be as follows:

GPIO18 - SCK

GPIO19 - MISO

GPIO23 - MOSI

GPIO5 - SS

Configuration

Currently the WiFi can either be configured from the terminal or with the help of the HomeSpan's Configuration Mode for which a GPIO pin needs to be assigned to a button(see Configuration File), more info about the Configuration Mode can be found on HomeSpan's wiki here

WIFI

To connect it to WiFi there are three options

  • Open the serial terminal, press W + Return
    • Now it should start searching for networks and after a few seconds a list of names should appear from which you can select using their respective numbers or just type the name manually.
  • Open the serial terminal, press A to start a temporary Access Point
    • Connect to the Wifi network "HomeSpan-Setup" with the password homespan and if you are on a phone it should automatically open up the page where you can configure the Wifi credentials, alternatively once connected to the AP you can access the page manually on http://192.168.4.1/hotspot-detect.html
  • Enter Configuration Mode by pressing the Control Button for 3 seconds, at which point the Status LED should begin to flash rapidly (10 times per second). Upon releasing the button the device will switch into the Device Configuration Mode.
    • Press the button briefly two times(with a brief pause in-between) and the Status LED should now blink three times with a pause in-between indicating Action 3 is selected which is Launch HomeSpan’s temporary WiFi network
    • Hold the button for 3 seconds to execute the action
    • Same steps as when starting the AP from terminal apply, connect to the HomeSpan-Setup network with the password homespan

HomeKit

The pairing code is the default 466-37-726 from the HomeSpan library that can be found in their documentation here. This can be changed at runtime from the terminal.

For any informations regarding the HomeKit implementation not related to the HomeKey feature, please see the repository for HomeSpan here where you will also found the documentation.

Configuration file

In order to connect to your MQTT Broker and WiFi, first modify the file called config.h in the src folder with the following content and modify it accordingly with your details

#define MQTT_HOST "0.0.0.0"
#define MQTT_PORT 1883
#define MQTT_CLIENTID "homekey_mqtt"
#define MQTT_USERNAME "username"
#define MQTT_PASSWORD "password"
#define MQTT_AUTH_TOPIC "topic/auth"
#define MQTT_SET_STATE_TOPIC "topic/set_state"
#define MQTT_SET_TARGET_STATE_TOPIC "topic/set_target_state"
#define MQTT_SET_CURRENT_STATE_TOPIC "topic/set_current_state"
#define MQTT_STATE_TOPIC "topic/state"
#define HK_CODE "46637726"
#define LED_PIN 2
#define OTA_PWD "homespan-ota"
#define CONTROL_PIN 26
#define NAME "HK Lock"
#define DISCOVERY "1"

MQTT_AUTH_TOPIC is where authentication details will be published on success

MQTT_SET_STATE_TOPIC is the control topic that sets the current and target state of the lock

MQTT_SET_TARGET_STATE_TOPIC controls the target state of the lock

MQTT_SET_CURRENT_STATE_TOPIC controls the current state of the lock

MQTT_STATE_TOPIC is where changes to the lock state will be published.

HK_CODE is the paring code for HomeKit

LED_PIN is the pin for the status led

OTA_PWD is the password for OTA

CONTROL_PIN is the pin for HomeSpan's Configuration Mode button

NAME is the name for the lock in HomeKit

DISCOVERY controls if discovery messages for the Home Assistant tag functionality are send at startup, set to 1 to enable, 0 to disable.

On the MQTT_AUTH_TOPIC topic, the data format is as follows, depending whether a homekey was authenticated or just an NFC Target was sensed.

  • HomeKey
{
  "endpointId": "000000000000", # This is unique per device
  "homekey": true,
  "issuerId": "0000000000000000" # This is unique per Apple ID
}
  • ISO14443A card
{
  "atqa": "0004",
  "homekey": false,
  "sak": "08",
  "uid": "00000000"
}

OTA

Authentication is enabled and the default password is homespan-ota.

To upload via OTA, define the address of the ESP on the environment variable PLATFORMIO_UPLOAD_PORT and then use the PlatformIO environment ota,

If the default password is not used, you probably know what you are doing, however, a custom password can be used by setting the environment variable PLATFORMIO_UPLOAD_FLAGS to --auth=<ota-password>