[mqtt.homeassistant] Add support for Button component (#15892)

* [mqtt.homeassistant] Add support for Button component
* use a StringValue instead of an OnOffValue

---------

Signed-off-by: Cody Cutrer <cody@cutrer.us>
This commit is contained in:
Cody Cutrer 2023-11-19 09:06:54 -07:00 committed by GitHub
parent 9a920a244a
commit fc9579430e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 141 additions and 0 deletions

View File

@ -0,0 +1,58 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.mqtt.homeassistant.internal.component;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.mqtt.generic.values.TextValue;
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
import com.google.gson.annotations.SerializedName;
/**
* An MQTT button, following the https://www.home-assistant.io/integrations/button.mqtt/ specification.
*
* @author Cody Cutrer - Initial contribution
*/
@NonNullByDefault
public class Button extends AbstractComponent<Button.ChannelConfiguration> {
public static final String BUTTON_CHANNEL_ID = "button";
/**
* Configuration class for MQTT component
*/
static class ChannelConfiguration extends AbstractChannelConfiguration {
ChannelConfiguration() {
super("MQTT Button");
}
protected @Nullable Boolean optimistic;
@SerializedName("command_topic")
protected @Nullable String commandTopic;
@SerializedName("payload_press")
protected String payloadPress = "PRESS";
}
public Button(ComponentFactory.ComponentConfiguration componentConfiguration) {
super(componentConfiguration, ChannelConfiguration.class);
TextValue value = new TextValue(new String[] { channelConfiguration.payloadPress });
buildChannel(BUTTON_CHANNEL_ID, value, getName(), componentConfiguration.getUpdateListener())
.commandTopic(channelConfiguration.commandTopic, channelConfiguration.isRetain(),
channelConfiguration.getQos())
.build();
}
}

View File

@ -57,6 +57,8 @@ public class ComponentFactory {
return new AlarmControlPanel(componentConfiguration);
case "binary_sensor":
return new BinarySensor(componentConfiguration);
case "button":
return new Button(componentConfiguration);
case "camera":
return new Camera(componentConfiguration);
case "cover":

View File

@ -230,6 +230,15 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests
ArgumentMatchers.eq(payload.getBytes(StandardCharsets.UTF_8)), anyInt(), anyBoolean());
}
/**
* Assert that nothing was published on given topic.
*
* @param mqttTopic Mqtt topic
*/
protected void assertNothingPublished(String mqttTopic) {
verify(bridgeConnection, never()).publish(eq(mqttTopic), any(), anyInt(), anyBoolean());
}
/**
* Publish payload to all subscribers on specified topic.
*

View File

@ -0,0 +1,72 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.mqtt.homeassistant.internal.component;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.openhab.binding.mqtt.generic.values.TextValue;
import org.openhab.core.library.types.StringType;
/**
* Tests for {@link Button}
*
* @author Cody Cutrer - Initial contribution
*/
@NonNullByDefault
public class ButtonTests extends AbstractComponentTests {
public static final String CONFIG_TOPIC = "button/0x847127fffe11dd6a_auto_lock_zigbee2mqtt";
@SuppressWarnings("null")
@Test
public void testButton() {
var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), """
{
"dev_cla":"restart",
"name":"Restart",
"entity_category":"config",
"cmd_t":"esphome/single-car-gdo/button/restart/command",
"avty_t":"esphome/single-car-gdo/status",
"uniq_id":"78e36d645710-button-ba0e8e32",
"dev":{
"ids":"78e36d645710",
"name":"Single Car Garage Door Opener",
"sw":"esphome v2023.10.4 Nov 1 2023, 09:27:02",
"mdl":"esp32dev",
"mf":"espressif"}
}
""");
assertThat(component.channels.size(), is(1));
assertThat(component.getName(), is("Restart"));
assertChannel(component, Button.BUTTON_CHANNEL_ID, "", "esphome/single-car-gdo/button/restart/command",
"Restart", TextValue.class);
assertThrows(IllegalArgumentException.class,
() -> component.getChannel(Button.BUTTON_CHANNEL_ID).getState().publishValue(new StringType("ON")));
assertNothingPublished("esphome/single-car-gdo/button/restart/command");
component.getChannel(Button.BUTTON_CHANNEL_ID).getState().publishValue(new StringType("PRESS"));
assertPublished("esphome/single-car-gdo/button/restart/command", "PRESS");
}
@Override
protected Set<String> getConfigTopics() {
return Set.of(CONFIG_TOPIC);
}
}