-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial contribution of a Niko Home Control binding. #1589
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great piece of work @mherwege, congratulations!
Thank you for this binding.
I've caught a few things worth improving.
Please read through the Code Guidelines and see what else could be missing.
Additionally:
- Please run code formatter on your files ("Format selection" or "Cleanup")
- Please add
about.html
file to the binding (without 3rd party license or with 3rd party license info)
Thanks again! 👍 🥇
@@ -0,0 +1,11 @@ | |||
# binding |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove this file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
File removed.
</config-description> | ||
</bridge-type> | ||
|
||
<thing-type id="onOff"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please reformat this file using the provided code formatter or clean up settings,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran the code formatter on all files.
@@ -0,0 +1,79 @@ | |||
# Niko Home Control Binding | |||
The openHAB2 Niko Home Control binding integrates with a [Niko Home Control](http://www.nikohomecontrol.be/) system through a Niko Home Control IP-interface. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a newline after each heading
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add blank lines.
<parent> | ||
<groupId>org.openhab.binding</groupId> | ||
<artifactId>pom</artifactId> | ||
<version>2.0.0-SNAPSHOT</version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please change version to 2.1.0-SNAPSHOT
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed snapshot version.
|
||
<groupId>org.openhab.binding</groupId> | ||
<artifactId>org.openhab.binding.nikohomecontrol</artifactId> | ||
<version>2.0.0-SNAPSHOT</version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please change version to 2.1.0-SNAPSHOT
@kubawolanin Thank you for your review and suggestions for improvement. I believe I have done all the changes you were requesting. I had another look at the coding guidlines and did a few changes to the logging levels based on that. I hope I have done everything right. Java development, using git and Eclipse is a new experience for me. So be critical if anything is not what it should be. I can only learn from it. |
A nuisance, please put the code blocks in your README in code blocks rather than indenting them. Thanks for contributing! |
@ThomDietrich Formatting changes have been done. I believe used 4 spaces in front of the lines, which I assumed also identify code. Unless I do something wrong, the backtick blocks don't render well in the Eclipse preview. |
@mherwege I don't know about the Eclipse preview. Normally I'd prefer the backticks style, as does the rest of the openHAB documentation. It's easier to manage and less error prone. One benefit is, that you can provide the language to syntax highlight with, otherwise the syntax will be auto detected (some markdown engines). The latter is not true for intended code blocks. Correction: Just tested (docs.openhab.org) and the four spaces version is also syntax highlighted after syntax autodetection. Still the backticks version should be the preferred choice. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @mherwege thanks for your contribution! i did an initial review, can you take a look at my remarks?
<advanced>true</advanced> | ||
</parameter> | ||
</config-description> | ||
</thing-type> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does not seem to be properly formatted, note that XML files should be formatted using tabs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be OK now.
Service-Component: OSGI-INF/*.xml | ||
Export-Package: org.openhab.binding.nikohomecontrol;uses:="org.eclipse.smarthome.core.thing", | ||
org.openhab.binding.nikohomecontrol.handler; | ||
uses:="org.eclipse.smarthome.core.thing, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The uses should not be there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
|
||
Copyright (c) 2014-2016 by the respective copyright holders. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that this file has an outdated copyright header, can you fix all of them by running
mvn license:format
Please commit only the ones for your binding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I started development in 2016. I manually changed dates in all of them as mvn license:format does not seem to work in my environment.
|
||
private Logger logger = LoggerFactory.getLogger(NikoHomeControlBridgeHandler.class); | ||
|
||
private NikoHomeControlCommunication nhcComm = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a reason you initialise this one and not for example the refreshTimer
, note that I prefer not to initialize fields to their defaults.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed all initialize to default.
if (config.get(CONFIG_HOST_NAME) != null) { | ||
logger.debug("Niko Home Control: bridge handler host {}", config.get(CONFIG_HOST_NAME).toString()); | ||
addr = InetAddress.getByName(config.get(CONFIG_HOST_NAME).toString()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if this not true
(ie. config.get(CONFIG_HOST_NAME) == null
) addr
will remain null
it feels incorrect?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A null hostname is allowed downstream as there is a mechanism to discover one. I have changed it a bit and put in comments to make this clearer.
// if that JSON cannot be converted, it should be an array of hashmaps in the data field | ||
nhcCmdAck = new NHCCmdAck(); | ||
nhcCmdAck = gson.fromJson(nhcMessage, NHCCmdAck.class); | ||
if (nhcCmdAck.cmd != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See 313
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
listThermostatHVAC(nhcCmdAck); | ||
} else if (nhcCmdAck.cmd.equals("readtariffdata")) { | ||
readTariffData(nhcCmdAck); | ||
} else if (nhcCmdAck.cmd.equals("getalarms")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could consider to use a switch for this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kept it, as the second block does look at cmd and event, making a switch more difficult. I did put it in a separate method.
thing.getConfiguration().put(CONFIG_HOST_NAME, nhcComm.getAddr().getHostAddress()); | ||
thing.getConfiguration().put(CONFIG_PORT, port); | ||
HashMap<String, String> properties = new HashMap<String, String>(); | ||
properties.put("IP Address", nhcComm.getAddr().getHostAddress()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it wise to store it with spaces, should you maybe use camelCase?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was in doubt, but followed your suggestion. I also put this all in a separate method, so I can easily call it on restart of the communication as well.
logger.debug("Niko Home Control: restart communication at scheduled time"); | ||
updateStatus(ThingStatus.OFFLINE); | ||
nhcComm.stopCommunication(true); | ||
thing.setProperty("IP Address", nhcComm.getAddr().getHostAddress()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better use a constant instead of duplicating it here and on line 126
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separated the whole properties block out in a separate method, so no duplication anymore.
public void run() { | ||
logger.debug("Niko Home Control: restart communication at scheduled time"); | ||
updateStatus(ThingStatus.OFFLINE); | ||
nhcComm.stopCommunication(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this method should publicly be called restartCommunication
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed and changed.
@martinvw many thanks for this review. I appreciate the time you spent on reviewing my code. I can't hide I am not a programmer by trade and Java is fairly new to me. I learned a lot from your feedback. |
@mherwege you are welcome thanks for your time to do the contribution! I also have to take a look at the discovery, I'll be back :-) |
@mherwege I fear that you are completely right, maybe @SJKA or @kaikreuzer can tell us whether this is indeed the best way to do thing discovery for items on a bridge? |
I didn't look too closely into the code yet, but it indeed seems that the ThingDiscoveryService (btw, a very awkward name here, should be better adapted to have the binding name in it as well) is nowhere registered as an OSGi service, is that right? @mherwege is correct that it cannot be done through XML as you will effectively need to register a ThingDiscoveryService per bridge, so you might end up with multiple instances. |
@martinvw I think I have covered all suggestions and questions. Thank you again for your time, effort and guidance on this. @kaikreuzer My implementation borrowed the discovery piece from the Milight binding. The discovery service is not registered in the thing handler factory, but in the thing handler initialize method. |
Ok, I found the registration here: https://github.com/openhab/openhab2-addons/pull/1589/files#diff-cab28c130e927102c8fbb50465c1b3c8R57, which means that the service registers itself in its code - that's a very uncommon construct. Please note that the |
@kaikreuzer Thank you for the information. I have done as requested and moved the discovery registration to the handler factory. |
@martinvw Thank you again for all your effort reviewing this. I believe I have now covered all your requests and suggestions, as well as the issue identified by you and Kai. I am happy to follow up on any further requests or suggestions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the changes, its a great improvement. I spotted some additional things. Nothing big mainly small improvements.
<name>Niko Home Control Binding</name> | ||
<packaging>eclipse-plugin</packaging> | ||
|
||
<properties> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could leave this out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
logger.debug("Niko Home Control: cannot discover, discovery service not started"); | ||
} | ||
|
||
} catch (IOException e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this only thrown from line 111 or can it also come from other places?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only from that line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to correct myself here. It is thrown from current line 123 (was 111) and line 119. Both of them are communication issues, so that's why I catch both of them together. The debug logs would show the underlying difference.
|
||
// This timer will restart the bridge connection periodically | ||
logger.debug("Niko Home Control: restart bridge connection every {} min", refreshInterval); | ||
refreshTimer = scheduler.scheduleAtFixedRate(new Runnable() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use scheduleWithFixedDelay which is preferred over scheduleAtFixedRate, see Coding Guidelines D.3
@Override | ||
public void run() { | ||
|
||
logger.debug("Niko Home Control: restart communication at scheduled time"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you really need to restart it by marking it offline and trying to reconnect? Should this method maybe start with a check:
if (nhcComm.communicationActive()) {
return;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran into issues when just checking for the connection to still be up. It looks like it was disconnecting automatically at the Niko controller side after a while whatever I did. So I fear that just checking for the connection and not doing anything will get it disconnected after a while. OH will then stop receiving channel updates without knowing anything is wrong until it sends something. I got over it by this periodic restart. I made it configurable. So it could be shortened or switched off if someone sees a different behaviour than I have.
*/ | ||
private void updateProperties() { | ||
|
||
HashMap<String, String> properties = new HashMap<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its best practice to use only the interface type for the declaration:
Map<String, String> properties = new HashMap<>();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
private String lastEnergyErase = ""; | ||
private String lastConfig = ""; | ||
|
||
private final ArrayList<Integer> locations = new ArrayList<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider to add the interface types here, so List
, Map
broadcastaddr = InetAddress.getByAddress(ipaddr); | ||
|
||
DatagramSocket datagramSocket = null; | ||
try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use the try with resources on the DatagramSocket
then you can get rid of the finally:
https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modified.
} else if ("listactions".equals(nhcCmdAck.cmd)) { | ||
listActions(nhcCmdAck); | ||
} else if ("listactions".equals(nhcCmdAck.event)) { | ||
for (HashMap<String, String> action : nhcCmdAck.data) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use interface instead of type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
try { | ||
nhcSocket.close(); | ||
} catch (IOException e) { | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of the times its better to make explicit that you ignore an exception. For this location it makes sense to ignore, but better do that explicit. You could name the exception ignore
and add a comment why you ignored it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -200,6 +200,12 @@ | |||
<bundle start-level="80">mvn:org.openhab.binding/org.openhab.binding.network/${project.version}</bundle> | |||
</feature> | |||
|
|||
<feature name="openhab-binding-nikohomecontrol" description="Niko Home Control Binding" version="${project.version}"> | |||
<feature>openhab-runtime-base</feature> | |||
<feature>esh-model-script</feature> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need this one? I see only one binding who has this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. Probably slipped in through copy/paste.
@martinvw Thank you once again for the review. I have done the changes, but will need to test again when I get home. I will push when it all works and let you know then. |
@martinvw The updated code has now been pushed. |
@martinvw I didn't encounter any issue when running locally. All changes have been pushed. I did notice that my local maven check build suddenly gave 'missing eol at line 0' errors on all my files, while I did not touch most of them. It is building and running fine, so I ignored it for now. My local check profile is still v1, so pretty old by now I believe. |
@martinvw I have made some extensive changes to my code base. These changes implement a custom gson deserializer, split the largest class in multiple classes (hopefully making the code easier to maintain) and implement auto-discovery for the bridge. As the changes touch many parts of the code, I am not sure I what the best way to proceed is. Should I push it? It will probably require another detailed review. Or should I stick with what is aleady here an wait for further feedback? |
Please push it, I'll do another review :-) |
@martinvw Thank you for your patience and understanding. I have pushed the changes. Let me know what you think. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for all the changes, a great improvement can you look at my remarks/questions?
<default>8000</default> | ||
<advanced>true</advanced> | ||
</parameter> | ||
<parameter name="BROADCASTADDR" type="text" required="false"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
XML files should be indented using tabs according to our code formatter, the github view suggests that it is a mix now.
<parameter name="ADDR" type="text" required="false"> | ||
<label>IP or Host Name</label> | ||
<description>Address will be resolved on connection if not configured</description> | ||
<advanced>true</advanced> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is every config advanced?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, as these are all optional in a typical home network and when running openHab on a machine connected to only one network segment. The documentation explains when these parameters are required. E.g. I don't need these when running openHab from my laptop, but I do when running from my Pi that doubles as a VPN server. On the Pi, discovery wrongly picks the VPN network interface to look for a broadcast address. There is no way to know what network to use unless the user configures one or more of these advanced parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds as if you are heavily mixing discovery with configuration here.
The configuration should really enable the handler to reach out to the (correct!) device immediately - so I would clearly expect the IP address being configured here. Otherwise you will be in big trouble if there ARE multiple gateways on the same network (which you should never rule out).
The job of the discovery service is to find devices on the network and provide their IP addresses for the thing configuration; note that they can even update existing Things in case their IP addresses change (this is e.g. how all the UPnP-discovered devices are handled).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kaikreuzer I am afraid I will need more help here. I can move the broadcastAddr parameter to the binding. But I don't know how to access it from the bridge discovery service then. From what I have seen, I can easily access it from the handler factory by overriding the activate method and adding componentContext.getProperties(). But that does not seem to help me with the bridge discovery.
I agree I would be in trouble if there are 2 gateways on the local network. However, I think this is highly unlikely. I even suspect the whole Niko system would not work if that was the case. However, I did run into the issue I have 2 separate network interfaces on my openHAB system, therefore making it impossible to reliably find the proper broadcast address automatically. I need to provide it. Once I have that, it is stable. The specific IP address is not stable though and my router does not allow me to fix it. So I cannot provide a fixed IP.
I am open to any guidance on how to do this better and indeed move the broadcast parameter to the binding level. Would that mean I have to register the discovery service from the handler factory, rather than through the declaration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a very valid question, I didn't think of that. In general, it would be possible to directly access the OSGi Configuration Admin and get the configuration for the binding out of it in the DiscoveryService code - but that isn't really nice.
Actually, there are quite some other bindings that have the requirement to figure out the correct network interface under which the openHAB instance is accessible. Would it make sense to have the user configure it and make the value available through a new method in NetUtil?
Another option is to do it similarly to UPnP and mDNS: Simply do the broadcast on ALL available interfaces :-)
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
|
||
Copyright (c) 2014-2017 by the respective copyright holders. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that this file has a non-default copyright header, can you fix all of them by running
mvn license:format
Please commit only the ones for your binding.
* | ||
* @author Mark Herwege | ||
*/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove empty line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
if (config.get(CONFIG_HOST_NAME) != null) { | ||
try { | ||
// If hostname or address was provided in the configuration, try to use this to for bridge and give | ||
// error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the line breaks became a little bit funny here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Too many edits. I cleaned it up.
|
||
for (HashMap<String, String> action : data) { | ||
|
||
int id = Integer.valueOf(action.get("id")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use valueOf if you want an integer if you want an int call parseInt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the info. I wasn't aware of that.
logger.debug("Niko Home Control: event execute action {} with state {}", id, state); | ||
try { | ||
this.actions.get(id).setState(state); | ||
} catch (Exception e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you really need to catch the Exception-class or are there more specific exceptions you could catch like the IOException or maybe only RuntimeException's (which is not that good either). The current code and also catching RuntimeException's might 'hide' programming errors like NullPointerExceptions occurring.
https://www.google.nl/search?q=java%20why%20not%20to%20catch%20exception
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I don't need to. Something is very wrong when I would get here. It would be a programming error. So I removed the try/catch.
|
||
message = new NhcMessageListMap(); | ||
|
||
List<HashMap<String, String>> dataList = new ArrayList<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Map
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected.
for (Entry<String, JsonElement> entry : jsonDataObject.entrySet()) { | ||
data.put(entry.getKey(), entry.getValue().getAsString()); | ||
} | ||
dataList.add((HashMap<String, String>) data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you define dataList correct you don't need this cast
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected.
|
||
return message; | ||
|
||
} catch (IllegalStateException | ClassCastException e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why/when do we get these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want the binding to completely fail when what I get back from the controller is different from what I expect. Debug logging will show me exactly what came back and will tell me if it cannot be interpreted. IllegalStateException can be thrown from the nested getAsJsonObject() calls when the inner element would be a json array or primitive, rather then an object. Similarly ClassCastException would occur if the getAsString() call is not on a primite, but an object or array.
A number of messages I get from the controller, but do not interpret at the moment, have formats that cannot be deserialized with the current logic yet. The nested logic would have to be refined. Also, I am not 100% sure all versions of the controller software use exactly the same json formats. This also shields from that. The debug log will show an 'Unsupported json type' message.
I learned the structure from this: http://www.javacreed.com/gson-deserialiser-example/. As the nesting can be complex and unpreditable, I only went with what I know for know, and will extend this part if I implement extra functionality.
@martinvw Thank you very much for the review. I think I made all changes. I have added some questions and remarks in the review. Could you have a look? I will already push what I have done. |
You've got it EXACTLY! That was exactly the discussion I had around wall buttons in KNX. And our conclusion was that - although we actually need to react on state updates - we will deprecate the
This is something I actually missed in the review: The correct granularity for such an activity would actually be a channel, not a thing. Having tens of Things with a single channel does not make much sense. For KNX we decided to have a basic thing with no fixed set of channels. This can then be either "discovered and populated with channels" or manually defined in a *.things file. Using the manual configuration, users would also be free to define multiple things for structuring their channels in logical groups (in KNX e.g. having a Thing for an 8-blinds actuator with 8 channels). Would that also make sense for NHC in order to reduce the number of Things? |
@kaikreuzer I am not sure yet the slave concept will solve it completely in my case. The issue is that if you define the NHC device as the slave, what will you do with updates coming from it? The NHC device and its defined 'activity' are both an input, an output and a state. The communication is always 2-way.
Actuators (inputs) and outputs are not separate in NHC at the level I am integrating. So it should act as a slave at one point in time, and as a master at another.
|
Signed-off-by: MHERWEGE <[email protected]>
Discard them. In slave mode, updates are not passed on to the items, only commands are. So yes, you will need to find some way for the user to configure that a certain channel is merely a button, which should send commands, so that in such a case your handler sends commands and not state updates.
Be careful not to mix up the item/functional and thing/physical levels here (see this explanation of "things" in openHAB. All what you describe make sense on an item level: Every light, shutter, etc. is naturally one ITEM (let's call if object). Each of this has a location. But the "Thing" (actuator) can have a different location and combine multiple channels (->items). For NHC, these are your things and their location is very likely the electrical cabinet. So the situation is very similar to KNX actually. |
But then I lose all possibility of having the LED work, as I won't have a correct state in the NHC system anymore. If the state is changed outside of NHC, it still needs to get a command to update its state. It will always reply with an update message that is indistinguishable from a message sent when the button was pressed on the NHC side. So the slave mechanism will not resolve the issue for the NHC binding.
I do understand the background to this and I do appreciate your advice on this. I just don't think this is a black or white situation.
I do believe this is certainly a boundary situation that could go either way. I don't feel comfortable changing it at this time for the reasons listed above. |
@kaikreuzer I am looking into bringing the broadcastAddr parameter on the binding level, rather than bridge level. This indeed is a more logical structure. I have a few questions on it though:
Thank you for your guidance and patience. |
@kaikreuzer I have done the easy changes so far. |
This clearly shows that the correct modelling would be a single thing with many channels, which are the exposed actions. This is how the ESH concepts are meant to be used. I understand your reasoning, though, as there isn't really nice support for dynamic channels (yet) in the UIs (but actually for textual configuration it would be easier to go that way). So let's leave it as is, but please keep in mind that it is rather considered as a workaround than as an example of how to ideally model things. :-)
Cool, that's than definitely the easiest way to move forward! |
Removed broadcastaddr parameter, used bridgediscovery to find IP address and use background discovery service to update if required. Don't change or discover IP address in bridge handler. Signed-off-by: MHERWEGE <[email protected]>
@kaikreuzer I believe I have now done all requested changes. Please let me know if you have any further feedback. |
Signed-off-by: MHERWEGE <[email protected]>
Cool, thank you so much @mherwege and congrats to have it finally merged 👍 |
* master: [senseBox] Forgot to add binding to feature.xml (openhab#2371) [Kodi] Fix audio sink (openhab#2301) (openhab#2303) Initial contribution of a Niko Home Control binding. (openhab#1589) [keba] fixed typo (openhab#2370) Removed utilisation of org.apache.http.client (openhab#2369) [RFXCOM] Make LWRF mood buttons work (openhab#2366) [senseBox] Switch caching to ESH ExpiringCacheMap (openhab#2361) Fixed problems found by AuthorTagCheck in the cometvisu bundle (openhab#2364) Added author tag where missing. (openhab#2351) [RFXCOM] Fix chill temperature (openhab#2362) initial contribution Windcentrale binding (openhab#1535) Tesla : reset the Even Stream connection to the Tesla Back-end if the event time stamps differ too much from the current system time (openhab#2358) Homematic: Some updates (openhab#2346) [RFXCOM] Support all data from wind sensors (openhab#2329) Gardena: Optimized refresh after command (openhab#2353) Fix some javadocs. (openhab#2349) Some small non-standard copyright banners which we missed while reviewing (openhab#2347)
* Initial contribution of Niko Home Control binding. Signed-off-by: Mark Herwege <[email protected]>
* Initial contribution of Niko Home Control binding. Signed-off-by: Mark Herwege <[email protected]>
* Initial contribution of Niko Home Control binding. Signed-off-by: Mark Herwege <[email protected]>
* Initial contribution of Niko Home Control binding. Signed-off-by: Mark Herwege <[email protected]>
* Initial contribution of Niko Home Control binding. Signed-off-by: Mark Herwege <[email protected]>
* Initial contribution of Niko Home Control binding. Signed-off-by: Mark Herwege <[email protected]>
* Initial contribution of Niko Home Control binding. Signed-off-by: Mark Herwege <[email protected]>
* Initial contribution of Niko Home Control binding. Signed-off-by: Mark Herwege <[email protected]>
* Initial contribution of Niko Home Control binding. Signed-off-by: Mark Herwege <[email protected]>
* Initial contribution of Niko Home Control binding. Signed-off-by: Mark Herwege <[email protected]>
Signed-off-by: Schrotti <[email protected]>
Signed-off-by: Mark Herwege [email protected]