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

Reworked auto-update infrastructure completely #5011

Merged
merged 22 commits into from
Sep 5, 2018

Conversation

sjsf
Copy link
Contributor

@sjsf sjsf commented Feb 1, 2018

This PR re-works the mechanism to automatically send item state events automatically when a command event was received.

Bindings (i.e. ThingHandlers via the ThingHandlerCallback) can set a AutoUpdatePolicy for any channel:

Policy Description
VETO It's not a good idea to send auto-updates, e.g. because the ThingHandler can (and will) do that much better. Makes sense especially for dimmers/rollershutters to have smooth transitions
DEFAULT The ThingHandler has no specific needs or opinions - the default if no policy is set explicitly
RECOMMEND It would be a good idea to send auto-updates (e.g. when a device doesn't expose its current state through its API) - unless another channel is linked to the same item which will take over this duty

The behavior of the AutoUpdateManager can be summarized like this:

Case Description Event Prediction
REQUIRED No channels are linked to the item -> act as a "binding" ✔️ -
RECOMMENDED Channels are linked but RECOMMENDed to send auto-updates ✔️ -
OPTIMISTIC At least one operational channel is linked with DEFAULT policy - *) changeStateTo
DONT At least one linked channel cast a VETO - -
REVERT All linked channel are not working - keepCurrentState

Therefore, in comparison to the previous implementation there are two major improvements:

  1. Sending automatic state updates before the binding can report back the real device status always happened based on the optimistic assumption that "everything will be alright". This doesn't hold true though when the framework already knows that this can't work, e.g. when the channel or thing does not exist, the ThingHandler is not there (yet) or the thing is in OFFLINE mode. In such cases there will be no automatic state update sent anymore.

  2. In the OPTIMISTIC case where the framework can assume that the binding eventually will send such a state update itself, by default now there won't be a automatic state update event sent out anymore. Instead, the prediction callback will be informed so that UIs still can react nicely, but the "real" item state is not affected anymore. This has the huge advantage that e.g. persistence services won't get fed anymore with such "false", optimistic state updates but the item state rather represents the "real" values. RECOMMENDED and REQUIRED cases remain the same, events are still sent out as before.

As a rough summary, these are the changes on technical level:

  • dropped the remainings of the AutoUpdateBindingConfigProvider
  • dropped the autoupdate "binding" bundle
  • Introduced the AutoUpdateManager as part of the core framework
  • Allow bindings to RECOMMEND or VETO the auto-update for specific channels
  • Created a new hook to allow UIs getting notified about "optimistic" state updates
  • Do not really send auto-updates anymore unless no channel is linked or a binding RECOMMENDs to do so for a channel (so that auto-updates can't be mixed-up with "real" updates anymore and e.g. won't get persisted anymore)
  • The previous behavior of always sending item updates can still be configured for backward compatibility - the *) case above

fixes #595
fixes #4356
Signed-off-by: Simon Kaufmann simon.kfm@googlemail.com

@openhab-bot
Copy link
Contributor

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/auoupdate-for-item-in-paperui/39602/2

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.

I just had a short look at the moment.

Shouldn't it also possible to set the auto update policy for all channels of a thing (handler) or for the whole binding? At least the handler should be able to set it easily for all channels of its things.

public enum AutoUpdatePolicy {
/**
* No automatic state update should be sent by the framework. The handler will make sure it sends a state update and
* it can to it better than just converting the command to a state.
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: ... can do it ...


/**
* The binding does not care and the framework may do what it deems to be right. The state update which the
* framework will send out normally will correspond the command state anyway. This is the default of no other policy
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: ... default if no ...

/**
* Give advice to the framework whether automatic state updates should be sent for the given channel or not.
*
* @param channelUID
Copy link
Contributor

Choose a reason for hiding this comment

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

A description should be added if it is ready for a final review (also if the comment is "the channel UID" only).
Same below and also in other classes...

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.

Looks like a pretty nice enhancement of the functionality.

After an initial review, I'd suggest a few changes, though:

  1. As the policy will depend on the channels, this information should imho be added to the channel definition (and the channel types) directly. This way, binding developers can simply add the information in the thing XMLs and do not require any programmatic logic and calls to the callback.
  2. The CommandResultPredictionListener could be removed when introducing a new "StatePrediction" event - the advantage of using events would be that not only sitemap-based UIs would benefit from this feature, but also UIs like the Paper UI or HABPanel.
  3. The auto-updates should be disabled in general for Group items as those will calculate their state based on their members and predictions aren't really possible in that case (or at least would be highly complex).

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 @SJKA, looks pretty good to me!
I didn't actively test it, but code-wise I think it is an excellent refactoring.


return channelXmlResult;
}

private AutoUpdatePolicy readAutoUpdatePlicy(NodeIterator nodeIterator) {
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: readAutoUpdateP[o]licy

private AutoUpdatePolicy readAutoUpdatePolicy(NodeIterator nodeIterator) {
String string = (String) nodeIterator.nextValue("autoUpdatePolicy", false);
if (string != null) {
return AutoUpdatePolicy.valueOf(string.toUpperCase(Locale.ENGLISH));
Copy link
Contributor

Choose a reason for hiding this comment

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

Any special reason for the locale parameter here? All defined values are plain ASCII, aren't they?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No. Just (good) habit.

*/
@NonNullByDefault
@Component(immediate = true, service = {
AutoUpdateManager.class }, configurationPid = "org.eclipse.smarthome.autoupdatemanager", configurationPolicy = ConfigurationPolicy.OPTIONAL)
Copy link
Contributor

Choose a reason for hiding this comment

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

I would suggest to change the pid to org.eclipse.smarthome.autoupdate

Recommendation autoUpdate = shouldAutoUpdate(itemName);

// consider user-override via item meta-data
MetadataKey key = new MetadataKey("autoupdate", itemName);
Copy link
Contributor

Choose a reason for hiding this comment

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

Would you want to put that string in a constant?

MetadataKey key = new MetadataKey("autoupdate", itemName);
Metadata metadata = metadataRegistry.get(key);
if (metadata != null && !metadata.getValue().trim().isEmpty()) {
boolean override = Boolean.getBoolean(metadata.getValue());
Copy link
Contributor

Choose a reason for hiding this comment

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

Careful! Boolean.getBoolean expects a system property name as a parameter - I doubt that this is what you want here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Argh, thanks! Of course...

ItemStatePredictedEvent prediction = (ItemStatePredictedEvent) event;
Item item = itemUIRegistry.get(prediction.getItemName());
if (item instanceof GroupItem) {
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you leave a comment on why we ignore group items here?

@@ -44,6 +47,7 @@
*/
public class PageChangeListener implements StateChangeListener {

private final ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool("ui");
Copy link
Contributor

Choose a reason for hiding this comment

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

Might this be a candidate for the new "common" pool?

public void keepCurrentState(Item item) {
scheduler.schedule(() -> {
constructAndSendEvents(item, item.getState());
}, 200, TimeUnit.MILLISECONDS);
Copy link
Contributor

Choose a reason for hiding this comment

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

200ms might be a bit tight, usually we go for 300ms for UI related feedback.

The following policies are supported:

* **veto**: No automatic state update should be sent by the framework. The thing handler will make sure it sends a state update and it can to it better than just converting the command to a state.
* **default**: The binding does not care and the framework may do what it deems to be right. The state update which the framework will send out normally will correspond the command state anyway. This is the default of no other policy is set explicitly.
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: [i]f no other


* **veto**: No automatic state update should be sent by the framework. The thing handler will make sure it sends a state update and it can to it better than just converting the command to a state.
* **default**: The binding does not care and the framework may do what it deems to be right. The state update which the framework will send out normally will correspond the command state anyway. This is the default of no other policy is set explicitly.
* **recommend**: An automatic state update should be sent by the framework because no updates will be sent by the binding. This usually is the case when devices don't expose their current state to the handler.
Copy link
Contributor

Choose a reason for hiding this comment

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

better: will be sent -> are sent

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 updates - may I ask you to rebase the branch?

@maggu2810
Copy link
Contributor

@SJKA My comment above has not been answered, yet.

I am currently using a service that implements that interface: https://github.com/maggu2810/shk/blob/master/bundles/shk-addon-autoupdate-configurator/src/main/java/de/maggu2810/shk/addon/autoupdate/configurator/AutoUpdateConfigurator.java

The implementation also implements the AutoUpdateBindingConfigProvider.

The implementation looks like: https://github.com/maggu2810/shk/blob/master/bundles/shk-addon-autoupdate-configurator/src/main/java/de/maggu2810/shk/addon/autoupdate/configurator/impl/AutoUpdateConfiguratorImpl.java

As you removed the AutoUpdateBindingConfigProvider can you give me an example how to easily disable the auto update for specific binding IDs?

@sjsf
Copy link
Contributor Author

sjsf commented Aug 13, 2018

@maggu2810 Sorry, I tried addressing your comments by making it a characteristic of the Channel/ChannelType, but clearly forgot to explicitly mention it here.
Therefore you can:

  1. as a binding, indicate the preference via the Channel (or rather the ChannelType, as its "template")
  2. as a user, set the preference on the item's metadata (i.e. autoupdate:<ITEM_NAME>)
  3. and last but not least, if you want to do this programmatically, you could also either set the corresponding metadata in the ManagedMetadataProvider or even have your own MetadataProvider which dynamically provides the corresponding metadata, e.g. for all items linked to a certain binding. In the latter case you'd just need to be sure to not interfere with the user and thereby have another MetadataProvider which provides metadata for the same keys.

Do you think one of these would cover your scenario?

@kaikreuzer
Copy link
Contributor

Just fresh from testing with the ESH demo setup:

smarthome send Weather_Temperature 1
Command has been sent successfully.
osgi> 17:25:31.834 INFO  s.event.ItemCommandEvent[:53] - Item 'Weather_Temperature' received command 1
17:25:31.838 DEBUG o.e.s.c.t.i.p.ProfileCallbackImpl[:69] - Delegating command '1 °C' for item 'Weather_Temperature' to handler for channel 'yahooweather:weather:berlin:temperature'
17:25:31.839 DEBUG o.e.s.c.i.c.InvocationHandlerSync[:55] - Already in a safe-call context, executing 'ThingHandler.handleCommand()' directly on 'org.eclipse.smarthome.binding.yahooweather.handler.YahooWeatherHandler@1e1cfe47'.
17:25:31.840 DEBUG o.e.s.b.y.h.YahooWeatherHandler[:157] - Command 1 °C is not supported for channel: temperature
17:25:31.843 ERROR o.e.s.c.i.events.EventHandler[:123] - Creation of ESH-Event failed, because one of the registered event factories has thrown an exception: Error getting class for simple name: 'nullType' using package name 'org.eclipse.smarthome.core.library.types.'.
java.lang.IllegalArgumentException: Error getting class for simple name: 'nullType' using package name 'org.eclipse.smarthome.core.library.types.'.
	at org.eclipse.smarthome.core.items.events.ItemEventFactory.parseSimpleClassName(ItemEventFactory.java:183)
	at org.eclipse.smarthome.core.items.events.ItemEventFactory.parseType(ItemEventFactory.java:158)
	at org.eclipse.smarthome.core.items.events.ItemEventFactory.getState(ItemEventFactory.java:136)
	at org.eclipse.smarthome.core.items.events.ItemEventFactory.createStatePredictedEvent(ItemEventFactory.java:123)
	at org.eclipse.smarthome.core.items.events.ItemEventFactory.createEventByType(ItemEventFactory.java:82)
	at org.eclipse.smarthome.core.events.AbstractEventFactory.createEvent(AbstractEventFactory.java:50)
	at org.eclipse.smarthome.core.internal.events.EventHandler.createESHEvent(EventHandler.java:121)
	at org.eclipse.smarthome.core.internal.events.EventHandler.handleEvent(EventHandler.java:95)
	at org.eclipse.smarthome.core.internal.events.EventHandler.handleEvent(EventHandler.java:72)
	at org.eclipse.smarthome.core.internal.events.ThreadedEventHandler.lambda$0(ThreadedEventHandler.java:67)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassNotFoundException: org.eclipse.smarthome.core.library.types.nullType cannot be found by org.eclipse.smarthome.core_0.10.0.qualifier
	at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:484)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:395)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:387)
	at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:150)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:264)
	at org.eclipse.smarthome.core.items.events.ItemEventFactory.parseSimpleClassName(ItemEventFactory.java:179)
	at org.eclipse.smarthome.core.items.events.ItemEventFactory.parseType(ItemEventFactory.java:158)
	at org.eclipse.smarthome.core.items.events.ItemEventFactory.getState(ItemEventFactory.java:136)
	at org.eclipse.smarthome.core.items.events.ItemEventFactory.createStatePredictedEvent(ItemEventFactory.java:123)

@sjsf
Copy link
Contributor Author

sjsf commented Aug 17, 2018

Oh well, nasty little conflict-resolution-mistake I did when rebasing.
À propos: I will do another rebase 😩 Hang on...

Simon Kaufmann added 8 commits September 3, 2018 15:34
Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
kaikreuzer added a commit to kaikreuzer/openhab1-addons that referenced this pull request Sep 3, 2018
kaikreuzer added a commit to kaikreuzer/openhab-core that referenced this pull request Sep 4, 2018
kaikreuzer added a commit to kaikreuzer/openhab-core that referenced this pull request Sep 4, 2018
kaikreuzer added a commit to kaikreuzer/openhab-core that referenced this pull request Sep 4, 2018
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.

lgtm. I have rebased the branch in order to resolve the conflicts.

@kaikreuzer kaikreuzer merged commit 1aade3a into eclipse-archived:master Sep 5, 2018
martinvw pushed a commit to openhab/openhab-core that referenced this pull request Sep 6, 2018
…390)

* adapted AutoUpdateDelegate to the new ESH auto update infrastructure
Related to eclipse-archived/smarthome#5011

Signed-off-by: Kai Kreuzer <kai@openhab.org>
@lolodomo
Copy link
Contributor

lolodomo commented Sep 6, 2018

Could we have a clear example what has to be changed in the *.items files please ?
I was setting autoupdate="false" on few of my switch items until now.

@kaikreuzer
Copy link
Contributor

If you mean autoupdate="false" then simply keep doing the very same - nothing has changed about that. The feature is meant for bindings to be able to influence the behavior on their own.

@lolodomo
Copy link
Contributor

lolodomo commented Sep 6, 2018

Ok, thank you @kaikreuzer for the information.

wborn pushed a commit to wborn/openhab-core that referenced this pull request Sep 10, 2018
…penhab#390)

* adapted AutoUpdateDelegate to the new ESH auto update infrastructure
Related to eclipse-archived/smarthome#5011

Signed-off-by: Kai Kreuzer <kai@openhab.org>
@openhab-bot
Copy link
Contributor

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/new-zwave-device-fails-attempts-to-fix-leads-to-all-new-thing-names-breaking-item-links-and-rules/51326/15

9037568 pushed a commit to openhab/openhab1-addons that referenced this pull request Sep 16, 2018
@openhab-bot
Copy link
Contributor

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/what-is-itemstatepredictedevent/52387/2

@lsafelix75
Copy link

Any binding example on how to apply this autoupdate feature? After reading this, i am still not clear what need to be done. Cheers

@maggu2810
Copy link
Contributor

It depends on your use case.
For the bindings I don't want the auto update mechanism I added this

<autoUpdatePolicy>veto</autoUpdatePolicy>

to my channel types in the XML.

@lsafelix75
Copy link

It depends on your use case.
For the bindings I don't want the auto update mechanism I added this

<autoUpdatePolicy>veto</autoUpdatePolicy>

to my channel types in the XML.

ok.. thanks.

@openhab-bot
Copy link
Contributor

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/light-behaves-weirdly-when-turned-on-via-rule-tradfri-homematic/56120/10

@openhab-bot
Copy link
Contributor

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/zwave-binding-updates/51080/290

@unparagoned
Copy link

It would be great if there was a global setting we could use to set to work the way it did before, or an easy way to make it work like it was before. I use custom items to trigger my rules, but that's not really working well now.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Circular reference between services Allow bindings to deactivate auto-update for channels
8 participants