package main import ( "log" "time" "dim13.org/anki" "github.com/currantlabs/gatt" ) func onStateChange(d gatt.Device, s gatt.State) { sid := gatt.MustParseUUID(anki.ServiceUUID) log.Println("State", s) switch s { case gatt.StatePoweredOn: log.Println("Scan...") d.Scan([]gatt.UUID{sid}, false) default: d.StopScanning() } } func onDiscover(p gatt.Peripheral, a *gatt.Advertisement, rssi int) { //defer p.Device().StopScanning() sid := gatt.MustParseUUID(anki.ServiceUUID) for _, s := range a.Services { log.Println("Found", p.ID()) if s.Equal(sid) { log.Println("Connect", p.ID()) p.Device().Connect(p) } } } func onRead(w gatt.ResponseWriter, r *gatt.ReadRequest) { log.Println("READ", r) } func onConnect(p gatt.Peripheral, err error) { ss, err := p.DiscoverServices(nil) if err != nil { log.Println(err) return } for _, s := range ss { cs, err := p.DiscoverCharacteristics(nil, s) if err != nil { log.Println("Discover Service", err) return } for _, c := range cs { /* ds, err := p.DiscoverDescriptors(nil, c) if err != nil { log.Println("Discover Descriptors", err) return } for _, d := range ds { log.Println("Descriptor", d.UUID()) } */ if (c.Properties() & (gatt.CharNotify | gatt.CharIndicate)) != 0 { if err := p.SetNotifyValue(c, onNotify); err != nil { log.Println("Set notify", err) return } } if (c.Properties() & gatt.CharWrite) != 0 { //p.WriteCharacteristic(c, []byte{0x01, 0x90}, true) // sdk go func(c *gatt.Characteristic) { t := time.NewTicker(time.Second * 10) defer t.Stop() for range t.C { log.Println("Ping") p.WriteCharacteristic(c, []byte{0x01, 0x16}, true) // ping time.Sleep(10 * time.Second) } }(c) //p.WriteCharacteristic(c, []byte{0x01, 0x18}, true) // version //p.WriteCharacteristic(c, []byte{0x01, 0x1a}, true) // battery lc := &anki.VehicleLightConfig{} lm := &anki.VehicleMsgLightsPattern{} lc.Set(anki.LightFrontL, anki.EffectSteady, 10, 0, 0) lm.Set(*lc) lc.Set(anki.LightFrontR, anki.EffectSteady, 10, 0, 0) lm.Set(*lc) lc.Set(anki.LightTail, anki.EffectSteady, 10, 0, 0) lm.Set(*lc) lb := anki.Encode(lm) p.WriteCharacteristic(c, lb, true) time.Sleep(time.Second) ss := &anki.VehicleMsgSetSpeed{} ss.Set(500, 2500) b := anki.Encode(ss) p.WriteCharacteristic(c, b, true) } } } } func onNotify(c *gatt.Characteristic, b []byte, err error) { if err != nil { log.Println(c.UUID(), err) } id, payload := anki.SplitMsg(b) switch id { case anki.VehicleMsgV2CStatusUpdate: su := anki.VehicleMsgStatusUpdate{} anki.Decode(b, &su) log.Printf("%+v\n", su) case anki.VehicleMsgV2CLocalizationTransitionUpdate: tu := anki.VehicleMsgLocalizationTransitionUpdate{} anki.Decode(b, &tu) log.Printf("%+v\n", tu) case anki.VehicleMsgV2CLocalizationPositionUpdate: pu := anki.VehicleLocalizationPositionUpdate{} anki.Decode(b, &pu) log.Printf("%+v\n", pu) default: log.Printf("ID: %v | % X\n", id, payload) } } func onDisconnect(p gatt.Peripheral, err error) { log.Println("Disconnect", p.ID()) p.Device().CancelConnection(p) } func main() { d, err := gatt.NewDevice() if err != nil { log.Fatal(err) } d.Handle( gatt.PeripheralDiscovered(onDiscover), gatt.PeripheralConnected(onConnect), gatt.PeripheralDisconnected(onDisconnect), ) d.Init(onStateChange) select {} }