Nibe uplink binding

Sure, but as the public API is still in development it could also change. The private API is now stable for about 3 years so I would say it is quite stable. Openhab itself is less stable.

Sorry to say that but adjusting the heating temperatures will not help to save any money. If you are using “floor heating” you should optimize your heating as follows:

  1. set the room thermostat to max in the room which should be the warmest one in your house (typically the bath room)
  2. adjust the heating curve and parallel shift of your nibe until the bathroom has the desired temperature.
  3. adjust the room thermostats in all other rooms if those are warmer than desired.
  4. steps 2+3 need to be repeated several times

I ended up with heating curve 4 and shift 0. The temperature in all rooms is very constant. If the weather is very sunny the bathroom might be a little bit warmer than usual but in general the system works very efficiently and my heating costs are very very low so no need for any micro management.

Could you explain how this works in details. I used the public API manually several times I had to enter my credentials, afterwards some kind of token was generated. If I remember correctly. I used Insomnia Rest client for that purpose. But however after a few minutes inactivity the token became invalid and I had to authenticate again. This is not very convenient if there is a power failure or internet connection failure or maintenance of NIBE web service the binding will lose authentication.

Autodiscovery is really nice but as my approach only uses one thing I think it is not a must have. My latest DEV version which is not yet merged contains a lot of simplification + support for dynamic channels which means you could add any number of custom channels. This was really missing my binding.

It could make sense to use public API for data retrieval and private API for write access. In fact the private write API is completly separated from the private read API except that both use the same authentication/session.
But in my opinion it does not make any sense to have two binding implementations within one binding. In order to integrate your and my binding both bindings should share a common code base. Only the code which is used to access the API should be different. As I said, my binding in general allows to use different implementations as I have implemented the “Command” pattern. I already used it to access different APIs that use different types of authentication in my Solaredge. So there is already a proof of concept that it could be used. But it will still be quite a lot of work to integrate it.

I don’t think it’s likely to change, but there’s a small risk.

I have done that as well, but we have radiators on our upper floor that are quicker to adjust. Even in winter the heatpump can allow the compressor to turn off completely for long periods on a sunny day, or run at a low frequency, and the electric addon (which are the biggest source of power consumption) don’t have to run as much. Money-wise it doesn’t add up to much, but it’s satisfying to see :wink:.

There’s different types of OAuth authentication. A simpler one, where the user logs in, and then the application (often browser-based) can get access to the data. This is called “implicit grant”. But if it’s meant for server-server communication the “authorization grant flow” is used, where the user authenticates, giving OH in this instance an authorization code. OH can then trade this for an access-token that can be used when querying the API. The token is only valid for a short time (30 minutes), but with it also comes a “refresh token” that can be user to obtain a new token when it has expired. This makes it able to continue without user interaction indefinitely, even if OH would be offline for several hours, the refresh token it has saved can be used to get a new access token. The token renewal is handled automatically by the framework. And since it’s a well defined standard, it works the same for many different services. The spotify binding uses it as well. I have had my own implementation running for over a year without having to do any re-authentication, even though both my server and Nibe’s have been offline from time to time.

It would be my preference as well to have as much as possible in common. I have made my binding the way I felt was easiest, just to get it working and to learn all the ins and outs of OH, but I can certainly try to adapt it more to your modelling. Do you know if it’s possible to have the same Thing working both with and without a bridge?

Ok, if you have radiators this is of course a different story. However my eletric addon was never activated in heating mode since I have the NIBE (about 4 years now).

Well, this is great. When I started development the framwork did not support OAuth and I am not so familiar with the standard. But you are right this seems to be the better option from a security perspective.

I am afraid this will not work. I think supporting both Thing-only and Bridge-based object model will not work. So either my code needs to be adopted to the Bridge based approach or your code should be adopted to the Thing only approach.

Either way, this would mean breaking changes for the users, since the existing thing-types would have to be altered, either to work with a bridge or to be able to select the type of connection and having two sets of fields for credential input (or having two versions of each thing, which would be the worst option, in which case we might as well have two entirely different approaches). I think in that case going with the bridge model would be the easiest for the users, to just move their user credentials to the bridge and then recreate the thing (and perhaps re-link all items). They could then easily just swap the bridge to the other type should they wish later on.

In my opinion it does not make much difference if a bridge or a thing will be used. Maybe a bridge is slightly better. But anyway you will need the OAuth token to store for read access + (optional) username + password to be able to use write access.
Otherwise you will end up in different things for read and write access and thus you will have duplicated channels. This will confuse end users and this implementation details should definetely be hidden from end users. Thus I strongly recommend to implement both APIs within the same bridge/thing. And of course it should work the way that public read API is activated by default and private write API could be activated in addition.

BTW: This is my pull request with latest changes / simplifications: [Nibeuplink] enhanced custom channel feature by alexf2015 · Pull Request #6696 · openhab/openhab-addons · GitHub

That sounds like a good approach, even though it’s a bit more difficult to set up, than just filling in username and password in a field. The spotify binding use the same approach (but registering an application at the nibe uplink developer site is simpler, than with spotify). Your code for updating settings could be left almost just as it is.

Getting the data would require a different model though I’m afraid. When fetching parameters from the api you are only allowed to request 15 at a time. With your model this would require several different classes that override the prepareRequest() method to create requests with different query strings (where a list of parameter to get is provided), and then the poller would have to put all of them in the queue. This in turn means that all parameters must be statically defined in the code and requested, even if there’s no item linked to that channel, and it might require even more different classes to cover the different combination of parameters for different models.

It would be easier to define a common interface with something like getParameters(), setParameters(), pollParameters() etc, and then the implementing class(es) can decide how to construct the requests and where to send them, and then report back to the handler’s updateChannelStatus() method.

Finally my latest enhancement of the binding was merged and will be available in 2.5.6:

This change will break the existing custom channel definition but will add this:

  • unlimited number of custom channels can be defined
  • scaling of values will be possible (unscaled, div by 10, div by 100)
1 Like

After the update to 2.5.6 I receive warnings on all channels like this one:

[WARN ] [ternal.model.DataResponseTransformer] - could not handle unknown type base-type-40004, channel nibeuplink:f1145:44a25413:base#40004, value 211

Should I completely remove and re-add the F1145 Thing and all it’s items?

UPDATE: Yes I had to remove the Thing and re-add it. Everything works perfect again now. Thanks for the nice update! Being more flexible in the custom channels is very nice :slight_smile:

Somehow the conversion of “degree minutes” seems to make some problems:

2020-12-07 15:52:44.359 [WARN ] [pse.smarthome.core.items.GenericItem] - failed notifying listener 'org.eclipse.smarthome.io.rest.sitemap.internal.PageChangeListener@c43c6e' about state update of item NIBE_DEG_MIN: null

java.lang.NullPointerException: null

	at org.eclipse.smarthome.ui.internal.items.ItemUIRegistryImpl.getLabel(ItemUIRegistryImpl.java:435) ~[?:?]

	at org.eclipse.smarthome.io.rest.sitemap.internal.PageChangeListener.constructSitemapEvents(PageChangeListener.java:228) ~[?:?]

	at org.eclipse.smarthome.io.rest.sitemap.internal.PageChangeListener.constructSitemapEvents(PageChangeListener.java:214) ~[?:?]

	at org.eclipse.smarthome.io.rest.sitemap.internal.PageChangeListener.constructAndSendEvents(PageChangeListener.java:172) ~[?:?]

	at org.eclipse.smarthome.io.rest.sitemap.internal.PageChangeListener.stateChanged(PageChangeListener.java:186) ~[?:?]

	at org.eclipse.smarthome.core.items.GenericItem$1.run(GenericItem.java:261) [bundleFile:?]

	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_265]

	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_265]

	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_265]

2020-12-07 15:52:44.366 [WARN ] [pse.smarthome.core.items.GenericItem] - failed notifying listener 'org.eclipse.smarthome.io.rest.sitemap.internal.PageChangeListener@34fadf' about state update of item NIBE_DEG_MIN: Can not compare incompatible units.

java.lang.IllegalArgumentException: Can not compare incompatible units.

	at org.eclipse.smarthome.core.library.types.QuantityType.compareTo(QuantityType.java:174) ~[bundleFile:?]

	at org.eclipse.smarthome.core.library.types.QuantityType.equals(QuantityType.java:156) ~[bundleFile:?]

	at org.eclipse.smarthome.core.items.GenericItem$1.run(GenericItem.java:260) [bundleFile:?]

	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_265]

	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_265]

	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_265]

2020-12-07 15:52:44.366 [ERROR] [me.core.internal.events.EventHandler] - Dispatching/filtering event for subscriber 'org.eclipse.smarthome.core.events.EventSubscriber' failed: Can not compare incompatible units.

java.lang.IllegalArgumentException: Can not compare incompatible units.

	at org.eclipse.smarthome.core.library.types.QuantityType.compareTo(QuantityType.java:174) ~[?:?]

	at org.eclipse.smarthome.core.library.types.QuantityType.equals(QuantityType.java:156) ~[?:?]

	at org.eclipse.smarthome.core.items.GenericItem.applyState(GenericItem.java:234) ~[?:?]

	at org.eclipse.smarthome.core.items.GenericItem.setState(GenericItem.java:219) ~[?:?]

	at org.eclipse.smarthome.core.library.items.NumberItem.setState(NumberItem.java:121) ~[?:?]

	at org.eclipse.smarthome.core.internal.items.ItemUpdater.receiveUpdate(ItemUpdater.java:75) ~[?:?]

	at org.eclipse.smarthome.core.items.events.AbstractItemEventSubscriber.receive(AbstractItemEventSubscriber.java:52) ~[?:?]

	at org.eclipse.smarthome.core.internal.events.EventHandler.lambda$0(EventHandler.java:155) ~[?:?]

	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_265]

	at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_265]

	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_265]

	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_265]

	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_265]

2020-12-07 16:09:44.554 [WARN ] [pse.smarthome.core.items.GenericItem] - failed notifying listener 'org.eclipse.smarthome.model.rule.runtime.internal.engine.RuleEngineImpl@1cf4a2c' about state update of item NIBE_DEG_MIN: Unable to convert to system unit during compare.

java.lang.IllegalArgumentException: Unable to convert to system unit during compare.

	at org.eclipse.smarthome.core.library.types.QuantityType.compareTo(QuantityType.java:171) ~[bundleFile:?]

	at org.eclipse.smarthome.core.library.types.QuantityType.equals(QuantityType.java:156) ~[bundleFile:?]

	at org.eclipse.smarthome.core.items.GenericItem$1.run(GenericItem.java:260) [bundleFile:?]

	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_265]

	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_265]

	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_265]

2020-12-07 16:22:44.699 [WARN ] [pse.smarthome.core.items.GenericItem] - failed notifying listener 'org.eclipse.smarthome.io.rest.sitemap.internal.PageChangeListener@34fadf' about state update of item NIBE_DEG_MIN: Unable to convert to system unit during compare.

java.lang.IllegalArgumentException: Unable to convert to system unit during compare.

	at org.eclipse.smarthome.core.library.types.QuantityType.compareTo(QuantityType.java:171) ~[bundleFile:?]

	at org.eclipse.smarthome.core.library.types.QuantityType.equals(QuantityType.java:156) ~[bundleFile:?]

	at org.eclipse.smarthome.core.items.GenericItem$1.run(GenericItem.java:260) [bundleFile:?]

	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_265]

	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_265]

	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_265]

Any idea why this is happening?

I’ve tried to use public API using instructions provided here, but no matter what I’m always getting an error “invalid_client”. Checked credentials & parameters multiple times, but cannot figure out what’s wrong. E.g. I’ve been able to verify that client_id & client_secret are correct as if I’m deliberately sending the wrong ones, I’m getting different error message(s).

Would you like to share the code/script you are using for getting the access token?

I’ve actually written an openhab binding that I personally use now, which works great, and is much easier to get connected. Not sure if I will get it included in the distribution though… But I could at least share it here if you’d like. Do you use OH 2 or 3?

I’m using OH 2

Then you can download the binding from this link, and put it in your addons folder.

To make it work, you need to set the Callback URL in your Nibe Uplink Application to <your-oh-address>/nibeuplinkconnect (e.g http://localhost:8080/nibeuplinkconnect)

Then, in openhab, add a bridge (NibeUplink REST API Bridge) and input your identifier and secret. After the bridge is created, go to <your-oh-address>/nibeuplinkconnect and click the Authorize button. If all goes well you should then be able to search for things and your heatpump should show up!

Let me know if you encounter any problems.

1 Like

After a long fight with perl scripts, this was unbelievably painless, thanks!! Working flawlessly

Hi
I updated my openhab to 2.5.11 and after that I no longer get any data from my NIBE F1255. it says Online in Paper UI but no data.
I updated the software on my NIBE at the same time but restored it to see if that was the problem but no result.
Thankful if anyone can help me!

The NibeUplink binding does not interact with your NIBE driectly. It gets its data via the NibeUplink service. Therefore it does not depend on any Firmware version of your local installation.
I recently updated to 2.5.11 as well but it works fine for me. If it is online it seems that connection to the NibeUplink service was established. It seems to be a little bit weird that it is online on the one hand but does not retrieve any data on the other hand. NibeUplink always returns data even if it is outdated and your NIBE is switched off or disconnected from the internet. Please check again if your configuration is correct, especially the ID of your device needs to be correct.

Thank you for you response.
I tried to uninstall and install the binding and it worked fine after that, don´t know what the issue was.

Hi @pacive,

I’m also looking for a another binding for Nibe. I’m using the SMO40 with F2120/20 and the generic binding doesn’t read all parameters.

I’m using OH3.

many thanks,
emiel

Hi @emiel! Glad that others feel that my binding is useful! You can download an OH3 version from here. Setup instructions are available in the README. If you have any questions or issues you can use this forum thread. Hope everything works for you. I haven’t tried it with any external heatpump addons (except for an extra heating circuit), but as long as Nibe reports it the binding should automatically create corresponding channels.

Hi @pacive Many thanks! I’ll start binding and I’ll let you know if it works in my setup!