Esempio n. 1
0
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 {}
}
Esempio n. 2
0
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 {}
}