Skip to content

Commit

Permalink
[mqtt.homeassistant] Add support for Button component (openhab#15892)
Browse files Browse the repository at this point in the history
* [mqtt.homeassistant] Add support for Button component
* use a StringValue instead of an OnOffValue

---------

Signed-off-by: Cody Cutrer <cody@cutrer.us>
  • Loading branch information
ccutrer authored and andrewfg committed Nov 26, 2023
1 parent 340fd3c commit f25b0d0
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ public static AbstractComponent<?> createComponent(ThingUID thingUID, HaID haID,
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":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,15 @@ protected void assertNotPublished(String mqttTopic, String payload) {
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.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}

0 comments on commit f25b0d0

Please sign in to comment.