How to set command_line switch's state from outside?

The thing is I’m using command line switch to turn on and off lights using my PLC. At the same time I can retrieve lights (outputs) states to know if anyone switched the light in other way than through HA (wall switch for instance). I’m retrieving them all at once with a single modbus command so I don’t need to do it twice and for every switch separatedly. So is there a way to couple switch state with state of binary sensor? I mean I could poll for states using command line magic directly from PLC or using CURL to get it from binary sensor but it’s such a waste of resources and introduces unnecessary delay. I’m thinking of something like automation that updates the state on entity change.

You could use a template switch.
Put something like this in your configuration.yaml

### Switches
switch:

  - platform: template
    switches:

      # Foscam Infra Led
      foscam_infra_led:
        friendly_name: "Foscam Infra Led"
        unique_id: foscam_infra_led
        value_template: "{{ is_state('binary_sensor.foscam_infra_led_state', 'on') }}"
        turn_on:
          - service: rest_command.foscam_open_infra_led
            data:
              ip:   !secret foscam_ip
              port: !secret foscam_port
              usr:  !secret foscam_usr
              pwd:  !secret foscam_pwd
          - delay:
              milliseconds: 250
          - service: homeassistant.update_entity
            data:
              entity_id: binary_sensor.foscam_infra_led_state
        turn_off:
          - service: rest_command.foscam_close_infra_led
            data:
              ip:   !secret foscam_ip
              port: !secret foscam_port
              usr:  !secret foscam_usr
              pwd:  !secret foscam_pwd
          - delay:
              milliseconds: 250
          - service: homeassistant.update_entity
            data:
              entity_id: binary_sensor.foscam_infra_led_state

The update_entity service calls are put in to speed up the state retrieval, as the binary_sensors normally update once per 5 seconds (rest sensors with scan_interval).

That is a good piece of code but i guess it works only when I turn switch on or off. I need something simmilar to what I can do manually in Developer Tools:

Just in automated way. And immediately when other entity changes, not when it refreshes on its own.

The refresh is normally immediate when the state changes, but because in my example the rest sensor is polled at an interval of 5s, I added a manual update after toggling.

A template switch is in fact a virtual switch that needs:

  • turn_on command
  • turn_off command
  • info on actual state

If you are using a command_line switch, something similar is value_template for the info, but then command_state will be ignored. With an additional template switch you could grab both the command_state from the command_line switch, and the state of a binary_sensor if needed.

Do you have a binary_sensor available already?

If you only want communication with the device when toggling the switch in Home Assistant, then how will you know if the wall switch is toggled?

Or do you want want to manually override the switch’s state? Then you could define an input_boolean helper and use it’s state in a template switch to override the command_state.

If you post some code, we can try to work out a solution.

NOTE 1: It seems that a command_line switch with command_state already polls for the state?!

NOTE 2: If you use modbus binary sensors, what about this:

switch:
  - platform: command_line
    switches:
      plc_light_1:
        command_on: "curl -X ..."
        command_off: "curl -X ..."
        value_template: '{{ states('binary_sensor.modbus_plc_light_1') }}'
        friendly_name: PLC Light 1

Ok, so let me put it all together. I have a command_line switch defined as

    sw_pralnia:
      command_on: "curl 'http://192.168.1.2/WRITEPI?ADR1=MX4.10&VALUE1=1&FORMAT1=%x'"
      command_off: "curl 'http://192.168.1.2/WRITEPI?ADR1=MX4.10&VALUE1=0&FORMAT1=%x'"
      command_state: "bash -c '/config/bash/reg_to_coil.sh 4 10'"
      value_template: '{{ value == "" }}'
      friendly_name: Pralnia

those commands are irrelative couse I can do all those thing in many different ways, however command_state will be executed every 5 seconds (or from what I observe less) - if I understand it correcly.

On the other hand I have a (set of) modbus binary sensor(s):

  binary_sensors:
    - name: wago_output
      slave: 1
      address: 512
      slave_count: 120
      scan_interval: 1

I will work on triggering the scan with a webhook or even update the binary sensor state with webhook but it’s a difterent topic. For now let’s stay with that.

So every time my wago_output chages I want this change to be reflected in sw_pralnia and I want sw_pralnia to be updated without delay and only when needed, not with interval.

For now the best I worked out is

    sw_pralnia:
      command_on: "curl 'http://192.168.1.2/WRITEPI?ADR1=MX4.10&VALUE1=1&FORMAT1=%x'"
      command_off: "curl 'http://192.168.1.2/WRITEPI?ADR1=MX4.10&VALUE1=0&FORMAT1=%x'"
      command_state: "bash -c 'exit'"
      value_template: '{{ states("binary_sensor.wago_output_42") == "on" }}'
      friendly_name: Pralnia

and automation to force update of switch

- id: '1671109819030'
  alias: template pralnia test
  description: ''
  trigger:
  - platform: state
    entity_id:
    - binary_sensor.wago_output_42
  condition: []
  action:
  - service: homeassistant.update_entity
    data: {}
    target:
      entity_id:
      - switch.sw_pralnia
  mode: single

the switch will not update it’s state without a command to execute so there needs to be something applied, and it will not update (or the update takes too long) if not forced with homeassistant.update_entity. If noone here has any better idea for command_state: “bash -c ‘exit’” I guess we could mark this thread as solved.

When using command_line switch, I think this is the best way indeed.

Otherwise you could drop the command_line switch and use a template switch instead, if you use separate shell_commands for the turn_on and turn_off actions.

switch:
  - platform: template
    switches:
      sw_pralnia:
        friendly_name: "Pralnia"
        unique_id: sw_pralnia
        value_template: '{{ states("binary_sensor.wago_output_42") }}'
        turn_on:
          - service: shell_command.sw_pralnia_turn_on
        turn_off:
          - service: shell_command.sw_pralnia_turn_off

shell_command:
  sw_pralnia_turn_on: "curl 'http://192.168.1.2/WRITEPI?ADR1=MX4.10&VALUE1=1&FORMAT1=%x'"
  sw_pralnia_turn_off: "curl 'http://192.168.1.2/WRITEPI?ADR1=MX4.10&VALUE1=0&FORMAT1=%x'"

So you won’t need above automation to update the switch state, as it gets updated on any state change of the binary_sensor already.

You might even be able to template the commands like this:

switch:
...
        turn_on:
          - service: shell_command.curl_cmd
            data:
              resource: 'http://192.168.1.2/WRITEPI?ADR1=MX4.10&VALUE1=1&FORMAT1=%x'
        turn_off:
          - service: shell_command.curl_cmd
            data:
              resource: 'http://192.168.1.2/WRITEPI?ADR1=MX4.10&VALUE1=0&FORMAT1=%x'
  
shell_command:
  curl_cmd: curl {{ resource }}

Not tested, maybe extra quotes needed around the {{ resource }} but apart from that it should work.

Indeed, I tunned it a bit and it works even better (using modbus instead of curl) and is shorter:

- platform: template
  switches:
    sw_pralnia:
      friendly_name: "Pralnia"
      unique_id: sw_pralnia
      value_template: '{{ states("binary_sensor.wago_output_42") }}'
      turn_on:
        - {service: modbus.write_coil, data:{address: 12362, hub: "wago", state: 1}}
      turn_off:
        - {service: modbus.write_coil, data:{address: 12362, hub: "wago", state: 0}}

Do you think I could replace value_template: '{{ states("binary_sensor.wago_output_42") }}' with a value obtained from a webhook? Not a restful cause my PLC has no easy option to add bearer token to request header.

1 Like

Webhooks can be used as triggers, but not for template switches, as these are state-based only. So I don’t think this is directly possible.

But of course an automation can be used to update the binary sensor if the webhook gets called.

See for an example of a trigger-based template sensor using a webhook:

Probably you can define a trigger-based webhook sensor directly, and use that in the value_template if your present template switch.