-
KERDREUX Jerome authoredKERDREUX Jerome authored
xaal.go 9.56 KiB
package main
import (
"fmt"
"log/slog"
"math"
"github.com/davecgh/go-spew/spew"
"gitlab.imt-atlantique.fr/xaal/code/go/core/schemas"
"gitlab.imt-atlantique.fr/xaal/code/go/core/uuid"
"gitlab.imt-atlantique.fr/xaal/code/go/core/xaal"
)
type XAALDevice struct {
*xaal.Device
}
type Contact struct {
XAALDevice
}
type Thermometer struct {
XAALDevice
}
type Hygrometer struct {
XAALDevice
}
type LinkQuality struct {
XAALDevice
}
type Battery struct {
XAALDevice
}
type PowerRelay struct {
XAALDevice
Property string
Z2MDevice Z2MDevice
}
type PowerMeter struct {
XAALDevice
}
type Lamp struct {
XAALDevice
Z2MDevice Z2MDevice
}
type LampDimmer struct {
XAALDevice
Z2MDevice Z2MDevice
}
type ButtonRemote struct {
XAALDevice
Z2MDevice Z2MDevice
}
type XAALDeviceInterface interface {
update(map[string]interface{})
getXAALDevice() *xaal.Device
}
func (dev *XAALDevice) setup(zDev *Z2MDevice) {
dev.VendorID = zDev.Definition.Vendor
dev.ProductID = zDev.Definition.Model
dev.HWID = zDev.IeeeAddress
dev.Version = zDev.SwBuildID
dev.Info = "z2m:" + zDev.Type + ":" + zDev.FriendlyName
}
func (dev *XAALDevice) getXAALDevice() *xaal.Device {
return dev.Device
}
// =============================================================================
// Contact
// =============================================================================
func NewContact(addr uuid.UUID, zDev *Z2MDevice) XAALDeviceInterface {
dev := &Contact{XAALDevice{schemas.NewContact(addr)}}
dev.setup(zDev)
return dev
}
func (dev *Contact) update(payload map[string]interface{}) {
value, exists := payload["contact"].(bool)
if exists {
dev.GetAttribute("detected").SetValue(!value)
}
}
// =============================================================================
// Thermometer
// =============================================================================
func NewThermometer(addr uuid.UUID, zDev *Z2MDevice) XAALDeviceInterface {
dev := &Thermometer{XAALDevice{schemas.NewThermometer(addr)}}
dev.setup(zDev)
return dev
}
func (dev *Thermometer) update(payload map[string]interface{}) {
value, exists := payload["temperature"].(float64)
if exists {
dev.GetAttribute("temperature").SetValue(value)
}
}
// =============================================================================
// Hygrometer
// =============================================================================
func NewHygrometer(addr uuid.UUID, zDev *Z2MDevice) XAALDeviceInterface {
dev := &Hygrometer{XAALDevice{schemas.NewHygrometer(addr)}}
dev.setup(zDev)
return dev
}
func (dev *Hygrometer) update(payload map[string]interface{}) {
value, exists := payload["humidity"].(float64)
if exists {
dev.GetAttribute("humidity").SetValue(value)
}
}
// =============================================================================
// LinkQuality
// =============================================================================
func NewLinkQuality(addr uuid.UUID, zDev *Z2MDevice) XAALDeviceInterface {
dev := &LinkQuality{XAALDevice{schemas.NewLinkquality(addr)}}
dev.setup(zDev)
dev.RemoveAttribute("devices")
dev.UnsupportedAttributes = []string{"devices"}
return dev
}
func (dev *LinkQuality) update(payload map[string]interface{}) {
value, exists := payload["linkquality"].(float64)
if exists {
value = math.Round(value / 255 * 100)
dev.GetAttribute("level").SetValue(value)
}
}
// =============================================================================
// Battery
// =============================================================================
func NewBattery(addr uuid.UUID, zDev *Z2MDevice) XAALDeviceInterface {
dev := &Battery{XAALDevice{schemas.NewBattery(addr)}}
dev.setup(zDev)
dev.RemoveAttribute("devices")
dev.UnsupportedAttributes = []string{"devices"}
return dev
}
func (dev *Battery) update(payload map[string]interface{}) {
value, exists := payload["battery"].(float64)
if exists {
dev.GetAttribute("level").SetValue(value)
}
}
// =============================================================================
// PowerRelay
// =============================================================================
func NewPowerRelay(addr uuid.UUID, zDev *Z2MDevice, property string) XAALDeviceInterface {
dev := &PowerRelay{XAALDevice{schemas.NewPowerrelayToggle(addr)}, property, *zDev}
dev.SetMethod("turn_on", dev.On)
dev.SetMethod("turn_off", dev.Off)
dev.SetMethod("toggle", dev.Toggle)
dev.setup(zDev)
return dev
}
func (dev *PowerRelay) update(payload map[string]interface{}) {
value, exists := payload[dev.Property].(string)
if exists {
power := dev.GetAttribute("power")
switch value {
case "ON":
power.SetValue(true)
case "OFF":
power.SetValue(false)
}
}
}
func (dev *PowerRelay) SetProperty(value string) {
body := fmt.Sprintf(`{"%s": "%s"}`, dev.Property, value)
dev.Z2MDevice.Set(body)
}
func (dev *PowerRelay) On(xaal.MessageBody) *xaal.MessageBody {
dev.SetProperty("ON")
return nil
}
func (dev *PowerRelay) Off(xaal.MessageBody) *xaal.MessageBody {
dev.SetProperty("OFF")
return nil
}
func (dev *PowerRelay) Toggle(xaal.MessageBody) *xaal.MessageBody {
dev.SetProperty("TOGGLE")
return nil
}
// =============================================================================
// PowerMeter
// =============================================================================
func NewPowerMeter(addr uuid.UUID, zDev *Z2MDevice) XAALDeviceInterface {
dev := &PowerMeter{XAALDevice{schemas.NewPowermeter(addr)}}
dev.setup(zDev)
dev.RemoveAttribute("devices")
dev.UnsupportedAttributes = []string{"devices"}
return dev
}
func (dev *PowerMeter) update(payload map[string]interface{}) {
// power
value, exists := payload["power"].(float64)
if exists {
dev.GetAttribute("power").SetValue(value)
}
// energy
value, exists = payload["energy"].(float64)
if exists {
dev.GetAttribute("energy").SetValue(value)
}
}
// =============================================================================
// Lamp
// =============================================================================
func NewLamp(addr uuid.UUID, zDev *Z2MDevice, expose *Expose) XAALDeviceInterface {
// This is the default lamp device, we will change it's devType if needed
dev := &Lamp{XAALDevice{schemas.NewLamp(addr)}, *zDev}
dev.SetMethod("turn_on", dev.turnOn)
dev.SetMethod("turn_off", dev.turnOff)
dev.SetMethod("toggle", dev.toggle)
if expose.GetFeature("brightness") != nil {
dev.DevType = "lamp.dimmer"
dev.AddAttribute("brightness", 0)
dev.AddMethod("set_brightness", dev.setBrightness)
}
if expose.GetFeature("color_temp") != nil {
// All bulb w/ color temp are dimmer
dev.AddAttribute("white_temperature", 0)
dev.AddMethod("set_white_temperature", dev.setWhiteTemperature)
}
if expose.GetFeature("color_xy") != nil {
dev.DevType = "lamp.color"
dev.AddAttribute("hsv", nil)
dev.AddAttribute("mode", nil)
dev.UnsupportedAttributes = []string{"scene"}
dev.AddMethod("set_hsv", dev.setHSV)
dev.AddMethod("set_mode", dev.setMode)
}
dev.setup(zDev)
return dev
}
func (dev *Lamp) update(payload map[string]interface{}) {
// state
state, exists := payload["state"].(string)
if exists {
light := dev.GetAttribute("light")
switch state {
case "ON":
light.SetValue(true)
case "OFF":
light.SetValue(false)
}
}
// brightness
brightness, exists := payload["brightness"].(float64)
if exists {
brightness = brightness / 255 * 100
dev.GetAttribute("brightness").SetValue(int(brightness))
}
// color_temp
color_temp, exists := payload["color_temp"].(float64)
if exists {
// Mired = 1,000,000 / Temperature in Kelvin
color_temp = 1000000 / color_temp
dev.GetAttribute("white_temperature").SetValue(int(color_temp))
}
}
func (dev *Lamp) turnOn(xaal.MessageBody) *xaal.MessageBody {
dev.Z2MDevice.Set(`{"state": "ON"}`)
return nil
}
func (dev *Lamp) turnOff(xaal.MessageBody) *xaal.MessageBody {
dev.Z2MDevice.Set(`{"state": "OFF"}`)
return nil
}
func (dev *Lamp) toggle(xaal.MessageBody) *xaal.MessageBody {
dev.Z2MDevice.Set(`{"state": "TOGGLE"}`)
return nil
}
func (dev *Lamp) setBrightness(body xaal.MessageBody) *xaal.MessageBody {
// TODO: I don't know why we receive a uint64 instead of a float64
value, exists := body["brightness"].(uint64)
if exists {
dev.Z2MDevice.Set(fmt.Sprintf(`{"brightness": %d}`, value*255/100))
}
return nil
}
func (dev *Lamp) setWhiteTemperature(body xaal.MessageBody) *xaal.MessageBody {
value, exists := body["white_temperature"].(uint64)
if exists {
value = 1000000 / value
dev.Z2MDevice.Set(fmt.Sprintf(`{"color_temp": %d}`, value))
}
return nil
}
func (dev *Lamp) setHSV(body xaal.MessageBody) *xaal.MessageBody {
spew.Dump(body)
return nil
}
func (dev *Lamp) setMode(body xaal.MessageBody) *xaal.MessageBody {
spew.Dump(body)
return nil
}
// =============================================================================
// NetButtonRemote
// =============================================================================
func NewButtonRemote(addr uuid.UUID, zDev *Z2MDevice) XAALDeviceInterface {
dev := &ButtonRemote{XAALDevice{schemas.NewButtonRemote(addr)}, *zDev}
dev.setup(zDev)
dev.SetMethod("get_buttons", dev.GetButtons)
return dev
}
func (dev *ButtonRemote) update(payload map[string]interface{}) {
value, exists := payload["action"].(string)
if exists {
body := make(xaal.MessageBody)
body["action"] = 0
body["button"] = value
dev.SendNotification("click", body)
}
}
func (dev *ButtonRemote) GetButtons(xaal.MessageBody) *xaal.MessageBody {
slog.Info("defaultGetButtons method: get_buttons")
body := make(xaal.MessageBody)
action := dev.Z2MDevice.GetExpose("action")
if action != nil {
body["buttons"] = action.Values
}
return &body
}