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") } }
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) } } }
// 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 } }
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) }
// 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 }
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) } } }
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) } }
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{}) } } }
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)) }) }
// 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 }
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() }
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) } }
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 }
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) } }
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 }
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) } } } }
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) } }
// 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 }
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{}) } } }
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) } } }
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) } } }
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 }
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) } }
func targetTempChangeRequest(temp float64) { err := hiveHome.SetTargetTemp(temp) if err != nil { log.Printf("[WARN] Unable to set target temperature: %v\n", err) } }
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) } }
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 }
// 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 }
// 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 }
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) }