Updated matter decoder to show more info, and added a homekit decoder.
This commit is contained in:
1 parent
548f2e701f
commit
27ebf13f6f
8 files changed
+831
-6
No files matched your search
Executable
+149
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# homekit-decode.fixed.sh — corrected decoder for a HomeKit setup payload.
|
||||
#
|
||||
# This is a fixed copy of homekit-decode.sh. It decodes using the *correct*
|
||||
# HomeKit bit layout (the one composeSetupUri in the homekit-code package
|
||||
# actually encodes), instead of the misaligned bit positions in the original.
|
||||
#
|
||||
# Correct layout, least-significant bit first:
|
||||
# bits 0-26 pin (27 bits)
|
||||
# bits 27-30 flag (4 bits: 1=NFC 2=IP 4=BLE 8=WAC/MFi)
|
||||
# bits 31-38 categoryId (8 bits)
|
||||
# bits 39-42 reserved (4 bits)
|
||||
# bits 43-45 version (3 bits)
|
||||
#
|
||||
# Fixes vs homekit-decode.sh:
|
||||
# - categoryId was (val >> 27) & 0xFF, which mixed in the flag field; the
|
||||
# categoryId field starts at bit 31, so it is now (val >> 31) & 0xFF.
|
||||
# - The original "IP/BLE/Thread" flags read bits 35/36/37, which live inside
|
||||
# the categoryId field. The real flag field is bits 27-30 with sub-flags
|
||||
# NFC(1)/IP(2)/BLE(4)/WAC(8); "Thread" was a misread and is dropped.
|
||||
# - version was (val >> 38) & 0xFF, overlapping reserved; it is a 3-bit field
|
||||
# at bits 43-45, so it is now (val >> 43) & 0x7.
|
||||
# - reserved (bits 39-42) is reported instead of being swallowed by version.
|
||||
# - the category id is resolved to its HAP name (e.g. 8 -> "Switch"); ids not
|
||||
# in the known table print as "unknown".
|
||||
#
|
||||
# Usage: ./homekit-decode.fixed.sh [PAYLOAD]
|
||||
# Defaults to the demo payload "005KEOUCE" when no argument is given, matching
|
||||
# the original so the two scripts decode the same thing by default.
|
||||
# The output also prints the setup id and a reconstructed "X-HM://" payload
|
||||
# rebuilt from the decoded fields: a complete record for recreating the barcode.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Strip the "X-HM://" prefix if present. The first 9 chars are the fixed
|
||||
# parameter block; the rest is the (variable-length) setup id, appended verbatim
|
||||
# and not part of the numeric block.
|
||||
body="${1:-005KEOUCE}"
|
||||
body="${body#X-HM://}"
|
||||
clean_str="${body:0:9}"
|
||||
setup_id="${body:9}"
|
||||
|
||||
# Step 1: Base36 -> integer (same as homekit-decode.sh).
|
||||
val=0
|
||||
for (( i = 0; i < ${#clean_str}; i++ )); do
|
||||
code=$(printf '%d' "'${clean_str:i:1}")
|
||||
if (( code >= 48 && code <= 57 )); then digit=$(( code - 48 ))
|
||||
elif (( code >= 65 && code <= 90 )); then digit=$(( code - 65 + 10 ))
|
||||
elif (( code >= 97 && code <= 122 )); then digit=$(( code - 97 + 10 ))
|
||||
else
|
||||
printf 'error: invalid Base36 character %q\n' "${clean_str:i:1}" >&2
|
||||
exit 1
|
||||
fi
|
||||
val=$(( val * 36 + digit ))
|
||||
done
|
||||
|
||||
# Step 2: Bitmask extraction, corrected to the HomeKit layout.
|
||||
pin=$(( val & 0x7FFFFFF )) # bits 0-26
|
||||
flag=$(( (val >> 27) & 0xF )) # bits 27-30
|
||||
category=$(( (val >> 31) & 0xFF )) # bits 31-38
|
||||
reserved=$(( (val >> 39) & 0xF )) # bits 39-42
|
||||
version=$(( (val >> 43) & 0x7 )) # bits 43-45
|
||||
|
||||
# Resolve the numeric category id to its HAP name (homekit_accessory_category_*).
|
||||
# https://developer.apple.com/documentation/homekit/hmaccessorycategory
|
||||
# A case statement (not a `declare -A` map) keeps this working on the stock
|
||||
# macOS bash 3.2 that `#!/usr/bin/env bash` resolves to. "Heater" corrects a
|
||||
# "Header" typo in the source table; id 25 is reserved by HomeKit, so unknown.
|
||||
cat_name="unknown"
|
||||
case "$category" in
|
||||
1) cat_name="Other" ;;
|
||||
2) cat_name="Bridge" ;;
|
||||
3) cat_name="Fan" ;;
|
||||
4) cat_name="Garage" ;;
|
||||
5) cat_name="Lightbulb" ;;
|
||||
6) cat_name="Door Lock" ;;
|
||||
7) cat_name="Outlet" ;;
|
||||
8) cat_name="Switch" ;;
|
||||
9) cat_name="Thermostat" ;;
|
||||
10) cat_name="Sensor" ;;
|
||||
11) cat_name="Security System" ;;
|
||||
12) cat_name="Door" ;;
|
||||
13) cat_name="Window" ;;
|
||||
14) cat_name="Window Covering" ;;
|
||||
15) cat_name="Programmable Switch" ;;
|
||||
16) cat_name="Range Extender" ;;
|
||||
17) cat_name="IP Camera" ;;
|
||||
18) cat_name="Video Door Bell" ;;
|
||||
19) cat_name="Air Purifier" ;;
|
||||
20) cat_name="Heater" ;;
|
||||
21) cat_name="Air Conditioner" ;;
|
||||
22) cat_name="Humidifier" ;;
|
||||
23) cat_name="Dehumidifier" ;;
|
||||
24) cat_name="Apple TV" ;;
|
||||
26) cat_name="Speaker" ;;
|
||||
27) cat_name="AirPort" ;;
|
||||
28) cat_name="Sprinkler" ;;
|
||||
29) cat_name="Faucet" ;;
|
||||
30) cat_name="Shower Head" ;;
|
||||
31) cat_name="Television" ;;
|
||||
32) cat_name="Target Controller" ;;
|
||||
esac
|
||||
|
||||
# Python's bool() prints "True"/"False"; treat any non-zero bit as true.
|
||||
to_bool() {
|
||||
if (( $1 != 0 )); then
|
||||
printf 'True'
|
||||
else
|
||||
printf 'False'
|
||||
fi
|
||||
}
|
||||
|
||||
# Base36 integer -> uppercase string (mirrors composeSetupUri's toString(36).toUpperCase()).
|
||||
to_base36() {
|
||||
local n=$1 digits='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' out=''
|
||||
if [ "$n" -eq 0 ]; then
|
||||
printf '0'
|
||||
return
|
||||
fi
|
||||
while [ "$n" -gt 0 ]; do
|
||||
out="${digits:n%36:1}${out}"
|
||||
n=$(( n / 36 ))
|
||||
done
|
||||
printf '%s' "$out"
|
||||
}
|
||||
|
||||
# Reconstruct the 9-char parameter block from the decoded fields (mirrors
|
||||
# composeSetupUri's stepwise packing) so the output is a complete record the
|
||||
# barcode can be rebuilt from.
|
||||
block=$(( version & 0x7 ))
|
||||
block=$(( (block << 4) | (reserved & 0xF) ))
|
||||
block=$(( (block << 8) | (category & 0xFF) ))
|
||||
block=$(( (block << 4) | (flag & 0xF) ))
|
||||
block=$(( (block << 27) | (pin & 0x7FFFFFF) ))
|
||||
block36="$(to_base36 "$block")"
|
||||
while [ ${#block36} -lt 9 ]; do block36="0${block36}"; done
|
||||
|
||||
printf 'Setup PIN: %08d\n' "$pin"
|
||||
printf 'Flag: %d\n' "$flag"
|
||||
printf ' Supports NFC: %s\n' "$(to_bool $(( flag & 1 )))"
|
||||
printf ' Supports IP: %s\n' "$(to_bool $(( flag & 2 )))"
|
||||
printf ' Supports BLE: %s\n' "$(to_bool $(( flag & 4 )))"
|
||||
printf ' Supports WAC/MFi: %s\n' "$(to_bool $(( flag & 8 )))"
|
||||
printf 'Category ID: %d (%s)\n' "$category" "$cat_name"
|
||||
printf 'Reserved: %d\n' "$reserved"
|
||||
printf 'Version: %d\n' "$version"
|
||||
printf 'Setup ID: %s\n' "${setup_id:-<none>}"
|
||||
printf 'Setup Payload: X-HM://%s%s\n' "$block36" "$setup_id"
|
||||
Reference in new issue
Block a user