storeStates, restoreStates

Tags: #<Tag:0x00007efecc22c9b0> #<Tag:0x00007efecc22c7d0>

I’m migrating the documentation of the Core Actions to the official docs and I’m confused by the storeStates and restoreStates actions. I’ve never heard of these before and the description on the wiki is not complete enough for me to understand. And given that at least one of the entries isn’t even an action (it’s a method call on a Group) I’m questioning whether these are indeed actions or something else.

The text:

Map<Item, State> storeStates(Item... items): Stores the current state of a list of items in a map which can be assigned to a variable. Group items are not themselves put into the map, but instead all their members.

restoreStates(Map<Item, State> statesMap): Restores item states from a map. If the saved state can be interpreted as a command, a command is sent for the item (and the physical device can send a status update if occurred). If it is no valid command, the item state is directly updated to the saved value.

Starting with storeStates:

  • does this return a Map<Item, State>? If I call this from one rule then restoreStates from another rule will it work? I’ve learned long ago that one cannot use the Item as the key in a Map and one must use the Item.name as the key because the object ID of the Item changes from one rule instance to the next.

  • Do I pass Items like the following: storeStates(Item1, Item2, Item3) or do I need to create a java.lang.List?

And with restoreStates:

  • The description on when a command is sent verses an update is unclear. Does this mean that if I have String or Number Items they will only receive updates whereas Switches and Contacts will receive commands?

Can someone please:

  1. confirm these are indeed actions
  2. are still valid for OH 2
  3. post a couple of examples

They appear to have been there since the beginning in @kai’s initial verison in 2013.

Many thanks!

1 Like

They are actions in the sense that they are a predefined function that can be called in rule body. I don’t see any evidence that either one is a method call on a Group.

Yes. The storeStates function is declared to return Map<Item, State>. From what I’ve read, this type cannot be literally defined in a rule file because Item is a keyword in the DSL. However, it can be defined like:

import java.util.Map
var Map states

It works for me. I’ve never heard that Items are rule-specific. Do you have a reference to a related discussion?

Yes.

states = storeStates(Item1, Item2, Item3)
```[quote="rlkoshak, post:1, topic:29994"]
And with restoreStates:

The description on when a command is sent verses an update is unclear. Does this mean that if I have String or Number Items they will only receive updates whereas Switches and Contacts will receive commands?
[/quote]

For each saved item state, if the _state_ implements the `Command` interface then that state will be sent as a command event. Otherwise the code will sent a state update event. It does not depend directly on the type of the Item.

[quote="rlkoshak, post:1, topic:29994"]
are still valid for OH 2
[/quote]

It appears that they are still valid. I did my testing with OH1, but I reviewed the code from the SmartHome GitHub repo for researching these questions.

That is incorrect. It is perfectly legal and valid to define a Map with Item, though I would probably go a little more specific and use GenericItem. Designer may complain about it but the rule will run just fine. At least based on my experiences back in 1.7.

I can’t remember if it was on this forum or the old Google forum. But I used to use a Map<Item, Boolean> in one of my rules. The intent was to set a flag in one rule and check the flag in another rule.

The other rule would often fail because the hash function for the Item changed in the second call to the rule. Watou recommended I should use the Item’s name instead of the Item reference as the key which works like a charm.

The explanation at the time was that a new Item Object is created for each instance of the Rule which results in a new return from the hash function which results in not being able to find the entry in the Hashmap.

Perhaps, given this is a built in action it works better or something has changed since then.

So if I have a switch and I want the state to be restored via a command I would put(ON) whereas if I want an update I would put("ON") into the Map, correct?

Thank you for your replies. They are a great help and will let me provide better documentation for these actions.

This is where Is saw it: https://groups.google.com/forum/#!topic/openhab/lWZKmn85wF0

However, that’s an old message and it may have been fixed since then. I didn’t try using the generic type declaration with Item in the rule. So you’ve tried it with storeStates and it works?

I’d be surprised if that works with storeStates. A Map<Item,State> should not be assigned to a Map<GenericItem,State> because the Item interface implementations might not be GenericItems. I’d hope the rule language would report an error if someone tried to do that.

It must have changed. In ESH, the hash is calculated from the category, label, name, tags and type fields in the GenericItem. If one of those changes, then the hashCode will almost always change. A value change or even a copy (which, AFAICT, doesn’t happen) wouldn’t change the hashCode.

However, the current ESH GenericItem hashCode implementation is dubious because some of the hash input fields are mutable (label, tags, etc.) and that may lead to undesirable behavior. Hash codes should only be computed on immutable values.

To be clear, you are asking about a scenario where you create the map yourself rather than using storeStates, right? If so, a Command will be sent in both cases but I think the string state will fail to be applied to a Switch. Note that a StringType implements the Command interface too. Speaking of that, you’d need to put new StringType("ON") in the map because a literal string is not a State.

My OH is currently hopelessly broken so I can’t try anything right now. I might have to go back to 2.0 Release.

The last time I browsed through the code all Items inherited from GenericItem and GenericItem implements Item. There would be a runtime error if there is an Item that isn’t a GenericItem but the last time I looked that would never be the case.

But I was mainly talking in general, not with the use of storeStates.

That sounds like it is worth filing an issue.

Not really. I’m thinking of a scenario where I storeState and then modify the Map with different States and the restoreState.

These are the sorts of edge cases that I’d like to capture in docs. These sorts of nuances cause users problems all the time.

From what you describe, this means that there really is no way to update a Switch Item using restoreState.

Doh, of course.

It can definitely be the case. For example, I’ve created a JSR223 Item provider that could provide alternative implementations of the Item interface.

That said, I did check whether Map<Item,State> works in a rule and it doesn’t appear to work (I assume because of the keyword issue described in the post I referenced). However, Map<GenericItem,State> does work. Also, Map<String,State> or Map<String> works which is totally incorrect. It seems that XText doesn’t check that the generic type parameters are valid. Given that behavior, there’s not much reason not to just use a plain Map declaration.

@steve1 - are you able to help provide some input HERE?

I’m looking to iron out the last error message I’m receiving in my output of rules loading. It seems to be related to the use of a MAP variable, storeStates, and restoreStates. I’ve provided the relevant sections of the rules file that use this. Seems you are using this and/or have a successful setup. Hoping you might be able to identify what I’m missing.

I can’t tell from the original topic if this issue is resolve now or not.