package hue2 import ( "encoding/json" "encoding/xml" "fmt" "git.aiterp.net/lucifer/new-server/internal/color" "strings" "time" ) type DeviceData struct { ID string `json:"id"` LegacyID string `json:"id_v1"` Metadata DeviceMetadata `json:"metadata"` Type string `json:"type"` ProductData DeviceProductData `json:"product_data"` Services []ResourceLink `json:"services"` } type DeviceMetadata struct { Archetype string `json:"archetype"` Name string `json:"name"` } type DeviceProductData struct { Certified bool `json:"certified"` ManufacturerName string `json:"manufacturer_name"` ModelID string `json:"model_id"` ProductArchetype string `json:"product_archetype"` ProductName string `json:"product_name"` SoftwareVersion string `json:"software_version"` } type SSEUpdate struct { CreationTime time.Time `json:"creationTime"` ID string `json:"id"` Type string `json:"type"` Data []ResourceData `json:"data"` } type ResourceData struct { ID string `json:"id"` LegacyID string `json:"id_v1"` Metadata DeviceMetadata `json:"metadata"` Type string `json:"type"` Mode *string `json:"mode"` Owner *ResourceLink `json:"owner"` ProductData *DeviceProductData `json:"product_data"` Services []ResourceLink `json:"services"` Button *SensorButton `json:"button"` Power *LightPower `json:"on"` Color *LightColor `json:"color"` ColorTemperature *LightCT `json:"color_temperature"` Dimming *LightDimming `json:"dimming"` Dynamics *LightDynamics `json:"dynamics"` Alert *LightAlert `json:"alert"` PowerState *PowerState `json:"power_state"` Temperature *SensorTemperature `json:"temperature"` Motion *SensorMotion `json:"motion"` Status *string `json:"status"` } func (res *ResourceData) ServiceID(kind string) *string { for _, ptr := range res.Services { if ptr.Kind == kind { return &ptr.ID } } return nil } func (res *ResourceData) ServiceIndex(kind string, id string) int { idx := 0 for _, link := range res.Services { if link.ID == id { return idx } else if link.Kind == kind { idx += 1 } } return -1 } func (res *ResourceData) WithUpdate(update ResourceUpdate) *ResourceData { resCopy := *res if update.Name != nil { resCopy.Metadata.Name = *update.Name } if update.Power != nil { cp := *resCopy.Power resCopy.Power = &cp resCopy.Power.On = *update.Power } if update.ColorXY != nil { cp := *resCopy.Color resCopy.Color = &cp resCopy.Color.XY = *update.ColorXY if resCopy.ColorTemperature != nil { cp := *resCopy.ColorTemperature resCopy.ColorTemperature = &cp resCopy.ColorTemperature.Mirek = nil } } if update.Mirek != nil { cp := *resCopy.ColorTemperature resCopy.ColorTemperature = &cp mirek := *update.Mirek resCopy.ColorTemperature.Mirek = &mirek } if update.Brightness != nil { cp := *resCopy.Dimming resCopy.Dimming = &cp resCopy.Dimming.Brightness = *update.Brightness } return &resCopy } type SensorButton struct { LastEvent string `json:"last_event"` } type SensorMotion struct { Motion bool `json:"motion"` Valid bool `json:"motion_valid"` } type SensorTemperature struct { Temperature float64 `json:"temperature"` Valid bool `json:"temperature_valid"` } type PowerState struct { BatteryState string `json:"battery_state"` BatteryLevel float64 `json:"battery_level"` } type LightPower struct { On bool `json:"on"` } type LightDimming struct { Brightness float64 `json:"brightness"` } type LightColor struct { Gamut color.Gamut `json:"gamut"` GamutType string `json:"gamut_type"` XY color.XY `json:"xy"` } type LightCT struct { Mirek *int `json:"mirek"` MirekSchema LightCTMirekSchema `json:"mirek_schema"` MirekValid bool `json:"mirek_valid"` } type LightCTMirekSchema struct { MirekMaximum int `json:"mirek_maximum"` MirekMinimum int `json:"mirek_minimum"` } type LightDynamics struct { Speed float64 `json:"speed"` SpeedValid bool `json:"speed_valid"` Status string `json:"status"` StatusValues []string `json:"status_values"` } type LightAlert struct { ActionValues []string `json:"action_values"` } type ResourceUpdate struct { Name *string Power *bool ColorXY *color.XY Brightness *float64 Mirek *int TransitionDuration *time.Duration } func (r ResourceUpdate) MarshalJSON() ([]byte, error) { chunks := make([]string, 0, 4) if r.Name != nil { s, _ := json.Marshal(*r.Name) chunks = append(chunks, fmt.Sprintf(`"metadata":{"name":%s}`, string(s))) } if r.Power != nil { chunks = append(chunks, fmt.Sprintf(`"on":{"on":%v}`, *r.Power)) } if r.ColorXY != nil { chunks = append(chunks, fmt.Sprintf(`"color":{"xy":{"x":%f,"y":%f}}`, r.ColorXY.X, r.ColorXY.Y)) } if r.Brightness != nil { chunks = append(chunks, fmt.Sprintf(`"dimming":{"brightness":%f}`, *r.Brightness)) } if r.Mirek != nil { chunks = append(chunks, fmt.Sprintf(`"color_temperature":{"mirek":%d}`, *r.Mirek)) } if r.TransitionDuration != nil { chunks = append(chunks, fmt.Sprintf(`"dynamics":{"duration":%d}`, r.TransitionDuration.Truncate(time.Millisecond*100).Milliseconds())) } return []byte(fmt.Sprintf("{%s}", strings.Join(chunks, ","))), nil } type ResourceLink struct { ID string `json:"rid"` Kind string `json:"rtype"` } func (rl *ResourceLink) Path() string { return fmt.Sprintf("/clip/v2/resource/%s/%s", rl.Kind, rl.ID) } type CreateUserInput struct { DeviceType string `json:"devicetype"` } type CreateUserResponse struct { Success *struct { Username string `json:"username"` } `json:"success"` Error *struct { Type int `json:"type"` Address string `json:"address"` Description string `json:"description"` } `json:"error"` } type DiscoveryEntry struct { Id string `json:"id"` InternalIPAddress string `json:"internalipaddress"` } type BridgeDeviceInfo struct { XMLName xml.Name `xml:"root"` Text string `xml:",chardata"` Xmlns string `xml:"xmlns,attr"` SpecVersion struct { Text string `xml:",chardata"` Major string `xml:"major"` Minor string `xml:"minor"` } `xml:"specVersion"` URLBase string `xml:"URLBase"` Device struct { Text string `xml:",chardata"` DeviceType string `xml:"deviceType"` FriendlyName string `xml:"friendlyName"` Manufacturer string `xml:"manufacturer"` ManufacturerURL string `xml:"manufacturerURL"` ModelDescription string `xml:"modelDescription"` ModelName string `xml:"modelName"` ModelNumber string `xml:"modelNumber"` ModelURL string `xml:"modelURL"` SerialNumber string `xml:"serialNumber"` UDN string `xml:"UDN"` PresentationURL string `xml:"presentationURL"` IconList struct { Text string `xml:",chardata"` Icon struct { Text string `xml:",chardata"` Mimetype string `xml:"mimetype"` Height string `xml:"height"` Width string `xml:"width"` Depth string `xml:"depth"` URL string `xml:"url"` } `xml:"icon"` } `xml:"iconList"` } `xml:"device"` }