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
closed
open

How it works

  • The entity file /etc/OliveTin/entities/water_valve.yaml holds the state of the valve (open or closed). 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 is open. This is done with enabledExpression, 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.

Entity file

/etc/OliveTin/entities/water_valve.yaml
- title: Garden water valve
  state: closed

Configuration

config.yaml
entities:
  - 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 echo commands 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.