Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

Mqtt Broker configuration binding #3839

Merged
merged 1 commit into from
Apr 30, 2018

Conversation

davidgraeff
Copy link
Contributor

@davidgraeff davidgraeff commented Jul 15, 2017

Abstract

At the moment it is possible to configure brokers in a textual way. Without intensively watching the log file, there is no way to tell if the provided configuration is correct and if the connection to the broker have been established, neither via the GUI (PaperUI) nor machine readable (REST interface).

This binding makes the configuration of brokers more intuitive and let the user add broker connections as things. The connections are synced to the io.transport.mqtt.MqttService and are therefore available for all other bindings to use.

Features include:

  • 2 different Bridges: SystemBrokerConnection, BrokerConnection
  • Rich status feedback for system broker connections. No longer skimming through log files if a connection doesn't work.
  • Auto discovery of brokers: Enumeration of MqttService shared broker connections, best effort subnet and localhost scan on standard Mqtt ports
  • Configurable reconnect time: This is not possible via textual configuration yet
  • Security Certificate and public key pinning for ssl connections to brokers
  • Extensive tests for all handlers, the discovery services and the SSLContextProvider.

Discussion

Points that need to be discussed might be:

  • No channels There are no channels on the broker Things. Everything is published to Thing properties right now. The connection status could be made available via a "status channel" additionally.
  • Security The public key and certificate hashes for key and certificate pinning are stored in the thing configuration. I'm not sure if this is the safest places to store them as the configuration can be changed via the rest interface. It is at least the only way to let the user configure them easily at the moment.

I'm happy to hear some feedback.

Cheers,
David

@davidgraeff davidgraeff changed the title [WIP] Mqtt binding [WIP] Mqtt Broker configuration binding Jul 15, 2017
@davidgraeff davidgraeff force-pushed the mqtt_binding branch 2 times, most recently from 66ca3ba to 44d52cd Compare July 21, 2017 12:19
@davidgraeff davidgraeff changed the title [WIP] Mqtt Broker configuration binding [RFC] Mqtt Broker configuration binding Jul 21, 2017
@davidgraeff davidgraeff force-pushed the mqtt_binding branch 8 times, most recently from c52073b to 9b841e5 Compare July 29, 2017 09:08
@davidgraeff davidgraeff force-pushed the mqtt_binding branch 2 times, most recently from fca6078 to db4c2ca Compare July 30, 2017 08:22
@davidgraeff davidgraeff changed the title [RFC] Mqtt Broker configuration binding Mqtt Broker configuration binding Jul 30, 2017
@davidgraeff
Copy link
Contributor Author

@htreu The PR is ready for review

Copy link
Contributor

@htreu htreu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @davidgraeff, I gave this a first round. Looks good from what I can say. Please find some comments inline.

import org.junit.Test;

/**
* Tests cases for {@link HexUtils}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually for the MqttWillAndTestamentBuilder

public void invalidHex() {
final String hexTest = "a2a1a0ll";
byte[] test = HexUtils.fromHex(hexTest);
assertThat(hexTest, is(HexUtils.toHexString(test)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this will fail in line 56, so the assertion is obsolete.

Copy link
Contributor Author

@davidgraeff davidgraeff Aug 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, makes sense this way: First an ascii hex is decoded to bytes and then those bytes are encoded to ascii hex again and compared.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In line 53 (@Test(expected = IllegalArgumentException.class)) you expect the code to throw the IAE which is done by the code in line 56. So I guess line 57 is never reached.

The following test case will run happily:

@Test(expected = IllegalArgumentException.class)
public void invalidHex() {
    final String hexTest = "a2a1a0ll";
    HexUtils.fromHex(hexTest);
    assertThat(true, is(false)); // should fail here if the line is reached.
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. fixed

*
* @author David Graeff - Initial contribution
*/
public class NetworkDiscoveryTests {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually the MqttServiceDiscoveryServiceTest?

import org.mockito.MockitoAnnotations;

/**
* Tests cases for {@link HexUtils}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for MqttServiceDiscoveryService?

import org.mockito.stubbing.Answer;

/**
* Tests cases for {@link HexUtils}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for NetworkDiscoveryService?

@@ -0,0 +1,131 @@
package org.eclipse.smarthome.binding.mqttbroker.internal.ssl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

license header missing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -0,0 +1,6 @@
package org.eclipse.smarthome.binding.mqttbroker.internal.ssl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

license header missing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -0,0 +1,9 @@
package org.eclipse.smarthome.binding.mqttbroker.internal.ssl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

license header missing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

package org.eclipse.smarthome.binding.mqttbroker.internal.ssl;

public interface PinnedCallback {
void pinnedLearnedHash(Pin pin);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add some javadoc (all methods).

@@ -0,0 +1,39 @@
package org.eclipse.smarthome.binding.mqttbroker.internal.ssl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

license header missing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -0,0 +1 @@
OSGI-INF/*.xml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please create the folder OSGI-INF and place the .gitignore with content *.xml inside. right now the folder is marked as new for git after checkout and build.

@davidgraeff
Copy link
Contributor Author

@htreu Changes incorporated

@htreu
Copy link
Contributor

htreu commented Aug 28, 2017

@davidgraeff looks good so far, please take another look at this comment #3839 (comment). Thanks.

Copy link
Contributor

@maggu2810 maggu2810 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems my comments has been incorporated.
So, okay from my side.

Thanks @davidgraeff for your whole MQTT work.

@htreu
Copy link
Contributor

htreu commented Apr 10, 2018

@davidgraeff do you want to wait for #5364 or adopt the timeout with another PR?

@davidgraeff
Copy link
Contributor Author

It is not possible to test broker handlers without a timeout. I will never get a thing online/offline status update. Therefore I'll reckon waiting is the better option.

@htreu
Copy link
Contributor

htreu commented Apr 11, 2018

Travis complains, I guess we already know this one:

[ERROR] /home/travis/build/eclipse/smarthome/extensions/binding/org.eclipse.smarthome.binding.mqtt/src/main/java/org/eclipse/smarthome/binding/mqtt/internal/MqttBrokerHandlerFactory.java:[38] 
[ERROR] 	@Component(immediate = true, service = ThingHandlerFactory.class, configurationPid = { "MqttBrokerHandlerFactory" })
[ERROR] 	                                                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[ERROR] Type mismatch: cannot convert from String[] to String

@htreu
Copy link
Contributor

htreu commented Apr 11, 2018

Some more Travis goodness:

[WARNING] /home/travis/build/eclipse/smarthome/extensions/binding/org.eclipse.smarthome.binding.mqtt/META-INF/MANIFEST.MF:[32]
The version of the package org.osgi.service.cm should not be specified
[ERROR] org.eclipse.smarthome.binding.mqtt.internal.ssl.PinnedCallback.java:[2]
Header line doesn't match pattern ^ \* Copyright \(c\) 2014,2018 Contributors to the Eclipse Foundation$

@davidgraeff
Copy link
Contributor Author

@htreu Done

Copy link
Contributor

@htreu htreu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested locally (w/o actual broker), works nicely with the MQTT connections from the managed service.

Thanks for the awesome work @davidgraeff!

@kaikreuzer let me know if you want to have another look and change your review status.

Copy link
Contributor

@kaikreuzer kaikreuzer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I still do have a few comments, please see below.

xmlns:binding="http://eclipse.org/smarthome/schemas/binding/v1.0.0"
xsi:schemaLocation="http://eclipse.org/smarthome/schemas/binding/v1.0.0 http://eclipse.org/smarthome/schemas/binding-1.0.0.xsd">

<name>MQTT Broker connections</name>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file describes the whole "mqtt" binding - not just the parts of this bundle.
So the name should imho be "MQTT Binding".

xsi:schemaLocation="http://eclipse.org/smarthome/schemas/binding/v1.0.0 http://eclipse.org/smarthome/schemas/binding-1.0.0.xsd">

<name>MQTT Broker connections</name>
<description>Add/remove MQTT broker connections and manage system-wide configured connections</description>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also update to be applicable for the binding in general.

@@ -0,0 +1,7 @@
binding.mqtt.name = MQTT Broker
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dito

@@ -0,0 +1,7 @@
binding.mqtt.name = MQTT Broker
binding.mqtt.description = Konfiguriere MQTT Broker Verbindungen
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dito

<context>network-address</context>
</parameter>

<parameter name="secure" type="text" required="true">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please apply the formatter

*
* @author David Graeff - Initial contribution
*/
@Component(immediate = true, service = DiscoveryService.class, configurationPid = "org.eclipse.smarthome.NetworkDiscoveryService")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> pid discovery.networkmqttbroker

lock.tryLock(TIMEOUT_IN_MS, TimeUnit.MILLISECONDS);

if (testConnection.connectionState() == MqttConnectionState.CONNECTED) {
logger.trace("Found service device at {}",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change to fully parameterised logging: {}:{}.


ThingUID thingUID = MqttThingID.getThingUID(testConnection.getHost(), testConnection.getPort());
thingDiscovered(DiscoveryResultBuilder.create(thingUID).withTTL(120).withProperties(properties)
.withLabel("Mqtt Broker (" + testConnection.getHost() + ")").build());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> "MQTT Broker" and declare "host" as representation property

try {
scanTarget(c);
} catch (ConfigurationException | MqttException | InterruptedException e) {
logger.trace("Scan of {} failed", c.getHost() + ":" + String.valueOf(c.getPort()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change to fully parameterised logging


for (MqttBrokerConnection c : o) {
scheduler.execute(() -> {
Thread.currentThread().setName("Discovery thread " + c.getHost() + ":" + String.valueOf(c.getPort()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not change the thread names - they are from a re-used pool and they are already named by the framework.

@davidgraeff
Copy link
Contributor Author

Comments are addressed. If the readme is meant to describe all features of the other MQTT bundles, it still needs some editing though.

Copy link
Contributor

@kaikreuzer kaikreuzer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update - looks good to me, just a few small issues left to fix; I'll quickly create a commit to fix them myself, so that @htreu can create the CQ for this PR.

f the readme is meant to describe all features of the other MQTT bundles, it still needs some editing though.

No, I think it is just fine as it is, thanks!

<parameter name="port" type="integer">
<label>Broker Port</label>
<description>The port is optional, if none is provided, the typical ports 1883 and 8883 (SSL) are used.</description>
<context>network-address</context>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the port must not have context network-address.

@@ -1,7 +1,7 @@
Manifest-Version: 1.0
Automatic-Module-Name: org.eclipse.smarthome.binding.mqtt
Bundle-ManifestVersion: 2
Bundle-Name: MQTT Broker Connections
Bundle-Name: MQTT Binging
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo


Map<String, Object> properties = new HashMap<>();
properties.put("host", testConnection.getHost());
properties.put("port", testConnection.getPort());

ThingUID thingUID = MqttThingID.getThingUID(testConnection.getHost(), testConnection.getPort());
thingDiscovered(DiscoveryResultBuilder.create(thingUID).withTTL(120).withProperties(properties)
.withLabel("Mqtt Broker (" + testConnection.getHost() + ")").build());
.withRepresentationProperty(testConnection.getHost()).withLabel("MQTT Broker").build());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the representation property must be the key, not the value!

@kaikreuzer
Copy link
Contributor

Done with 509ab06.

@htreu I think everything is ready for creating a CQ now.

@htreu
Copy link
Contributor

htreu commented Apr 23, 2018

Unfortunately we have to tranquillise Travis one more time:

unnecessary Mockito stubbings(org.eclipse.smarthome.binding.mqtt.internal.discovery.NetworkDiscoveryServiceTest)  Time elapsed: 0.072 sec  <<< ERROR!
org.mockito.exceptions.misusing.UnnecessaryStubbingException: 
Unnecessary stubbings detected in test class: NetworkDiscoveryServiceTest
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
  1. -> at org.eclipse.smarthome.binding.mqtt.internal.discovery.NetworkDiscoveryServiceTest$NetworkDiscoveryServiceEx.createTestConnections(NetworkDiscoveryServiceTest.java:80)
  2. -> at org.eclipse.smarthome.binding.mqtt.internal.discovery.NetworkDiscoveryServiceTest$NetworkDiscoveryServiceEx.createTestConnections(NetworkDiscoveryServiceTest.java:81)
Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.

This is the main mqtt binding.

At the moment it is possible to configure brokers in a textual way. Without intensively watching the log file, there is no way to tell if the provided configuration is correct and if the connection to the broker have been established, neither via the GUI (PaperUI) nor machine readable (REST interface).

This binding makes the configuration of brokers more intuitive and let the user add broker connections as things.
The connections are synced to the io.transport.mqtt MqttService and are therefore available for all other bindings to use.

Features include:
* 2 different Bridges: SystemBrokerConnection, BrokerConnection
* Rich status feedback for textual configured brokers. No longer skimming through log files if a connection doesn't work.
* Auto discovery of brokers (Enumeration of MqttService shared broker connections, best effort subnet and localhost scan on standard Mqtt ports)
* Configurable reconnect time (this is not possible via textual configuration yet)
* Certificate and public key pinning for ssl connections to brokers
* Extensive tests for all handlers, the discovery services and the SSLContextProvider.

Signed-off-by: David Graeff <david.graeff@web.de>
@htreu
Copy link
Contributor

htreu commented Apr 24, 2018

FTR: CQ16168 created.

@htreu htreu added the CQ label Apr 27, 2018
@htreu
Copy link
Contributor

htreu commented Apr 30, 2018

FTR: CQ16168 approved.

@htreu htreu removed the CQ label Apr 30, 2018
@htreu htreu merged commit 3250489 into eclipse-archived:master Apr 30, 2018
ermartens pushed a commit to ermartens/smarthome that referenced this pull request Jun 15, 2018
This is the main mqtt binding.

At the moment it is possible to configure brokers in a textual way. Without intensively watching the log file, there is no way to tell if the provided configuration is correct and if the connection to the broker have been established, neither via the GUI (PaperUI) nor machine readable (REST interface).

This binding makes the configuration of brokers more intuitive and let the user add broker connections as things.
The connections are synced to the io.transport.mqtt MqttService and are therefore available for all other bindings to use.

Features include:
* 2 different Bridges: SystemBrokerConnection, BrokerConnection
* Rich status feedback for textual configured brokers. No longer skimming through log files if a connection doesn't work.
* Auto discovery of brokers (Enumeration of MqttService shared broker connections, best effort subnet and localhost scan on standard Mqtt ports)
* Configurable reconnect time (this is not possible via textual configuration yet)
* Certificate and public key pinning for ssl connections to brokers
* Extensive tests for all handlers, the discovery services and the SSLContextProvider.

Signed-off-by: David Graeff <david.graeff@web.de>
@htreu htreu added this to the 0.10.0 milestone Oct 30, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants