#Examples

The following examples are for file-based rules but most of them are applicable to UI rules as well.

#Trigger when an item changed state

rule 'Turn on light when sensor changed to open' do
  changed Door_Sensor, to: OPEN
  run { Cupboard_Light.on }
end

Use multiple triggers

rule 'Control light based on multiple doors' do
  changed Door_Sensor1, to: OPEN
  changed Door_Sensor2, to: OPEN
  run { Cupboard_Light.on }
end

# Which is the same as:
rule 'Control light based on multiple doors' do
  changed Door_Sensor1, Door_Sensor2, to: OPEN
  run { Cupboard_Light.on }
end

Check against multiple states

rule 'Control light based on door state' do
  changed Door_Sensor, to: [OPEN, CLOSED]
  run { Cupboard_Light << Door_Sensor.open? } # Send a boolean command to a Switch Item
end

#Trigger when a group member changed state

# Assumption: Motion sensor items are named using the pattern RoomName_Motion
# and Light switch items are named with the pattern RoomName_Light
rule 'Generic motion rule' do
  changed Motion_Sensors.members, to: ON
  run do |event|
    light = items[event.item.name.sub('_Motion', '_Light')] # Lookup item name from a string
    light&.on
  end
end

See also: Triggers

#Various ways of sending a command to an item

# Using the shovel operator
Light1 << ON
DimmerItem1 << 100
Set_Temperature << '24 °C'

# Using command predicates
Light1.on
Rollershutter1.up
Player1.play

# Using .command
ColorItem1.command '#ffff00'
ColorItem1.command {r: 255, g: 0xFF, b: 0}

# Send a command to all the array members
# Note The << operator doesn't send a command here because it's for appending to the array
[SwitchItem1, SwitchItem2, SwitchItem3].on
[RollerItem1, RollerItem2, RollerItem3].down
[NumberItem1, NumberItem2, NumberItem3].command 100

Each item type supports command helpers relevant to the type. For example, a SwitchItem supports on and off. See specific item types under OpenHAB::Core::Items

#Dealing with Item States

# Items:
# Number:Temperature Outside_Temperature e.g. 28 °C
# Number:Temperature Inside_Temperature e.g. 22 °C
temperature_difference = Outside_Temperature.state - Inside_Temperature.state
logger.info("Temperature difference: #{temperature_difference}") # "Temperature difference: 6 °C"

Items have predicates to query its state.

Switch1.on?    # => true if Switch1.state == ON
Shutter1.up?   # => true if Shutter1.state == UP

#Detect change duration without creating an explicit timer

rule 'Warn when garage door is open a long time' do
  changed Garage_Door, to: OPEN, for: 15.minutes
  run { Voice.say "Warning, the garage door is open" } # call TTS to the default audio sink
end

#Automatic activation of exhaust fan based on humidity sensor

This uses the evolution_rate persistence feature, coupled with an easy way to specify duration. It is accessed simply through ItemName.persistence_function.

# Note: don't activate the exhaust fan if the bathroom light is off at night
# Sun_Elevation is an Astro item. Its state is positive during daylight
rule "Humidity: Control ExhaustFan" do
  updated BathRoom_Humidity
  triggered do |humidity|
    evo_rate = humidity.evolution_rate(4.minutes.ago, :influxdb)
    logger.info("#{humidity.name} #{humidity.state} evolution_rate: #{evo_rate}")

    if (humidity.state > 70 && evo_rate > 15) || humidity.state > 85
      BathRoom_ExhaustFan.ensure.on if Sun_Elevation.state.positive? || BathRoom_Light.state.nil? || BathRoom_Light.on?
    elsif humidity.state < 70 || evo_rate < -5
      BathRoom_ExhaustFan.ensure.off
    end
  end
end

#Gem Cleanup

The openHAB JRuby add-on will automatically download and install the latest version of the library according to the settings in jruby.cfg. Over time, the older versions of the library will accumulate in the gem_home directory. The following code saved as gem_cleanup.rb or another name of your choice can be placed in the automation/ruby directory to perform uninstallation of the older gem versions every time openHAB starts up.

require "rubygems/commands/uninstall_command"
require "pathname"

after(3.minutes) do
  cmd = Gem::Commands::UninstallCommand.new

  # uninstall all the older versions of the openhab-scripting gems
  Gem::Specification.find_all
                    .select { |gem| gem.name == "openhab-scripting" }
                    .sort_by(&:version)
                    .tap(&:pop) # don't include the latest version
                    .each do |gem|
    cmd.handle_options ["-x", "-I", gem.name, "--version", gem.version.to_s]
    cmd.execute
  end

  # Delete gems in other ruby versions
  next unless (gem_home = ENV.fetch("GEM_HOME", nil))

  gem_home = Pathname.new(gem_home)
  next unless gem_home.parent.basename.to_s == ".gem"

  gem_home.parent.children.reject { |p| p == gem_home }.each(&:rmtree)
end

#UI rules

#Reset the switch that triggered the rule after 5 seconds

Trigger defined as:

  • When: a member of an item group receives a command
  • Group: Reset_5Seconds
  • Command: ON
logger.info("#{event.item.name} Triggered the rule")
after 5.seconds do
  event.item.off
end

#Update a DateTime Item with the current time when a motion sensor is triggered

Given the following group and items:

Group MotionSensors
Switch Sensor1 (MotionSensors)
Switch Sensor2 (MotionSensors)

DateTime Sensor1_LastMotion
DateTime Sensor2_LastMotion

Trigger defined as:

  • When: the state of a member of an item group is updated
  • Group: MotionSensors
  • State: ON
logger.info("#{event.item.name} Triggered")
items["#{event.item_name}_LastMotion"].update Time.now

#Trigger a Scene with an ON/OFF Switch

Use Scenes in combination with Semantic Model

Trigger defined as:

  • When: the state of a member of an item group is updated
  • Group: LightSwitches
# Find scenes for the specific room by matching the scene's tags against the
# Location item name of the room, e.g. "BedRoom1", "Downstairs_BedRoom", etc.
# This is when you have multiple locations/rooms with the same semantic location e.g. (Bedroom)
scenes = rules.scenes.tagged(event.item.location.name)

# If none were defined, try finding scenes assigned to the same semantic location as the motion sensor
# You can have scenes for LivingRoom, LaundryRoom, Garage, etc. provided that they are unique
scenes = rules.scenes.tagged(event.item.location.location_type) if scenes.empty?

# the Active_Scene item can be set to the Scene tag that we wish to activate when motion is detected
# e.g. ACTIVE/RELAXING/MOVIE/READING
# To do nothing when motion was detected, just set the Active_Scene to blank so no scenes would match
active_scene = event.state.on ? Active_Scene.state.to_s : "OFF" # Get the active scene name
scenes.tagged(active_scene).each(&:trigger) # Execute the scenes