All devices are now stored in a central map, part of large refactor
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -59,6 +59,10 @@ func (c *computer) GetID() string {
|
||||
return c.macAddress
|
||||
}
|
||||
|
||||
func (c *computer) GetName() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
func (c *computer) SetState(state bool) {
|
||||
if state {
|
||||
http.Get(c.url)
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
type kettle struct {
|
||||
Info DeviceInfo
|
||||
info DeviceInfo
|
||||
client paho.Client
|
||||
updated chan bool
|
||||
|
||||
@@ -63,7 +63,7 @@ func (k *kettle) timerFunc() {
|
||||
select {
|
||||
case <- k.timer.C:
|
||||
log.Println("Turning kettle automatically off")
|
||||
if token := k.client.Publish(fmt.Sprintf("zigbee2mqtt/%s/set", k.Info.FriendlyName), 1, false, `{"state": "OFF"}`); token.Wait() && token.Error() != nil {
|
||||
if token := k.client.Publish(fmt.Sprintf("zigbee2mqtt/%s/set", k.info.FriendlyName), 1, false, `{"state": "OFF"}`); token.Wait() && token.Error() != nil {
|
||||
log.Println(token.Error())
|
||||
}
|
||||
|
||||
@@ -79,14 +79,14 @@ func (k *kettle) Delete() {
|
||||
}
|
||||
|
||||
func NewKettle(info DeviceInfo, client paho.Client, s *google.Service) *kettle {
|
||||
k := &kettle{Info: info, client: client, updated: make(chan bool, 1), timerLength: 5 * time.Minute, stop: make(chan interface{})}
|
||||
k := &kettle{info: info, client: client, updated: make(chan bool, 1), timerLength: 5 * time.Minute, stop: make(chan interface{})}
|
||||
k.timer = time.NewTimer(k.timerLength)
|
||||
k.timer.Stop()
|
||||
|
||||
// Start function
|
||||
go k.timerFunc()
|
||||
|
||||
if token := k.client.Subscribe(fmt.Sprintf("zigbee2mqtt/%s", k.Info.FriendlyName), 1, k.stateHandler); token.Wait() && token.Error() != nil {
|
||||
if token := k.client.Subscribe(fmt.Sprintf("zigbee2mqtt/%s", k.info.FriendlyName), 1, k.stateHandler); token.Wait() && token.Error() != nil {
|
||||
log.Println(token.Error())
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ func (k *kettle) Sync() *google.Device {
|
||||
device := google.NewDevice(k.GetID(), google.TypeKettle)
|
||||
device.AddOnOffTrait(false, false)
|
||||
|
||||
s := strings.Split(k.Info.FriendlyName, "/")
|
||||
s := strings.Split(k.info.FriendlyName, "/")
|
||||
room := ""
|
||||
name := s[0]
|
||||
if len(s) > 1 {
|
||||
@@ -122,9 +122,9 @@ func (k *kettle) Sync() *google.Device {
|
||||
}
|
||||
|
||||
device.DeviceInfo = google.DeviceInfo{
|
||||
Manufacturer: k.Info.Manufacturer,
|
||||
Model: k.Info.ModelID,
|
||||
SwVersion: k.Info.SoftwareBuildID,
|
||||
Manufacturer: k.info.Manufacturer,
|
||||
Model: k.info.ModelID,
|
||||
SwVersion: k.info.SoftwareBuildID,
|
||||
}
|
||||
|
||||
return device
|
||||
@@ -180,7 +180,15 @@ func (k *kettle) Execute(execution google.Execution, updatedState *google.Device
|
||||
}
|
||||
|
||||
func (k *kettle) GetID() string {
|
||||
return k.Info.IEEEAdress
|
||||
return k.info.IEEEAdress
|
||||
}
|
||||
|
||||
func (k *kettle) GetName() string {
|
||||
return k.info.FriendlyName
|
||||
}
|
||||
|
||||
func (k *kettle) GetDeviceInfo() DeviceInfo {
|
||||
return k.info
|
||||
}
|
||||
|
||||
func (k *kettle) SetState(state bool) {
|
||||
@@ -189,7 +197,8 @@ func (k *kettle) SetState(state bool) {
|
||||
msg = "ON"
|
||||
}
|
||||
|
||||
if token := k.client.Publish(fmt.Sprintf("zigbee2mqtt/%s/set", k.Info.FriendlyName), 1, false, fmt.Sprintf(`{ "state": "%s" }`, msg)); token.Wait() && token.Error() != nil {
|
||||
if token := k.client.Publish(fmt.Sprintf("zigbee2mqtt/%s/set", k.info.FriendlyName), 1, false, fmt.Sprintf(`{ "state": "%s" }`, msg)); token.Wait() && token.Error() != nil {
|
||||
log.Println(token.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@ package device
|
||||
|
||||
import (
|
||||
"automation/integration/google"
|
||||
"automation/integration/kasa"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/kr/pretty"
|
||||
@@ -14,15 +16,88 @@ import (
|
||||
paho "github.com/eclipse/paho.mqtt.golang"
|
||||
)
|
||||
|
||||
type BaseDevice interface {
|
||||
GetName() string
|
||||
}
|
||||
|
||||
type Devices struct {
|
||||
Devices map[string]interface{}
|
||||
}
|
||||
|
||||
func NewDevices() *Devices {
|
||||
return &Devices{Devices: make(map[string]interface{})}
|
||||
}
|
||||
|
||||
func (d *Devices) GetGoogleDevices() map[string]google.DeviceInterface {
|
||||
devices := make(map[string]google.DeviceInterface)
|
||||
|
||||
for _, device := range d.Devices {
|
||||
if gd, ok := device.(google.DeviceInterface); ok {
|
||||
// Instead of using name we use the internal ID for google, that way devices can freely be renamed without causing issues with google home
|
||||
devices[gd.GetID()] = gd
|
||||
}
|
||||
}
|
||||
|
||||
return devices
|
||||
}
|
||||
|
||||
func (d *Devices) GetGoogleDevice(name string) (google.DeviceInterface, error) {
|
||||
device, ok := d.GetGoogleDevices()[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Device does not exist")
|
||||
}
|
||||
|
||||
return device, nil
|
||||
}
|
||||
|
||||
func (d *Devices) GetZigbeeDevices() map[string]ZigbeeDevice {
|
||||
devices := make(map[string]ZigbeeDevice)
|
||||
|
||||
for name, device := range d.Devices {
|
||||
if zd, ok := device.(ZigbeeDevice); ok {
|
||||
devices[name] = zd
|
||||
}
|
||||
}
|
||||
|
||||
return devices
|
||||
}
|
||||
|
||||
func (d *Devices) GetKasaDevices() map[string]*kasa.Kasa {
|
||||
devices := make(map[string]*kasa.Kasa)
|
||||
|
||||
for _, device := range d.Devices {
|
||||
if gd, ok := device.(*kasa.Kasa); ok {
|
||||
// Instead of using name we use the internal ID for google, that way devices can freely be renamed without causing issues with google home
|
||||
devices[gd.GetName()] = gd
|
||||
}
|
||||
}
|
||||
|
||||
return devices
|
||||
}
|
||||
|
||||
func (d *Devices) GetKasaDevice(name string) (*kasa.Kasa, error) {
|
||||
device, ok := d.GetKasaDevices()[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Device does not exist")
|
||||
}
|
||||
|
||||
return device, nil
|
||||
}
|
||||
|
||||
type DeviceInfo struct {
|
||||
IEEEAdress string `json:"ieee_address"`
|
||||
FriendlyName string `json:"friendly_name"`
|
||||
Description string `json:"description"`
|
||||
Manufacturer string `json:"manufacturer"`
|
||||
ModelID string `json:"model_id"`
|
||||
IEEEAdress string `json:"ieee_address"`
|
||||
FriendlyName string `json:"friendly_name"`
|
||||
Description string `json:"description"`
|
||||
Manufacturer string `json:"manufacturer"`
|
||||
ModelID string `json:"model_id"`
|
||||
SoftwareBuildID string `json:"software_build_id"`
|
||||
}
|
||||
|
||||
type ZigbeeDevice interface {
|
||||
GetDeviceInfo() DeviceInfo
|
||||
SetState(state bool)
|
||||
}
|
||||
|
||||
type DeviceInterface interface {
|
||||
google.DeviceInterface
|
||||
SetState(state bool)
|
||||
@@ -30,10 +105,9 @@ type DeviceInterface interface {
|
||||
|
||||
type Provider struct {
|
||||
Service *google.Service
|
||||
userID string
|
||||
userID string
|
||||
|
||||
devices map[string]DeviceInterface
|
||||
manualDevices map[string]DeviceInterface
|
||||
Devices *Devices
|
||||
}
|
||||
|
||||
type credentials []byte
|
||||
@@ -56,15 +130,17 @@ func (p *Provider) devicesHandler(client paho.Client, msg paho.Message) {
|
||||
log.Println("zigbee2mqtt devices:")
|
||||
pretty.Logln(devices)
|
||||
|
||||
// Remove all automatically added devices
|
||||
p.devices = p.manualDevices
|
||||
for name := range p.Devices.GetZigbeeDevices() {
|
||||
// Delete all zigbee devices from the device list
|
||||
delete(p.Devices.Devices, name)
|
||||
}
|
||||
|
||||
for _, device := range devices {
|
||||
switch device.Description {
|
||||
case "Kettle":
|
||||
kettle := NewKettle(device, client, p.Service)
|
||||
p.devices[device.IEEEAdress] = kettle
|
||||
log.Printf("Added Kettle (%s) %s\n", device.IEEEAdress, device.FriendlyName)
|
||||
p.Devices.Devices[kettle.GetDeviceInfo().FriendlyName] = kettle
|
||||
log.Printf("Added Kettle (%s) %s\n", kettle.GetDeviceInfo().IEEEAdress, kettle.GetDeviceInfo().FriendlyName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +149,7 @@ func (p *Provider) devicesHandler(client paho.Client, msg paho.Message) {
|
||||
}
|
||||
|
||||
func NewProvider(config Config, client paho.Client) *Provider {
|
||||
provider := &Provider{userID: "Dreaded_X", devices: make(map[string]DeviceInterface), manualDevices: make(map[string]DeviceInterface)}
|
||||
provider := &Provider{userID: "Dreaded_X", Devices: NewDevices()}
|
||||
|
||||
homegraphService, err := homegraph.NewService(context.Background(), option.WithCredentialsJSON(config.Credentials))
|
||||
if err != nil {
|
||||
@@ -89,15 +165,14 @@ func NewProvider(config Config, client paho.Client) *Provider {
|
||||
return provider
|
||||
}
|
||||
|
||||
func (p *Provider) AddDevice(device DeviceInterface) {
|
||||
p.devices[device.GetID()] = device
|
||||
p.manualDevices[device.GetID()] = device
|
||||
func (p *Provider) AddDevice(device BaseDevice) {
|
||||
p.Devices.Devices[device.GetName()] = device
|
||||
}
|
||||
|
||||
func (p *Provider) Sync(_ context.Context, _ string) ([]*google.Device, error) {
|
||||
var devices []*google.Device
|
||||
|
||||
for _, device := range p.devices {
|
||||
for _, device := range p.Devices.GetGoogleDevices() {
|
||||
devices = append(devices, device.Sync())
|
||||
}
|
||||
|
||||
@@ -108,10 +183,10 @@ func (p *Provider) Query(_ context.Context, _ string, handles []google.DeviceHan
|
||||
states := make(map[string]google.DeviceState)
|
||||
|
||||
for _, handle := range handles {
|
||||
if device, found := p.devices[handle.ID]; found {
|
||||
if device, err := p.Devices.GetGoogleDevice(handle.ID); err == nil {
|
||||
states[handle.ID] = device.Query()
|
||||
} else {
|
||||
log.Printf("Device (%s) not found\n", handle.ID)
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,18 +195,18 @@ func (p *Provider) Query(_ context.Context, _ string, handles []google.DeviceHan
|
||||
|
||||
func (p *Provider) Execute(_ context.Context, _ string, commands []google.Command) (*google.ExecuteResponse, error) {
|
||||
resp := &google.ExecuteResponse{
|
||||
UpdatedState: google.NewDeviceState(true),
|
||||
FailedDevices: make(map[string]struct{Devices []string}),
|
||||
UpdatedState: google.NewDeviceState(true),
|
||||
FailedDevices: make(map[string]struct{ Devices []string }),
|
||||
}
|
||||
|
||||
for _, command := range commands {
|
||||
for _, execution := range command.Execution {
|
||||
for _, handle := range command.Devices {
|
||||
if device, found := p.devices[handle.ID]; found {
|
||||
if device, err := p.Devices.GetGoogleDevice(handle.ID); err == nil {
|
||||
errCode, online := device.Execute(execution, &resp.UpdatedState)
|
||||
|
||||
// Update the state
|
||||
p.devices[handle.ID] = device
|
||||
p.Devices.Devices[handle.ID] = device
|
||||
if !online {
|
||||
resp.OfflineDevices = append(resp.OfflineDevices, handle.ID)
|
||||
} else if len(errCode) == 0 {
|
||||
@@ -142,7 +217,7 @@ func (p *Provider) Execute(_ context.Context, _ string, commands []google.Comman
|
||||
resp.FailedDevices[errCode] = e
|
||||
}
|
||||
} else {
|
||||
log.Printf("Device (%s) not found\n", handle.ID)
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,9 +225,3 @@ func (p *Provider) Execute(_ context.Context, _ string, commands []google.Comman
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (p *Provider) TurnAllOff() {
|
||||
for _, device := range p.devices {
|
||||
device.SetState(false)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user