Skip to content

Instantly share code, notes, and snippets.

@Marcocanc
Created January 3, 2018 09:38
Show Gist options
  • Save Marcocanc/adbcc240bfbf7f34e804b55b2ee86f56 to your computer and use it in GitHub Desktop.
Save Marcocanc/adbcc240bfbf7f34e804b55b2ee86f56 to your computer and use it in GitHub Desktop.
Reverse engineering HomeKit QR Code decoding/encoding
import Foundation
func setupCodeFrom(uri: String) -> String {
let startIndex = uri.index(uri.startIndex, offsetBy: "X-HM://".count)
let endIndex = uri.index(uri.endIndex, offsetBy: -4)
var actualString = uri[startIndex..<endIndex]
let number = UInt(actualString, radix: 36)!
var code = String(format: "%08u", number & 0x7ffffff)
code.insert("-", at: code.index(code.startIndex, offsetBy: 3))
code.insert("-", at: code.index(code.startIndex, offsetBy: 6))
let category = HKCategory(rawValue: number >> 0x1f & 0xff)
let flags = number >> 0x1b & 0xf
let reserved = number >> 0x27 & 15
let version = number >> 0x2b & 7
return code
}
func setupCodeToURI(code: UInt) -> String {
let version: UInt = 0
let flags: UInt = 2
let reserved: UInt = 0
let category: HKCategory = .bridge
let resAndVer = reserved & 0xf | version << 0x4 & 0x70
let catResAndVer = category.rawValue & 0xff | (resAndVer & 0xff) << 0x8
let other = flags & 0xf & 0xff | catResAndVer << 0x4
let resnum = other << 0x1b | code & 0x7ffffff
var outString = String(resnum, radix: 36, uppercase: true)
while outString.count < 9 {
outString.insert("0", at: outString.startIndex)
}
return outString
}
setupCodeFrom(uri: "X-HM://0009N5SP0JJ3K")
setupCodeToURI(code: 23748153)
enum HKCategory: UInt {
case other = 1
case bridge = 2
case fan = 3
case garage = 4
case lightbulb = 5
case doorLock = 6
case outlet = 7
case `switch` = 8
case thermostat = 9
case sensor = 10
case securitySystem = 11
case door = 12
case window = 13
case windowCovering = 14
case programmableSwitch = 15
case rangeExtender = 16
case ipCamera = 17
case videoDoorBell = 18
case airPurifier = 19
case reserved = 20
}
@McOrLi1
Copy link

McOrLi1 commented Feb 9, 2018

hi,
are you sure both function return the match code / URI ?
here what i get

462-26-308
from
X-HM://0009N5SP0JJ3K
and
X-HM://00248GCJO
from
46226308

@justinshuls
Copy link

hi,
are you sure both function return the match code / URI ?
here what i get

462-26-308
from
X-HM://0009N5SP0JJ3K
and
X-HM://00248GCJO
from
46226308

Same result. Any solution?

@namannik
Copy link

Thanks for this gist. I tested it out on a new accessory that I unboxed today. This accessory's URI is much longer:

X-HM://0EBML5MNUXZEI07UG9503PZKTR0XK3K

This causes setupCodeFrom to raise an exception. I fixed it by ignoring the extra characters, changing line 5 to this:

let endIndex = uri.index(startIndex, offsetBy: 9)

(I assume the extra characters at the end are some sort of vendor-specific parameters used during setup.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment