Service Call for setting binary_sensor and sensor

Many times, the value of a sensor or binary sensor needs to be calculated based on various conditions and events. Writing automations to determine when these states should change is, obviously, an exercise left to each user and their use case, however, there’s no easy way to actually set a binary_sensor from an automation. So, instead, workarounds are used. Like…:

  1. Use input_boolean instead of a binary_sensor even though the boolean should never be toggled by a user. This provides restored state and is settable via a service call.
  2. Use input_text instead of a sensor, even though the value should never be set by a user. This provides restored state and is settable via a service call.
  3. Write a python_script that calls hass.states.set(). This provides a better entity type (sensor, or binary_sensor), however, state is not restored, it requires the additional python_script, and the entity_id is not changable in the UI. There is also the risk that a future integration will create an entity with the same name and thus, you will be overwriting those values with this call.
  4. Publish a MQTT discovery message at startup, and then publish the desired state to MQTT via an automation. This is cumbersome and requires and MQTT server, but, provides the correct entity_type and restores state (because it’s preserved in MQTT).

Having a service call dedicated to this task would solve a lot of these issues. The data would be in an appropriate domain (binary_sensor, or sensor, depending). The UI would allow the entity_id to be changed (presumably because the service call would operate on a unique ID and not the entity_id). And state could be restored on Home Assistant restart.

Even if only implemented as a custom_component, it would be advantageous.

Why not?

I thought this was the exact use case they were designed to be used in.

I believe it’s the binary_sensors and sensors that shouldn’t typically be set by the user. Those should only be set by the system. And in actual use you can set those yourself in the states page but they will almost immediately be set back to what they should be by the system.

1 Like

What I mean is, they should never be set by the UI user. And I don’t mean input_booleans shouldn’t, in general. I mean, if I have a bunch of automations to determine something and turn off/on an input_boolean accordingly, then a UI user shouldn’t turn that input_boolean off because it was set by “the system” (i.e. the automations I wrote to set it).

There are things you want to be toggled in the UI. That’s what input_booleans are for. binary_sensors, well, SENSE something. They are indicating something that can’t (shouldn’t be changed) without changing the something instead.

As an example:

I have a device that triggers an event when it senses vibration. So I write an automation that sees that event and increments a counter. After a certain amount of time, without an increment, another automation resets it to 0. If the counter reaches a certain number, then the device is considered “in use”. When it’s “in use” an input_boolean is turned on, and then other logic, waiting for no more vibrations, sense when it is no longer in use and set the input_boolean to off. (this is an often used formula for determining if a clothes dryer is running, though I use an alternate method).

If the input_boolean is toggled in the UI, then it could break the automations. If it’s ever incorrect, it isn’t the UI that needs to be toggled, the automations need to be corrected.

Another example: A python_script that access an API (that doesn’t meet the requirements of the REST sensor, etc) to provide a value. This value should be a sensor. But, as it is now, it would be an input_text. One that should never be changed by someone as it would no longer reflect the actual data returned by the API.

There is a difference between things users should change (do I want dim lights or bright lights? do I have a guest over? etc) because automations can’t be written to detect them, and things automations CAN detect. This second group of things should be represented as sensors/binary_sensors so they render in the UI as unchangeable (aside from the states page, as you mentioned).

Again, it works perfectly fine as an input_boolean/input_text. It’s just less desirable.

Ah, OK. that was the part I was missing. I see what you are saying now.

Tho, it is (should be…) easy enough to hide that input_x from the average user.

But barring that, from what you are describing tho I think that a new service for the binary_sensor/sensor wouldn’t really solve the problem. Since the system could change the state of the binary_sensor/sensor at any point with zero control from you. Unless you also have the option to set some sort of access control that only allows the sensor to be controlled by the “not-system” (IOW, automation only).

I think you might be asking for a completely new type of entity - like a variable. That can be defined as a bool or string or int, float, etc. And that can only be set thru the automation/script service call.

1 Like

Well, the “not-system” would be the only thing that would set these sensors because they wouldn’t be attached to any other integration.

Similar, for instance, to a template sensor. It uses a template to produce a value and updates the value whenever entities in the template change. This works great, as long as your sensor logic can be encapsulated in a single template. If it can’t however, then input_text is the next option.

Yes, you can hide it from view in the UI. But, more importantly is the idea behind it. It is, ultimately, a “sensor”. It’s not an "box for inputting text (i.e. input_text). Thus, it should exist inside that domain. Another benefit of having it as a “sensor” is that, should you ever buy a new device that provides the same data you’re computing via automations on its own, it will already be a sensor. So, you may not have to change any automations that use that sensor at all. Just remove your custom, calculated sensor, and replace with the device provided one.

Got an example of some logic that can’t be encapsulated in a template?

Yes!

Of course, it’s going to be a bit complicated because a template sensor/binary_sensor is perfect for all the easy cases.

I prefer to have binary_sensors that represent room occupancy. I use the occupancy sensor to trigger lights on/off, etc. In the simplest of cases, this is a motion sensor (binary_sensor) and a template binary_sensor with a delay_off of something reasonable for the room. Like this:

 office_occupied:
     device_class: "occupancy"
     delay_off:
         minutes: 5
     value_template: >
         {{
             is_state('binary_sensor.office_motion', 'on')
         }}

But, the simplest example I can contrive is setting it up so that if the office door opens it’s also marked as occupied. I can’t just use the state of the door being open in the template binary_sensor, since I don’t want the room occupied just because the door is open. I just want the event of it opening to start the process. So here are those automations using an input_boolean instead:

- alias: office occupancy
  mode: restart
  trigger:
    - platform: state
      entity_id: binary_sensor.office_door
      to: 'on'
      from: 'off'
    - platform: state
      entity_id: binary_sensor.office_motion
  action:
    - service: input_boolean.turn_on
      data:
        entity_id: input_boolean.office_occupied
    - wait_template: "{{ is_state('binary_sensor.office_motion', 'off') }}"
    - delay:
        minutes: 5
    - service: input_boolean.turn_off
      data:
        entity_id: input_boolean.office_occupied

I haven’t actually used this automation so there may be bugs. My actual automations are more complex than this and look at “events” from more than just a single door, and are dependent on more states than just a single motion sensor.

Have you considered the Bayesian sensor?

I don’t use it for a few reasons.

The biggest of all is that they are both difficult to fine tune and ALSO require a Home Assistant restart for changes to take effect. The process of adjusting and restarting over and over is tedious.

They also don’t support events (like template binary_sensors) and don’t (easily) support the “for” aspect of an automation trigger, so detecting something like a door opening requires a chunk of template code. And that same code, if written for the Bayesian sensor, could just as easily be used in a template binary_sensor.

For instance, the example above about the door open event… since the door has a state I could wrap it in a template binary_sensor like this:

 office_occupied:
     device_class: "occupancy"
     delay_off:
         minutes: 5
     value_template: >
         {{
             states('sensor.time')
             and (
               is_state('binary_sensor.office_motion', 'on')
               or (
                 is_state('binary_sensor.office_door','on') 
                 and ((as_timestamp(now()) - as_timestamp(binary_sensor.office_door.last_changed)) > 5)
               )
             )
         }}

This will reevaluate every minute (which is annoying from a performance perspective) and the delayed off could end up being up to a minute longer than it should be, but it would work. However, My actual conditions are more complex than this, making the template even more complex. And I have quite a few of them, all evaluating every single minute needlessly.

@balloob alluded to the possibility of a triggered binary_sensor citing potential configuration like this:

binary_sensor:
  platform: trigger
  trigger: # standard trigger validation
    platform: event
    event: esphome_movement
  timeout: 20 # standard duration config

Such an implementation would also serve the needs of this Feature Request.

1 Like

I’m suffering from the same issues, I’m currently doing it woth AppDaemon only entities as a workaround. However, I think once the WTH for global variables will be fully implemented, one can do it through variables.

That’s a long thread, so I only skimmed over it.

I think global variables like this are a step in the right direction. We SORT of have this with a few different custom components, however, as far as I’ve seen so far, they all require a restart of home assistant to add a new variable, which is tedious.

The issue, even with this, is that the domain on these entities will still be “wrong”. It’s a binary_sensor… I’d like to be able to call it one. If I don’t care about that, and I’m okay with hiding the entity in the UI, an input_boolean serves the purpose just as well (though I do understand the needs some others have that can’t be encapsulated in an input_boolean/input_text).

Like, use, I use AppDaemon (or pyscript, recently) to “create” binary sensors. It works fine except for the issues mentioned in the OP regarding state restoration as entity overwrites. I have some AppDaemon code to get around both of these issues, but it’s not fun.

If the WTH is implemented as suggested, variables can be created without needing a restart and their state be restored on restart.

However, I see your issue with the “wrong” domain.

That’d be the best case.

As it stands now, I’m just using input_boolean and input_text for any cases when I need state restore. Otherwise, I’m using hass.set_state (via AppDaemon or pyscript).

Well, I’ve now created hass-setter.

It’s pretty much the least amount of code required to get the desired result. It doesn’t really do anything in the right ways, it’ll probably break with the next Home Assistant release, and it’ll likely drink straight out of the milk carton in the middle of the night. But, it’s something.

PRs happily accepted. I’m sure there are better ways to do just about everything I’ve done. I’m not well versed in Home Assistant internals.

1 Like