Ejemplo n.º 1
0
func NewDevice(device common.Device) {
	if light, ok := device.(common.Light); ok {
		hkLight := GetHKLight(light)

		hkLight.sub, _ = light.NewSubscription()
		for {
			event := <-hkLight.sub.Events()
			switch event.(type) {
			case common.EventUpdateLabel:
				log.Printf("[INFO] Updated Label for %s to %s", hkLight.accessory.Name(), event.(common.EventUpdateLabel).Label)
				// TODO Add support for label changes to HomeControl
				log.Printf("[INFO] Unsupported by HomeControl")
			case common.EventUpdatePower:
				log.Printf("[INFO] Updated Power for %s", hkLight.accessory.Name())
				hkLight.light.SetOn(event.(common.EventUpdatePower).Power)
			case common.EventUpdateColor:
				log.Printf("[INFO] Updated Color for %s", hkLight.accessory.Name())

				hue, saturation, brightness := ConvertLIFXColor(event.(common.EventUpdateColor).Color)

				hkLight.light.SetHue(hue)
				hkLight.light.SetSaturation(saturation)
				hkLight.light.SetBrightness(int(brightness))

			default:
				log.Printf("[INFO] Unknown Device Event: %T", event)
			}
		}
	} else {
		log.Println("[INFO] Unsupported Device")
	}
}
Ejemplo n.º 2
0
func (handler *Characteristics) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	var res io.Reader
	var err error

	handler.mutex.Lock()
	switch request.Method {
	case netio.MethodGET:
		log.Printf("[VERB] %v GET /characteristics", request.RemoteAddr)
		request.ParseForm()
		res, err = handler.controller.HandleGetCharacteristics(request.Form)
	case netio.MethodPUT:
		log.Printf("[VERB] %v PUT /characteristics", request.RemoteAddr)
		session := handler.context.GetSessionForRequest(request)
		conn := session.Connection()
		err = handler.controller.HandleUpdateCharacteristics(request.Body, conn)
	default:
		log.Println("[WARN] Cannot handle HTTP method", request.Method)
	}
	handler.mutex.Unlock()

	if err != nil {
		log.Println("[ERRO]", err)
		response.WriteHeader(http.StatusInternalServerError)
	} else {
		if res != nil {
			response.Header().Set("Content-Type", netio.HTTPContentTypeHAPJson)
			wr := netio.NewChunkedWriter(response, 2048)
			b, _ := ioutil.ReadAll(res)
			wr.Write(b)
		} else {
			response.WriteHeader(http.StatusNoContent)
		}
	}
}
Ejemplo n.º 3
0
// Handles event which are sent when pairing with a device is added or removed
func (t *ipTransport) Handle(ev interface{}) {
	switch ev.(type) {
	case event.DevicePaired:
		log.Printf("[INFO] Event: paired with device")
		t.updateMDNSReachability()
	case event.DeviceUnpaired:
		log.Printf("[INFO] Event: unpaired with device")
		t.updateMDNSReachability()
	default:
		break
	}
}
Ejemplo n.º 4
0
func main() {
	log.Println("[ERRO] Just an error")
	log.Printf("[ERRO] Just an error %d", 1)
	log.Println("[WARN] Just a warning")
	log.Printf("[WARN] Just a warning %d", 1)
	log.Println("[INFO] Just an info")
	log.Printf("[INFO] Just an info %d", 1)
	log.Println("[VERB] Just an info")
	log.Printf("[VERB] Just an info %d", 1)

	log.Error = false
	log.Warn = false
	log.Info = false
	log.Verbose = false

	log.Println("MUST be displayed")
	log.Println("[ERRO] MUST NOT be displayed")
	log.Printf("[ERRO] MUST NOT be displayed %d", 1)
	log.Println("[WARN] MUST NOT be displayed")
	log.Printf("[WARN] MUST NOT be displayed %d", 1)
	log.Println("[INFO] MUST NOT be displayed")
	log.Printf("[INFO] MUST NOT be displayed %d", 1)
	log.Println("[VERB] MUST NOT be displayed")
	log.Printf("[VERB] MUST NOT be displayed %d", 1)
}
Ejemplo n.º 5
0
// HandleUpdateCharacteristics handles an update characteristic request. The bytes must represent
// a data.Characteristics json.
func (ctr *CharacteristicController) HandleUpdateCharacteristics(r io.Reader, conn net.Conn) error {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}

	var chars data.Characteristics
	err = json.Unmarshal(b, &chars)
	if err != nil {
		return err
	}

	log.Println("[VERB]", string(b))

	for _, c := range chars.Characteristics {
		characteristic := ctr.GetCharacteristic(c.AccessoryID, c.ID)
		if characteristic == nil {
			log.Printf("[ERRO] Could not find characteristic with aid %d and iid %d\n", c.AccessoryID, c.ID)
			continue
		}

		if c.Value != nil {
			characteristic.SetValueFromConnection(c.Value, conn)
		}

		if events, ok := c.Events.(bool); ok == true {
			characteristic.SetEventsEnabled(events)
		}
	}

	return err
}
Ejemplo n.º 6
0
func (handler *PairVerify) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	log.Printf("[VERB] %v POST /pair-verify", request.RemoteAddr)
	response.Header().Set("Content-Type", netio.HTTPContentTypePairingTLV8)

	key := handler.context.GetConnectionKey(request)
	session := handler.context.Get(key).(netio.Session)
	controller := session.PairVerifyHandler()
	if controller == nil {
		log.Println("[VERB] Create new pair verify controller")
		controller = pair.NewVerifyServerController(handler.database, handler.context)
		session.SetPairVerifyHandler(controller)
	}

	res, err := pair.HandleReaderForHandler(request.Body, controller)

	if err != nil {
		log.Println(err)
		response.WriteHeader(http.StatusInternalServerError)
	} else {
		io.Copy(response, res)
		// Setup secure session
		if controller.KeyVerified() == true {
			// Verification is done
			// Switch to secure session
			secureSession, err := crypto.NewSecureSessionFromSharedKey(controller.SharedKey())
			if err != nil {
				log.Println("[ERRO] Could not setup secure session.", err)
			} else {
				log.Println("[VERB] Setup secure session")
			}
			session.SetCryptographer(secureSession)
		}
	}
}
Ejemplo n.º 7
0
func (handler *PairSetup) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	log.Printf("[VERB] %v POST /pair-setup", request.RemoteAddr)
	response.Header().Set("Content-Type", netio.HTTPContentTypePairingTLV8)

	key := handler.context.GetConnectionKey(request)
	session := handler.context.Get(key).(netio.Session)
	controller := session.PairSetupHandler()
	if controller == nil {
		log.Println("[VERB] Create new pair setup controller")
		var err error
		controller, err = pair.NewSetupServerController(handler.device, handler.database)
		if err != nil {
			log.Println(err)
		}

		session.SetPairSetupHandler(controller)
	}

	res, err := pair.HandleReaderForHandler(request.Body, controller)

	if err != nil {
		log.Println("[ERRO]", err)
		response.WriteHeader(http.StatusInternalServerError)
	} else {
		io.Copy(response, res)
	}
}
Ejemplo n.º 8
0
func (endpoint *Pairing) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	log.Printf("[VERB] %v POST /pairings", request.RemoteAddr)
	response.Header().Set("Content-Type", netio.HTTPContentTypePairingTLV8)

	var err error
	var in util.Container
	var out util.Container

	if in, err = util.NewTLV8ContainerFromReader(request.Body); err == nil {
		out, err = endpoint.controller.Handle(in)
	}

	if err != nil {
		log.Println(err)
		response.WriteHeader(http.StatusInternalServerError)
	} else {
		io.Copy(response, out.BytesBuffer())

		// Send events based on pairing method type
		b := in.GetByte(pair.TagPairingMethod)
		switch pair.PairMethodType(b) {
		case pair.PairingMethodDelete: // pairing removed
			endpoint.emitter.Emit(event.DeviceUnpaired{})

		case pair.PairingMethodAdd: // pairing added
			endpoint.emitter.Emit(event.DevicePaired{})

		}
	}
}
Ejemplo n.º 9
0
func setupHive() {
	// Connect to Hive
	var err error
	hiveHome, err = hive.Connect(hive.Config{
		Username:        username,
		Password:        password,
		RefreshInterval: 30 * time.Second,
	})

	if err != nil {
		log.Fatal(err)
		return
	}

	hiveHome.HandleStateChange(func(state *hive.State) {
		accessoryUpdate.Lock()
		defer accessoryUpdate.Unlock()

		log.Printf("[VERB] Syncing status with HomeKit\n")

		hotWaterSwitch.Switch.On.SetValue(state.HotWater)

		heatingBoostSwitch.Switch.On.SetValue(state.HeatingBoosted)

		thermostat.Thermostat.CurrentTemperature.SetValue(state.CurrentTemp)
		thermostat.Thermostat.TargetTemperature.SetValue(state.TargetTemp)
		thermostat.Thermostat.CurrentHeatingCoolingState.SetValue(modeForHiveMode(state.CurrentHeatingMode))
		thermostat.Thermostat.TargetHeatingCoolingState.SetValue(modeForHiveMode(state.TargetHeatingMode))
	})
}
Ejemplo n.º 10
0
// Handle processes a container to pair with a new client without going through the pairing process.
func (c *PairingController) Handle(cont util.Container) (util.Container, error) {
	method := pairMethodType(cont.GetByte(TagPairingMethod))
	username := cont.GetString(TagUsername)
	publicKey := cont.GetBytes(TagPublicKey)

	log.Println("[VERB] ->   Method:", method)
	log.Println("[VERB] -> Username:"******"[VERB] ->     LTPK:", publicKey)

	entity := db.NewEntity(username, publicKey, nil)

	switch method {
	case PairingMethodDelete:
		log.Printf("[INFO] Remove LTPK for client '%s'\n", username)
		c.database.DeleteEntity(entity)
	case PairingMethodAdd:
		err := c.database.SaveEntity(entity)
		if err != nil {
			log.Println("[ERRO]", err)
			return nil, err
		}
	default:
		return nil, fmt.Errorf("Invalid pairing method type %v", method)
	}

	out := util.NewTLV8Container()
	out.SetByte(TagSequence, 0x2)

	return out, nil
}
Ejemplo n.º 11
0
func Connect() {
	var wg sync.WaitGroup

	authenticate()

	urlString := fmt.Sprintf("http://%s/sensors", viper.GetString("Host"))
	req, _ := newRequest("GET", urlString, nil)

	res, _ := client.Do(req)
	defer res.Body.Close()
	jsonBytes, _ := ioutil.ReadAll(res.Body)

	jsonParsed, _ := gabs.ParseJSON(jsonBytes)
	children, _ := jsonParsed.Search("sensors").Children()
	wg.Add(len(children))
	for _, child := range children {
		port := uint8(child.Path("port").Data().(float64))
		output := child.Path("output").Data().(float64) != 0

		log.Printf("[INFO] Discovered Sensor %d", port)

		sensor := &MPSensor{port, output}
		go NewSensor(wg, sensor)
	}

	wg.Wait()
}
Ejemplo n.º 12
0
func NewSensor(wg sync.WaitGroup, sensor *MPSensor) {
	defer wg.Done()

	hkSwitch := GetHKSwitch(sensor)
	hkSwitch.ticker = time.NewTicker(30 * time.Second)

	for {
		<-hkSwitch.ticker.C

		log.Printf("[INFO] Updating %s", hkSwitch.accessory.Info.Name.GetValue())

		urlString := fmt.Sprintf("http://%s/sensors/%d", viper.GetString("Host"), hkSwitch.sensor.port)
		req, _ := newRequest("GET", urlString, nil)

		res, _ := client.Do(req)
		defer res.Body.Close()
		jsonBytes, _ := ioutil.ReadAll(res.Body)

		jsonParsed, _ := gabs.ParseJSON(jsonBytes)
		output := jsonParsed.Path("sensors").Index(0).Path("output").Data().(float64) != 0

		hkSwitch.sensor.output = output
		hkSwitch.accessory.Switch.On.SetValue(output)
	}
}
Ejemplo n.º 13
0
func (h *Hive) getStatus(force bool) {
	log.Printf("[VERB] Refreshing Hive status")
	h.refreshing.Lock()
	defer h.refreshing.Unlock()

	now := time.Now().Unix()
	if force == false && h.lastRefresh > now-avoidRetrySeconds {
		return
	}

	res, err := h.getHTTP(h.baseURL + "/omnia/nodes")
	if err != nil {
		log.Printf("[WARN] Unable to get nodes info: %s", err)
		return
	}
	defer res.Body.Close()

	decoder := json.NewDecoder(res.Body)
	var reply nodesReply
	err = decoder.Decode(&reply)

	if err != nil {
		log.Printf("[WARN] Unable to get nodes info: %s", err)
		return
	}

	state := newStateFromNodes(reply.Nodes)
	if err != nil {
		log.Printf("[WARN] Unable to extract state from reply: %s", err)
		return
	}

	h.lastState = *state
	if h.stateChangeHandler != nil {
		go h.stateChangeHandler(state)
	}

	h.lastRefresh = now
}
Ejemplo n.º 14
0
func (handler *Pairing) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	log.Printf("[VERB] %v POST /pairings", request.RemoteAddr)
	response.Header().Set("Content-Type", netio.HTTPContentTypePairingTLV8)

	res, err := pair.HandleReaderForHandler(request.Body, handler.controller)

	if err != nil {
		log.Println(err)
		response.WriteHeader(http.StatusInternalServerError)
	} else {
		io.Copy(response, res)
	}
}
Ejemplo n.º 15
0
func GetHKSwitch(sensor *MPSensor) *HKSwitch {
	hkSwitch, found := switches[sensor.port]
	if found {
		return hkSwitch
	}

	label := fmt.Sprintf("mPower Port %d", sensor.port)
	log.Printf("[INFO] Creating New HKSwitch for %s", label)

	info := accessory.Info{
		Name:         label,
		Manufacturer: "Ubiquiti Networks",
	}

	acc := accessory.NewSwitch(info)
	acc.Switch.On.SetValue(sensor.output)

	config := hc.Config{Pin: pin}
	transport, err := hc.NewIPTransport(config, acc.Accessory)
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		transport.Start()
	}()

	hkSwitch = &HKSwitch{acc, sensor, nil, transport}
	switches[sensor.port] = hkSwitch

	acc.OnIdentify(func() {
		timeout := 1 * time.Second

		for i := 0; i < 4; i++ {
			ToggleSensor(sensor)
			time.Sleep(timeout)
		}
	})

	acc.Switch.On.OnValueRemoteUpdate(func(on bool) {
		SetOutput(sensor, on)
	})

	return hkSwitch
}
Ejemplo n.º 16
0
func (endpoint *PairVerify) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	log.Printf("[VERB] %v POST /pair-verify", request.RemoteAddr)
	response.Header().Set("Content-Type", netio.HTTPContentTypePairingTLV8)

	key := endpoint.context.GetConnectionKey(request)
	session := endpoint.context.Get(key).(netio.Session)
	ctlr := session.PairVerifyHandler()
	if ctlr == nil {
		log.Println("[VERB] Create new pair verify controller")
		ctlr = pair.NewVerifyServerController(endpoint.database, endpoint.context)
		session.SetPairVerifyHandler(ctlr)
	}

	var err error
	var in util.Container
	var out util.Container
	var secSession crypto.Cryptographer

	if in, err = util.NewTLV8ContainerFromReader(request.Body); err == nil {
		out, err = ctlr.Handle(in)
	}

	if err != nil {
		log.Println(err)
		response.WriteHeader(http.StatusInternalServerError)
	} else {
		io.Copy(response, out.BytesBuffer())

		// When key verification is done, switch to a secure session
		// based on the negotiated shared session key
		b := out.GetByte(pair.TagSequence)
		switch pair.VerifyStepType(b) {
		case pair.VerifyStepFinishResponse:
			if secSession, err = crypto.NewSecureSessionFromSharedKey(ctlr.SharedKey()); err == nil {
				log.Println("[VERB] Setup secure session")
				session.SetCryptographer(secSession)
			} else {
				log.Println("[ERRO] Could not setup secure session.", err)
			}
		}
	}
}
Ejemplo n.º 17
0
func (t *ipTransport) notifyListener(a *accessory.Accessory, c *characteristic.Characteristic, except net.Conn) {
	conns := t.context.ActiveConnections()
	for _, conn := range conns {
		if conn == except {
			continue
		}
		resp, err := event.New(a, c)
		if err != nil {
			log.Fatal(err)
		}

		// Write response into buffer to replace HTTP protocol
		// specifier with EVENT as required by HAP
		var buffer = new(bytes.Buffer)
		resp.Write(buffer)
		bytes, err := ioutil.ReadAll(buffer)
		bytes = event.FixProtocolSpecifier(bytes)
		log.Printf("[VERB] %s <- %s", conn.RemoteAddr(), string(bytes))
		conn.Write(bytes)
	}
}
Ejemplo n.º 18
0
// HandleGetCharacteristics handles a get characteristic request.
func (ctr *CharacteristicController) HandleGetCharacteristics(form url.Values) (io.Reader, error) {
	var b bytes.Buffer
	aid, cid, err := ParseAccessoryAndCharacterID(form.Get("id"))
	containerChar := ctr.GetCharacteristic(aid, cid)
	if containerChar == nil {
		log.Printf("[WARN] No characteristic found with aid %d and iid %d\n", aid, cid)
		return &b, nil
	}

	chars := data.NewCharacteristics()
	char := data.Characteristic{AccessoryID: aid, ID: cid, Value: containerChar.GetValue(), Events: containerChar.EventsEnabled()}
	chars.AddCharacteristic(char)

	result, err := json.Marshal(chars)
	if err != nil {
		log.Println("[ERRO]", err)
	}

	b.Write(result)
	return &b, err
}
Ejemplo n.º 19
0
func (endpoint *PairSetup) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	log.Printf("[VERB] %v POST /pair-setup", request.RemoteAddr)
	response.Header().Set("Content-Type", netio.HTTPContentTypePairingTLV8)

	var err error
	var in util.Container
	var out util.Container

	key := endpoint.context.GetConnectionKey(request)
	session := endpoint.context.Get(key).(netio.Session)
	ctrl := session.PairSetupHandler()
	if ctrl == nil {
		log.Println("[VERB] Create new pair setup controller")

		if ctrl, err = pair.NewSetupServerController(endpoint.device, endpoint.database); err != nil {
			log.Println(err)
		}

		session.SetPairSetupHandler(ctrl)
	}

	if in, err = util.NewTLV8ContainerFromReader(request.Body); err == nil {
		out, err = ctrl.Handle(in)
	}

	if err != nil {
		log.Println("[ERRO]", err)
		response.WriteHeader(http.StatusInternalServerError)
	} else {
		io.Copy(response, out.BytesBuffer())

		// Send event when key exchange is done
		b := out.GetByte(pair.TagSequence)
		switch pair.PairStepType(b) {
		case pair.PairStepKeyExchangeResponse:
			endpoint.emitter.Emit(event.DevicePaired{})
		}
	}
}
Ejemplo n.º 20
0
func (handler *Accessories) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	log.Printf("[VERB] %v GET /accessories", request.RemoteAddr)
	response.Header().Set("Content-Type", netio.HTTPContentTypeHAPJson)

	handler.mutex.Lock()
	res, err := handler.controller.HandleGetAccessories(request.Body)
	handler.mutex.Unlock()

	if err != nil {
		log.Println("[ERRO]", err)
		response.WriteHeader(http.StatusInternalServerError)
	} else {
		// Write the data in chunks of 2048 bytes
		// http.ResponseWriter should do this already, but crashes because of an unkown reason
		wr := netio.NewChunkedWriter(response, 2048)
		b, _ := ioutil.ReadAll(res)
		log.Println("[VERB]", string(b))
		_, err := wr.Write(b)
		if err != nil {
			log.Println("[ERRO]", err)
		}
	}
}
Ejemplo n.º 21
0
func Connect() {
	client, err := golifx.NewClient(&protocol.V2{Reliable: true})
	if err != nil {
		log.Fatalf("[ERR] Failed to initiliaze the client: %s", err)
	}

	client.SetDiscoveryInterval(30 * time.Second)

	sub, _ := client.NewSubscription()
	for {
		event := <-sub.Events()
		switch event.(type) {
		case common.EventNewLocation:
			log.Printf("[INFO] Discovered Location %s", event.(common.EventNewLocation).Location.GetLabel())
		case common.EventNewGroup:
			log.Printf("[INFO] Discovered Group %s", event.(common.EventNewGroup).Group.GetLabel())
		case common.EventNewDevice:
			label, _ := event.(common.EventNewDevice).Device.GetLabel()
			log.Printf("[INFO] Discovered Device %s", label)

			go NewDevice(event.(common.EventNewDevice).Device)

		case common.EventExpiredLocation:
			log.Printf("[INFO] Expired Location %s", event.(common.EventExpiredLocation).Location.GetLabel())
		case common.EventExpiredGroup:
			log.Printf("[INFO] Expired Group %s", event.(common.EventExpiredGroup).Group.GetLabel())
		case common.EventExpiredDevice:
			label, _ := event.(common.EventExpiredDevice).Device.GetLabel()
			log.Printf("[INFO] Expired Device %s", label)

			ExpireDevice(event.(common.EventExpiredDevice).Device)

		default:
			log.Printf("[INFO] Unknown Client Event: %T", event)
		}
	}
}
Ejemplo n.º 22
0
func GetHKLight(light common.Light) *HKLight {
	hkLight, found := lights[light.ID()]
	if found {
		return hkLight
	}

	label, _ := light.GetLabel()
	log.Printf("[INFO] Creating New HKLight for %s", label)

	info := accessory.Info{
		Name:         label,
		Manufacturer: "LIFX",
	}

	acc := accessory.NewLightbulb(info)

	power, _ := light.GetPower()
	acc.Lightbulb.On.SetValue(power)

	color, _ := light.GetColor()
	hue, saturation, brightness := ConvertLIFXColor(color)

	acc.Lightbulb.Brightness.SetValue(int(brightness))
	acc.Lightbulb.Saturation.SetValue(saturation)
	acc.Lightbulb.Hue.SetValue(hue)

	config := hc.Config{Pin: pin}
	transport, err := hc.NewIPTransport(config, acc.Accessory)
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		transport.Start()
	}()

	hkLight = &HKLight{acc, transport, nil}
	lights[light.ID()] = hkLight

	acc.OnIdentify(func() {
		timeout := 1 * time.Second

		for i := 0; i < 4; i++ {
			ToggleLight(light)
			time.Sleep(timeout)
		}
	})

	acc.Lightbulb.On.OnValueRemoteUpdate(func(power bool) {
		log.Printf("[INFO] Changed State for %s", label)
		light.SetPowerDuration(power, transitionDuration)
	})

	updateColor := func(light common.Light) {
		currentPower, _ := light.GetPower()

		// HAP: [0...360]
		// LIFX: [0...MAX_UINT16]
		hue := acc.Lightbulb.Hue.GetValue()

		// HAP: [0...100]
		// LIFX: [0...MAX_UINT16]
		saturation := acc.Lightbulb.Saturation.GetValue()

		// HAP: [0...100]
		// LIFX: [0...MAX_UINT16]
		brightness := acc.Lightbulb.Brightness.GetValue()

		// [HSBKKelvinMin..HSBKKelvinMax]
		kelvin := HSBKKelvinDefault

		lifxHue := math.MaxUint16 * float64(hue) / float64(HueMax)
		lifxSaturation := math.MaxUint16 * float64(saturation) / float64(SaturationMax)
		lifxBrightness := math.MaxUint16 * float64(brightness) / float64(BrightnessMax)

		color := common.Color{
			uint16(lifxHue),
			uint16(lifxSaturation),
			uint16(lifxBrightness),
			kelvin,
		}

		light.SetColor(color, transitionDuration)

		if brightness > 0 && !currentPower {
			log.Printf("[INFO] Color changed for %s, turning on power.", label)
			light.SetPowerDuration(true, transitionDuration)
		} else if brightness == 0 && currentPower {
			log.Printf("[INFO] Color changed for %s, but brightness = 0 turning off power.", label)
			light.SetPower(false)
		}
	}

	acc.Lightbulb.Hue.OnValueRemoteUpdate(func(value float64) {
		log.Printf("[INFO] Changed Hue for %s to %f", label, value)
		updateColor(light)
	})

	acc.Lightbulb.Saturation.OnValueRemoteUpdate(func(value float64) {
		log.Printf("[INFO] Changed Saturation for %s to %f", label, value)
		updateColor(light)
	})

	acc.Lightbulb.Brightness.OnValueRemoteUpdate(func(value int) {
		log.Printf("[INFO] Changed Brightness for %s to %d", label, value)
		updateColor(light)
	})

	return hkLight
}
Ejemplo n.º 23
0
func hotWaterStateChangeRequest(on bool) {
	err := hiveHome.ToggleHotWater(on, time.Minute*time.Duration(hotWaterDuration))
	if err != nil {
		log.Printf("[WARN] Unable to toggle hot water: %v\n", err)
	}
}
Ejemplo n.º 24
0
func targetTempChangeRequest(temp float64) {
	err := hiveHome.SetTargetTemp(temp)
	if err != nil {
		log.Printf("[WARN] Unable to set target temperature: %v\n", err)
	}
}
Ejemplo n.º 25
0
func heatingBoostStateChangeRequest(on bool) {
	err := hiveHome.ToggleHeatingBoost(on, time.Minute*time.Duration(boostDuration))
	if err != nil {
		log.Printf("[WARN] Unable to set heating boost: %v\n", err)
	}
}
Ejemplo n.º 26
0
func GetHKLight(light common.Light) *HKLight {
	hkLight, found := lights[light.ID()]
	if found {
		return hkLight
	}

	label, _ := light.GetLabel()
	log.Printf("[INFO] Creating New HKLight for %s", label)

	info := model.Info{
		Name:         label,
		Manufacturer: "LIFX",
	}

	lightBulb := accessory.NewLightBulb(info)

	power, _ := light.GetPower()
	lightBulb.SetOn(power)

	color, _ := light.GetColor()
	hue, saturation, brightness := ConvertLIFXColor(color)

	lightBulb.SetBrightness(int(brightness))
	lightBulb.SetSaturation(saturation)
	lightBulb.SetHue(hue)

	transport, err := hap.NewIPTransport(pin, lightBulb.Accessory)
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		transport.Start()
	}()

	hkLight = &HKLight{lightBulb.Accessory, nil, transport, lightBulb}
	lights[light.ID()] = hkLight

	lightBulb.OnIdentify(func() {
		timeout := 1 * time.Second

		for i := 0; i < 4; i++ {
			ToggleLight(light)
			time.Sleep(timeout)
		}
	})

	lightBulb.OnStateChanged(func(power bool) {
		log.Printf("[INFO] Changed State for %s", label)
		light.SetPower(power)
	})

	updateColor := func(light common.Light) {
		// HAP: [0...360]
		// LIFX: [0...MAX_UINT16]
		hue := lightBulb.GetHue()

		// HAP: [0...100]
		// LIFX: [0...MAX_UINT16]
		saturation := lightBulb.GetSaturation()

		// HAP: [0...100]
		// LIFX: [0...MAX_UINT16]
		brightness := lightBulb.GetBrightness()

		// [HSBKKelvinMin..HSBKKelvinMax]
		kelvin := HSBKKelvinDefault

		lifxHue := math.MaxUint16 * float64(hue) / float64(characteristic.MaxHue)
		lifxSaturation := math.MaxUint16 * float64(saturation) / float64(characteristic.MaxSaturation)
		lifxBrightness := math.MaxUint16 * float64(brightness) / float64(characteristic.MaxBrightness)

		color := common.Color{
			uint16(lifxHue),
			uint16(lifxSaturation),
			uint16(lifxBrightness),
			kelvin,
		}

		light.SetColor(color, 500*time.Millisecond)
	}

	lightBulb.OnHueChanged(func(value float64) {
		log.Printf("[INFO] Changed Hue for %s to %d", label, value)
		updateColor(light)
	})

	lightBulb.OnSaturationChanged(func(value float64) {
		log.Printf("[INFO] Changed Saturation for %s to %d", label, value)
		updateColor(light)
	})

	lightBulb.OnBrightnessChanged(func(value int) {
		log.Printf("[INFO] Changed Brightness for %s to %d", label, value)
		updateColor(light)
	})

	return hkLight
}
Ejemplo n.º 27
0
// SetTargetHeatMode sets the desired heating mode on the Hive
func (h *Hive) SetTargetHeatMode(mode HeatCoolMode) error {
	log.Printf("[INFO] Changing HeatCoolMode is unsupported at this time\n")
	return nil
}
Ejemplo n.º 28
0
// Client -> Server
// - encrypted tlv8: entity ltpk, entity name and signature (of H, entity name, ltpk)
// - auth tag (mac)
//
// Server
// - Validate signature of encrpyted tlv8
// - Read and store entity ltpk and name
//
// Server -> Client
// - encrpyted tlv8: bridge ltpk, bridge name, signature (of hash, bridge name, ltpk)
func (setup *SetupServerController) handleKeyExchange(in util.Container) (util.Container, error) {
	out := util.NewTLV8Container()

	setup.step = PairStepKeyExchangeResponse

	out.SetByte(TagSequence, setup.step.Byte())

	data := in.GetBytes(TagEncryptedData)
	message := data[:(len(data) - 16)]
	var mac [16]byte
	copy(mac[:], data[len(message):]) // 16 byte (MAC)
	log.Println("[VERB] ->     Message:", hex.EncodeToString(message))
	log.Println("[VERB] ->     MAC:", hex.EncodeToString(mac[:]))

	decrypted, err := chacha20poly1305.DecryptAndVerify(setup.session.EncryptionKey[:], []byte("PS-Msg05"), message, mac, nil)

	if err != nil {
		setup.reset()
		log.Println("[ERRO]", err)
		out.SetByte(TagErrCode, ErrCodeUnknown.Byte()) // return error 1
	} else {
		decryptedBuf := bytes.NewBuffer(decrypted)
		in, err := util.NewTLV8ContainerFromReader(decryptedBuf)
		if err != nil {
			return nil, err
		}

		username := in.GetString(TagUsername)
		clientltpk := in.GetBytes(TagPublicKey)
		signature := in.GetBytes(TagSignature)
		log.Println("[VERB] ->     Username:"******"[VERB] ->     ltpk:", hex.EncodeToString(clientltpk))
		log.Println("[VERB] ->     Signature:", hex.EncodeToString(signature))

		// Calculate hash `H`
		hash, _ := hkdf.Sha512(setup.session.PrivateKey, []byte("Pair-Setup-Controller-Sign-Salt"), []byte("Pair-Setup-Controller-Sign-Info"))
		var material []byte
		material = append(material, hash[:]...)
		material = append(material, []byte(username)...)
		material = append(material, clientltpk...)

		if crypto.ValidateED25519Signature(clientltpk, material, signature) == false {
			log.Println("[WARN] ed25519 signature is invalid")
			setup.reset()
			out.SetByte(TagErrCode, ErrCodeAuthenticationFailed.Byte()) // return error 2
		} else {
			log.Println("[VERB] ed25519 signature is valid")
			// Store entity ltpk and name
			entity := db.NewEntity(username, clientltpk, nil)
			setup.database.SaveEntity(entity)
			log.Printf("[INFO] Stored ltpk '%s' for entity '%s'\n", hex.EncodeToString(clientltpk), username)

			ltpk := setup.device.PublicKey()
			ltsk := setup.device.PrivateKey()

			// Send username, ltpk, signature as encrypted message
			hash, err := hkdf.Sha512(setup.session.PrivateKey, []byte("Pair-Setup-Accessory-Sign-Salt"), []byte("Pair-Setup-Accessory-Sign-Info"))
			material = make([]byte, 0)
			material = append(material, hash[:]...)
			material = append(material, []byte(setup.session.Username)...)
			material = append(material, ltpk...)

			signature, err := crypto.ED25519Signature(ltsk, material)
			if err != nil {
				log.Fatal(err)
				return nil, err
			}

			tlvPairKeyExchange := util.NewTLV8Container()
			tlvPairKeyExchange.SetBytes(TagUsername, setup.session.Username)
			tlvPairKeyExchange.SetBytes(TagPublicKey, ltpk)
			tlvPairKeyExchange.SetBytes(TagSignature, []byte(signature))

			log.Println("[VERB] <-     Username:"******"[VERB] <-     ltpk:", hex.EncodeToString(tlvPairKeyExchange.GetBytes(TagPublicKey)))
			log.Println("[VERB] <-     Signature:", hex.EncodeToString(tlvPairKeyExchange.GetBytes(TagSignature)))

			encrypted, mac, _ := chacha20poly1305.EncryptAndSeal(setup.session.EncryptionKey[:], []byte("PS-Msg06"), tlvPairKeyExchange.BytesBuffer().Bytes(), nil)
			out.SetByte(TagSequence, PairStepKeyExchangeRequest.Byte())
			out.SetBytes(TagEncryptedData, append(encrypted, mac[:]...))
		}
	}

	return out, nil
}
Ejemplo n.º 29
0
func (i *Identify) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	log.Printf("[VERB] %v POST /identify", request.RemoteAddr)
	i.handler.IdentifyAccessory()
	response.WriteHeader(http.StatusNoContent)
}