package mqtt import ( "fmt" "log" "git.k7n.net/mats/go-telldus/pkg/datastore" "git.k7n.net/mats/go-telldus/pkg/telldus" ) // DeviceDiscovery represents Home Assistant device discovery payload type DeviceDiscovery struct { Name string `json:"name"` CommandTopic string `json:"command_topic"` StateTopic string `json:"state_topic"` UniqueID string `json:"unique_id"` Device map[string]interface{} `json:"device"` } // SensorDiscovery represents Home Assistant sensor discovery payload type SensorDiscovery struct { Name string `json:"name"` StateTopic string `json:"state_topic"` UnitOfMeasurement string `json:"unit_of_measurement,omitempty"` DeviceClass string `json:"device_class,omitempty"` UniqueID string `json:"unique_id"` Device map[string]interface{} `json:"device"` } // PublishAllDiscovery publishes Home Assistant discovery messages for all devices and sensors func (c *Client) PublishAllDiscovery() error { if err := c.publishDeviceDiscovery(); err != nil { return err } if err := c.publishSensorDiscovery(); err != nil { return err } return nil } // publishDeviceDiscovery publishes discovery for all devices func (c *Client) publishDeviceDiscovery() error { for device := range c.store.ListDevices() { if err := c.PublishDeviceDiscovery(device.ID); err != nil { log.Printf("Error publishing discovery for device %d: %v", device.ID, err) } } return nil } // PublishDeviceDiscovery publishes Home Assistant discovery for a single device func (c *Client) PublishDeviceDiscovery(deviceID int) error { device, err := c.store.GetDevice(deviceID) if err != nil { return fmt.Errorf("device %d not found: %w", deviceID, err) } topic := fmt.Sprintf("homeassistant/switch/%s/config", device.UniqueID) payload := fmt.Sprintf(`{ "name": "%s", "command_topic": "telldus/device/%d/set", "state_topic": "telldus/device/%d/state", "unique_id": "%s", "device": { "identifiers": ["telldus_%d"], "name": "%s", "manufacturer": "Telldus" } }`, device.Name, deviceID, deviceID, device.UniqueID, deviceID, device.Name) c.client.Publish(topic, 0, true, payload) return nil } // publishSensorDiscovery publishes discovery for all sensors func (c *Client) publishSensorDiscovery() error { var protocol, model string var id, dataTypes int ret := telldus.Sensor(&protocol, &model, &id, &dataTypes) for ret == 0 { sensor, err := c.store.GetSensorByIdentity(protocol, model, id) if err != nil || sensor.Hidden { log.Printf("Sensor %s %s %d not in DB or hidden, skipping", protocol, model, id) ret = telldus.Sensor(&protocol, &model, &id, &dataTypes) continue } if err := c.publishSensorDiscoveryForSensor(sensor, dataTypes); err != nil { log.Printf("Error publishing discovery for sensor %s %s %d: %v", protocol, model, id, err) } ret = telldus.Sensor(&protocol, &model, &id, &dataTypes) } return nil } // PublishSensorDiscovery publishes Home Assistant discovery for a single sensor func (c *Client) PublishSensorDiscovery(protocol, model string, id int) error { sensor, err := c.store.GetSensorByIdentity(protocol, model, id) if err != nil { return fmt.Errorf("sensor %s %s %d not found: %w", protocol, model, id, err) } // Get current data types from telldus var p, m string var sensorID, dataTypes int ret := telldus.Sensor(&p, &m, &sensorID, &dataTypes) // Find matching sensor for ret == 0 { if p == protocol && m == model && sensorID == id { return c.publishSensorDiscoveryForSensor(sensor, dataTypes) } ret = telldus.Sensor(&p, &m, &sensorID, &dataTypes) } return fmt.Errorf("sensor %s %s %d not found in telldus", protocol, model, id) } // publishSensorDiscoveryForSensor publishes discovery messages for a sensor's data types func (c *Client) publishSensorDiscoveryForSensor(sensor *datastore.Sensor, dataTypes int) error { if dataTypes&telldus.DataTypeTemperature != 0 && sensor.TemperatureUniqueID != "" { topic := fmt.Sprintf("homeassistant/sensor/%s/config", sensor.TemperatureUniqueID) payload := fmt.Sprintf(`{ "name": "%s Temperature", "state_topic": "telldus/sensor/%s/%s/%d/temperature", "unit_of_measurement": "°C", "device_class": "temperature", "unique_id": "%s", "device": { "identifiers": ["telldus_sensor_%s_%s_%d"], "name": "%s", "manufacturer": "Telldus" } }`, sensor.Name, sensor.Protocol, sensor.Model, sensor.ID, sensor.TemperatureUniqueID, sensor.Protocol, sensor.Model, sensor.ID, sensor.Name) c.client.Publish(topic, 0, true, payload) } if dataTypes&telldus.DataTypeHumidity != 0 && sensor.HumidityUniqueID != "" { topic := fmt.Sprintf("homeassistant/sensor/%s/config", sensor.HumidityUniqueID) payload := fmt.Sprintf(`{ "name": "%s Humidity", "state_topic": "telldus/sensor/%s/%s/%d/humidity", "unit_of_measurement": "%%", "device_class": "humidity", "unique_id": "%s", "device": { "identifiers": ["telldus_sensor_%s_%s_%d"], "name": "%s", "manufacturer": "Telldus" } }`, sensor.Name, sensor.Protocol, sensor.Model, sensor.ID, sensor.HumidityUniqueID, sensor.Protocol, sensor.Model, sensor.ID, sensor.Name) c.client.Publish(topic, 0, true, payload) } return nil }