Latching Toggle
A latching toggle controls something that has two states, using two actions: one sets the state and the other resets it. The current state is latched - it is remembered between button presses - and the dashboard always shows it.
The two actions are also interlocked: only the action that is valid for the current state can be clicked. You cannot open a valve that is already open, or close one that is already closed.
In OliveTin, the latched state is stored in an entity file, which the actions update themselves, and the interlock is done with enabled expressions.
This differs from Human in the Control Loop, which shows a live reading next to a single manual action that can always be run.
The example on this page controls a garden water valve.
| Valve closed | Valve open |
|---|---|
|
|
How it works
-
The entity file
/etc/OliveTin/entities/water_valve.yamlholds the state of the valve (openorclosed). It is the single source of truth for the dashboard. -
Open valve is only enabled when the state is
closed, and Close valve is only enabled when the state isopen. This is done withenabledExpression, which reads the state from.CurrentEntity. -
Each action writes the new state back to the entity file after it has done its work. OliveTin watches entity files, so the dashboard and the enabled buttons update as soon as the file changes.
Configuration
config.yamlentities:
- file: /etc/OliveTin/entities/water_valve.yaml
name: water_valve
actions:
- title: Open valve
icon: '💧'
entity: water_valve
enabledExpression: '{{ eq .CurrentEntity.state "closed" }}'
shell: |
set -e
echo "Opening {{ .CurrentEntity.title }}"
printf -- '- title: %s\n state: open\n' "{{ .CurrentEntity.title }}" > /etc/OliveTin/entities/water_valve.yaml
- title: Close valve
icon: '🚫'
entity: water_valve
enabledExpression: '{{ eq .CurrentEntity.state "open" }}'
shell: |
set -e
echo "Closing {{ .CurrentEntity.title }}"
printf -- '- title: %s\n state: closed\n' "{{ .CurrentEntity.title }}" > /etc/OliveTin/entities/water_valve.yaml
dashboards:
- title: Water Valve
contents:
- title: "{{ water_valve.title }}"
type: fieldset
entity: water_valve
contents:
- type: display
title: |
State: <strong>{{ water_valve.state }}</strong>
- title: Open valve
- title: Close valve
Customising this pattern
-
The same pattern works for anything with two states, such as lights, relays, services, or a maintenance mode.
-
Replace the
echocommands with your real hardware control, for example a GPIO command, an MQTT publish, or a call to a smart plug API. -
Only write the new state to the entity file once the hardware command has succeeded. If the command fails, the shell exits before the state changes and the dashboard keeps showing the real state.
-
If something else can change the device (a physical switch, a schedule), have a script update the entity file too. The dashboard will then follow it.
-
These actions rewrite the whole entity file, so to control several valves, give each one its own entity file (or update the file in place with a tool such as
yq). -
Add ACLs if only certain users should be able to operate the valve.