-
Notifications
You must be signed in to change notification settings - Fork 140
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
examples: add FindMy example showing how to create an AirTag style BL…
…E beacon. The data format is be compatible with OpenHaystack and other similar ways to use the Apple FindMy network to track personal Bluetooth devices. Signed-off-by: deadprogram <[email protected]>
- Loading branch information
1 parent
5623054
commit 54be3e0
Showing
3 changed files
with
98 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// example showing how to use the Bluetooth package to advertise a FindMy compatible device. | ||
// aka AirTag | ||
// see https://github.com/biemster/FindMy | ||
// | ||
// To build: | ||
// tinygo flash -target nano-rp2040 -ldflags="-X main.PublicKey='SGVsbG8sIFdvcmxkIQ=='" ./examples/findmy | ||
// | ||
// For Linux: | ||
// go run ./examples/findmy SGVsbG8sIFdvcmxkIQ== | ||
package main | ||
|
||
import ( | ||
"encoding/base64" | ||
"errors" | ||
"time" | ||
|
||
"tinygo.org/x/bluetooth" | ||
) | ||
|
||
var adapter = bluetooth.DefaultAdapter | ||
|
||
func main() { | ||
time.Sleep(2 * time.Second) // wait for USB serial to be available | ||
|
||
key, err := getKeyData() | ||
if err != nil { | ||
panic("failed to get key data: " + err.Error()) | ||
} | ||
println("key is", PublicKey, "(", len(key), "bytes)") | ||
|
||
opts := bluetooth.AdvertisementOptions{ | ||
AdvertisementType: bluetooth.AdvertisingTypeNonConnInd, | ||
Interval: bluetooth.NewDuration(1285000 * time.Microsecond), // 1285ms | ||
ManufacturerData: []bluetooth.ManufacturerDataElement{findMyData(key)}, | ||
} | ||
|
||
must("enable BLE stack", adapter.Enable()) | ||
adapter.SetRandomAddress(bluetooth.MAC{key[5], key[4], key[3], key[2], key[1], key[0] | 0xC0}) | ||
adv := adapter.DefaultAdvertisement() | ||
|
||
println("advertising...") | ||
must("config adv", adv.Configure(opts)) | ||
|
||
println("starting...") | ||
must("start adv", adv.Start()) | ||
|
||
address, _ := adapter.Address() | ||
for { | ||
println("FindMy /", address.MAC.String()) | ||
time.Sleep(time.Second) | ||
} | ||
} | ||
|
||
func getKeyData() ([]byte, error) { | ||
val, err := base64.StdEncoding.DecodeString(PublicKey) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if len(val) != 28 { | ||
return nil, errors.New("public key must be 28 bytes long") | ||
} | ||
|
||
return val, nil | ||
} | ||
|
||
func findMyData(keyData []byte) bluetooth.ManufacturerDataElement { | ||
data := make([]byte, 0, 27) | ||
data = append(data, 0x12, 0x19) // Offline Finding type and length | ||
data = append(data, 0x10) // state | ||
data = append(data, keyData[6:]...) // copy last 22 bytes of public key | ||
data = append(data, (keyData[0] >> 6)) // First two bits | ||
data = append(data, 0x00) // Hint (0x00) | ||
|
||
return bluetooth.ManufacturerDataElement{ | ||
CompanyID: 0x004C, // Apple, Inc. | ||
Data: data, | ||
} | ||
} | ||
|
||
func must(action string, err error) { | ||
if err != nil { | ||
panic("failed to " + action + ": " + err.Error()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
//go:build tinygo | ||
|
||
package main | ||
|
||
// PublicKey is the public key of the device. Must be base64 encoded. | ||
var PublicKey string |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
//go:build !tinygo | ||
|
||
package main | ||
|
||
import "os" | ||
|
||
// PublicKey is the public key of the device. Must be base64 encoded. | ||
var PublicKey = os.Args[1] |