JRuby OpenHAB Rules System

I haven’t ever touched Ruby until you’ve posted this topic here. Whilst I still have a lot to learn, I am really really loving the Ruby syntax and what you’ve created here to make writing rules for openhab so nice, compact and elegant.

Please continue your efforts to make this a mature solution for OpenHAB scripting.

I am starting to convert some of my rules to JRuby now. There’s no reason why I can’t run it side by side with jython for the time being.

2 Likes

I have released version 2.1.0 with additional ruby like syntactic sugar for timer methods (active?, running?, terminated?).

Changelog
Latest Documentation

Thanks!

Please feel free to share your journey and ask questions here so we can evolve this as a community.

There is a discussion in the GitHub issues about the off? method and ! for switches

The discussion is around how the helper library should handle the UNDEF and NULL state.

Should the library consider the switch ‘off’ if it is in the UNDEF or NULL state? That would enable the following.

SwitchItem << ON if SwitchItem.off?  #This doesn't work right now for UNDEF or NULL
SwitchItem << !SwitchItem  #This doesn't work right now for UNDEF or NULL

I am inclined to treat undef or null as off to assist in those cases, would there be any concerns?

I think it can be beneficial if off? only returns true for OFF state, it would be easy enough to alter the rule to:

SwitchItem << ON if SwitchItem.off? || SwitchItem.null?

There are cases where you want to be sure that the state is actually OFF before any action is taken.

SwitchItem << ON if SwitchItem.off? || SwitchItem.null?

There are cases where you want to be sure that the state is actually OFF before any action is taken.

And if you wanted to cover both cases (null and undef) you could either do

SwitchItem << ON unless SwitchItem.on?

What about inversion/toggle? !SwitchItem

Hello all I agree with Anders for me OFF would not be the same as null or undef so I would also not expect them to be inverse to ON.

Perhaps the easiest solution is to have SwitchItem.toggle instead of SwitchItem << !SwitchItem. It is also shorter to type if your item names are long as mine usually are :slight_smile:

I disagree. SwitchItem.off? should only be true when the state is actually OFF, not null/undef. The same as Item.null? should only be true when it’s null and not undef.

If we wanted to know if it’s off/null or undef, we could just use !Item.on

Sounds like most people don’t want off? to include null or undef. I am good with that.

What should !SwitchItem do when off? or null? Right now it just returns nil.

So you would have to do:
SwitchItem << !SwitchItem if SwitchItem.state?

That work for everyone?

Changing ! to toggle doesn’t change the underlying decision about the use case.

There are two separate issues, and my proposal would be:

  • SwitchItem.off? - must return true only when the state is actually OFF. It should return false when its state is either null, undef, or ON
  • !SwitchItem will return ON if SwitchItem is not ON. So any other state, including OFF, NULL, or UNDEF will cause !SwitchItem to return ON. This will make SwitchItem << !SwitchItem toggle the item even when SwitchItem is null or undef.

.toggle(), if needed/implemented would be something like

def toggle
  if .on? 
    .command(OFF)
  else
    .command(ON)
  end
end

This seems like a bad idea, because no toggling will occur if SwitchItem is null/undef

I have released version 2.2.0. With support for Things and changed/updated triggers for things.

This release represents a milestone. At this point I believe all current trigger types are now possible with the JRuby Rules Systems.

Still a long way to go with additional item support, transformations, metadata, actions, etc.

Changelog
Latest Documentation

1 Like

An idea for the item metadata. Can it be implemented as a hash attribute of the item?

item1.metadata['key']
Item1.metadata.key?('x')
Item1.metadata?('x')

Maybe @broconne has thought of a solution, but one problem I see is in the way the metadata is structured: it has a namespace key with a corresponding value, and then possibly some additional key-value pairs within that namespace. In your first example item.metadata['key'] for example, it would have to return either the value or a hash of the other key-value pairs, but how would one get the other?
Example from item definition:

{ ga="Fan" [speeds="0=away:zero,50=default:standard:one,100=high:two", lang="en", ordered=true ] }

Should "Fan" be returned or { :speeds => "0=away:zero,50=default:standard:one,100=high:two", :lang => "en", :ordered => true }?

I have released version 2.2.1. with a fix for !SwitchItem to return ON if the switch is undef or null.

Changelog
Latest Documentation

My plan was to attach it directly to the item without the metadata accessor.
So it would be:

to get
item1['key']
or to set
item1['key']= value

However, I have not looked into the complications that @pacive notes below.

Switch Item1 { ga="Fan" [speeds="0=away:zero,50=default:standard:one,100=high:two", lang="en", ordered=true ] }

Not sure if this is proper Ruby… just an idea:

Item1['ga'] # returns "Fan", is a String object, but with added attributes below
Item1['ga'].has_configs? # returns true
Item1['ga'].configs # hash containing the configs
Item1['ga'].configs.keys # [ 'speeds', 'lang', 'ordered' ]
Item1['ga'].configs['speeds'] #returns "0=away:zero,50=default:standard:one,100=high:two"
Item1['ga'].configs['lang'] # returns "en"
Item1['ga'].configs['ordered'] # returns true

This could be done if you create a custom class that wraps the value. If you change the string class those methods would be available on all strings, which is a bad idea.

You would then have to implement the .== method to take a string argument and compare to the contained value, and the .[]= method on the metadata would have to convert it before saving. Other string methods could be available by just passing them to the contained string using method_missing.

Not sure if there would be more issues I have missed, but seems doable :slight_smile:

Looking at the visual representation here, I think it could look something like this:

Item1[:ga][:value]
Item1[:ga][:config][:key1]...

I would want to support indifferent access (symbols and strings for lookup). The difficulty I see is that I would prefer to support all hash methods, but it doesn’t seem easy to delegate the storage of a hash to a different backend.

I’d like to hear your reasoning behind making the metadata the direct index to the Item variable.

I am wondering, what about, say tags, or group memberships. Assigning metadata as the direct array index for the Item1 makes it more special than other attributes of the item. However, it isn’t immediately apparent to those who read the code that Item1[key] refers to metadata, and not something else. Another point, I’m not sure if there’s a way to enumerate all the metadata keys (namespaces?) this way, but from what I’m finding out about Ruby so far, there seems to always be a way :slight_smile:

Making it Item1.metadata[key] makes it clear that we’re dealing with metadata while reading the code, not tags/groups memberships, etc. Equally, perhaps we could have Item1.tags as an enumerable / array, since the importance of the semantic model in OH3.

My reasoning was that metadata are descriptors specifically and inherently attached to the object itself. However, I had not considered tags which have the same type of classification. I haven’t looked closely at tags - but it seems odd to me that syntactic tags are not just a specific form of metadata - oh well.

It could very well be that the best way to access them is via .metadata or .meta.

We could then reserve [] for attaching arbitrary objects to the items for use in rules (like you proposed in GitHub for timers). Although, I am not quite sure how to implement that as the objects often fall out of JRuby scope.