What kind of component or entity do I need for this?

This is tied in with using a delay. I want something that acts like a boolean, but I’m not sure of what to use for scope and access.

When I turn a switch on, I want the boolean to be true. Then, after I turn the switch off, and the delay has ended, I want the boolean to change to false. I’m not worried about how to set it or read it. The problem is I want a component that HA can read and, if possible, I can see on the web page and using REST to read JSON data. But, as for as access to it, I need:

  • to be able to change it from within this ESPHome device
  • to be able to read it from Home Assistant, the web server page, or using REST to read JSON data
  • to be UNable to alter it using REST, a template on the web page, or through HA.

I don’t know what to uses or what to do to use a value I can edit locally, display outside of the system, but make it also uneditable from outside the device.

I think you simply want a switch. When it is on in HA it will beon in esphome, and vice versa. Stop overthinking.

But is there a way to make a switch so it can’t be turned on and off by HA or the web page?

Seems like a template binary sensor would meet your needs:

1 Like

There’s some examples in this config of how to set up a template binary sensor which only gets updated from “manual calls” elsewhere in the code.

Search it for batt_level_recieved for example.

I don’t think binary_sensor.template.publish can be called from HA, only inside ESPHome.

The examples in the ESPlanty helped. I finally set up a Binary Sensor Template like this:

binary_sensor
  - platform: template
    name: "Switch 1 Delay State"
    id: "Switch1_Delay_State"
    lambda: 'return id(MainSwitchDelay) == true;'

MainSwitchDelay is a bool. I’m surprised there’s no simple way to just check if a bool is true or false. Maybe there is, but I couldn’t find it - which means someone will post a link to an obvious page in the docs about it that I missed!

Anyway, I also did this while experimenting:

time:
  - platform: sntp
    on_time:
      - seconds: /3
        then:
          - if:
              condition:
                lambda: 'return id(MainSwitchDelay) == true;'
              then:
                - logger.log: "DEBUG CYCLE 1A: Delay TRUE"
              else:
                - logger.log: "DEBUG CYCLE 1B: Delay FALSE"

The intent here was NOT to just print the status, but to make sure I could use the bool I created as a condition for branching. I would have thought, since MainSwitchDelay is a bool, that all I’d have to do is use it as a condition, but that didn’t work. (Or does it and I just might have used the wrong punctuation?) I would think there’s an easy way to have a bool work as a condition without having to use a lambda. Is that possible?

But back to the template: It worked fine the way I have it above. I did, of course, have to create a global bool for it. I watched the logging every 3 seconds and any messages of changes of the bool variable I was using to verify it was changing back and forth between true and false as needed.

How is MainSwitchDelay defined (share the yaml)? Typically you’d just use the relevant switch or binary sensor condition.

MainSwitchDelay is a global bool:

globals:
  - id: TestText
    type: String
    initial_value: '"Original Text"'
  - id: MainSwitchDelay
    type: bool
    initial_value: "false"

The problem is the delay, itself, is not from a sensor. I have this on MainSwitch (lots of debugging statements in here, still):

binary_sensor:
  #
  #Toggle switch group first, with master switch first in that group.
  #
  - platform: gpio
    id: "Mainswitch"
    name: "Main Switch"
    web_server:
      sorting_group_id: sorting_group_master
      sorting_weight: 1
    pin:
      number: ${MasterSwitchPin}
      mode:
        input: true
        pulldown: true
    filters:
      delayed_on: 10ms
    device_class: power
    on_press:
      - logger.log:
          format: "DEBUG PRESS 1: Test Variable Value: %s"
          args: id(TestText).c_str()
      - logger.log:
          format: "DEBUG PRESS 2: Test boolean value: %d"
          args: 'id(MainSwitchDelay)'
      - globals.set:
          id: MainSwitchDelay
          value: 'true'
      - logger.log:
          format: "DEBUG PRESS 3: Test boolean value: %d"
          args: 'id(MainSwitchDelay)'
    on_release:
      - logger.log:
          format: "DEBUG RELEASE 2: Test boolean value: %d"
          args: 'id(MainSwitchDelay)'
      - logger.log: "DEBUG RELEASE 2:    <== Switch released, calling script"
      - script.execute: MainSwitch_Delay_Script
      - logger.log: "DEBUG RELEASE 3:    <== Script returned"
      - logger.log:
          format: "DEBUG RELEASE 4: Test boolean value: %d"
          args: 'id(MainSwitchDelay)'

So when MainSwitch is turned on, of course its state will be ON. When it is turned off, the sensor for the switch itself does not go to OFF. Instead it runs the script with the delay (again, a lot of debugging statements still in here):

script:
  - id: MainSwitch_Delay_Script
    mode: restart
    then:
      - logger.log:
          format: "DEBUG SCRIPT 1: Test boolean value: %d"
          args: 'id(MainSwitchDelay)'
      - delay: 5 seconds
      - logger.log:
          format: "DEBUG SCRIPT 2: Test boolean value: %d"
          args: 'id(MainSwitchDelay)'
      - globals.set:
          id: MainSwitchDelay
          value: 'false'
      - logger.log:
          format: "DEBUG SCRIPT 3: Test Variable value: %d"
          args: 'id(MainSwitchDelay)'
      - logger.log: "DEBUG SCRIPT 4: <-- Delay script ending"

MainSwitchDelay is true when the switch is turned on and stays true for, in this test, 5 seconds after it’s turned off. While this value is related to the state of MainSwitch, its value is not always the same as MainSwitch. So what I need to publish is not the state of a sensor, but the state of the delay. That’s why I’m making the Sensor Template dependent on a bool that I can turn on when the switch goes on and turn off later, after the switch goes off.

The two things I’m still trying to work out is how to use the value of a template number in a statement like this, to replace the fixed value of 5:

- delay: 5 seconds

and I need to have the delay available for 4 switches and 4 sensors. Since I can only use arrays for C++ variables, like bool, int, and String, I can’t have arrays of Binary Sensors, Number Templates, and scripts. (As best I can tell, I can’t make a script use paremeters, so I can’t call a script with a value to change.)

(Side note: On the control board, I have DTPST switches to turn on the board, the CNC, the laser driver, and the laser itself. One pole of each switch controls a device, like the CNC, the other is connected to a GPIO. In the code, I call these switches, but the component in ESPHome is a Binary Sensor. I do not want something like a CNC or an etching laser to be accessible from the ESPHome or HA interface. You can imagine the mess if even an etching laser was somehow accidentally turned on through HA and was not turned off. I want only direct physical control of these systems.)
.