Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.4 #131

Merged
merged 45 commits into from
Oct 6, 2024
Merged

v0.4 #131

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
463b052
s3 env
rednblkx Jul 22, 2024
7960430
autoPoll() causes a crash
rednblkx Jul 22, 2024
add0869
replaced jsoncons
rednblkx Aug 8, 2024
4ebfb7f
configurable lwt topic
rednblkx Aug 8, 2024
e4d372e
dev branch
rednblkx Aug 8, 2024
cb661ec
branch switch on PRs
rednblkx Aug 21, 2024
ba9de49
autoclose issues with no reponse within timeframe
rednblkx Aug 21, 2024
f34b3e2
revamped webui & added neopixel rgb fields
rednblkx Aug 23, 2024
23f5328
added web elements of momentary state for homekit simple gpio
rednblkx Aug 23, 2024
831e31f
separated gpio business into individual tasks
rednblkx Aug 23, 2024
d48287d
Added image preview for Card Finish (#114)
adukale Aug 23, 2024
c818c14
Delete .github/workflows/no-response.yml
rednblkx Aug 23, 2024
8209e48
insert server response
rednblkx Aug 23, 2024
634af00
remove workflow
rednblkx Aug 24, 2024
d71a81e
added web authentication
rednblkx Aug 26, 2024
42928dd
design things
rednblkx Aug 26, 2024
e996521
vscode stuff
rednblkx Sep 6, 2024
e6306a0
replaced adafruit neopixel library
rednblkx Sep 6, 2024
74893b4
ota pass field is of password type
rednblkx Sep 6, 2024
58af47b
dynamically create the gpio task when needed and fixed momentary state
rednblkx Sep 6, 2024
e4dc7ff
serialize misc and mqtt data to msgpack
rednblkx Sep 6, 2024
953e013
flip the current state of homekit lock
rednblkx Sep 6, 2024
521001a
fix gpio initialization
rednblkx Sep 6, 2024
1195ab0
formatting
rednblkx Sep 12, 2024
84d6a20
disabled c++ exceptions
rednblkx Sep 12, 2024
298306c
publish unique id on auth
rednblkx Sep 12, 2024
43a0922
section reboot notes
rednblkx Sep 17, 2024
14e4890
added page load animation
rednblkx Sep 17, 2024
eb3c049
root path only serves index.html
rednblkx Sep 17, 2024
fd98a4e
some logs
rednblkx Sep 18, 2024
c8f2cdb
changed load animation
rednblkx Sep 18, 2024
228f55a
mqtt username & password is not required
rednblkx Sep 19, 2024
02959f8
proper defaults for mqtt
rednblkx Sep 19, 2024
8af5671
store colors as byte array
rednblkx Sep 29, 2024
27d54f4
reboot and reset endpoints & ui buttons
rednblkx Oct 1, 2024
a9cf6f0
pinned commits for libs
rednblkx Oct 1, 2024
eced236
remove branch-switcher.yml
rednblkx Oct 1, 2024
94e6445
cleaner readme
rednblkx Oct 1, 2024
b6936fc
don't run CI if not code-related
rednblkx Oct 1, 2024
e4ae3ac
Update esp32.yml
rednblkx Oct 1, 2024
a353439
Update README.md
rednblkx Oct 1, 2024
bf1a913
lexical and design fixes
rednblkx Oct 5, 2024
ff10f62
added pixelType selector
rednblkx Oct 5, 2024
773d00e
nfc tag detection should be a failed event
rednblkx Oct 5, 2024
6e79d47
wording
rednblkx Oct 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions .github/workflows/esp32.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,25 @@
name: CI

# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
push:
branches: [ main ]
branches: [ main, dev ]
paths:
- 'src/**'
- 'platformio.ini'
- 'sdkconfig.defaults'
- 'data/**'
- 'with_ota.csv'
- 'fs.py'
pull_request:
branches: [ main, dev ]
paths:
- 'src/**'
- 'data/**'
- 'platformio.ini'
- 'sdkconfig.defaults'
- 'with_ota.csv'
- 'fs.py'

jobs:
build:
Expand Down Expand Up @@ -67,3 +76,15 @@ jobs:
with:
name: esp32c3-app-firmware
path: .pio/build/c3/firmware.bin
- name: Build Firmware ESP32-S3
run: pio run -e s3
- name: Archive merged firmware
uses: actions/upload-artifact@v4
with:
name: esp32s3-firmware-merged
path: .pio/build/s3/firmware_merged.bin
- name: Archive firmware
uses: actions/upload-artifact@v4
with:
name: esp32s3-app-firmware
path: .pio/build/s3/firmware.bin
9 changes: 7 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@
"mutex": "cpp",
"thread": "cpp",
"valarray": "cpp",
"*.ipp": "cpp"
}
"*.ipp": "cpp",
"charconv": "cpp",
"scoped_allocator": "cpp",
"variant": "cpp"
},
"python.terminal.activateEnvInCurrentTerminal": true,
"python.terminal.activateEnvironment": false
}
51 changes: 34 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,47 @@
<img src="https://github.com/rednblkx/HomeKey-ESP32/assets/29458132/6c2e1ea8-f74e-41ac-a690-461e339525acb" width="250" height="250">
![homekey-logo-white](https://github.com/user-attachments/assets/fc93a70a-ef1e-4390-9067-6fafb255e5ac)

# HomeKey-ESP32 [![Discord Badge](https://img.shields.io/badge/Discord-5865F2?logo=discord&logoColor=fff&style=for-the-badge)](https://discordapp.com/invite/VWpZ5YyUcm)
[![CI](https://github.com/rednblkx/HomeKey-ESP32/actions/workflows/esp32.yml/badge.svg?branch=main)](https://github.com/rednblkx/HomeKey-ESP32/actions/workflows/esp32.yml)
### ESP32 HomeKit Lock with support for the HomeKey
# HomeKey-ESP32 [![Discord](https://badgen.net/discord/members/VWpZ5YyUcm?icon=discord)](https://discord.com/invite/VWpZ5YyUcm) [![CI](https://github.com/rednblkx/HomeKey-ESP32/actions/workflows/esp32.yml/badge.svg?branch=main)](https://github.com/rednblkx/HomeKey-ESP32/actions/workflows/esp32.yml)

Credit to [@kormax](https://github.com/kormax) for reverse-engineering the Homekey [NFC Protocol](https://github.com/kormax/apple-home-key) and publishing a [POC](https://github.com/kormax/apple-home-key-reader) and credit to [@kupa22](https://github.com/kupa22) for the [research](https://github.com/kupa22/apple-homekey) on the HAP side of things, this project was possible thanks to their work.
Additionaly, thanks to the Arduino library [HomeSpan](https://github.com/HomeSpan/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.
### HomeKey functionality for the rest of us.

## Overview

This project aims to provide the Apple HomeKey functionality with just an ESP32 and PN532 NFC Module. Sole purpose of the project is to provide the HomeKey functionality and other NFC functionalities such as MIfare Authentication or others are out of scope.

- It integrates with HomeAssistant's Tags which makes it easier to create automations based on a person(issuer) or device(endpoint).
- The internal 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 publish the UID, ATQA and SAK on the same MQTT topic as HomeKey with the `"homekey"` field set to `false`
- Code is not ready for battery-powered applications
- Designed for a board with an ESP32 chip and 4MB Flash size

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

For more advanced functionality, you might also be interested in [HAP-ESPHome](https://github.com/rednblkx/HAP-ESPHome) which attempts to integrate HomeKit (and HomeKey) into ESPHome for ultimate automations.

## Usage

Visit the [wiki](https://github.com/rednblkx/HomeKey-ESP32/wiki) for documentation on the project

## 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.
While functional as it is now, the project should still be considered as a **work in progress** so expect breaking changes.

## Overview
## Contributing

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.
All contributions to the repository are welcomed, if you think you can bring an improvement into the project, feel free to fork the repository and submit your pull requests.

- It integrates with HomeAssistant's Tags and can be used to create automations based on a person(issuer) or device(endpoint).
- The lock's 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 due to the power hungry WiFi and the code not being optimized for this
- Designed for a board with an ESP32 chip and 4MB Flash size
If you have a suggestion or are in need of assistance, you can open an issue. Additionally, you can join the Discord server at https://discord.com/invite/VWpZ5YyUcm

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 :) .
## Support

## Usage
If you like the project, please consider giving it a start to show the appreciation and for others to know this repository is worth something.

Visit the [wiki](https://github.com/rednblkx/HomeKey-ESP32/wiki) for documentation on the project
Additionally, if you have the means and are willing to, you can donate using the [Sponsor](https://github.com/sponsors/rednblkx) button.

## Credits

- [@kormax](https://github.com/kormax) for reverse-engineering the Homekey [NFC Protocol](https://github.com/kormax/apple-home-key) and publishing a [PoC](https://github.com/kormax/apple-home-key-reader)
- [@kupa22](https://github.com/kupa22) for the [research](https://github.com/kupa22/apple-homekey) on the HAP side of things for Homekey
- [HomeSpan](https://github.com/HomeSpan/HomeSpan) which is being used as the framework implementing the HomeKit accessory
205 changes: 205 additions & 0 deletions data/actions.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
<form id="actions-config" action="actions-config" method="post"
style="display: inline-flex; flex-direction: column;margin-bottom: 0rem;">

<h2 style="text-align: center;">Hardware Actions</h2>
<h5 style="margin-top: 0;margin-bottom: 1rem;text-align: center;">Assigning 255 to any Pin field will disable the respective option</h5>

<div
style="display: flex;flex-direction: column;border: 1px #8e8271 solid;border-radius: 8px;padding: 1rem;box-shadow: 0px 1px 1px 0px;margin-bottom: 1rem;background-color: #2d1d1d;">
<h3 style="margin-top: 0;text-align: center;">HomeKey/NFC Triggers</h3>
<h4 style="margin-top: 0;">Executed on successful/failed HomeKey Authentication and on NFC Tag detection(marked as a failed event)</h4>
<h4 style="margin-top: 0;">Both Neopixel and Simple GPIO have a momentary state</h4>
<div style="display:flex;flex-direction: column;border: 2px #8e8271 dashed;padding: 1rem;margin-bottom: 1rem;">
<h3 style="margin: 0 0 1rem;">Neopixel</h3>
<div style="display: flex; flex-direction: column;">
<label for="nfc-s-pin">Auth Success/Failure GPIO Pin</label>
<input type="number" name="nfc-neopixel-pin" id="nfc-neopixel-pin" placeholder="8" required value="%NFCNEOPIXELPIN%" min="0" max="255">
</div>
<div style="display: flex;flex-direction: column;margin-top: .7rem;">
<label for="neopixel-s-time">Timeout (ms) - Auth Success</label>
<input type="number" name="neopixel-s-time" id="neopixel-s-time" placeholder="1000" required value="%NEOSTIME%">
</div>
<div style="display: flex;flex-direction: column;margin-top: .7rem;">
<label for="neopixel-f-time">Timeout (ms) - Auth Failed</label>
<input type="number" name="neopixel-f-time" id="neopixel-f-time" placeholder="1000" required value="%NEOFTIME%">
</div>
<div style="display: flex;flex-direction: column;margin-top: .7rem;">
<label for="neo-pixel-type">Pixel Type</label>
<select name="neo-pixel-type" id="neo-pixel-type">
<option value="0">RGB</option>
<option value="1">RBG</option>
<option value="2">BRG</option>
<option value="3">BGR</option>
<option value="4">GBR</option>
<option value="5">GRB</option>
</select>
</div>
<div
style="display: flex;gap: 8px;border: 1px #8e8271 solid;padding: .5rem;margin-top: 1rem;justify-content: space-around;">
<div id="nfc-s-color" style="display: flex;flex-direction: column;">
<div style="display: flex;">
<h4 style="margin: .1rem 0 0;text-align: center;">Auth Success Color</h4>
</div>
<div id="nfc-s-vals" style="display: flex;gap:8px;flex-wrap: wrap;justify-content: center;">
<div style="display: flex; flex-direction: column;">
<label for="nfc-s-red-pixel">R</label>
<input type="number" style="max-width: 3.5rem" name="nfc-s-red-pixel" id="nfc-s-red-pixel" min="0" max="255" placeholder="255" required value="%SREDPIXELVAL%">
</div>
<div style="display: flex; flex-direction: column;">
<label for="nfc-s-green-pixel">G</label>
<input type="number" style="max-width: 3.5rem" name="nfc-s-green-pixel" id="nfc-s-green-pixel" min="0" max="255" placeholder="255" required value="%SGREENPIXELVAL%">
</div>
<div style="display: flex; flex-direction: column;">
<label for="nfc-s-blue-pixel">B</label>
<input type="number" style="max-width: 3.5rem" name="nfc-s-blue-pixel" id="nfc-s-blue-pixel" min="0" max="255" placeholder="255" required value="%SBLUEPIXELVAL%">
</div>
</div>
</div>
<span style="border: 1px #8e8271 solid; margin: 1rem;"></span>
<div id="nfc-f-color" style="display: flex;flex-direction: column;">
<div style="display: flex;">
<h4 style="margin: .1rem 0 0;text-align: center;">Auth Failure Color</h4>
</div>
<div id="nfc-f-vals" style="display: flex;gap:8px;flex-wrap: wrap;justify-content: center;">
<div style="display: flex; flex-direction: column;">
<label for="nfc-f-red-pixel">R</label>
<input type="number" style="max-width: 3.5rem" name="nfc-f-red-pixel" id="nfc-f-red-pixel" min="0" max="255" placeholder="255" required value="%FREDPIXELVAL%">
</div>
<div style="display: flex; flex-direction: column;">
<label for="nfc-f-green-pixel">G</label>
<input type="number" style="max-width: 3.5rem" name="nfc-f-green-pixel" id="nfc-f-green-pixel" min="0" max="255" placeholder="255" required value="%FGREENPIXELVAL%">
</div>
<div style="display: flex; flex-direction: column;">
<label for="nfc-f-blue-pixel">B</label>
<input type="number" style="max-width: 3.5rem" name="nfc-f-blue-pixel" id="nfc-f-blue-pixel" min="0" max="255" placeholder="255" required value="%FBLUEPIXELVAL%">
</div>
</div>
</div>
</div>
</div>

<div style="display:flex;flex-direction: column;border: 2px #8e8271 dashed;padding: 1rem;align-items: center;">
<h3 style="margin: 0 0 1rem;align-self: flex-start;">Simple GPIO</h3>
<div style="display: flex;gap: 8px;flex-wrap: wrap;justify-content: center;">
<div style="display: flex;">
<fieldset>
<legend>Auth Success</legend>
<div style="display: flex;flex-direction: column;">
<label for="nfc-s-pin">GPIO Pin</label>
<input type="number" name="nfc-s-pin" id="nfc-s-pin" placeholder="2" required value="%NFC1PIN%" min="0" max="255">
</div>
<div style="display: flex;flex-direction: column;margin-top: .7rem;">
<label for="nfc-s-time">Timeout (ms)</label>
<input type="number" name="nfc-s-time" id="nfc-s-time" placeholder="1000" required value="%NFC1TIME%">
</div>
<div style="display: flex;margin-top: .7rem;gap: 8px;">
<label for="nfc-s-hl">GPIO State</label>
<select name="nfc-s-hl" id="nfc-s-hl">
<option value="0">LOW</option>
<option value="1">HIGH</option>
</select>
</div>
</fieldset>
</div>
<div style="display: flex;">
<fieldset>
<legend>Auth Failure</legend>
<div style="display: flex;flex-direction: column;">
<label for="nfc-f-pin">GPIO Pin</label>
<input type="number" name="nfc-f-pin" id="nfc-f-pin" placeholder="2" required value="%NFC2PIN%" min="0" max="255">
</div>
<div style="display: flex;flex-direction: column;margin-top: .7rem;">
<label for="nfc-f-time">Timeout (ms)</label>
<input type="number" name="nfc-f-time" id="nfc-f-time" placeholder="1000" required value="%NFC2TIME%">
</div>
<div style="display: flex;margin-top: .7rem;gap: 8px;">
<label for="nfc-f-hl">GPIO State</label>
<select name="nfc-f-hl" id="nfc-f-hl">
<option value="0">LOW</option>
<option value="1">HIGH</option>
</select>
</div>
</fieldset>
</div>
</div>
</div>
</div>
<div style="display: flex;flex-direction: column;border: 1px #8e8271 solid;border-radius: 8px;padding: 1rem;box-shadow: 0px 1px 1px 0px;background-color: #2d1d1d;">
<h3 style="margin-top: 0;text-align: center;">HomeKit/HomeKey Triggers</h3>
<h4 style="margin-top: 0;margin-bottom: .5rem;">Executed upon interaction in the Home app and on successful HomeKey Authentication</h4>
<h4 style="margin-top: 0;">Follows "Always Lock/Unlock on HomeKey" option</h4>
<div style="display:flex;flex-direction: column;border: 2px #8e8271 dashed;padding: 1rem;">
<h3 style="margin: 0 0 1rem;align-self: flex-start;">Simple GPIO</h3>
<div style="display: flex;gap: 8px;">
<label for="gpio-a-pin">GPIO Pin</label>
<input type="number" name="gpio-a-pin" id="gpio-a-pin" placeholder="2" required value="%GPIOAPIN%" style="width: 4rem;" min="0" max="255">
</div>
<div style="display: flex;margin-top: .7rem;gap: 8px;">
<label for="gpio-a-momentary">HK Momentary State</label>
<select name="gpio-a-momentary" id="gpio-a-momentary">
<option value="0">Disabled</option>
<option value="1">Enabled</option>
</select>
</div>
<div style="display: flex;margin-top: .7rem;gap: 8px;">
<label for="gpio-a-mo-timeout">HK Momentary Timeout</label>
<input type="number" name="gpio-a-mo-timeout" id="gpio-a-mo-timeout" placeholder="2" required value="%GPIOAMOTIME%" style="width: 4rem;">
</div>
<div style="display: flex;margin-top: .7rem;gap: 8px;">
<label for="gpio-a-lock">GPIO State - Locked</label>
<select name="gpio-a-lock" id="gpio-a-lock">
<option value="0">LOW</option>
<option value="1">HIGH</option>
</select>
</div>
<div style="display: flex;margin-top: .7rem;gap: 8px;">
<label for="gpio-a-unlock">GPIO State - Unlocked</label>
<select name="gpio-a-unlock" id="gpio-a-unlock" value="0">
<option value="0">LOW</option>
<option value="1">HIGH</option>
</select>
</div>
</div>
</div>
<div id="buttons-group" style="display: flex;justify-content: space-around;margin-top: 2rem;">
<button type="submit" style="cursor: pointer;">Submit</button>
<button type="reset" style="cursor: pointer;" class="destructive-btn">Reset</button>
</div>
</form>
<script>
let nfcshl = document.querySelector("#nfc-s-hl");
let nfcfhl = document.querySelector("#nfc-f-hl");
let actionunlock = document.querySelector("#gpio-a-unlock");
let actionlock = document.querySelector("#gpio-a-lock");
let actionMomentary = document.querySelector("#gpio-a-momentary");
let pixelType = document.querySelector("#neo-pixel-type")
pixelType.selectedIndex = "%NEOPIXELTYPE%"
nfcshl.selectedIndex = "%NFC1HL%";
nfcfhl.selectedIndex = "%NFC2HL%";
actionlock.selectedIndex = "%GPIOALOCK%";
actionunlock.selectedIndex = "%GPIOAUNLOCK%";
actionMomentary.selectedIndex = "%GPIOAMOEN%";
let form = document.getElementById("actions-config");
async function handleForm(event) {
event.preventDefault();
let response = await fetch("actions-config", {
body: new FormData(form),
method: "post",
});
let string = await response.text();
let element = document.querySelector("#status-text");
if (element) {
element.remove();
}
let component = document.getElementById("buttons-group");
let elStatus = document.createElement("h4");
elStatus.id = "status-text";
elStatus.style = "color: red;text-align: center;margin-bottom: 0;";
elStatus.innerText = string;
component.insertAdjacentElement("beforebegin", elStatus);
setTimeout(() => {
document.querySelector("#status-text").remove();
}, 5000);
}
form.addEventListener("submit", handleForm);
</script>
Binary file added data/assets/favicon.ico
Binary file not shown.
Binary file added data/assets/hk-finish-0.webp
Binary file not shown.
Binary file added data/assets/hk-finish-1.webp
Binary file not shown.
Binary file added data/assets/hk-finish-2.webp
Binary file not shown.
Binary file added data/assets/hk-finish-3.webp
Binary file not shown.
Binary file added data/assets/logo-white.webp
Binary file not shown.
Loading