JRuby OpenHAB Rules System

JRuby addon in openhab 5 supports / uses conf/automation/ruby/Gemfile for the jrubyscripting environment. See https://openhab.github.io/openhab-jruby/main/#bundle_gemfile

So you had inadvertently enabled this feature, so the Gemfile is used for both vscode (rubylsp) and the jrubyscripting addon. You don’t want to have gem "rubocop" for your normal jrubyscripting scripts. That’s what caused the errors in your openhab logs: jrubyscripting is trying to install the rubocop gem which depends on prism.

As to why your rubylsp / rubocop is playing up that’s probably a separate issue.

In any case, I’d suggest moving your Gemfile for RubyLSP and .rubocop.yml files to ~/conf - assuming that is the root of your vscode workspace. Also I’d suggest adding ~/conf/.ruby-version that contains:

3.4.6

Or whatever is the latest version in 3.4.x

and set your rubocop to TargetRubyVersion: 3.4, because in openhab 5, jrubyscripting addon uses jruby 10.x which supports ruby 3.4 compatibility. But using 3.1 in rubocop / .ruby-version is fine too if that’s what you prefer.

You should install ruby-3.x (i.e. mri, matching your .ruby-version and rubocop) using rbenv. This will be for rubylsp only. It won’t affect jrubyscripting which will use jruby shipped / bundled with the addon.

If you want to use Gemfile for jrubyscripting, you can put that in ~/conf/automation/ruby.

1 Like

Hi @jimtng ,

thanks again for your help. I’m still struggling with UoM. I have a timeseries of type Number:EnergyPrice enforced by the binding it creates. That unit is breaking all my attempts on processing the timeseries. Is there any way to get rid of it? I don’t need it. I tried using numeric_state somehow, but it’s not working.

min_states = SpotPrice.all_states_between(daystart_time,sunset1_time,:inmemory).each_slice(4).map { |slice| slice.sum.to_f / slice.size }

fails like this:

2025-10-05 19:45:43.685 [ERROR] [.handler.AbstractScriptModuleHandler] - Script execution of rule with UID '44c808bd42' failed: javax.measure.UnconvertibleException: javax.measure.IncommensurableException: EUR/kWh is not compatible with one

Thanks!

numeric_state is the “invention” / convention in jsscripting and mainui js. It doesn’t exist in the openhab core / jruby / dsl.

Is there more code involved than what you’ve pasted?

Well, there is not much more relevant.

SpotPrice is the timeseries of type Number:EnergyPrice in 15min intervals. It is using inMemory persistence.

daystart_time = LocalTime.parse(‘0am’).to_zoned_date_time

sunset1_time = things[‘astro:sun:local’].getEventTime(‘SUN_SET’,nil,nil)

I want to convert the timeseries to hourly by averaging 4 15min elements. The rule runs once an hour at 0sec, 0min using a cron trigger.

Fix:

min_states = SpotPrice.all_states_between(daystart_time,sunset1_time,:inmemory).each_slice(4).map { |slice| slice.sum(0 | "EUR/kWh").to_f / slice.size }

to_f can be omitted if you want to retain the unit.

1 Like

Thank you! Followed your instructions and no errors anymore!

Too early… Error is still there, I just did not recognize it. I tried to bring openHAB into a “as clean as possible” state when it comes to JRuby. No success. Neither do I have an own Gemfile anywhere in the openhab conf subfolders nor are the VSC extensions for Ruby LSP or rubocop installed. I stopped the openHAB Docker container, removed the “.gem” folder inside ./openhab/conf/automation/ruby and restarted the openHAB container resulting in the following two errors:
[ipt.internal.ScriptEngineManagerImpl] - ScriptEngine for language 'application/x-ruby' could not be found for identifier: e95531a6-0463-4003-8edf-fb651c5ac166

and

org.jruby.exceptions.StandardError: (InstallError) Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
    current directory: /openhab/conf/automation/ruby/.gem/10.0.0.1/gems/prism-1.5.2/ext/prism
/usr/lib/jvm/java-21-openjdk-amd64/bin/java -cp /openhab/runtime/lib/boot/org.apache.karaf.diagnostic.boot-4.4.7.jar:/openhab/runtime/lib/boot/org.apache.karaf.jaas.boot-4.4.7.jar:/openhab/runtime/lib/boot/org.apache.karaf.main-4.4.7.jar:/openhab/runtime/lib/boot/org.apache.karaf.specs.activator-4.4.7.jar:/openhab/runtime/lib/boot/osgi.core-8.0.0.jar:/openhab/runtime/lib/jdk9plus/istack-commons-runtime-3.0.12.jar:/openhab/runtime/lib/jdk9plus/jakarta.xml.bind-api-2.3.3.jar:/openhab/runtime/lib/jdk9plus/javax.annotation-api-1.3.2.jar:/openhab/runtime/lib/jdk9plus/jaxb-runtime-2.3.9.jar:/openhab/runtime/lib/jdk9plus/org.apache.servicemix.specs.activation-api-1.2.1-1.2.1_3.jar:/openhab/runtime/lib/jdk9plus/txw2-2.3.9.jar org.jruby.Main extconf.rb
extconf failedBad file descriptor - /bin/sh
Gem files will remain installed in /openhab/conf/automation/ruby/.gem/10.0.0.1/gems/prism-1.5.2 for inspection.
Results logged to /openhab/conf/automation/ruby/.gem/10.0.0.1/extensions/universal-java-21/3.4.0/prism-1.5.2/gem_make.out
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/rubygems/ext/builder.rb:103:in 'run'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/rubygems/ext/ext_conf_builder.rb:30:in 'build'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/rubygems/ext/builder.rb:195:in 'build_extension'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/rubygems/ext/builder.rb:229:in 'block in build_extensions'
  org/jruby/RubyArray.java:2079:in 'each'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/rubygems/ext/builder.rb:226:in 'build_extensions'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/rubygems/installer.rb:844:in 'build_extensions'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/rubygems_gem_installer.rb:111:in 'build_extensions'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/rubygems_gem_installer.rb:30:in 'install'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/source/rubygems.rb:205:in 'install'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/installer/gem_installer.rb:55:in 'install'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/installer/gem_installer.rb:17:in 'install_from_spec'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/installer/parallel_installer.rb:133:in 'do_install'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/installer/parallel_installer.rb:124:in 'block in worker_pool'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/worker.rb:62:in 'apply_func'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/worker.rb:57:in 'block in process_queue'
  org/jruby/RubyKernel.java:1658:in 'loop'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/worker.rb:54:in 'process_queue'
  uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/worker.rb:90:in 'block in create_threads'
An error occurred while installing prism (1.5.2), and Bundler cannot continue.
In Gemfile:
  rubocop was resolved to 1.81.1, which depends on
    rubocop-ast was resolved to 1.47.1, which depends on
      prism
	at RUBY.handle_error(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/installer/parallel_installer.rb:167) ~[?:?]
	at RUBY.call(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/installer/parallel_installer.rb:97) ~[?:?]
	at RUBY.call(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/installer/parallel_installer.rb:66) ~[?:?]
	at RUBY.install(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/installer.rb:198) ~[?:?]
	at RUBY.run(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/installer.rb:84) ~[?:?]
	at RUBY.open_file_with_flock(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/rubygems.rb:828) ~[?:?]
	at org.jruby.RubyIO.open(org/jruby/RubyIO.java:1284) ~[?:?]
	at RUBY.open_file_with_flock(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/rubygems.rb:816) ~[?:?]
	at RUBY.open_file_with_lock(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/rubygems.rb:802) ~[?:?]
	at RUBY.lock(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/process_lock.rb:13) ~[?:?]
	at RUBY.filesystem_access(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/shared_helpers.rb:105) ~[?:?]
	at RUBY.lock(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/process_lock.rb:12) ~[?:?]
	at RUBY.run(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/installer.rb:71) ~[?:?]
	at RUBY.install(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/installer.rb:23) ~[?:?]
	at RUBY.gemfile(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/inline.rb:64) ~[?:?]
	at RUBY.temporary(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/settings.rb:159) ~[?:?]
	at RUBY.gemfile(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/inline.rb:63) ~[?:?]
	at RUBY.temporary(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/settings.rb:159) ~[?:?]
	at RUBY.gemfile(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/bundler/inline.rb:58) ~[?:?]
	at RUBY.<main>(<script>:6) ~[?:?]

ChatGPT could not help me out that’s why I am here again. :grin:

I presume you’re on openhab 5.0.x

In the openhab karaf console, type

jrubyscripting info

That message says that you have a Gemfile and inside that Gemfile, it listed rubocop.

jrubyscripting info will tell you where that Gemfile is.

openhab> jrubyscripting info                                                                                                                                                                                                                    
JRuby 10.0.0.1                
JRuby Scripting Library 5.42.1
ENV['GEM_HOME']: /openhab/conf/automation/ruby/.gem/10.0.0.1
ENV['RUBYLIB']: /openhab/conf/automation/ruby/lib
Script path: /openhab/conf/automation/ruby

JRuby Scripting Add-on Configuration:
=====================================
Ruby Gems
  gems: openhab-scripting=~>5.0,rubocop
  bundle_gemfile: /openhab/conf/automation/ruby/Gemfile
  check_update: true
  require: openhab/dsl

Ruby Environment
  gem_home: /openhab/conf/automation/ruby/.gem/{RUBY_ENGINE_VERSION}
  rubylib: /openhab/conf/automation/ruby/lib
  dependency_tracking: true

System Properties
  local_context: singlethread
  local_variable: transient

JRuby Console
  console: irb

But when removing the /openhab/conf/automation/ruby/.gem folder entirely it gets recreated after rebooting openHAB.

Edit: Yes, openHAB 5.0.1 inside Docker

Do you have Gemfile.lock in conf/automation/ruby? If so, try deleting that file.

Ohh wait!!! There’s rubocop! Remove that from your config.

1 Like

Thanks!!! That did it! Interesting, the only occurance of rubocop was in ./openhab/userdata/config/org/openhab/automation/jrubyscripting.config and gems=“openhab-scripting=~>5.0,rubocop”.

No idea how it got there. Removing it and restarting it finally made the error go away. The only booting error I see is this: [ipt.internal.ScriptEngineManagerImpl] - ScriptEngine for language 'application/x-ruby' could not be found for identifier: e625164f-5f28-418d-8382-232bcd869007

I cannot grep any e625164f-5f28-418d-8382-232bcd869007on the whole openHAB file system. I mean, I can live with it, but do you have any idea where this might come from?

If you configured it from file, check conf/services/jruby.cfg. If you configured it using the UI then check the UI settings.

It’s probably a managed rule / script / transformation, or an inline transformation script. The error / warning can probably be ignored. The rule got loaded before the jrubyscripting addon loaded.

1 Like

Hello,

super-duper-n00b question: I want to react on a Number:Dimensionlessitem with unit="%”reaching 100 %.

changed MyNumberItem, to: 100 does not fire the rule.

changed MyNumberItem, to: (100..)does fire the rule. Any idea?

Try

changed MyNumberItem, to: "100 %"

#or

changed MyNumberItem, to: 100 | "%"

It’s because your state is QuantityType which cannot be compared against plain number.

items.build do
  number_item Test100, unit: "%"
end

rule do
  # changed Test100, to: 100 # "100 %"
  changed Test100, to: (100..)
  run { logger.info "Test100 changed to #{Test100.state}" }
end

Test100.update(100)

logger.info "Test100 == 100: #{Test100.state == 100}" # => false
logger.info "Test100 == 100 %: #{Test100.state == "100 %"}" # => true

I need to look into why using an endless range like that worked.

1 Like

Hello fellow JRubyians,

I have a rule warning me when a specific thing turned offline:

rule "Steckdosen: Balkonkraftwerk ist offline" do
  changed things["shelly:shellyplusplug:<ID>"], from: :online, to: :offline, for: 1.minute
  run do
    # Some foo stuff...
  end
end

It triggers as expected, but it also triggers when the Shelly binding tries to find the plug in the network and fails. Check out this event.log entry:

2026-02-04 11:40:30.050 \[INFO \] \[ab.event.ThingStatusInfoChangedEvent\] - Thing ‘shelly:shellyplusplug:<ID>’ changed from ONLINE (CONFIGURATION_PENDING): Gerät wird initialisiert oder im Schlafmodus. to OFFLINE (COMMUNICATION_ERROR): Verbindung zu Gerät fehlgeschlagenh: NoRouteToHostException: No route to host

The rule should only fire when something like this happens:

your 2026-02-04 11:35:16.188 [INFO ] [ab.event.ThingStatusInfoChangedEvent] - Thing 'shelly:shellyplusplug:<ID>' changed from ONLINE to OFFLINE (COMMUNICATION_ERROR): Das Gerät antwortet nicht und scheint nicht mehr verfügbar zu sein.code goes here

Can I check more fine granular the type of “online”?

rule "Steckdosen: Balkonkraftwerk ist offline" do
  changed things["shelly:shellyplusplug:<ID>"], from: :online, to: :offline, for: 1.minute
  only_if { |event| event.was.status_detail == org.openhab.core.thing.ThingStatusDetail::NONE }
  # or alternatively
  # only_if { |event| event.was.status_detail.to_s == "NONE" }
  run do
    # Some foo stuff...
  end
end

References:

1 Like