func main() { cloud, err := NewdbusWrapper("/com/devicehive/cloud", "com.devicehive.cloud") if err != nil { log.Panic(err) } ble, err := NewdbusWrapper("/com/devicehive/bluetooth", "com.devicehive.bluetooth") ble.deviceMap = make(map[string]*deviceInfo) if err != nil { log.Panic(err) } enocean, err := NewdbusWrapper("/com/devicehive/enocean", "com.devicehive.enocean") if err != nil { log.Panic(err) } myMelody := NewMelody(ble) ble.RegisterHandler("PeripheralDiscovered", func(args ...interface{}) { mac := strings.ToLower(args[0].(string)) name := strings.ToLower(args[1].(string)) if _, ok := ble.scanMap[name]; ok { if _, ok := ble.deviceMap[mac]; !ok { log.Printf("Discovered new device [mac: %s, name: %s]", mac, name) ble.deviceLock.Lock() ble.deviceMap[mac] = &deviceInfo{name: name} ble.deviceLock.Unlock() } } cloud.SendNotification("PeripheralDiscovered", map[string]interface{}{ "mac": args[0].(string), "name": args[1].(string), "rssi": args[2].(int16), }, 100) }) ble.RegisterHandler("PeripheralConnected", func(args ...interface{}) { ble.deviceLock.Lock() if v, ok := ble.deviceMap[args[0].(string)]; ok { ble.SendInitCommands(args[0].(string), v) } ble.deviceLock.Unlock() cloud.SendNotification("PeripheralConnected", map[string]interface{}{ "mac": args[0].(string), }, 100) }) ble.RegisterHandler("PeripheralDisconnected", func(args ...interface{}) { cloud.SendNotification("PeripheralDisconnected", map[string]interface{}{ "mac": args[0].(string), }, 100) }) enocean.RegisterHandler("message_received", func(args ...interface{}) { log.Printf("Enocean message_received: %+v", args) v := args[0].(string) var res map[string]interface{} err := json.Unmarshal([]byte(v), &res) if err != nil { log.Printf("Error parsing enocean response: %s", err) return } state := "" sender, ok := res["sender"].(string) if !ok { return } r1, ok := res["R1"].(map[string]interface{}) if !ok { return } if int32(r1["raw_value"].(float64)) == 2 { state = "ON" } if int32(r1["raw_value"].(float64)) == 3 { state = "OFF" } cloud.SendNotification("EnoceanNotificationReceived", map[string]interface{}{ "sender": sender, "state": state, }, 1) }) ble.RegisterHandler("NotificationReceived", func(args ...interface{}) { uuid := strings.ToLower(args[1].(string)) mac := strings.ToLower(args[0].(string)) value := strings.ToLower(args[2].(string)) if _, ok := ble.readingsBuffer[mac]; !ok { ble.readingsBuffer[mac] = new([]float64) } // f000aa11 for old sensortag, f000aa81 for new sensortag if uuid == "f000aa1104514000b000000000000000" || uuid == "f000aa8104514000b000000000000000" { if len(*ble.readingsBuffer[mac]) > 9 { vS, _ := stats.VarS(*ble.readingsBuffer[mac]) cloud.SendNotification("NotificationReceived", map[string]interface{}{ "mac": mac, "uuid": uuid, "value": vS, }, 1) // log.Printf("Variance: [S: %v, P: %v]", vS, vP) ble.readingsBuffer[mac] = new([]float64) } else { r := *ble.readingsBuffer[mac] n := append(r, getAcceleration(value, uuid)) ble.readingsBuffer[mac] = &n // log.Printf("Acceleration buffer: %v", ble.readingsBuffer[mac]) } } else { cloud.SendNotification("NotificationReceived", map[string]interface{}{ "mac": mac, "uuid": uuid, "value": value, }, 1) } }) ble.RegisterHandler("IndicationReceived", func(args ...interface{}) { cloud.SendNotification("IndicationReceived", map[string]interface{}{ "mac": args[0].(string), "uuid": args[1].(string), "value": args[2].(string), }, 1) }) cloudHandlers := make(map[string]cloudCommandHandler) cloudHandlers["init"] = func(p map[string]interface{}) (map[string]interface{}, error) { return nil, ble.Init(p["mac"].(string), p["type"].(string)) } cloudHandlers["connect"] = func(p map[string]interface{}) (map[string]interface{}, error) { t, found := p["type"] // public or random random := false if found { switch { case t.(string) == "random": random = true case t.(string) == "public": random = false default: return nil, errors.New("Invalid type, should be random or public") } } return nil, ble.BleConnect(p["mac"].(string), random) } cloudHandlers["scan/start"] = func(map[string]interface{}) (map[string]interface{}, error) { return nil, ble.BleScanStart() } cloudHandlers["scan/stop"] = func(map[string]interface{}) (map[string]interface{}, error) { ble.BleScanStop() return nil, ble.BleScanStop() } cloudHandlers["gatt/read"] = func(p map[string]interface{}) (map[string]interface{}, error) { return ble.BleGattRead(p["mac"].(string), p["uuid"].(string)) } cloudHandlers["gatt/write"] = func(p map[string]interface{}) (map[string]interface{}, error) { _, err := ble.BleGattWrite(p["mac"].(string), p["uuid"].(string), p["value"].(string)) return nil, err } cloudHandlers["gatt/notifications"] = func(p map[string]interface{}) (map[string]interface{}, error) { _, err := ble.BleGattNotifications(p["mac"].(string), p["uuid"].(string), true) return nil, err } cloudHandlers["gatt/notifications/stop"] = func(p map[string]interface{}) (map[string]interface{}, error) { _, err := ble.BleGattNotifications(p["mac"].(string), p["uuid"].(string), false) return nil, err } cloudHandlers["gatt/indications"] = func(p map[string]interface{}) (map[string]interface{}, error) { _, err := ble.BleGattIndications(p["mac"].(string), p["uuid"].(string), true) return nil, err } cloudHandlers["gatt/indications/stop"] = func(p map[string]interface{}) (map[string]interface{}, error) { _, err := ble.BleGattIndications(p["mac"].(string), p["uuid"].(string), false) return nil, err } cloudHandlers["play"] = func(p map[string]interface{}) (map[string]interface{}, error) { mac := p["mac"].(string) if !ble.BleConnected(mac) { ble.BleConnect(mac, true) } return nil, myMelody.Play(mac, p["melody"].(string), int(p["bpm"].(float64))) } cloud.RegisterHandler("CommandReceived", func(args ...interface{}) { id := args[0].(uint32) command := args[1].(string) params := args[2].(string) var dat map[string]interface{} b := []byte(params) json.Unmarshal(b, &dat) if h, ok := cloudHandlers[command]; ok { res, err := h(dat) if err != nil { cloud.CloudUpdateCommand(id, fmt.Sprintf("ERROR: %s", err.Error()), nil) } else { cloud.CloudUpdateCommand(id, "success", res) } } else { log.Printf("Unhandled command: %s", command) } }) // Scan for devices per // go func() { // for { // ble.BleScanStart() // time.Sleep(5 * time.Second) // ble.BleScanStop() // time.Sleep(10 * time.Second) // } // }() go func() { for { for mac, _ := range ble.deviceMap { if !ble.BleConnected(mac) { err := ble.BleConnect(mac, false) if err != nil { log.Printf("Error while trying to connect: %s", err.Error()) } } } time.Sleep(3 * time.Second) } }() // Look for pre-configured devices // ble.Init("68c90b047306", "cc2650 sensortag") // ble.Init("", "satechiled-0") // ble.Init("", "delight") // ble.Init("", "pod") // dashMac := "c84998f6a543" // r, _ := ble.Connected(dashMac) // log.Printf("BleConnected: %v", r["value"].(bool)) // ble.BleConnect(dashMac, true) // r, _ = ble.Connected(dashMac) // log.Printf("BleConnected: %v", r["value"].(bool)) // // time.Sleep(5 * time.Second) // myMelody.Play(dashMac, "8cegCegCcgCceCgec", 60) select {} }
func main() { // parse command-line args confFile := "" flag.StringVar(&confFile, "conf", "", "YAML configuration for this demo") if !flag.Parsed() { flag.Parse() } sampleConf := Conf{} sampleConf.HeartRateSensorMac = "112233445566" sampleConf.LedMac = "665544332211" sampleConf.HighHeartRate = 75 sampleYaml, _ := yaml.Marshal(sampleConf) if confFile == "" { flag.PrintDefaults() fmt.Fprintf(os.Stderr, "Sample config:\n") fmt.Printf("%s", sampleYaml) return } conf := Conf{} // parse config yamlFile, err := ioutil.ReadFile(confFile) if err != nil { log.Panic(err) } err = yaml.Unmarshal(yamlFile, &conf) if err != nil { log.Panic(err) } // set defaults if conf.HighHeartRate == 0 { // value above which we switch to red conf.HighHeartRate = 80 } if conf.LedMac == "" || conf.HeartRateSensorMac == "" { fmt.Fprintf(os.Stderr, "LedMac or HeartRateSensorMac not set in config; sample config:\n") fmt.Printf("%s", sampleYaml) return } cloud, err := NewdbusWrapper("/com/devicehive/cloud", "com.devicehive.cloud") if err != nil { log.Panic(err) } ble, err := NewdbusWrapper("/com/devicehive/bluetooth", "com.devicehive.bluetooth") ble.deviceMap = make(map[string]*deviceInfo) if err != nil { log.Panic(err) } enocean, err := NewdbusWrapper("/com/devicehive/enocean", "com.devicehive.enocean") if err != nil { log.Panic(err) } myMelody := NewMelody(ble) // pulse LED based on heart rate; default of 0 disables until // we find a heart rate sensor heartRate := 0 ledMac := conf.LedMac heartSensorMac := conf.HeartRateSensorMac go func() { for { if heartRate > 0 && ble.BleConnected(ledMac) { log.Printf("heartRate=%d", heartRate) pulsePeriod := time.Duration(60*1000/heartRate) * time.Millisecond //log.Printf("pulsePeriod=%s, full=%s, dim=%s", pulsePeriod, pulsePeriod * 2/3, pulsePeriod * 1/3) RED := "0f0d0300ff00006400000000000067ffff" DIMRED := "0f0d0300ff00001e00000000000021ffff" GREEN := "0f0d030000ff006400000000000067ffff" DIMGREEN := "0f0d030000ff001e00000000000021ffff" if heartRate > conf.HighHeartRate { // RED ble.BleGattWrite(ledMac, "fff3", RED) time.Sleep(pulsePeriod * 2 / 3) // DIM RED ble.BleGattWrite(ledMac, "fff3", DIMRED) time.Sleep(pulsePeriod * 1 / 3) } else { // GREEN ble.BleGattWrite(ledMac, "fff3", GREEN) time.Sleep(pulsePeriod * 2 / 3) // DIM GREEN ble.BleGattWrite(ledMac, "fff3", DIMGREEN) time.Sleep(pulsePeriod * 1 / 3) } } else { time.Sleep(3 * time.Second) } } }() ble.RegisterHandler("PeripheralDiscovered", func(args ...interface{}) { mac := strings.ToLower(args[0].(string)) name := strings.ToLower(args[1].(string)) log.Printf("Discovered new device mac: %s, name: %s", mac, name) if _, ok := ble.scanMap[name]; ok { if _, ok := ble.deviceMap[mac]; !ok { log.Printf("Discovered new device [mac: %s, name: %s]", mac, name) ble.deviceLock.Lock() ble.deviceMap[mac] = &deviceInfo{name: name} ble.deviceLock.Unlock() } } log.Printf("PeripheralDiscovered mac=%s, name=%s", args[0].(string), args[1].(string)) cloud.SendNotification("PeripheralDiscovered", map[string]interface{}{ "mac": args[0].(string), "name": args[1].(string), "rssi": args[2].(int16), }, 100) }) ble.RegisterHandler("PeripheralConnected", func(args ...interface{}) { ble.deviceLock.Lock() if v, ok := ble.deviceMap[args[0].(string)]; ok { log.Printf("sending init commands for mac=%s, name=%s", args[0].(string), v.name) ble.SendInitCommands(args[0].(string), v) } ble.deviceLock.Unlock() log.Printf("PeripheralConnected mac=%s", args[0].(string)) cloud.SendNotification("PeripheralConnected", map[string]interface{}{ "mac": args[0].(string), }, 100) }) ble.RegisterHandler("PeripheralDisconnected", func(args ...interface{}) { log.Printf("PeripheralDisconnected mac=%s", args[0].(string)) cloud.SendNotification("PeripheralDisconnected", map[string]interface{}{ "mac": args[0].(string), }, 100) }) enocean.RegisterHandler("message_received", func(args ...interface{}) { log.Printf("Enocean message_received: %+v", args) v := args[0].(string) var res map[string]interface{} err := json.Unmarshal([]byte(v), &res) if err != nil { log.Printf("Error parsing enocean response: %s", err) return } state := "" sender, ok := res["sender"].(string) if !ok { return } r1, ok := res["R1"].(map[string]interface{}) if !ok { return } if int32(r1["raw_value"].(float64)) == 2 { state = "ON" } if int32(r1["raw_value"].(float64)) == 3 { state = "OFF" } cloud.SendNotification("EnoceanNotificationReceived", map[string]interface{}{ "sender": sender, "state": state, }, 1) }) ble.RegisterHandler("NotificationReceived", func(args ...interface{}) { uuid := strings.ToLower(args[1].(string)) mac := strings.ToLower(args[0].(string)) value := strings.ToLower(args[2].(string)) log.Printf("NotificationReceived mac=%s, uuid=%s, value=%s", mac, uuid, value) if _, ok := ble.readingsBuffer[mac]; !ok { ble.readingsBuffer[mac] = new([]float64) } // f000aa11 for old sensortag, f000aa81 for new sensortag if uuid == "f000aa1104514000b000000000000000" || uuid == "f000aa8104514000b000000000000000" { if len(*ble.readingsBuffer[mac]) > 9 { vS, _ := stats.VarS(*ble.readingsBuffer[mac]) cloud.SendNotification("NotificationReceived", map[string]interface{}{ "mac": mac, "uuid": uuid, "value": vS, }, 1) // log.Printf("Variance: [S: %v, P: %v]", vS, vP) ble.readingsBuffer[mac] = new([]float64) } else { r := *ble.readingsBuffer[mac] n := append(r, getAcceleration(value, uuid)) ble.readingsBuffer[mac] = &n // log.Printf("Acceleration buffer: %v", ble.readingsBuffer[mac]) } } else { // heart rate measurement if uuid == "2a37" { heartRate = parseHRate(value) } cloud.SendNotification("NotificationReceived", map[string]interface{}{ "mac": mac, "uuid": uuid, "value": value, }, 1) } }) ble.RegisterHandler("IndicationReceived", func(args ...interface{}) { cloud.SendNotification("IndicationReceived", map[string]interface{}{ "mac": args[0].(string), "uuid": args[1].(string), "value": args[2].(string), }, 1) }) cloudHandlers := make(map[string]cloudCommandHandler) cloudHandlers["init"] = func(p map[string]interface{}) (map[string]interface{}, error) { return nil, ble.Init(p["mac"].(string), p["type"].(string)) } cloudHandlers["connect"] = func(p map[string]interface{}) (map[string]interface{}, error) { t, found := p["type"] // public or random random := false if found { switch { case t.(string) == "random": random = true case t.(string) == "public": random = false default: return nil, errors.New("Invalid type, should be random or public") } } return nil, ble.BleConnect(p["mac"].(string), random) } cloudHandlers["scan/start"] = func(map[string]interface{}) (map[string]interface{}, error) { return nil, ble.BleScanStart() } cloudHandlers["scan/stop"] = func(map[string]interface{}) (map[string]interface{}, error) { ble.BleScanStop() return nil, ble.BleScanStop() } cloudHandlers["gatt/read"] = func(p map[string]interface{}) (map[string]interface{}, error) { return ble.BleGattRead(p["mac"].(string), p["uuid"].(string)) } cloudHandlers["gatt/write"] = func(p map[string]interface{}) (map[string]interface{}, error) { _, err := ble.BleGattWrite(p["mac"].(string), p["uuid"].(string), p["value"].(string)) return nil, err } cloudHandlers["gatt/notifications"] = func(p map[string]interface{}) (map[string]interface{}, error) { _, err := ble.BleGattNotifications(p["mac"].(string), p["uuid"].(string), true) return nil, err } cloudHandlers["gatt/notifications/stop"] = func(p map[string]interface{}) (map[string]interface{}, error) { _, err := ble.BleGattNotifications(p["mac"].(string), p["uuid"].(string), false) return nil, err } cloudHandlers["gatt/indications"] = func(p map[string]interface{}) (map[string]interface{}, error) { _, err := ble.BleGattIndications(p["mac"].(string), p["uuid"].(string), true) return nil, err } cloudHandlers["gatt/indications/stop"] = func(p map[string]interface{}) (map[string]interface{}, error) { _, err := ble.BleGattIndications(p["mac"].(string), p["uuid"].(string), false) return nil, err } cloudHandlers["play"] = func(p map[string]interface{}) (map[string]interface{}, error) { mac := p["mac"].(string) if !ble.BleConnected(mac) { ble.BleConnect(mac, true) } return nil, myMelody.Play(mac, p["melody"].(string), int(p["bpm"].(float64))) } cloud.RegisterHandler("CommandReceived", func(args ...interface{}) { id := args[0].(uint32) command := args[1].(string) params := args[2].(string) var dat map[string]interface{} b := []byte(params) json.Unmarshal(b, &dat) if h, ok := cloudHandlers[command]; ok { res, err := h(dat) if err != nil { cloud.CloudUpdateCommand(id, fmt.Sprintf("ERROR: %s", err.Error()), nil) } else { cloud.CloudUpdateCommand(id, "success", res) } } else { log.Printf("Unhandled command: %s", command) } }) // do a single scan on startup log.Printf("Starting scan...") ble.BleScanStart() time.Sleep(5 * time.Second) log.Printf("Settling after scan...") ble.BleScanStop() time.Sleep(1 * time.Second) // Scan for devices per // go func() { // for { // ble.BleScanStart() // time.Sleep(5 * time.Second) // ble.BleScanStop() // time.Sleep(10 * time.Second) // } // }() go func() { for { for mac, _ := range ble.deviceMap { if !ble.BleConnected(mac) { log.Printf("Connecting mac=%s", mac) err := ble.BleConnect(mac, false) if err != nil { log.Printf("Error while trying to connect: %s", err.Error()) } } } time.Sleep(3 * time.Second) } }() // Look for pre-configured devices // ble.Init("68c90b047306", "cc2650 sensortag") // ble.Init("", "satechiled-0") // ble.Init("", "delight") // ble.Init("", "pod") // dashMac := "c84998f6a543" // r, _ := ble.Connected(dashMac) // log.Printf("BleConnected: %v", r["value"].(bool)) // ble.BleConnect(dashMac, true) // r, _ = ble.Connected(dashMac) // log.Printf("BleConnected: %v", r["value"].(bool)) // // time.Sleep(5 * time.Second) // myMelody.Play(dashMac, "8cegCegCcgCceCgec", 60) // prefix logs with short filename log.SetFlags(log.Flags() | log.Lshortfile) // connect just to this particular LED; NB: device name is actually // SATECHILED-0 ble.Init(ledMac, "satechiled-0") // this should connect to all LEDs of this type, but no // PeripheralConnected is triggered in this case //ble.Init("", "SATECHILED-0") // reported device name is empty; looking manually at GAP's 0x2a00, it // is "Polar H7 637B4E12"; just use polar-h7 ble.Init(heartSensorMac, "polar-h7") select {} }