Trying to set state of button to off

You can do it from a Python Script, which you can call from an automation. And the automation can pass data to it (such as the entity_id.)

Basically in the script you would call hass.states.set(entity_id, new_state). Let me know if you’d like more detailed help.

2 Likes

Otherwise maybe write a home_assistant.turnon/off handler for binary sensor?

That sounds like it might be a winner. I could have it call that script after the action I need to run. Perfect!

If you could show me a quick script that I might be able to build off of that would be super helpful. I think I understand how to get the rest setup.

Thanks again!

Here is a very basic script that will set the state of an entity. The parameters are entity_id and state.

entity_id = data.get('entity_id')
if not entity_id:
    logger.error('No entity_id provided')
state = data.get('state')
if not state:
    logger.error('No state provided')
hass.states.set(entity_id, state)

Copy that code into a file in your <config>/python_scripts folder, where <config> is your HA configuration folder. The name of the file should have a .py extension. The name of the file will become the object_id of the script. So, e.g., if the file is <config>/python_scripts/set_state.py, then the service you want to call from your automation would be python_script.set_state. You can first test it, though, by calling it from the Services page. The nice thing about python_scripts are you don’t have to restart HA when you create them or change them. You can just call the python_script.reload service from the Services page.

Oh, and you need to add python_script: to your configuration.yaml file.

4 Likes

perfect!!!

Ok got it setup but have run into some errors. I can get it to trigger, but cant figure out how to proceed.

This python script =

entity_id = data.get(‘binary_sensor.samjin_button_0100bd6b_1_1280’)
if not entity_id:
logger.error(‘No entity_id provided’)
state = data.get(‘off’)
if not state:
logger.error(‘No state provided’)
hass.states.set(entity_id, state)

Gives this error =

2018-09-05 22:43:44 INFO (MainThread) [homeassistant.helpers.script] Script Exit Button - Test: Executing step call service
2018-09-05 22:43:44 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: domain=python_script, service=exit_button_reset, service_data=>
2018-09-05 22:43:44 INFO (SyncWorker_13) [homeassistant.components.python_script] Executing exit_button_reset.py: {}
2018-09-05 22:43:44 ERROR (SyncWorker_13) [homeassistant.components.python_script.exit_button_reset.py] No entity_id provided
2018-09-05 22:43:44 ERROR (SyncWorker_13) [homeassistant.components.python_script.exit_button_reset.py] No state provided
2018-09-05 22:43:44 ERROR (SyncWorker_13) [homeassistant.components.python_script.exit_button_reset.py] Error executing script: ‘NoneType’ object has no attribute ‘lower’
Traceback (most recent call last):
File “/usr/local/lib/python3.6/site-packages/homeassistant/components/python_script.py”, line 166, in execute
exec(compiled.code, restricted_globals, local)
File “exit_button_reset.py”, line 7, in
File “/usr/local/lib/python3.6/site-packages/homeassistant/core.py”, line 815, in set
context,
File “/usr/local/lib/python3.6/concurrent/futures/_base.py”, line 432, in result
return self.__get_result()
File “/usr/local/lib/python3.6/concurrent/futures/_base.py”, line 384, in __get_result
raise self.exception
File "/usr/local/lib/python3.6/site-packages/homeassistant/util/async
.py", line 176, in run_callback
future.set_result(callback(*args))
File “/usr/local/lib/python3.6/site-packages/homeassistant/core.py”, line 832, in async_set
entity_id = entity_id.lower()
AttributeError: ‘NoneType’ object has no attribute ‘lower’

If I comment out the logger part in the script like this =

entity_id = data.get(‘binary_sensor.samjin_button_0100bd6b_1_1280’)
if not entity_id:
#…logger.error(‘No entity_id provided’)
state = data.get(‘off’)
if not state:
#…logger.error(‘No state provided’)
hass.states.set(entity_id, state)

I get this error =

2018-09-05 22:48:28 INFO (MainThread) [homeassistant.core] Bus:Handling <Event service_executed[L]>
2018-09-05 22:48:28 INFO (MainThread) [homeassistant.helpers.script] Script Exit Button - Test: Executing step call service
2018-09-05 22:48:28 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: domain=python_script, service=exit_button_reset, service_data=>
2018-09-05 22:48:28 ERROR (SyncWorker_5) [homeassistant.components.python_script] Error loading script exit_button_reset.py: Line 4: IndentationError: expected an indented block in on statement: state = data.get(‘off’)
2018-09-05 22:48:28 INFO (MainThread) [homeassistant.core] Bus:Handling <Event service_executed[L]>

I have tried a few variables but cant seem to figure it out. Thanks for the support, I feel we are almost there!

I was thinking, could I call hass.states.set directly from the automation? I used this as the service data =

{
“entity_id”: “binary_sensor.samjin_button_0100bd6b_1_1280”,
“state”: “off”
}

And get this as the error at the top =

Message malformed: Service hass.scripts.set does not match format <domain>.<name> for dictionary value @ data[‘action’][1][‘service’]

Again, thanks for the help!

So you misunderstand how to use the script. You don’t need to change it. Make it just what I showed you. You just need to pass the entity_id and state as variables. E.g.:

  - service: python_script.set_state
    data:
      entity_id: binary_sensor.samjin_button_0100bd6b_1_1280
      state: 'off'
2 Likes

Perfect! Thanks for the push in the right direction. Now I am starting to understand.

That script works exactly how I hoped.

One thing I noticed, is it breaks the friendly_name tag. How can I add that to the script so it remains the same after it runs?

Thanks again!

Ah, ok. Try this on for size:

entity_id = data.get('entity_id')
if not entity_id:
    logger.error('No entity_id provided')
state = data.get('state')
if not state:
    logger.error('No state provided')
old_state = hass.states.get(entity_id)
if old_state:
    attrs = old_state.attributes
else:
    attrs = None
hass.states.set(entity_id, state, attrs)

I haven’t tried this, but hopefully it will work. Let me know.

4 Likes

Worked like a charm!

Thanks so much for the support, your help has been amazing.

This just worked great for me too. I can use the Button now for a single action and it seems to be fine.

Any ideas how we could expand to get double click and long click actions working?

I have an issue that makes this not work. So I have the automation that says if he button is pressed, then reset the state to off. Then I have another automation that uses the state to turn on a Light. So I press the button, the light turns on or off, then the other automation runs, sets the state back to off, then my other automation runs again and the light turns off.

I’m just trying to use this button to turn on and off some lights, feel like it’s close.

I just removed that delay from the automation and it seems to be working now.

I actually had to remove the delay from the switch back to off, and add a delay, of at least 600 ms to the automation to turn on the light to make the timing work out out. I will see if that is reliable. I would assume I would just have to increase the delay on the light toggle action more to ensure it goes off after the automation that sets the state back to off.

For what it’s worth, I have a version of the set_state script that works the same way for changing the state, but also allows you to change any attribute.
https://community.home-assistant.io/t/how-to-manually-set-state-value-of-sensor/43975/8

Nice!

FWIW, here are some improvements you might want to consider:

if 'entity_id' not in data:
    logger.warning("===== entity_id is required if you want to set something.")
else:
    data = data.copy()
    inputEntity = data.pop('entity_id')
    inputStateObject = hass.states.get(inputEntity)
    if inputStateObject:
        inputState = inputStateObject.state
        inputAttributesObject = inputStateObject.attributes.copy()
    else:
        inputState = 'unknown'
        inputAttributesObject = {}
    if 'state' in data:
        inputState = data.pop('state')
    logger.debug("===== new attrs: {}".format(data))
    inputAttributesObject.update(data)

    hass.states.set(inputEntity, inputState, inputAttributesObject)

Haven’t tested this, so adjust as necessary if you choose to use any of it.

EDIT: I tried it. Turns out data is not a normal dictionary, so you can’t call the pop method. So I added a line to turn it into a normal dictionary. Now it seems to work.

I’m not sure why the state matters. When I set up my Mijia button, the default state shown by the binary sensor entity is ‘on’, then when I press the button it changes to ‘off’ then immediately back to on. So I set up my automation to detect the ‘off’ state instead of on.

As far as double-click and long press, I had to look at my debug logs for those. It sends an event with a value that shows the number of clicks, so it was just a matter of grabbing that value for multi-click. It didn’t have a separate “long press” value, so I wrote a function that checks the time between the press and release. Anything over half a second is considered a long press.

Can you share your code? I just added these devices and only see temp, battery percent (which is some crazy high number), and a binary sensor which is always on. Thanks

1 Like

Oops, meant to reply to you. See my reply to the main thread.

I’m getting crazy battery with this device as well. Haven’t investigated what’s going on but it looks like the device is just reporting this number from the % battery remaining cluster.