Skip to main content Link Search Menu Expand Document (external link)

How Do I…?

Items

Get an Item

Items and Groups are referred to by their name:

My_Item
gWindowBlinds

Items can be retrieved dynamically:

the_item = items['My_Item'] # This returns an item object, not just its state
# For all intents and purposes, the_item variable is the same as My_Item in the previous example

Get the Item’s Name as a String

My_Item.name

Get the Item’s Label

My_Item.label
my_light_item = items[My_Switch.name.sub('_Switch', '_Light')]

Send a Command to an Item

These three variants do the same thing:

My_Item.on
My_Item.command ON
My_Item << ON

Note: all possible commands are supported on the corresponding item types, e.g. on, off, up, down, play, pause, stop, etc. For more details, see the individual item type sub-sections under Items

Send a Command to an Item Only When Its State is Different

My_Item.ensure.on
My_Item.ensure.command ON
My_Item.ensure << ON

Send a Timed Command

A Timed command is similar to the OpenHAB Item’s expire parameter but it offers more flexibility. It removes the need to manually create a timer.

My_Switch.on for: 5.minutes

Send an Update to an Item

My_Switch.update ON

Get State of an Item

Item’s state is inferred in the item object. Most operations can be done directly using the item itself. Explicitly, My_Item.state can also be used to refer to the item’s state.

if My_Item == ON
  # do something
end

# This syntax is equivalent and preferred:
if My_Item.on?
  # do something
end

# Items can be compared directly against its state or against another item's state
if Indoor_Temperature > '20 °C' || Indoor_Temperature > Outdoor_Temperature
  # do something
end

# This is possible but unnecessary
Indoor_Temperature.state > '20 °C' || Indoor_Temperature.state > Outdoor_Temperature.state

Note: all boolean helper methods are available depending on the item / state type. For example up?, down?, closed?, open?, etc.

Check if an Item’s state is NULL of UNDEF

if My_Item.state?
  logger.info 'My_Item is not NULL nor UNDEF'
end

Compare Item’s State

String_Item == 'test string'
Number_Item > 5.3
items['Number_Item'] == 10

Temperature_Item > '24 °C'
Temperature_Item > 24| '°C'
Indoor_Temperature > Outdoor_Temperature 
Indoor_Temperature > Outdoor_Temperature + '5 °C'
Indoor_Temperature - Outdoor_Temperature > '5 °C'

Get the Thing Linked to an Item

linked_thing = My_Item.thing
thing_uid = My_Item.thing.uid

Get All Linked Things

An item can be linked to multiple things.

My_Item.things.each do |thing|
  logger.info("Thing: #{thing.uid}")
end

Groups

Get the Members or All Members of a Group

gTest.members

gTest.all_members

Intersection of Two Groups

Group members work like a Ruby array so you can use & for intersection, | for union, and - for difference.

curtains_in_family_room = gFamilyRoom.members & gCurtains.members

Iterate Over Members of a Group

gTest.each do |item|
  # process item
end

# The same:
gTest.members.each do |item|
  # process item
end

# Iterate over all members, including members of members
gTest.all_members.each do |item|
  # process item
end

Filter Members of a Group

members_that_are_on = gTest.grep(ON)
# Alternatively
members_that_are_on = gTest.select(&:on?)

# exclude state
members_that_are_not_on = gTest.grep_v(ON)
# the same as:
members_that_are_not_on = gTest.reject(&:on?)

# Filter with code:
high_temperatures = gTemperatures.select(&:state?).select { |item| item > '30 °C' }

Get the First Item in a Filtered List of Group Members

Because group acts like an array, simply use Ruby’s Array#first

my_item = gTest.grep(ON).first

Get first 5 Items from a filtered list of Group members

my_item = gTest.grep(ON)[0, 5]
my_item = gTest.grep(ON)[0..4]
my_item = gTest.grep(ON)[0...5]
my_item = gTest.grep(ON).slice(0, 5)

See Accessing elements in a Ruby array.

Get a sorted list of Group members matching a condition

sorted_items_by_battery_level = gBattery.select(&:state?) # only include non NULL / UNDEF members
                                        .select { |item| item < 20 } # select only those with low battery
                                        .sort # sort is done by comparing items, which does it by their states

Get a List of Values Mapped from the Members of a Group

battery_levels = gBattery.select(&:state?) # only include non NULL / UNDEF members
                         .sort
                         .map { |item| "#{item.label}: #{item}" } # Use item state default formatting

Perform Arithmetic on Values from Members of a Group

weekly_rainfall = gRainWeeklyForecast.sum

Rules

Create a Rule

rule 'my first rule' do
  received_command My_Switch, to: ON
  run do
    My_Light.on
  end
end

This applies to file-based rules. See Rules

Create a Rule with One Line of Code

received_command(My_Switch, to: ON) { My_Light.on }

This applies to file-based rules. See Terse Rules

Create a Rule in the Main UI

See Creating Rules in the UI

Get the Triggering Item

event.item

Get the Triggering Item’s Name

event.item.name

Get the Triggering Item’s Label

event.item.label

Get the Triggering Item’s State

event.state

or

event.item.state

The item’s state can also be obtained by accessing the triggering item itself.

# Item can be compared against their state
if event.item == ON
  # do something
end
# or
if event.item.on?
  # do something
end

Get the Triggering Item’s Previous State

event.was

Example:

if event.was.on?
  # do something
end

Compare Triggering Item’s State Against Previous State

event.state > event.was

Get the Received Command

event.command

Example:

if event.command.on?
  # do something
end

Create a Member-of-Group Trigger

rule 'Trigger by Member of' do
  changed gGroupName.members
  run do |event|
    logger.info "Triggered item: #{event.item.name}"
  end
end

Run a Rule on Start Up

rule 'initialize things' do
  on_start # This also triggers whenever the script (re)loads
  run { logger.info 'Here we go!' }
end

Use Multiple Triggers

rule 'multiple triggers' do
  changed Switch1, to: ON
  changed Switch2, to: ON
  run { |event| logger.info "Switch: #{event.item.name} changed to: #{event.item}" }
end

When the trigger conditions are the same, the triggers can be combined

rule 'multiple triggers' do
  changed Switch1, Switch2, to: ON
  run { |event| logger.info "Switch: #{event.item.name} changed to: #{event.item}" }
end

Use Multiple Conditions

rule 'multiple conditions' do
  changed Button_Action, to: ['single', 'double']
  run { |event| logger.info "Action: #{event.item}" }
end

Create a Simple Cron Rule

rule 'run every day' do
  every :day, at: '2:35pm'
  run { Amazon_Echo_TTS << "It's time to pick up the kids!" }
end
rule 'run every 5 mins' do
  every 5.minutes
  run { logger.info 'openHAB is awesome' }
end
rule 'Anniversary Reminder' do
  every '10-15' # Trigger on 15th of October at midnight
  run do
    things['mail:smtp:mymailthing'].sendMail('me@example.com', 'Anniversary Reminder!', 'Today is your anniversary!') 
  end
end

See Every

Create a Complex Cron Rule

rule 'cron rule' do
  cron '0 0,15 15-19 L * ?'
  run { logger.info 'Cron run' }
end

or an easier syntax:

rule 'cron rule' do
  cron second: 0, minute: '0,15', hour: '15-19', dom: 'L'
  run { logger.info 'Cron run' }
end

See Cron

Use Rule Guards

rule 'motion sensor' do
  updated Motion_Sensor, to: ON
  only_if Sensor_Enable # Run rule only if Sensor_Enable item is ON
  not_if { Sun_Elevation.positive? } # and not while the sun is up
  run { LightItem.on }
end

See Guards

Restrict Rule Executions to Certain Time of Day

rule 'doorbell' do
  updated DoorBell_Button, to: 'single'
  between '6am'..'8:30pm'
  run { play_sound 'doorbell_chime.mp3' }
end

Stop a Rule if the Triggering Item’s State is NULL or UNDEF

Use next within a file-based rule, because it’s in a block:

next unless event.item.state?

Use return within a UI rule:

return unless event.item.state?

Suppress Item State Flapping

Only execute a rule when an item state changed and stayed the same for a period of time. This method can only be done using a file-based rule.

rule 'Announce pool temperature' do
  changed Pool_Temperature, for: 10.minutes # Only when temp is stable for at least 10 minutes
  only_if Pool_Heater # And only when the pool heater is running
  run { say "The pool temperature is now #{Pool_Temperature}" }
end

Add a Pause / Sleep / Delay

sleep 1.5 # sleep for 1.5 seconds

See Ruby docs on sleep

sleep should be avoided if possible. A delay can be inserted in between two execution blocks to achieve the same result. This delay is implemented with a timer. This is available only on file-based rules.

rule 'delay something' do
  on_start
  run { logger.info 'This will run immediately' }
  delay 10.seconds
  run { logger.info 'This will run 10 seconds after' }
end

Alternatively a timer can be used in either a file-based rule or in a UI based rule:

rule 'delay something' do
  on_start
  run do
    logger.info 'This will run immediately' 
    after(10.seconds) do
      logger.info 'This will run 10 seconds after'
    end
  end
end

Things

Get Thing Status

things['lgwebos:WebOSTV:main-tv'].status

Check if Thing is Online

things['lgwebos:WebOSTV:main-tv'].online?

or

things['lgwebos:WebOSTV:main-tv'].status == ThingStatus::ONLINE

Enable/Disable a Thing

thing_manager = OpenHAB::Core::OSGI.service('org.openhab.core.thing.ThingManager')

thing = things['lgwebos:WebOSTV:main-tv']

thing_manager.set_enabled(thing.uid, false)
logger.info "TV enabled: #{thing.enabled?}"

thing_manager.set_enabled(thing.uid, true)
logger.info "TV enabled: #{thing.enabled?}"

Timers

Create a Timer

after 3.minutes do
  My_Light.on
end

See Timers

Reschedule a Timer

A timer can be rescheduled inside the timer body

after 3.minutes do |timer|
  My_Light.on
  timer.reschedule # This will reschedule it for the same initial duration, i.e. 3 minutes in this case
end

Or it can be rescheduled from outside the timer

my_timer = after 3.minutes do
  My_Light.on
end

my_timer.reschedule # Use the same initial duration

It can be rescheduled to a different duration

after 3.minutes do |timer|
  My_Light.on
  timer.reschedule 1.minute
end

Manage Multiple Timers

Multiple timers can be managed in the traditional way by storing the timer objects in a hash

@timers = {}

rule 'a timer for each group member' do
  received_command gOutdoorLights.members do
  run do |event|
    if @timers[event.item]
      @timers[event.item].reschedule 
    else
      @timers[event.item] = after 3.minutes do # Use the triggering item as the timer ID
        event.item.off
        @timers.delete(event.item)
      end
    end
  end
end

However, a built in mechanism is available to help manage multiple timers. This is done using timer IDs. The following rule automatically finds and reschedules the timer matching the same ID, which corresponds to each group member.

rule 'a timer for each group member' do
  received_command gOutdoorLights.members do
  run do |event|
    after 3.minutes, id: event.item do # Use the triggering item as the timer ID
      event.item.off
    end
  end
end

Furthermore, you can manipulate the managed timers using the built-in timers[] hash.

# timers[] is a special hash to access the timers created with an id
# Note here we use Ruby's safe navigation operator in case the timer
# no longer exists, in which case timers[id] returns nil
rule 'cancel all timers' do
  received_command Cancel_All_Timers, to: ON # Send a command to this item to cancel all timers
  run do
    gOutdoorLights.each do |item_as_timer_id|
      timers[item_as_timer_id]&.cancel 
    end
  end
end

rule 'reschedule all timers' do
  received_command Reschedule_All_Timers, to: ON # Send a command to this item to restart all timers
  run do
    gOutdoorLights.each do |item_as_timer_id|
      timers[item_as_timer_id]&.reschedule
    end
  end
end

Use Metadata

metadata = My_Item.meta['namespace'].value

See Metadata

Use Persistence

daily_max = My_Item.maximum_since(24.hours)

See Persistence

Use Semantic Model

# get the lightbulbs (equipment) in the room (location) 
room_lights = LivingRoom_Motion.location.equipments(Semantics::Lightbulb)
# get the switches (points)
light_switches = room_lights.members.points(Semantics::Switch)
# turn them all on if they're not already on
light_switches.ensure.on

See Semantics

Use Logging

logger.info("My Item's state is: #{My_Item}")

See Logging

Use Actions

See Actions

Publish an MQTT Message

things['mqtt:broker:mybroker'].publishMQTT('topic/name', 'payload')

Send an Email

things['mail:smtp:mymailthing'].sendMail('me@example.com', 'Subject', 'message body')

Play Sound Through the Default Audio Sink

play_sound 'sound_file.mp3'

Execute a Command

Exec.executeCommandLine('/path/to/program')

Date/Time

Use ZonedDateTime

ZonedDateTime.now.plus_minutes(30)

Convert ZonedDateTime to Ruby Time

Time.at(ZonedDateTime.now.to_epoch_second)

Convert Ruby Time to ZonedDateTime

ruby_time = Time.now
ruby_time.to_java(ZonedDateTime)

Work with Time of Day

if TimeOfDay.now > '7am'
  logger.info 'Wake up!'
end
# The range can cross midnight
if TimeOfDay.now.between?('10pm'..'5am')
  logger.info 'Sleep time'
end

See TimeOfDay

Work with MonthDay

if MonthDay.now == '02-14'
  logger.info "Happy Valentine's Day!"
end

See MonthDay

Ruby

Install Additional Gems

gemfile do
  source 'https://rubygems.org'
  gem 'httparty'
end

See Inline Bundler

Use Shared Library

See Shared Code

Miscellaneous

Get the UID of a Rule

This applies to file-based rules:

rule_obj = rule 'my rule name' do
  received_command My_Item
  run do
    # rule code here
  end
end

rule_uid = rule_obj.uid

Get the UID of a Rule by Name

rule_uid = OpenHAB::Core.rule_registry.all.select { |rule| rule.name == 'This is the name of my rule' }.first.uid

Enable or Disable a Rule by UID

rule_manager = OpenHAB::Core::OSGI.service('org.openhab.core.automation.RuleManager')
rule_manager.set_enabled(rule_uid, true) # enable rule
rule_manager.set_enabled(rule_uid, false) # disable rule

Run a rule by UID

rule_manager = OpenHAB::Core::OSGI.service('org.openhab.core.automation.RuleManager')
rule_manager.run_now(rule_uid)

Use a Java Class

java_import java.time.format.DateTimeFormatter

formatter = DateTimeFormatter.of_pattern('yyyy MM dd')
formatter = Java::JavaTimeFormat::DateTimeFormatter.of_pattern('yyyy MM dd')

See: Calling Java from JRuby