Open jimtng opened 1 year ago
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, which shall be referred to as the
final state
.
Timed commands are initiated by using the for:
argument with the
command. This is available on both the {Core::Items::GenericItem#command
GenericItem#command} method and any command-specific methods, e.g.
{SwitchItem#on SwitchItem#on}.
Final State
By default, the timed command will command (or update) the item to its prior state when the timed command was issued. As a special case for {SwitchItem}, it will receive a command to revert / toggle its state, i.e. from {ON} to {OFF} and vice versa.
This can be overridden by providing an on_expire:
argument or a
block.
The timer will be cancelled, and the item's state will not be changed
to the final state
if:
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.
These timed commands are reentrant, meaning if the same timed command
is issued while an outstanding timed command exists, that timed
command will be rescheduled rather than creating a new timed command.
This also means that the default final state
, i.e. the state the item
reverts to, is the original final state prior to the start of the first
timed command, unless the subsequent timed command overrides it with
an on_expire
argument or a block.
However, if a different timed command is issued, the previous timed command
will be cancelled, and a new timed command will be created. In this case
the default final state
when not explicitly specified, will be
the current state. Note that in the case of {SwitchItem SwitchItem},
it will use the inverse of the given command.
Sending a different duration (for:
) value for the timed
command will reschedule the timed command for that new duration.
@example Simple timed command with a default final state
NumberItem1.update(10) # Set the initial state
NumberItem1.command(20, for: 3.seconds)
# after 3 seconds, NumberItem1 will receive a command `10`
@example Timed command interrupted by another command
NumberItem1.update(10) # sets the initial state
NumberItem1.command(20, for: 3.seconds)
NumberItem1.update(20) # This won't cancel the timed command
# because it's only an update to the same state
NumberItem1.command(20) # This cancels the timed command above because it's a command
# NumberItem1 will not revert to 10
@example Timed command interrupted by an update to a different state
NumberItem1.update(10) # sets the initial state
NumberItem1.command(20, for: 3.seconds)
NumberItem1.update(21) # This cancels the timed command above.
# NumberItem1 will not revert to 10
@example Reentrancy with default final state
on a Number Item
Number1.update(10)
Number1.command(20, for: 10.seconds)
sleep 5
Number1.command(20, for: 10.seconds) # This is the same timed command.
# It extends the timer, the final state is still 10
@example Reentrancy with a different command
Number1.update(10)
Number1.command(20, for: 10.seconds)
Number1.command(30, for: 10.seconds) # This is a different timed command
# It cancels the previous timed command,
# and the final state is now 20
@example Reentrancy with an explicit on_expire
Number1.update(10)
Number1.command(20, for: 10.seconds)
Number1.command(20, for: 5.seconds, on_expire: 15) # This cancels the previous timed command
# In 5 seconds, Number1 will receive a command `15`
@example Timed Command on a Switch Item. The final state
is the inverse of the command
Switch1.on # sets the initial state, which doesn't matter here
Switch1.on for: 3.seconds # Switch1 will receive OFF command in 3 seconds
@example Reentrancy on a Switch Item
Switch1.on for: 3.seconds
Switch1.on for: 10.seconds
# Switch1 will remain ON for 10 seconds and then receive an OFF command
# unless it received another command or its state updated to anything other than ON
this all sounds great. good docs too
I'd like to clarify the behaviour of timed command's on_expire and I've written the following documentation to describe it. It will be in a separate PR to #130 because that is a fix for a separate issue (when on_expire isn't used) which is affecting my existing scripts.