diff --git a/cli/cmd/consts.go b/cli/cmd/consts.go index 55ff237..51472b6 100755 --- a/cli/cmd/consts.go +++ b/cli/cmd/consts.go @@ -32,5 +32,6 @@ const ( LogoutCmdName = "logout" PingCmdName = "ping" HomeAssistantCmdName = "ha" - ArgDoPeriodicRequests = "doPeriodicRequests" + ArgDoorStatusSupported = "doorStatusSupported" + ArgDevicePortsName = "devicePorts" ) diff --git a/cli/cmd/homeAssistant.go b/cli/cmd/homeAssistant.go index 5afd6f7..ec10209 100755 --- a/cli/cmd/homeAssistant.go +++ b/cli/cmd/homeAssistant.go @@ -25,8 +25,8 @@ func init() { mqttPassword string mqttTelePeriod time.Duration mqttTelePeriodFast time.Duration - devicePort int - doPeriodicRequests bool + devicePorts []int + doorStatusSupported bool ) haCmd := &cobra.Command{ @@ -52,8 +52,8 @@ func init() { mqttPassword = viper.GetString(ArgMqttPasswordName) mqttTelePeriod = viper.GetDuration(ArgMqttTelePeriodName) mqttTelePeriodFast = viper.GetDuration(ArgMqttTelePeriodFastName) - devicePort = viper.GetInt(ArgDevicePortName) - doPeriodicRequests = viper.GetBool(ArgDoPeriodicRequests) + devicePorts = viper.GetIntSlice(ArgDevicePortsName) + doorStatusSupported = viper.GetBool(ArgDoorStatusSupported) mqttClientId := fmt.Sprintf("clientId_%s", deviceMac) @@ -67,7 +67,7 @@ func init() { cli.Log, localMac, mac, username, password, host, port, token, mqttServerName, mqttClientId, mqttServerPort, mqttServerTls, mqttServerTlsValidaton, mqttBaseTopic, mqttDeviceName, mqttUserName, mqttPassword, mqttTelePeriod, mqttTelePeriodFast, - byte(devicePort), doPeriodicRequests, + devicePorts, doorStatusSupported, ) if err != nil { cli.Log.Fatalf("%v", err) @@ -93,8 +93,8 @@ func init() { haCmd.Flags().StringVarP(&mqttDeviceName, ArgMqttDeviceNameName, "n", "garage", "Name of the local device in MQTT messages") haCmd.Flags().DurationVarP(&mqttTelePeriod, ArgMqttTelePeriodName, "e", 15*time.Second, "Frequency of device state publish") haCmd.Flags().DurationVarP(&mqttTelePeriodFast, ArgMqttTelePeriodFastName, "f", 5*time.Second, "Frequency of device state publish when door might be moving") - haCmd.Flags().IntVar(&devicePort, ArgDevicePortName, 0, "Port number of the door") - haCmd.Flags().BoolVar(&doPeriodicRequests, ArgDoPeriodicRequests, true, "Whether periodic status requests should be sent or not") + haCmd.Flags().IntSliceVar(&devicePorts, ArgDevicePortsName, []int{}, "Port numbers of the doors") + haCmd.Flags().BoolVar(&doorStatusSupported, ArgDoorStatusSupported, true, "Whether the controlled door supports door status (opening state) or not") flag.Parse() err := viper.BindPFlags(haCmd.Flags()) if err != nil { diff --git a/cli/homeAssistant/actions.go b/cli/homeAssistant/actions.go index 0268696..49cf0f1 100644 --- a/cli/homeAssistant/actions.go +++ b/cli/homeAssistant/actions.go @@ -59,12 +59,12 @@ func (ha *HomeAssistanceMqttClient) forceReLogin() error { return nil } -func (ha *HomeAssistanceMqttClient) setStateMultiCall(count int) error { - return ha.setStateBisecurMultiCall(count) +func (ha *HomeAssistanceMqttClient) setStateMultiCall(count int, devicePort byte) error { + return ha.setStateBisecurMultiCall(count, devicePort) //return mockDoor.SetStateMockMultiCall(count) } -func (ha *HomeAssistanceMqttClient) setStateBisecurMultiCall(count int) error { +func (ha *HomeAssistanceMqttClient) setStateBisecurMultiCall(count int, devicePort byte) error { const delayDuration = 1500 * time.Millisecond for i := 0; i < count; i++ { @@ -75,7 +75,7 @@ func (ha *HomeAssistanceMqttClient) setStateBisecurMultiCall(count int) error { return fmt.Errorf("auto login failed. %v", err) } - err = bisecur.SetState(ha.localMac, ha.deviceMac, ha.host, ha.port, ha.devicePort, ha.token) + err = bisecur.SetState(ha.localMac, ha.deviceMac, ha.host, ha.port, devicePort, ha.token) if err != nil { return fmt.Errorf("failed to get door status. %v", err) } @@ -88,34 +88,45 @@ func (ha *HomeAssistanceMqttClient) setStateBisecurMultiCall(count int) error { return nil } -func (ha *HomeAssistanceMqttClient) openDoor() error { +func (ha *HomeAssistanceMqttClient) impuls(devicePort byte) any { + ha.log.Info("Sending impuls...") + + err := ha.setStateMultiCall(1, devicePort) + if err != nil { + return fmt.Errorf("failed to send impuls. %v", err) + } + + return nil +} + +func (ha *HomeAssistanceMqttClient) openDoor(devicePort byte) error { ha.log.Info("Opening door...") - direction, position, err := ha.getDoorStatus() + direction, position, err := ha.getDoorStatus(devicePort) if err != nil { return fmt.Errorf("failed to get door status. %v", err) } switch direction { case utils.CLOSING: - err := ha.setStateMultiCall(2) + err := ha.setStateMultiCall(2, devicePort) if err != nil { return fmt.Errorf("failed to set state. %v", err) } case utils.STOPPED, utils.OPEN, utils.CLOSED: if position < 100 { // check if door is not already fully open - err := ha.setStateMultiCall(1) + err := ha.setStateMultiCall(1, devicePort) if err != nil { return fmt.Errorf("failed to set state. %v", err) } - newDirection, _, err := ha.getDoorStatus() + newDirection, _, err := ha.getDoorStatus(devicePort) if err != nil { return fmt.Errorf("failed to get door status to confirm it is moving into the right direction. %v", err) } if newDirection != utils.OPENING && newDirection != utils.OPEN { // check if door needs to be reversed - err := ha.setStateMultiCall(2) + err := ha.setStateMultiCall(2, devicePort) if err != nil { return fmt.Errorf("failed to reverse moving direction. %v", err) } @@ -132,34 +143,34 @@ func (ha *HomeAssistanceMqttClient) openDoor() error { return nil } -func (ha *HomeAssistanceMqttClient) closeDoor() error { +func (ha *HomeAssistanceMqttClient) closeDoor(devicePort byte) error { ha.log.Info("Closing door...") - direction, position, err := ha.getDoorStatus() + direction, position, err := ha.getDoorStatus(devicePort) if err != nil { return fmt.Errorf("failed to get door status. %v", err) } switch direction { case utils.OPENING: - err := ha.setStateMultiCall(2) // stop then reverse + err := ha.setStateMultiCall(2, devicePort) // stop then reverse if err != nil { return fmt.Errorf("failed to set state. %v", err) } case utils.STOPPED, utils.OPEN: if position > 0 { // check if door is not already fully closed - err := ha.setStateMultiCall(1) + err := ha.setStateMultiCall(1, devicePort) if err != nil { return fmt.Errorf("failed to set state. %v", err) } - newDirection, _, err := ha.getDoorStatus() + newDirection, _, err := ha.getDoorStatus(devicePort) if err != nil { return fmt.Errorf("failed to get door status to confirm it is moving into the right direction. %v", err) } if newDirection != utils.CLOSING && newDirection != utils.CLOSED { // check if door needs to be reversed - err := ha.setStateMultiCall(2) + err := ha.setStateMultiCall(2, devicePort) if err != nil { return fmt.Errorf("failed to reverse moving direction. %v", err) } @@ -176,16 +187,16 @@ func (ha *HomeAssistanceMqttClient) closeDoor() error { return nil } -func (ha *HomeAssistanceMqttClient) stopDoor() error { +func (ha *HomeAssistanceMqttClient) stopDoor(devicePort byte) error { ha.log.Infof("Stopping door...") - direction, _, err := ha.getDoorStatus() + direction, _, err := ha.getDoorStatus(devicePort) if err != nil { return fmt.Errorf("failed to get door status. %v", err) } if direction == utils.OPENING || direction == utils.CLOSING { // anything which means moving door - err := ha.setStateMultiCall(1) + err := ha.setStateMultiCall(1, devicePort) if err != nil { return fmt.Errorf("failed to stop the door. %v", err) } @@ -198,7 +209,7 @@ func (ha *HomeAssistanceMqttClient) stopDoor() error { return nil } -func (ha *HomeAssistanceMqttClient) getDoorStatus() (direction string, position int, err error) { +func (ha *HomeAssistanceMqttClient) getDoorStatus(devicePort byte) (direction string, position int, err error) { /* status="{\"StateInPercent\":0,\"DesiredStateInPercent\":0,\"ErrorResponse\":false,\"AutoClose\":false,\"DriveTime\":0, \"Gk\":257,\"Hcp\":{\"PositionOpen\":false,\"PositionClose\":true,\"OptionRelais\":false,\"LightBarrier\":false, @@ -218,7 +229,7 @@ func (ha *HomeAssistanceMqttClient) getDoorStatus() (direction string, position var status *payload.HmGetTransitionResponse err = utils.RetryAlways(utils.RetryCount, func() error { var err2 error - status, err2 = bisecur.GetStatus(ha.localMac, ha.deviceMac, ha.host, ha.port, ha.devicePort, ha.token) + status, err2 = bisecur.GetStatus(ha.localMac, ha.deviceMac, ha.host, ha.port, devicePort, ha.token) if err2.Error() == "PERMISSION_DENIED" { // TODO don't like string comparisons so should be refactored somehow while relogin also should be make more generic (think of other commands) // Does it make sense to force relogin after a PERMISSION_DENIED error? diff --git a/cli/homeAssistant/client.go b/cli/homeAssistant/client.go index a18426d..7142921 100644 --- a/cli/homeAssistant/client.go +++ b/cli/homeAssistant/client.go @@ -10,6 +10,8 @@ import ( "log" "os" "os/signal" + "strconv" + "strings" "syscall" "time" @@ -42,16 +44,16 @@ type HomeAssistanceMqttClient struct { mqttPassword string mqttTelePeriod time.Duration mqttTelePeriodFast time.Duration - devicePort byte + devicePorts []int log *logrus.Logger mqttClient mqtt.Client requestFastUpdate time.Time - doPeriodicRequests bool + doorStatusSupported bool } func NewHomeAssistanceMqttClient(log *logrus.Logger, localMac [6]byte, deviceMac [6]byte, deviceUsername string, devicePassword string, host string, port int, token uint32, mqttServerName string, mqttClientId string, mqttServerPort int, mqttServerTls bool, mqttServerTlsValidaton bool, mqttBaseTopic string, - mqttDeviceName string, mqttUserName string, mqttPassword string, mqttTelePeriod time.Duration, mqttTelePeriodFast time.Duration, devicePort byte, doPeriodicRequests bool) (*HomeAssistanceMqttClient, error) { + mqttDeviceName string, mqttUserName string, mqttPassword string, mqttTelePeriod time.Duration, mqttTelePeriodFast time.Duration, devicePorts []int, doorStatusSupported bool) (*HomeAssistanceMqttClient, error) { ha := &HomeAssistanceMqttClient{ localMac: localMac, @@ -72,10 +74,10 @@ func NewHomeAssistanceMqttClient(log *logrus.Logger, localMac [6]byte, deviceMac mqttPassword: mqttPassword, mqttTelePeriod: mqttTelePeriod, mqttTelePeriodFast: mqttTelePeriodFast, - devicePort: devicePort, + devicePorts: devicePorts, log: log, requestFastUpdate: time.UnixMicro(0), // initial value must be in the past - doPeriodicRequests: doPeriodicRequests, + doorStatusSupported: doorStatusSupported, } return ha, nil @@ -103,24 +105,34 @@ func (ha *HomeAssistanceMqttClient) Start() error { homeAssistantSetPossitionMessagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ha.log.Debugf("Received set position message: %s from topic: %s", msg.Payload(), msg.Topic()) + devicePort, err := strconv.Atoi(strings.Split(msg.Topic(), "/")[2]) // extract device port from topic + if err != nil { + ha.log.Errorf("failed to parse device port. %v", err) + return + } command := string(msg.Payload()) switch command { case "CLOSE": - err := ha.closeDoor() + err := ha.closeDoor(byte(devicePort)) if err != nil { ha.log.Errorf("failed to close door. %v", err) } case "OPEN": - err := ha.openDoor() + err := ha.openDoor(byte(devicePort)) if err != nil { ha.log.Errorf("failed to open door. %v", err) } case "STOP": - err := ha.stopDoor() + err := ha.stopDoor(byte(devicePort)) if err != nil { ha.log.Errorf("failed to stop door. %v", err) } + case "PRESS": + err := ha.impuls(byte(devicePort)) + if err != nil { + ha.log.Errorf("failed to do impuls. %v", err) + } } } @@ -133,7 +145,7 @@ func (ha *HomeAssistanceMqttClient) Start() error { protocol = "tls" } brokerUrl := fmt.Sprintf("%s://%s:%d", protocol, ha.mqttServerName, ha.mqttServerPort) - ha.log.Debugf("MQTT Broken url: %s", brokerUrl) + ha.log.Debugf("MQTT Broker url: %s", brokerUrl) opts.AddBroker(brokerUrl) opts.SetClientID(ha.mqttClientId) @@ -146,8 +158,10 @@ func (ha *HomeAssistanceMqttClient) Start() error { opts.SetTLSConfig(tlsConfig) opts.SetAutoReconnect(true) - // Configure offline availability message - opts.SetWill(ha.getAvailabilityTopic(), ha.getAvabilityMessage(false), qosAtLeastOnce, true) + // Configure offline availability messages + for _, devicePort := range ha.devicePorts { + opts.SetWill(ha.getAvailabilityTopic(devicePort), ha.getAvabilityMessage(false), qosAtLeastOnce, true) + } ha.mqttClient = mqtt.NewClient(opts) mqttToken := ha.mqttClient.Connect() @@ -157,16 +171,18 @@ func (ha *HomeAssistanceMqttClient) Start() error { defer func() { ha.log.Debugf("Disconnecting from MQTT server") - err := ha.PublishAvabilityMessage(false) - if err != nil { - ha.log.Errorf("failed to publish availability message (offline). %v", err) + for _, devicePort := range ha.devicePorts { + err := ha.PublishAvabilityMessage(false, devicePort) + if err != nil { + ha.log.Errorf("failed to publish availability message (offline). %v", err) + } } ha.mqttClient.Disconnect(250) ha.log.Infof("Disconnected from MQTT server") - err = ha.LogoutBisecur() + err := ha.LogoutBisecur() if err != nil { ha.log.Errorf("Error logging out of bisecur") } else { @@ -177,21 +193,23 @@ func (ha *HomeAssistanceMqttClient) Start() error { // Subscribe to home assistant's status topic (get notification when HA restarts) ha.mqttClient.Subscribe(utils.HomeAssistantStatusTopic, 0, homeAssistantStatusMessagePubHandler) - // Subscribe to topic for receiving commands - setPositionTopicName := ha.getSetPositionTopic() - ha.log.Debugf("Subscribing to topic: %s", setPositionTopicName) - ha.mqttClient.Subscribe(setPositionTopicName, 0, homeAssistantSetPossitionMessagePubHandler) + for _, devicePort := range ha.devicePorts { + // Subscribe to topics for receiving commands + setPositionTopicName := ha.getSetPositionTopic(devicePort) + ha.log.Debugf("Subscribing to topic: %s", setPositionTopicName) + ha.mqttClient.Subscribe(setPositionTopicName, 0, homeAssistantSetPossitionMessagePubHandler) - // Publish discovery message - err := ha.PublishDiscoveryMessage() - if err != nil { - ha.log.Errorf("failed to publish discovery message. %v", err) - } + // Publish discovery messages + err := ha.PublishDiscoveryMessage(devicePort) + if err != nil { + ha.log.Errorf("failed to publish discovery message. %v", err) + } - // Configure availability - err = ha.PublishAvabilityMessage(true) - if err != nil { - ha.log.Errorf("failed to publish availability message (online). %v", err) + // Configure availabilities + err = ha.PublishAvabilityMessage(true, int(devicePort)) + if err != nil { + ha.log.Errorf("failed to publish availability message (online). %v", err) + } } mockDoor.StartTicker() @@ -217,11 +235,13 @@ out: ha.log.Infof("Exiting") break out case <-ticker.C: - if ha.doPeriodicRequests { - err := ha.doorStatus() - if err != nil { - ha.log.Errorf("failed to publish current door status. %v", err) - continue + if ha.doorStatusSupported { + for _, devicePort := range ha.devicePorts { + err := ha.doorStatus(byte(devicePort)) + if err != nil { + ha.log.Errorf("failed to publish current door status. %v", err) + continue + } } } else { ha.log.Debug("Status request skipped due to disable periodic requests.") @@ -231,11 +251,13 @@ out: continue } - if ha.doPeriodicRequests { - err := ha.doorStatus() - if err != nil { - ha.log.Errorf("failed to publish current door status. %v", err) - continue + if ha.doorStatusSupported { + for _, devicePort := range ha.devicePorts { + err := ha.doorStatus(byte(devicePort)) + if err != nil { + ha.log.Errorf("failed to publish current door status. %v", err) + continue + } } } else { ha.log.Debug("Status request skipped due to disable periodic requests.") @@ -254,11 +276,11 @@ func (ha *HomeAssistanceMqttClient) requestFastDootStatus() bool { return ha.requestFastUpdate.After(time.Now()) // check if fast update timeout is still not reached } -func (ha *HomeAssistanceMqttClient) doorStatus() error { +func (ha *HomeAssistanceMqttClient) doorStatus(devicePort byte) error { ha.log.Tracef("Publish current door status") startTs := time.Now() - direction, position, err := ha.getDoorStatus() + direction, position, err := ha.getDoorStatus(devicePort) endTs := time.Now() ha.log.Debugf("Get door status took %v", endTs.Sub(startTs)) if err != nil { @@ -278,7 +300,7 @@ func (ha *HomeAssistanceMqttClient) doorStatus() error { state = utils.OPEN } - err = ha.PublishCurrentDoorStatus(position, direction, state) + err = ha.PublishCurrentDoorStatus(position, direction, state, int(devicePort)) if err != nil { return fmt.Errorf("failed to publish current door status. %v", err) } @@ -286,18 +308,18 @@ func (ha *HomeAssistanceMqttClient) doorStatus() error { return nil } -func (ha *HomeAssistanceMqttClient) PublishCurrentDoorStatus(position int, direction string, state string) error { - mqttToken := ha.mqttClient.Publish(ha.getGetStateTopicName(), qosAtLeastOnce, false, state) +func (ha *HomeAssistanceMqttClient) PublishCurrentDoorStatus(position int, direction string, state string, devicePort int) error { + mqttToken := ha.mqttClient.Publish(ha.getGetStateTopicName(devicePort), qosAtLeastOnce, false, state) if mqttToken.Wait() && mqttToken.Error() != nil { return fmt.Errorf("failed to publish discovery message. %v", mqttToken.Error()) } - mqttToken = ha.mqttClient.Publish(ha.getPositionTopicName(), qosAtLeastOnce, false, fmt.Sprintf("%d", position)) + mqttToken = ha.mqttClient.Publish(ha.getPositionTopicName(devicePort), qosAtLeastOnce, false, fmt.Sprintf("%d", position)) if mqttToken.Wait() && mqttToken.Error() != nil { return fmt.Errorf("failed to publish discovery message. %v", mqttToken.Error()) } - mqttToken = ha.mqttClient.Publish(ha.getDirectionTopicName(), qosAtLeastOnce, false, direction) + mqttToken = ha.mqttClient.Publish(ha.getDirectionTopicName(devicePort), qosAtLeastOnce, false, direction) if mqttToken.Wait() && mqttToken.Error() != nil { return fmt.Errorf("failed to publish discovery message. %v", mqttToken.Error()) } @@ -307,7 +329,7 @@ func (ha *HomeAssistanceMqttClient) PublishCurrentDoorStatus(position int, direc return nil } -func (ha *HomeAssistanceMqttClient) PublishAvabilityMessage(online bool) error { +func (ha *HomeAssistanceMqttClient) PublishAvabilityMessage(online bool, devicePort int) error { var message string if online { @@ -316,7 +338,7 @@ func (ha *HomeAssistanceMqttClient) PublishAvabilityMessage(online bool) error { message = utils.OFFLINE } - mqttToken := ha.mqttClient.Publish(ha.getAvailabilityTopic(), qosAtLeastOnce, true, message) + mqttToken := ha.mqttClient.Publish(ha.getAvailabilityTopic(devicePort), qosAtLeastOnce, true, message) if mqttToken.Wait() && mqttToken.Error() != nil { return fmt.Errorf("failed to publish avability message. %v", mqttToken.Error()) } @@ -326,13 +348,13 @@ func (ha *HomeAssistanceMqttClient) PublishAvabilityMessage(online bool) error { return nil } -func (ha *HomeAssistanceMqttClient) PublishDiscoveryMessage() error { - discoveryMsg, err := ha.getDiscoveryMessage() +func (ha *HomeAssistanceMqttClient) PublishDiscoveryMessage(devicePort int) error { + discoveryMsg, err := ha.getDiscoveryMessage(devicePort) if err != nil { return fmt.Errorf("failed to generate discovery message. %v", err) } - mqttToken := ha.mqttClient.Publish(ha.getDiscoveryTopic(), qosAtLeastOnce, true, discoveryMsg) + mqttToken := ha.mqttClient.Publish(ha.getDiscoveryTopic(devicePort), qosAtLeastOnce, true, discoveryMsg) if mqttToken.Wait() && mqttToken.Error() != nil { return fmt.Errorf("failed to publish discovery message. %v", mqttToken.Error()) } diff --git a/cli/homeAssistant/messages.go b/cli/homeAssistant/messages.go index 8fcae20..7fb90c9 100644 --- a/cli/homeAssistant/messages.go +++ b/cli/homeAssistant/messages.go @@ -5,17 +5,21 @@ import ( "fmt" ) -func (ha *HomeAssistanceMqttClient) getDiscoveryMessage() (string, error) { - name := ha.getUniqueObjectId() - uniqueId := ha.getUniqueObjectId() - commandTopic := ha.getSetPositionTopic() - positionTopic := ha.getPositionTopicName() +func (ha *HomeAssistanceMqttClient) getDiscoveryMessage(devicePort int) (string, error) { + name := ha.getUniqueObjectId(devicePort) + uniqueId := ha.getUniqueObjectId(devicePort) + device_class := `"device_class": "garage",` + if !ha.doorStatusSupported { + device_class = "" + } + commandTopic := ha.getSetPositionTopic(devicePort) + positionTopic := ha.getPositionTopicName(devicePort) messageTemplate := ` { "name": "%s", "unique_id": "%s", - "device_class": "garage", + %s "command_topic": "%s", "position_topic": "%s", "device": { @@ -27,7 +31,7 @@ func (ha *HomeAssistanceMqttClient) getDiscoveryMessage() (string, error) { "payload_not_available": "%s" }` - message := fmt.Sprintf(messageTemplate, name, uniqueId, commandTopic, positionTopic, uniqueId, name, ha.getAvailabilityTopic(), ha.getAvabilityMessage(true), ha.getAvabilityMessage(false)) + message := fmt.Sprintf(messageTemplate, name, uniqueId, device_class, commandTopic, positionTopic, uniqueId, name, ha.getAvailabilityTopic(devicePort), ha.getAvabilityMessage(true), ha.getAvabilityMessage(false)) return message, nil } diff --git a/cli/homeAssistant/topics.go b/cli/homeAssistant/topics.go index 6c25523..bfa7a44 100644 --- a/cli/homeAssistant/topics.go +++ b/cli/homeAssistant/topics.go @@ -5,33 +5,36 @@ import ( "fmt" ) -func (ha *HomeAssistanceMqttClient) getPositionTopicName() string { - return fmt.Sprintf("%s/%s/position", ha.mqttBaseTopic, ha.mqttDeviceName) +func (ha *HomeAssistanceMqttClient) getPositionTopicName(devicePort int) string { + return fmt.Sprintf("%s/%d/position", ha.mqttBaseTopic, devicePort) } -func (ha *HomeAssistanceMqttClient) getSetPositionTopic() string { - return fmt.Sprintf("%s/cmnd/%s/position", ha.mqttBaseTopic, ha.mqttDeviceName) +func (ha *HomeAssistanceMqttClient) getSetPositionTopic(devicePort int) string { + return fmt.Sprintf("%s/cmnd/%d/position", ha.mqttBaseTopic, devicePort) } -func (ha *HomeAssistanceMqttClient) getDirectionTopicName() string { - return fmt.Sprintf("%s/%s/direction", ha.mqttBaseTopic, ha.mqttDeviceName) +func (ha *HomeAssistanceMqttClient) getDirectionTopicName(devicePort int) string { + return fmt.Sprintf("%s/%d/direction", ha.mqttBaseTopic, devicePort) } -func (ha *HomeAssistanceMqttClient) getGetStateTopicName() string { - return fmt.Sprintf("%s/%s/state", ha.mqttBaseTopic, ha.mqttDeviceName) +func (ha *HomeAssistanceMqttClient) getGetStateTopicName(devicePort int) string { + return fmt.Sprintf("%s/%d/state", ha.mqttBaseTopic, devicePort) } -func (ha *HomeAssistanceMqttClient) getDiscoveryTopic() string { +func (ha *HomeAssistanceMqttClient) getDiscoveryTopic(devicePort int) string { ////[/]/config - - return fmt.Sprintf("homeassistant/cover/halsecur/%s/config", ha.getUniqueObjectId()) + entity_type := "cover" + if !ha.doorStatusSupported { + entity_type = "button" + } + return fmt.Sprintf("homeassistant/%s/halsecur/%s/config", entity_type, ha.getUniqueObjectId(devicePort)) } -func (ha *HomeAssistanceMqttClient) getUniqueObjectId() string { +func (ha *HomeAssistanceMqttClient) getUniqueObjectId(devicePort int) string { deviceMacStr := hex.EncodeToString(ha.deviceMac[:]) - return fmt.Sprintf("%s%d", deviceMacStr, ha.devicePort) + return fmt.Sprintf("%s%d", deviceMacStr, devicePort) } -func (ha *HomeAssistanceMqttClient) getAvailabilityTopic() string { - return fmt.Sprintf("%s/%s/availability", ha.mqttBaseTopic, ha.mqttDeviceName) +func (ha *HomeAssistanceMqttClient) getAvailabilityTopic(devicePort int) string { + return fmt.Sprintf("%s/%d/availability", ha.mqttBaseTopic, devicePort) }