Skip to content
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

[hdpowerview] Add support for calibrating a shade #12002

Merged
merged 15 commits into from
Jan 14, 2022

Conversation

jlaur
Copy link
Contributor

@jlaur jlaur commented Jan 9, 2022

Fixes #11767

Signed-off-by: Jacob Laursen jacob-github@vindvejr.dk

This pull request adds support for calibrating a shade.

Some refactoring had to be done in order to avoid boilerplate code. While doing this I found some additional issues that have been addressed:

  • When setting shade positions, response was not used to update channels, but instead a new request was made to refresh positions. This has been fixed to use the positions in the response, so new position will be updated much faster.
  • Since there is now multiple code paths for updating shade positions, initialization of capabilities had to be refactored as well.
  • Unused id variables in request classes removed.
  • 10 second delay in refreshing positions for no apparent reason.
  • Shade thing status will now initially be set to UNKNOWN until data for shade has been received. This is more transparent and also fixes situation when a shade would be configured with wrong Shade ID and initially be ONLINE, then OFFLINE after some time.
  • Any pending/ongoing tasks are now killed when disposing handler.
  • Shade ID is now only parsed after changing configuration.

Tests

Position update after UP/DOWN command:

2022-01-09 23:57:42.302 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'Blind9_Position' received command DOWN
2022-01-09 23:57:42.306 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'Blind9_Position' predicted to become DOWN
2022-01-09 23:57:42.324 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'Blind9_Position' changed from 83 to 100

STOP command after UP/DOWN:

2022-01-10 00:07:03.942 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'Blind9_Position' received command UP
2022-01-10 00:07:03.946 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'Blind9_Position' predicted to become UP
2022-01-10 00:07:03.957 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'Blind9_Position' changed from 100 to 0
2022-01-10 00:07:12.093 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'Blind9_Position' received command STOP
2022-01-10 00:07:17.041 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'Blind9_Position' changed from 0 to 65

@jlaur jlaur force-pushed the 11767-hdpowerview-calibration branch 2 times, most recently from 65dc4bf to 668292a Compare January 9, 2022 12:15
@wborn wborn added the enhancement An enhancement or new feature for an existing add-on label Jan 9, 2022
@jlaur jlaur added the work in progress A PR that is not yet ready to be merged label Jan 9, 2022
@andrewfg
Copy link
Contributor

When setting shade positions, response was not used to update channels, but instead a new request was made to refresh positions. This has been fixed to use the positions in the response, so new position will be updated much faster.

@jlaur in one of my own recent PR's I addressed and solved this issue here, in the moveShade() method, so perhaps you trying to "double solve" it ?? => Please check and advise.

@jlaur
Copy link
Contributor Author

jlaur commented Jan 10, 2022

in one of my own recent PR's I addressed and solved this issue here, in the moveShade() method, so perhaps you trying to "double solve" it ?? => Please check and advise.

Thanks for being vigilant! You definitely solved it. You solved it by using the calculated new position(s) to update the channels immediately. This works fine, and probably it will always work fine, unless we have a bug trying to set invalid positions which would then be rejected and positions would actually be unchanged.

Now it's slightly refactored to use positions from the response for being (also) immediately updated. This should not change anything, as the returned values should be the same as the new positions requested. This is also what I have seen in my tests - as documented in PR description. The reason for this change is that I noticed multiple REST services actually returning an updated Shade object, and we didn't use this "free information" at all. This way we can now update positions the same unified way after each REST call returning a Shade object with position information.

Copy link
Contributor

@andrewfg andrewfg left a comment

Choose a reason for hiding this comment

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

@jlaur you have made some quite extensive changes which are difficult to track via the GitHub browser; so instead I will have to download and build the jar in my IDE and test it on my own installation; however here a a few trivial comments concerning adding new @return declarations to the java docs.

@andrewfg
Copy link
Contributor

Again, trivial, but I saw a couple of Maven build warnings (however as they refer to JSON objects, they might not be resolvable; but see Shade/ShadeData..)

image

@andrewfg
Copy link
Contributor

@jlaur now I have studied your code in my Eclipse IDE (where it is much easier to understand your changes), and I can confirm that the changes look good to me (except the trivia noted above).

The new JAR is now running on my live system, and all the properties and channels are updating correctly; also I tried a few commands which worked too. However if you want me to try any specific tests, please let me know.

@jlaur
Copy link
Contributor Author

jlaur commented Jan 10, 2022

you have made some quite extensive changes which are difficult to track via the GitHub browser;

Yes, first commit is kind of big because I didn't want to introduce boilerplate code in order to remove it again in next commit. So the refactoring already started in this single commit. However, after that I tried to provide explicit commits for each distinct change. It might be easier to read commit by commit?

so instead I will have to download and build the jar in my IDE and test it on my own installation; however here a a few trivial comments concerning adding new @return declarations to the java docs.

I will have a look and try to fix them. Thanks for the help!

@andrewfg
Copy link
Contributor

My prior post crossed with yours.

@jlaur
Copy link
Contributor Author

jlaur commented Jan 10, 2022

The new JAR is now running on my live system, and all the properties and channels are updating correctly; also I tried a few commands which worked too. However if you want me to try any specific tests, please let me know.

Thanks, Andrew! Besides updating the examples in the README, I plan to improve handling of dispose while there are still ongoing requests. It works correctly now, but an error is logged which could be confusing. Besides that I don't plan to do anything major, so you should be able to catch up just reading the next few commits. Hopefully I will get it done tonight, and make the pull request ready for review after that. :-)

@jlaur
Copy link
Contributor Author

jlaur commented Jan 10, 2022

@andrewfg - and a little teaser: Of course I got some new ideas when working with this and testing it. invoke() is synchronized, so only one request at a time. A lot of calls are continuously made. So the more important calls (like "stop shade") are queued and can only happen after other calls like updating the scene list every minute. I'll create an issue, and we might brainstorm about solutions if you are interested and also see a problem.

@andrewfg
Copy link
Contributor

^
Obviously invoke() has to remain a synchronised method, but it sounds like you want the scheduler to have a Double Ended Queue “DEQue”. It would mean ditching the OH built in scheduler, and implementing something else within the binding. I think there are DEQue schedulers already existing in various standard libraries..

@jlaur
Copy link
Contributor Author

jlaur commented Jan 10, 2022

Again, trivial, but I saw a couple of Maven build warnings (however as they refer to JSON objects, they might not be resolvable; but see Shade/ShadeData..)

image

I'll need to dig a little deeper to find a good solution for this. To be honest, I'm relatively new to Java and I have a hate/love relationship with all this null annotation stuff. Having @NonNullByDefault for classes used solely for serialization is kind of annoying since everything within needs to be annotated as @Nullable anyway. So in this context nullable is not an exception from default, it's a rule. I will address it since I introduced it, but maybe not in context of this PR (not introduced in this PR).

@andrewfg
Copy link
Contributor

find a good solution for this.

Perhaps I will make a proposal tomorrow..

@jlaur jlaur marked this pull request as ready for review January 10, 2022 21:44
@jlaur jlaur removed the work in progress A PR that is not yet ready to be merged label Jan 10, 2022
@jlaur jlaur requested a review from a team January 10, 2022 22:29
@andrewfg
Copy link
Contributor

andrewfg commented Jan 11, 2022

I'll need to dig a little deeper to find a good solution for this. To be honest, I'm relatively new to Java and I have a hate/love relationship with all this null annotation stuff.

Attached are your de-serializer classes with @null annotations added.

HDPowerView Null Annotations.zip

Using these annotations, does in fact reveal some potential NPE failure points in your code in HDPowerViewHubHandler.updateFirmwareProperties() where additional null checks on potential de-serializer errors should be made as follows..

EDIT: use exceptions rather than return with logger.warn()

    private void updateFirmwareProperties() throws JsonParseException, HubProcessingException, HubMaintenanceException {
        if (firmwareVersions != null) {
            return;
        }
        HDPowerViewWebTargets webTargets = this.webTargets;
        if (webTargets == null) {
            throw new HubProcessingException("Web targets not initialized");
        }
        FirmwareVersion firmwareVersion = webTargets.getFirmwareVersion();
        FirmwareVersions firmwareVersions = firmwareVersion != null ? firmwareVersion.firmware : null;
        if (firmwareVersions == null) {
            throw new JsonParseException("Unable to get firmware version.");
        }
        this.firmwareVersions = firmwareVersions;
        Firmware mainProcessor = firmwareVersions.mainProcessor;
        if (mainProcessor == null) {
            throw new JsonParseException("Main processor firmware version missing in response.");
        }
        logger.debug("Main processor firmware version received: {}, {}", mainProcessor.name, mainProcessor.toString());
        Map<String, String> properties = editProperties();
        String processorName = mainProcessor.name;
        if (processorName != null) {
            properties.put(HDPowerViewBindingConstants.PROPERTY_FIRMWARE_NAME, processorName);
        }
        properties.put(Thing.PROPERTY_FIRMWARE_VERSION, mainProcessor.toString());
        Firmware radio = firmwareVersions.radio;
        if (radio != null) {
            logger.debug("Radio firmware version received: {}", radio.toString());
            properties.put(HDPowerViewBindingConstants.PROPERTY_RADIO_FIRMWARE_VERSION, radio.toString());
        }
        updateProperties(properties);
    }

@jlaur
Copy link
Contributor Author

jlaur commented Jan 11, 2022

Using these annotations, does in fact reveal some potential NPE failure points in your code in HDPowerViewHubHandler.updateFirmwareProperties() where additional null checks on potential de-serializer errors should be made as follows..

Thanks @andrewfg, I'll have a look and provide a separate PR for resolving these existing (although recently introduced) issues tonight. I'll also test what how gson will react when having a @NonNull attribute that is omitted in the JSON to be parsed. I suppose defining the contract more clearly with some attributes being mandatory might even increase the code quality as we could have unified exception handling instead of null checks everywhere. So might extend the scope a bit, at least I need to investigate a few things to provide a clean solution.

@andrewfg
Copy link
Contributor

how gson will react when having a @nonnull attribute that is omitted in the JSON to be parsed

I guess it will do the following..

  1. throw JsonParseException for any @nonnull objects,
  2. return a null value (with no error) for @nullable objects
  3. return 0 / false for any primitives

@jlaur
Copy link
Contributor Author

jlaur commented Jan 11, 2022

I guess it will do the following..

  1. throw JsonParseException for any @nonnull objects,
  2. return a null value (with no error) for @nullable objects
  3. return 0 / false for any primitives

Let's continue in #12027. It will not be part of this PR as it's unrelated, and also I would like to extend the scope to fix not only the annotations, but also error handling and contract verification in general for all methods.

Copy link
Contributor

@andrewfg andrewfg left a comment

Choose a reason for hiding this comment

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

LGTM

@jlaur
Copy link
Contributor Author

jlaur commented Jan 13, 2022

@openhab/add-ons-maintainers - beowulfe is listed as codeowner for the hdpowerview binding, but the user doesn't exist on GitHub anymore. What's the procedure - just remove? Secondly, @andrewfg, would you like to be added as you have been quite actively contributing to this binding? I have added myself as I'm quite into the binding at this point and feel responsibility for it.

@jlaur
Copy link
Contributor Author

jlaur commented Jan 13, 2022

@openhab/add-ons-maintainers - beowulfe is listed as codeowner for the hdpowerview binding, but the user doesn't exist on GitHub anymore. What's the procedure - just remove?

@openhab/add-ons-maintainers - I just did a quick check, and he seems to be the only one missing as GitHub user - but listed as owner for two bindings:

#!/usr/bin/python3

import requests

github_user = 'jlaur'
github_token = ''
github_root = 'https://api.github.com'

file = open('CODEOWNERS', 'r')
lines = file.readlines()
file.close()

headers = {
        'User-Agent': github_user,
        'Authorization': 'token ' + github_token
}

for line in lines:
        if line[0:9] == "/bundles/":
                parsed_line = line.split()
                for idx, val in enumerate(parsed_line):
                        if idx == 0:
                                binding = val
                        else:
                                user = val.lstrip('@')
                                if user == "openhab/add-ons-maintainers":
                                        continue
                                url = github_root + '/users/' + user
                                response = requests.get(url, headers=headers)
                                if response.status_code == 404:
                                        print(binding + ": User " + user + " does not exist.")

Result:

$ ./check_codeowners.py
/bundles/org.openhab.binding.hdpowerview/: User beowulfe does not exist.
/bundles/org.openhab.io.homekit/: User beowulfe does not exist.

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
@jlaur jlaur force-pushed the 11767-hdpowerview-calibration branch from 3ad3e75 to 585a706 Compare January 14, 2022 19:10
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
@jlaur
Copy link
Contributor Author

jlaur commented Jan 14, 2022

CI build failed with:

/opt/hostedtoolcache/maven/3.8.4/x64/bin/mvn: 194: exec: /opt/hostedtoolcache/Java_Zulu_jdk/11.0.13-8/x64/bin/java: not found
Error: Process completed with exit code 127.

Copy link
Contributor

@lolodomo lolodomo left a comment

Choose a reason for hiding this comment

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

LGTM

@lolodomo lolodomo added rebuild Triggers Jenkins PR build and removed rebuild Triggers Jenkins PR build labels Jan 14, 2022
@lolodomo
Copy link
Contributor

@wborn for help with the failing CI build.
Is it safe to merge as the other build succeeded?

@jlaur
Copy link
Contributor Author

jlaur commented Jan 14, 2022

Is it safe to merge as the other build succeeded?

I see that a new Jenkins build was scheduled, but previous one succeeded. Also CI build succeeded before last two commits. So IMHO it should be safe.

@lolodomo lolodomo merged commit 2832567 into openhab:main Jan 14, 2022
@lolodomo lolodomo added this to the 3.3 milestone Jan 14, 2022
moesterheld pushed a commit to moesterheld/openhab-addons that referenced this pull request Jan 18, 2022
* Add support for calibrating a shade.

Fixes openhab#11767

* Fix startup problems by decoupling capabilities cache from updateSoftProperties.
* Minor refactoring of capabilities and shade id handling.
* Dispose faster/safer by killing any remaining tasks.
* Set shade thing status to UNKNOWN until we receive any data for shade.
* Fix position update glitch after setting position.
* Remove unneeded catch after shade id refactoring.
* Document return values in Javadoc.
* Avoid logging InterruptedException during dispose.
* Add calibration example item.
* Reduce nesting.
* Add myself as reviewer for binding.
* Add Andrew Fiddian-Green as reviewer for binding.
* Handle JsonParseException.
* Fix alphabetic order.

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
nemerdaud pushed a commit to nemerdaud/openhab-addons that referenced this pull request Jan 28, 2022
* Add support for calibrating a shade.

Fixes openhab#11767

* Fix startup problems by decoupling capabilities cache from updateSoftProperties.
* Minor refactoring of capabilities and shade id handling.
* Dispose faster/safer by killing any remaining tasks.
* Set shade thing status to UNKNOWN until we receive any data for shade.
* Fix position update glitch after setting position.
* Remove unneeded catch after shade id refactoring.
* Document return values in Javadoc.
* Avoid logging InterruptedException during dispose.
* Add calibration example item.
* Reduce nesting.
* Add myself as reviewer for binding.
* Add Andrew Fiddian-Green as reviewer for binding.
* Handle JsonParseException.
* Fix alphabetic order.

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
NickWaterton pushed a commit to NickWaterton/openhab-addons that referenced this pull request Apr 27, 2022
* Add support for calibrating a shade.

Fixes openhab#11767

* Fix startup problems by decoupling capabilities cache from updateSoftProperties.
* Minor refactoring of capabilities and shade id handling.
* Dispose faster/safer by killing any remaining tasks.
* Set shade thing status to UNKNOWN until we receive any data for shade.
* Fix position update glitch after setting position.
* Remove unneeded catch after shade id refactoring.
* Document return values in Javadoc.
* Avoid logging InterruptedException during dispose.
* Add calibration example item.
* Reduce nesting.
* Add myself as reviewer for binding.
* Add Andrew Fiddian-Green as reviewer for binding.
* Handle JsonParseException.
* Fix alphabetic order.

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Nick Waterton <n.waterton@outlook.com>
andan67 pushed a commit to andan67/openhab-addons that referenced this pull request Nov 6, 2022
* Add support for calibrating a shade.

Fixes openhab#11767

* Fix startup problems by decoupling capabilities cache from updateSoftProperties.
* Minor refactoring of capabilities and shade id handling.
* Dispose faster/safer by killing any remaining tasks.
* Set shade thing status to UNKNOWN until we receive any data for shade.
* Fix position update glitch after setting position.
* Remove unneeded catch after shade id refactoring.
* Document return values in Javadoc.
* Avoid logging InterruptedException during dispose.
* Add calibration example item.
* Reduce nesting.
* Add myself as reviewer for binding.
* Add Andrew Fiddian-Green as reviewer for binding.
* Handle JsonParseException.
* Fix alphabetic order.

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
andrasU pushed a commit to andrasU/openhab-addons that referenced this pull request Nov 12, 2022
* Add support for calibrating a shade.

Fixes openhab#11767

* Fix startup problems by decoupling capabilities cache from updateSoftProperties.
* Minor refactoring of capabilities and shade id handling.
* Dispose faster/safer by killing any remaining tasks.
* Set shade thing status to UNKNOWN until we receive any data for shade.
* Fix position update glitch after setting position.
* Remove unneeded catch after shade id refactoring.
* Document return values in Javadoc.
* Avoid logging InterruptedException during dispose.
* Add calibration example item.
* Reduce nesting.
* Add myself as reviewer for binding.
* Add Andrew Fiddian-Green as reviewer for binding.
* Handle JsonParseException.
* Fix alphabetic order.

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Andras Uhrin <andras.uhrin@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement An enhancement or new feature for an existing add-on
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[hdpowerview] Add support for calibrating a shade
4 participants