Just set the timer to > the update rate, e.g. 100s.
Will your motion sensor trigger quicker after OFF state?
Although it should be fine, I would suggest sticking with the built in jruby scripting addon (and therefore jruby 9.3.x). JRuby 9.4.0.0 is still very new, so it might have some minor bugs (which might very well not affect you at all). I’m currently waiting for 9.4.2.0 to be released.
You could still use the version 5.0 of the library with the built in addon, but before that, you should read up on the CHANGELOG
Here, I added some extra code so it would only start the timer when the state is not on (i.e. off)
ALLOWED_ROOMS = %w[AZ BZ F2]
################################
# Lighting with motions sensors
rule "Lighting generic" do
changed groupMotionsensorPresences.members
run do |event|
room_code = get_room_code(event.item.name)
# Escape if room is not allowed to be switched
next unless ALLOWED_ROOMS.include? room_code
enabled = items["Motionsensors_#{room_code}_enable"] # A switch to turn off motion detection
next unless enabled.on?
dimmer = items["groupLight_#{room_code}_dimmers"]
light = items["groupLight_#{room_code}_switches"]
light_current_value = items["groupMotionsensors_#{room_code}_light"]&.state # including brightness values, no light is needed if its bright enough
light_on_value = items["Motionsensors_#{room_code}_lightOnValue"]&.state
timer_duration = items["Motionsensors_#{room_code}_timerDuration"]&.state&.to_i&.seconds || 3.minutes # NumberItem to set the individual timer duration
next unless light_on_value >= light_current_value
dimmer.command(100)
logger.info "LIGHTS-MOTION-CONTROL: Canceled timer after presence is detected"
if event.state.on?
timers[room_code]&.cancel # for library version 4.x
# for library version 5.x:
# timers.cancel(room_code)
next
end
after(timer_duration, id: room_code) do |timer|
next unless light.on?
next unless enabled.on?
if dimmer.state == 50
light.off
logger.info "LIGHTS-MOTION-CONTROL: Switched light in #{room_code} to OFF, no presence anymore."
else
dimmer.command(50)
logger.info "LIGHTS-MOTION-CONTROL: Dimm light in #{room_code}, no presence anymore."
timer.reschedule 10.seconds
end
end
end
end
# Example of presence items: Motionsensor_BZ_1_presence
def get_room_code(item_name)
item_name.split("_")[1]
end
For getting the related items like room etc. You should use the semantic model. In combination with jruby library it is really nice. You won’t need to deduce rooms and related devices from naming patterns any more.
You can’t really have “global variables” in the traditional manner. Each script file is isolated from one another under the default threading option, so a Ruby $global in one file isn’t visible in another file.
In any case it’s usually not recommended to use a global variable, but if you happen to need one, you could use the Shared Cache feature. It uses the built in mechanism from openHAB, so beware that openHAB will invalidate/remove the stored value when all scripts accessing that key was unloaded (e.g. reloaded?).
I usually use item’s metadata to store a global “flag” that I need in my rules.
Hoping someone can help me please I recently moved my openhab to docker. I am running the stable release. Recently my JRuby Scripting rules stopped working and I am at a loss as to why.
I have pasted the error from the logs below.
2023-08-10 10:07:27.434 [INFO ] [ort.loader.AbstractScriptFileWatcher] - (Re-)Loading script '/openhab/conf/automation/jsr223/personal/keba.rb'
2023-08-10 10:07:27.812 [WARN ] [ernal.JRubyScriptEngineConfiguration] - Error evaluating `require 'openhab'`
org.jruby.exceptions.LoadError: (LoadError) no such file to load -- openhab
Did you mean? open3
at org.jruby.RubyKernel.require(org/jruby/RubyKernel.java:1057) ~[?:?]
at RUBY.require(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/rubygems/core_ext/kernel_require.rb:85) ~[?:?]
at RUBY.<main>(<script>:1) ~[?:?]
2023-08-10 10:07:27.827 [ERROR] [ipt.internal.ScriptEngineManagerImpl] - Error during evaluation of script '/openhab/conf/automation/jsr223/personal/keba.rb': Error during evaluation of Ruby in org/jruby/RubyKernel.java at line 1057: (LoadError) no such file to load -- openhab
Did you mean? open3
2023-08-10 10:07:27.828 [WARN ] [ort.loader.AbstractScriptFileWatcher] - Script loading error, ignoring file '/openhab/conf/automation/jsr223/personal/keba.rb'
If you’ve recently upgraded your jruby helper library to version 5.x, you’ll need to make some changes.
Remove the require 'openhab' line at the top of your script. It is no longer required, because the addon now injects the require line by default. If you do want to have the explicit require statement, that’s fine too, because requiring the same file multiple times are simply ignored. In any case the new require line is require 'openhab/dsl'.
You will also be affected by other breaking changes from 4.x to 5.x so please read through the v5.0.0 changelog
If you encounter any other issues, feel free to post here again.
No Problem, I can push you in the right direction.
You will find the extension settings in your user-folder:
USER/.vscode/extensions/openhab.openhab-1.0.0
2.Within this folder you can open the json-file /meta/openhab.tmLanguage.json
3.Here you should add “rb” to the fileTypes part. Then you can study the file and maybe change some other settings.
After saving the file, you have to restart VSCode, i think. And now the coloring of the text in the rb-files should be DSL-Rules like. And you should have access to the value of an item by howering the mouse pointer over it.
I have an issue with simple class. I’m completely new with jRuby.
#file utils.rb
@can_send_pushover_message = true
class PushoverMessenger
def initialize
@can_send_pushover_message = true
end
def send_pushover_html_message(pushover_message, wait_time_for_next_message)
if @can_send_pushover_message
pushover_account = things["pushover:pushover-account:xxxxxxxxxx"]
pushover_account.sendHtmlMessage(pushover_message, "openHAB")
@can_send_pushover_message = false
after wait_time_for_next_message.minutes do
@can_send_pushover_message = true
end
end
end
end
and i call method:
require "utils.rb" # here is class definition
pushover_messenger = PushoverMessenger.new
rule "test" do
on_load
every 10.seconds
run do
pushover_messenger.send_pushover_html_message("Hello: <font color='#EDBB99'><b>World</b></font>",15)
end
end
and when I create a class instance and call method I get error:
undefined local variable or method `things’
What should I add as require or what other trick should I do.
things is not available by default inside a class context, only at top level. You either need to call OpenHAB::DSL.things explicitly, or include OpenHAB::DSL into the class to make it available there.
Note also that your @can_send_pushover_message at top level is a different variable than the one inside your class. You don’t (currently) assign to the top level one anywhere, so it will work fine as is. Just warning you if you try to modify it from something not inside the class, and can’t figure out why the class instance isn’t seeing it.
I have an issue using delay. I receive this error: undefined method 'delay' for main:Object (NoMethodError) with the following code snippet:
brightness = 0
while(brightness <= 100)
brightness = brightness + 1
prevBrightness = brightness
light << brightness
delay 15.seconds
next if prevBrightness != brightness # User changed brightness in the meantime
end
It should be a simple wakeup light which increases brightness over time and aborts if the user changed the brightness in the meantime.
The script works nice with sleep but I would like to avoid using it.
If I’m not mistaken, delay creates a timer, meaning it schedules the code after it to run later. This is only available in the rule context, so when you’re in another code block, like a loop, it doesn’t exist. If it had been working, I think this rule would have spun out of control anyway, creating tons of new timers.
delay is not meant to be used like that. It is not the same as “sleep” or pause. It is actually an execution block, similar to run and triggered. The link will show you some examples of how to use it properly.
Firstly, in Ruby there are better ways than looping with for, while, do, e.g.:
0.upto(100).each do |brightness|
# code here to use brightness
end
Secondly, the next if .... above won’t do anything. I think you meant to use break?
Lastly, to implement what you are trying to do, you should use timers instead of some form of sleep.
Something like this perhaps:
rule "Brighten my morning!" do
every :day, at: "5am"
run do
next if light.on? # don't do the gradual thing if light is already on
level = 0
after(15.seconds) do |timer|
next unless light.state.to_i == level # Stop the routine if it got changed manually
# Note to_i above to round the state to integer in case it has fractions
level = level + 1
light << level
timer.reschedule if level < 100 && !timer.cancelled?
end
end
end