## Supported Bridges
* Broker: This bridge represents an MQTT Broker connection, configured and managed by this binding.
-* SystemBroker: A system configured broker cannot be changed by this binding and will be listed as read-only system-broker.
## Bridge Configuration
public static final String BINDING_ID = "mqtt";
// List of all Thing Type UIDs
- public static final ThingTypeUID BRIDGE_TYPE_SYSTEMBROKER = new ThingTypeUID(BINDING_ID, "systemBroker");
public static final ThingTypeUID BRIDGE_TYPE_BROKER = new ThingTypeUID(BINDING_ID, "broker");
public static final String PUBLISH_TRIGGER_CHANNEL = "publishTrigger";
+++ /dev/null
-/**
- * Copyright (c) 2010-2022 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.handler;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
-import org.openhab.core.io.transport.mqtt.MqttConnectionState;
-import org.openhab.core.io.transport.mqtt.MqttService;
-import org.openhab.core.io.transport.mqtt.MqttServiceObserver;
-import org.openhab.core.io.transport.mqtt.MqttWillAndTestament;
-import org.openhab.core.io.transport.mqtt.reconnect.PeriodicReconnectStrategy;
-import org.openhab.core.thing.Bridge;
-import org.openhab.core.thing.ThingStatus;
-import org.openhab.core.thing.ThingStatusDetail;
-
-/**
- * This handler does not much except providing all information from a
- * {@link MqttBrokerConnection} via Thing properties and put the Thing
- * offline or online depending on the connection.
- *
- * @author David Graeff - Initial contribution
- */
-@NonNullByDefault
-public class SystemBrokerHandler extends AbstractBrokerHandler implements MqttServiceObserver {
- // Properties
- public static final String PROPERTY_URL = "url";
- public static final String PROPERTY_USERNAME = "username";
- public static final String PROPERTY_PASSWORD = "password";
- public static final String PROPERTY_QOS = "qos";
- public static final String PROPERTY_RETAIN = "retain";
- public static final String PROPERTY_LAST_WILL = "lastwill";
- public static final String PROPERTY_RECONNECT_TIME = "reconnect_time_ms";
- public static final String PROPERTY_KEEP_ALIVE_TIME = "keep_alive_time_ms";
- public static final String PROPERTY_CONNECT_TIMEOUT = "connect_timeout_ms";
-
- protected final MqttService service;
-
- protected String brokerID = "";
- protected boolean discoveryEnabled = true;
-
- public SystemBrokerHandler(Bridge thing, MqttService service) {
- super(thing);
- this.service = service;
- }
-
- @Override
- public void connectionStateChanged(MqttConnectionState state, @Nullable Throwable error) {
- Map<String, String> properties = new HashMap<>();
-
- properties.put(PROPERTY_URL, connection.getHost() + ":" + String.valueOf(connection.getPort()));
- final String username = connection.getUser();
- final String password = connection.getPassword();
- if (username != null && password != null) {
- properties.put(PROPERTY_USERNAME, username);
- properties.put(PROPERTY_PASSWORD, password);
- }
- properties.put(PROPERTY_QOS, String.valueOf(connection.getQos()));
- final MqttWillAndTestament lastWill = connection.getLastWill();
- if (lastWill != null) {
- properties.put(PROPERTY_LAST_WILL, lastWill.toString());
- } else {
- properties.put(PROPERTY_LAST_WILL, "");
- }
- if (connection.getReconnectStrategy() instanceof PeriodicReconnectStrategy) {
- final PeriodicReconnectStrategy strategy = (PeriodicReconnectStrategy) connection.getReconnectStrategy();
- if (strategy != null) {
- properties.put(PROPERTY_RECONNECT_TIME, String.valueOf(strategy.getReconnectFrequency()));
- }
- }
- properties.put(PROPERTY_KEEP_ALIVE_TIME, String.valueOf(connection.getKeepAliveInterval()));
-
- updateProperties(properties);
- super.connectionStateChanged(state, error);
- }
-
- /**
- * The base implementation will set the connection variable to the given broker
- * if it matches the brokerID and will start to connect to the broker if there
- * is no connection established yet.
- */
- @Override
- @SuppressWarnings("PMD.CompareObjectsWithEquals")
- public void brokerAdded(String connectionName, MqttBrokerConnection addedConnection) {
- if (!connectionName.equals(brokerID) || connection == addedConnection) {
- return;
- }
-
- this.connection = addedConnection;
- super.initialize();
- }
-
- @Override
- public void brokerRemoved(String connectionName, MqttBrokerConnection removedConnection) {
- final MqttBrokerConnection connection = this.connection;
- if (removedConnection.equals(connection)) {
- connection.removeConnectionObserver(this);
- this.connection = null;
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.sharedremoved");
- return;
- }
- }
-
- @Override
- public void initialize() {
- this.brokerID = getThing().getConfiguration().get("brokerid").toString();
- this.discoveryEnabled = (Boolean) getThing().getConfiguration().get("enableDiscovery");
-
- service.addBrokersListener(this);
-
- connection = service.getBrokerConnection(brokerID);
- if (connection == null) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
- "@text/offline.notextualconfig [\"" + brokerID + "\"");
- return;
- }
- super.initialize();
- }
-
- @Override
- public void dispose() {
- service.removeBrokersListener(this);
- super.dispose();
- }
-
- @Override
- public boolean discoveryEnabled() {
- return discoveryEnabled;
- }
-}
import org.openhab.binding.mqtt.discovery.MQTTTopicDiscoveryService;
import org.openhab.binding.mqtt.handler.AbstractBrokerHandler;
import org.openhab.binding.mqtt.handler.BrokerHandler;
-import org.openhab.binding.mqtt.handler.SystemBrokerHandler;
import org.openhab.core.io.transport.mqtt.MqttService;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
public class MqttBrokerHandlerFactory extends BaseThingHandlerFactory implements MQTTTopicDiscoveryService {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream
- .of(MqttBindingConstants.BRIDGE_TYPE_SYSTEMBROKER, MqttBindingConstants.BRIDGE_TYPE_BROKER)
- .collect(Collectors.toSet());
+ .of(MqttBindingConstants.BRIDGE_TYPE_BROKER).collect(Collectors.toSet());
private final Logger logger = LoggerFactory.getLogger(MqttBrokerHandlerFactory.class);
final ThingTypeUID thingTypeUID = thing.getThingTypeUID();
final AbstractBrokerHandler handler;
- if (thingTypeUID.equals(MqttBindingConstants.BRIDGE_TYPE_SYSTEMBROKER)) {
- handler = new SystemBrokerHandler((Bridge) thing, mqttService);
- } else if (thingTypeUID.equals(MqttBindingConstants.BRIDGE_TYPE_BROKER)) {
+ if (thingTypeUID.equals(MqttBindingConstants.BRIDGE_TYPE_BROKER)) {
handler = new BrokerHandler((Bridge) thing);
} else {
throw new IllegalStateException("Not supported " + thingTypeUID.toString());
public static ThingUID getThingUID(String host, int port) {
return new ThingUID(MqttBindingConstants.BRIDGE_TYPE_BROKER, getThingID(host, port));
}
-
- public static ThingUID getTextualThingUID(String host, int port) {
- return new ThingUID(MqttBindingConstants.BRIDGE_TYPE_SYSTEMBROKER, getThingID(host, port));
- }
}
+++ /dev/null
-/**
- * Copyright (c) 2010-2022 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.internal.discovery;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import org.openhab.binding.mqtt.MqttBindingConstants;
-import org.openhab.core.config.discovery.AbstractDiscoveryService;
-import org.openhab.core.config.discovery.DiscoveryResultBuilder;
-import org.openhab.core.config.discovery.DiscoveryService;
-import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
-import org.openhab.core.io.transport.mqtt.MqttService;
-import org.openhab.core.io.transport.mqtt.MqttServiceObserver;
-import org.openhab.core.thing.ThingUID;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Deactivate;
-import org.osgi.service.component.annotations.Reference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The {@link MqttServiceDiscoveryService} is responsible for discovering connections on
- * the MqttService shared connection pool.
- *
- * @author David Graeff - Initial contribution
- */
-@Component(service = DiscoveryService.class, configurationPid = "discovery.systemmqttbroker")
-public class MqttServiceDiscoveryService extends AbstractDiscoveryService implements MqttServiceObserver {
- private final Logger logger = LoggerFactory.getLogger(MqttServiceDiscoveryService.class);
- MqttService mqttService;
-
- public MqttServiceDiscoveryService() {
- super(Stream.of(MqttBindingConstants.BRIDGE_TYPE_SYSTEMBROKER, MqttBindingConstants.BRIDGE_TYPE_BROKER)
- .collect(Collectors.toSet()), 0, true);
- }
-
- @Override
- @Activate
- protected void activate(Map<String, Object> config) {
- super.activate(config);
- }
-
- @Override
- @Deactivate
- protected void deactivate() {
- super.deactivate();
- }
-
- @Reference
- public void setMqttService(MqttService service) {
- mqttService = service;
- }
-
- public void unsetMqttService(MqttService service) {
- mqttService = null;
- }
-
- @Override
- protected void startScan() {
- mqttService.addBrokersListener(this);
- mqttService.getAllBrokerConnections().forEach((brokerId, broker) -> brokerAdded(brokerId, broker));
- stopScan();
- }
-
- @Override
- protected void startBackgroundDiscovery() {
- if (mqttService == null) {
- return;
- }
- mqttService.addBrokersListener(this);
- mqttService.getAllBrokerConnections().forEach((brokerId, broker) -> brokerAdded(brokerId, broker));
- }
-
- @Override
- protected void stopBackgroundDiscovery() {
- if (mqttService == null) {
- return;
- }
- mqttService.removeBrokersListener(this);
- }
-
- @Override
- public void brokerAdded(String brokerId, MqttBrokerConnection broker) {
- logger.trace("Found broker connection {}", brokerId);
-
- Map<String, Object> properties = new HashMap<>();
- properties.put("host", broker.getHost());
- properties.put("port", broker.getPort());
- properties.put("brokerid", brokerId);
- ThingUID thingUID;
- thingUID = new ThingUID(MqttBindingConstants.BRIDGE_TYPE_SYSTEMBROKER, brokerId);
- thingDiscovered(DiscoveryResultBuilder.create(thingUID).withProperties(properties)
- .withRepresentationProperty("brokerid").withLabel("MQTT Broker").build());
- }
-
- @Override
- public void brokerRemoved(String brokerId, MqttBrokerConnection broker) {
- ThingUID thingUID;
- thingUID = new ThingUID(MqttBindingConstants.BRIDGE_TYPE_SYSTEMBROKER, brokerId);
- thingRemoved(thingUID);
- }
-}
thing-type.mqtt.broker.label = MQTT Broker
thing-type.mqtt.broker.description = A connection to a MQTT broker
-thing-type.mqtt.systemBroker.label = System MQTT Broker
-thing-type.mqtt.systemBroker.description = A system configured and therefore read-only broker connection. Properties are reflecting the configuration and internal connection status.
# thing types config
thing-type.config.mqtt.broker.secure.description = Uses TLS/SSL to establish a secure connection to the broker.
thing-type.config.mqtt.broker.username.label = Username
thing-type.config.mqtt.broker.username.description = The MQTT username
-thing-type.config.mqtt.systemBroker.brokerid.label = Broker ID
-thing-type.config.mqtt.systemBroker.brokerid.description = Each system wide configured MQTT broker has a unique broker ID.
-thing-type.config.mqtt.systemBroker.enableDiscovery.label = Enable Discovery
-thing-type.config.mqtt.systemBroker.enableDiscovery.description = If set to true enables this broker for all discovery services.
# channel types
thing-type.mqtt.broker.label = MQTT bróker
thing-type.mqtt.broker.description = Kapcsolat az MQTT brókerhez
-thing-type.mqtt.systemBroker.label = Rendszer MQTT bróker
-thing-type.mqtt.systemBroker.description = Rendszerbeállított és ezért csak olvasható bróker kapcsolat. A tulajdonságok a beállítások és belső kapcsolat állapotot tükrözik.
# thing types config
thing-type.config.mqtt.broker.secure.description = TLS/SSL használata a bróker biztonságos kapcsolódásához.
thing-type.config.mqtt.broker.username.label = Felhasználónév
thing-type.config.mqtt.broker.username.description = Az MQTT felhasználói neve
-thing-type.config.mqtt.systemBroker.brokerid.label = Bróker azonosító
-thing-type.config.mqtt.systemBroker.brokerid.description = Minden rendszerszintú MQTT brókerhez egyedi bórker azonosító tartozik.
-thing-type.config.mqtt.systemBroker.enableDiscovery.label = Felderítés használata
-thing-type.config.mqtt.systemBroker.enableDiscovery.description = Ha bekapcsolja a felderítés szolgáltatótk ezt a brókert fogják használni.
# channel types
thing-type.mqtt.broker.label = Broker MQTT
thing-type.mqtt.broker.description = Una connessione a un broker MQTT
-thing-type.mqtt.systemBroker.label = Broker MQTT di Sistema
-thing-type.mqtt.systemBroker.description = Un sistema configurato e quindi con connessione broker di sola lettura. Le proprietà riflettono lo stato della configurazione e della connessione interna.
# thing types config
thing-type.config.mqtt.broker.secure.description = Utilizza TLS/SSL per stabilire una connessione sicura al broker.
thing-type.config.mqtt.broker.username.label = Username
thing-type.config.mqtt.broker.username.description = Il nome utente MQTT
-thing-type.config.mqtt.systemBroker.brokerid.label = ID Broker
-thing-type.config.mqtt.systemBroker.brokerid.description = Ogni broker MQTT configurato in tutto il sistema ha un ID broker unico.
-thing-type.config.mqtt.systemBroker.enableDiscovery.label = Abilita Ricerca
-thing-type.config.mqtt.systemBroker.enableDiscovery.description = Se impostato a true abilita questo broker per la scoperta di tutti i servizi.
# channel types
</config-description>
</bridge-type>
- <bridge-type id="systemBroker" extensible="publishTrigger">
- <label>System MQTT Broker</label>
- <description>A system configured and therefore read-only broker connection. Properties are reflecting the
- configuration and internal connection status.</description>
-
- <properties>
- <property name="url"/>
- <property name="username"/>
- <property name="password"/>
- <property name="qos"/>
- <property name="retain"/>
- <property name="lastwill"/>
- <property name="reconnect_time_ms"/>
- <property name="keep_alive_time_ms"/>
- </properties>
-
- <config-description>
- <parameter name="brokerid" type="text" required="true">
- <label>Broker ID</label>
- <description>Each system wide configured MQTT broker has a unique broker ID.</description>
- </parameter>
- <parameter name="enableDiscovery" type="boolean">
- <label>Enable Discovery</label>
- <description>If set to true enables this broker for all discovery services.</description>
- <advanced>true</advanced>
- <default>true</default>
- </parameter>
- </config-description>
- </bridge-type>
-
<channel-type id="publishTrigger">
<kind>trigger</kind>
<label>Publish Trigger</label>
+++ /dev/null
-/**
- * Copyright (c) 2010-2022 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.handler;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.*;
-
-import java.util.Collections;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.mockito.junit.jupiter.MockitoSettings;
-import org.mockito.quality.Strictness;
-import org.openhab.binding.mqtt.internal.MqttThingID;
-import org.openhab.core.config.core.Configuration;
-import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
-import org.openhab.core.io.transport.mqtt.MqttException;
-import org.openhab.core.io.transport.mqtt.MqttService;
-import org.openhab.core.thing.Bridge;
-import org.openhab.core.thing.binding.ThingHandlerCallback;
-import org.osgi.service.cm.ConfigurationException;
-
-/**
- * Tests cases for {@link org.openhab.binding.mqtt.handler.AbstractBrokerHandler}.
- *
- * @author David Graeff - Initial contribution
- */
-@ExtendWith(MockitoExtension.class)
-@MockitoSettings(strictness = Strictness.WARN)
-public class AbstractBrokerHandlerTest {
- private final String HOST = "tcp://123.1.2.3";
- private final int PORT = 80;
- private SystemBrokerHandler handler;
- int stateChangeCounter = 0;
-
- private @Mock ThingHandlerCallback callback;
- private @Mock Bridge thing;
- private @Mock MqttService service;
-
- @BeforeEach
- public void setUp() {
- doReturn(new Configuration(Collections.singletonMap("brokerid", MqttThingID.getThingUID(HOST, PORT).getId())))
- .when(thing).getConfiguration();
- handler = new SystemBrokerHandler(thing, service);
- handler.setCallback(callback);
- assertThat(handler.getThing().getConfiguration().get("brokerid"), is(MqttThingID.getThingID(HOST, PORT)));
- stateChangeCounter = 0;
- }
-
- @Test
- public void brokerAddedWrongID() throws ConfigurationException, MqttException {
- MqttBrokerConnection brokerConnection = mock(MqttBrokerConnection.class);
- handler.brokerAdded("nonsense_id", brokerConnection);
- assertNull(handler.connection);
- // We do not expect a status change, because brokerAdded will do nothing with invalid connections.
- verify(callback, times(0)).statusUpdated(any(), any());
- }
-
- @Test
- public void brokerRemovedBroker() throws ConfigurationException, MqttException {
- MqttBrokerConnectionEx connection = spy(
- new MqttBrokerConnectionEx("10.10.0.10", 80, false, "BrokerHandlerTest"));
- handler.brokerAdded(handler.brokerID, connection);
- assertThat(handler.connection, is(connection));
- handler.brokerRemoved("something", connection);
- assertNull(handler.connection);
- }
-
- @Test
- public void brokerAdded() throws ConfigurationException, MqttException {
- MqttBrokerConnectionEx connection = spy(
- new MqttBrokerConnectionEx("10.10.0.10", 80, false, "BrokerHandlerTest"));
-
- verify(callback, times(0)).statusUpdated(any(), any());
- handler.brokerAdded(handler.brokerID, connection);
-
- assertThat(handler.connection, is(connection));
-
- verify(connection).start();
-
- // First connecting then connected and another connected after the future completes
- verify(callback, times(3)).statusUpdated(any(), any());
- }
-}
+++ /dev/null
-/**
- * Copyright (c) 2010-2022 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.internal.discovery;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.*;
-
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.mockito.junit.jupiter.MockitoSettings;
-import org.mockito.quality.Strictness;
-import org.openhab.binding.mqtt.MqttBindingConstants;
-import org.openhab.core.config.discovery.DiscoveryListener;
-import org.openhab.core.config.discovery.DiscoveryResult;
-import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
-import org.openhab.core.io.transport.mqtt.MqttService;
-
-/**
- * Tests cases for {@link org.openhab.binding.mqtt.internal.discovery.MqttServiceDiscoveryService}.
- *
- * @author David Graeff - Initial contribution
- */
-@ExtendWith(MockitoExtension.class)
-@MockitoSettings(strictness = Strictness.WARN)
-public class ServiceDiscoveryServiceTest {
-
- private @Mock MqttService service;
- private @Mock DiscoveryListener discoverListener;
-
- @BeforeEach
- public void initMocks() {
- Map<String, MqttBrokerConnection> brokers = new TreeMap<>();
- brokers.put("testname", new MqttBrokerConnection("tcp://123.123.123.123", null, false, null));
- brokers.put("textual", new MqttBrokerConnection("tcp://123.123.123.123", null, true, null));
- when(service.getAllBrokerConnections()).thenReturn(brokers);
- }
-
- @Test
- public void testDiscovery() {
- // Setting the MqttService will enable the background scanner
- MqttServiceDiscoveryService d = new MqttServiceDiscoveryService();
- d.addDiscoveryListener(discoverListener);
- d.setMqttService(service);
- d.startScan();
-
- // We expect 3 discoveries. An embedded thing, a textual configured one, a non-textual one
- ArgumentCaptor<DiscoveryResult> discoveryCapture = ArgumentCaptor.forClass(DiscoveryResult.class);
- verify(discoverListener, times(2)).thingDiscovered(eq(d), discoveryCapture.capture());
- List<DiscoveryResult> discoveryResults = discoveryCapture.getAllValues();
- assertThat(discoveryResults.size(), is(2));
- assertThat(discoveryResults.get(0).getThingTypeUID(), is(MqttBindingConstants.BRIDGE_TYPE_SYSTEMBROKER));
- assertThat(discoveryResults.get(1).getThingTypeUID(), is(MqttBindingConstants.BRIDGE_TYPE_SYSTEMBROKER));
-
- // Add another thing
- d.brokerAdded("anotherone", new MqttBrokerConnection("tcp://123.123.123.123", null, false, null));
- discoveryCapture = ArgumentCaptor.forClass(DiscoveryResult.class);
- verify(discoverListener, times(3)).thingDiscovered(eq(d), discoveryCapture.capture());
- discoveryResults = discoveryCapture.getAllValues();
- assertThat(discoveryResults.size(), is(3));
- assertThat(discoveryResults.get(2).getThingTypeUID(), is(MqttBindingConstants.BRIDGE_TYPE_SYSTEMBROKER));
- }
-}