package main import ( "encoding/json" "log/slog" "slices" mqtt "github.com/eclipse/paho.mqtt.golang" "gitlab.imt-atlantique.fr/xaal/code/go/core/xaal" ) type Gateway struct { Client mqtt.Client Engine *xaal.Engine Devices map[string]*Z2MDevice Config *Config } func NewGW(cfg *Config, eng *xaal.Engine) *Gateway { gw := &Gateway{Devices: make(map[string]*Z2MDevice)} gw.Config = cfg gw.Engine = eng gw.Client = MQTTSetup(cfg, gw.MQTTHandler) return gw } func (gw *Gateway) GetZDevice(name string) *Z2MDevice { return gw.Devices[name] } func (gw *Gateway) AddZDevice(zDev *Z2MDevice) { for _, xDev := range zDev.XAALDevices { dev := xDev.GetXAALDevice() slog.Debug("Adding device", "dev", dev.String()) gw.Engine.AddDevice(dev) } zDev.Gateway = gw gw.Devices[zDev.FriendlyName] = zDev } func (gw *Gateway) RemoveZDevice(zDev *Z2MDevice) { for _, xDev := range zDev.XAALDevices { dev := xDev.GetXAALDevice() slog.Debug("Removing device", "dev", dev.String()) gw.Engine.RemoveDevice(dev) } zDev.Gateway = nil delete(gw.Devices, zDev.FriendlyName) } func (gw *Gateway) GetZDevices() map[string]*Z2MDevice { return gw.Devices } func (gw *Gateway) GetZDeviceByTopic(topic string) *Z2MDevice { name := topic[len(gw.Config.topic+"/"):] return gw.GetZDevice(name) } // MQTTHandler handles all incoming MQTT messages // If the topic is /bridge/devices it will parse the json and create new devices // Else it will find the device with the topic and call the HandleMessage func (gw *Gateway) MQTTHandler(client mqtt.Client, msg mqtt.Message) { // some messages are empty if len(msg.Payload()) == 0 { return } // we ignore some topics if slices.Contains(gw.Config.ignoredTopics, msg.Topic()) { return } // Is it devices definitions ? if msg.Topic() == gw.Config.topic+"/bridge/devices" { gw.Z2MParseDevices(msg) } else { zDev := gw.GetZDeviceByTopic(msg.Topic()) if zDev != nil { zDev.HandleMessage(msg) } } } // Z2MParseDevices parses the bridge/devices json and and sync xAAL with results func (gw *Gateway) Z2MParseDevices(msg mqtt.Message) { var devices []Z2MDevice slog.Debug("Parsing devices") err := json.Unmarshal(msg.Payload(), &devices) if err != nil { slog.Error("Error decoding JSON", "err", err) return } // search for new devices for _, zDev := range devices { known := gw.GetZDevice(zDev.FriendlyName) if known != nil { continue } slog.Debug("Found new device", "name", zDev.FriendlyName) zDev.Dump() zDev.FindXAALDevices(gw) gw.AddZDevice(&zDev) zDev.Sync() // zDev.Available() } // search for deleted devices for _, zDev := range gw.GetZDevices() { found := false for _, dev := range devices { if dev.FriendlyName == zDev.FriendlyName { found = true break } } if !found { slog.Debug("Device removed", "name", zDev.FriendlyName) gw.RemoveZDevice(zDev) } } }