Module: OpenHAB::DSL::Items::TimedCommand

Included in:
Core::Items::GenericItem
Defined in:
lib/openhab/dsl/items/timed_command.rb

Overview

Extensions for Item to implement timed commands

All items have an implicit timer associated with them, enabling to easily set an item into a specific state for a specified duration and then at the expiration of that duration have the item automatically change to another state. These timed commands are reentrant, meaning if the same timed command is triggered while an outstanding timed command exist, that timed command will be rescheduled rather than creating a distinct timed command.

Timed commands are initiated by using the ‘for:’ argument with the command. This is available on both the ‘command’ method and any command-specific methods, e.g. Core::Items::SwitchItem#on.

The timer will be cancelled, and the item’s state will not be changed to the on_expire state if:

  • The item receives any command within the timed command duration.

  • The item is updated to a different state, even if it is then updated back to the same state.

For example, if you have a Switch on a timer and another rule sends a command to that item, even when it’s commanded to the same state, the timer will be automatically canceled.

Sending a different duration (for:) value for the timed command will reschedule the timed command for that new duration.

Defined Under Namespace

Classes: TimedCommandDetails

Instance Method Summary collapse

Instance Method Details

#command(command, for: nil, on_expire: nil) {|timed_command| ... } ⇒ self

Note:

If a block is provided, and the timer is canceled because the item changed state while it was waiting, the block will still be executed. Be sure to check #expired? and/or #cancelled? to determine why the block was called.

Sends command to an item for specified duration, then on timer expiration sends the expiration command to the item

Examples:

Switch.command(ON, for: 5.minutes)
Switch.on for: 5.minutes
Dimmer.on for: 5.minutes, on_expire: 50
Dimmer.on(for: 5.minutes) { |event| Dimmer.off if Light.on? }

Parameters:

  • command (Command)

    to send to object

  • for (Duration) (defaults to: nil)

    duration for item to be in command state

  • on_expire (Command) (defaults to: nil)

    Command to send when duration expires

Yields:

  • If a block is provided, ‘on_expire` is ignored and the block is expected to set the item to the desired state or carry out some other action.

Yield Parameters:

Returns:

  • (self)


106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/openhab/dsl/items/timed_command.rb', line 106

def command(command, for: nil, on_expire: nil, &block)
  duration = binding.local_variable_get(:for)
  return super(command) unless duration

  on_expire = block if block

  TimedCommand.timed_commands.compute(self) do |_key, timed_command_details|
    if timed_command_details.nil?
      # no prior timed command
      on_expire ||= default_on_expire(command)
      super(command)
      create_timed_command(command, duration: duration, on_expire: on_expire)
    else
      timed_command_details.mutex.synchronize do
        if timed_command_details.resolution
          # timed command that finished, but hadn't removed itself from the map yet
          # (it doesn't do so under the mutex to prevent a deadlock).
          # just create a new one
          on_expire ||= default_on_expire(command)
          super(command)
          create_timed_command(command, duration: duration, on_expire: on_expire)
        else
          # timed command still pending; reset it
          logger.trace "Outstanding Timed Command #{timed_command_details} encountered - rescheduling"
          timed_command_details.on_expire = on_expire unless on_expire.nil?
          timed_command_details.timer.reschedule(duration)
          # disable the cancel rule while we send the new command
          DSL.rules[timed_command_details.rule_uid].disable
          super(command)
          DSL.rules[timed_command_details.rule_uid].enable
          timed_command_details
        end
      end
    end
  end

  self
end