Set state without communicating with device?

Yep, maybe that’s the way to do it, but it seems a little clunky to have to call the external API from inside HA :slight_smile: I was hoping there was a service that could be used to simply set the state.

The problem is this:

  1. Lamp is off. Lamp state in HA is off. Wall remote in HA shows is off.
  2. I press “on” on the wall remote.
  3. The lamp is switched on by the wall remote.
  4. HA picks up the wall remote switch and the state changes to on.

Unless I do something here, the lamp state in HA still shows as off - no longer in sync with actual status. I then tried to add an automation rule based on the wall remote state change, something like:

- alias: WallRemoteSync
  trigger:
    platform: state
    entity_id: switch.remote_kitchen_1
    from: 'off'
    to: 'on'
  
  action:
    service: homeassistant.turn_on
    entity_id: switch.kitchen_lamp

This works, but the side effect is that the homeassistant.turn_on service actually sends the turn on command to the lamp. This is fine, except in the case of a dimmer, where the second “on” signal causes the dimmer cycle to start.

Looks as if the set_state function in the API only sets state internally in HA. Maybe I can use this from an AppDaemon instance to accomplish what I want.

+1
I also ran into an issue where being able to change the state of a switch without actually communicating with it would be useful.

I solved this through setting up AppDaemon. I can check my setup later and post an example here.

1 Like

@magnushacker yes please!

Ok, I’m using this to synchronize the HA state with my wall remotes, so when I turn on a lamp using the wall remote the state in HA changes even though the lamp itself doesn’t tell HA that it was switched on (I’m using 433 Mhz devices). This is a description on how I configured it.

First step is to add your wall remotes to HA. For me, they are autodiscovered by HA since I have them added to my /etc/tellstick.conf and telldusd knows about them and listen to events for them. When I press the wall remote, I can see it changing in HA. Next step is to get the state replicated to the actual lamp/outlet that the wall remote controls.

Add an appdaemon app as .homeassistant/apps/remotesync.py:

import appdaemon.appapi as appapi

#
# Sync remotes and switches so the switches have the correct
# status (on/off) when triggered by the remote from outside HA.

#
# Args:
# switch: entity ID of switch
# app name: entity ID of remote to sync with

class RemoteSync(appapi.AppDaemon):

  def initialize(self):
    self.listen_state(self.state_change, self.name)
    self.log("RemoteSync to %s" % self.args["switch"])

  def state_change(self, entity, attribute, old, new, kwargs):
   if new != old:
     self.set_state(self.args["switch"], state=new)

As you can see, I’m using set_state() to just set the state without actually sending the state to the device.

Now, in appdeamon.cfg I instantiate this app like this:

[switch.remote_garage_b]
module = remotesync
class = RemoteSync
switch = switch.utebelysning_uppfart

[switch.remote_kitchen_b]
module = remotesync
class = RemoteSync
switch = switch.taklampa_kok

Here, I’m basically telling AppDaemon how I have paired by wall remotes with lamps - the remote named switch.remote_garage_b controls the lamp named switch.utebelysning_uppfart, and so on.

Now, whenever the remote switch.remote_garage_b changes state, it sets the state of switch.utebelysning_uppfart to the same value.

4 Likes

Hi All,

I’m just wondering if anyone knows how to use set state using a standard YAML script?

I’m in a similar situation where remotes can put dumb devices out of sync and I need to override without actually firing a HA switch etc.

Cheers,

Lint

I don’t think so - unless there is a undocumented/hidden service available that does exactly this (e.g only set the state, nothing else).

But the AppDaemon solution has worked good for me so far.

Such a shame.

Ok so looks like I have to figure out Python. I already have AppDaemon installed for HADashboard (though yet to go further than the installation really) so thats a start.

Would I be able to call this python app from a script or trigger from an automation? Or its pretty self contained as you have your own automation as a listen_state?

AppDeamon is actually a separate automation engine that runs in parallel to the native HA automation engine, so it’s entirely self-contained. It uses the HA API to access the event bus in HA.

You probably have everything you need already, just modify the appdeamon config file and add the script above. Here’s the relevant portion of my appdeamon.yaml file:

AppDaemon:
    logfile: /export/home/hacker/.homeassistant/appdaemon.log
    errorfile: /export/home/hacker/.homeassistant/appdaemon.err
    app_dir: /export/home/hacker/.homeassistant/apps
    threads: 10
    time_zone: Europe/Stockholm

HASS:
    ha_url: http://192.168.1.70:8123
    ha_key: <secret>

# Apps
switch.garage_remote:
    module: remotesync
    class: RemoteSync
    switch: switch.outside_garage

switch.kitchen_remote:
    module: remotesync
    class: RemoteSync
    switch: switch.kitchen_ceiling

Hey @magnushacker, thank you for that important tidbit on the appdaemon setup.

Ha so I’m trying to look at your example and use it as a base for my own without really knowing the basics (which is always a bad idea) and just wondering if you wouldn’t mind confirming a theory?

I have an entity fan.living_room_fan that has a basic state attribute of ‘off’. I have an xiaomi smart plug I’d like to use as an override for the fan’s state. The important attribute here is load_power: < 10 = on

I’m thinking to get the load power I need something like
state = self.get_state("switch.plug_158d0001a65815", "load_power")

then using your example, I’m hoping I can essentially replace
if new != old:

with something along the lines of
if state = <10: self.set_state(self.args["fan.living_room_fan"], state = on)

if state = <10: self.set_state(self.args["fan.living_room_fan"], state = off)

Think I’m on the right track? may also make no sense :stuck_out_tongue::stuck_out_tongue:

cheers,

Lint

you are on the right track.
but i would go like this to avoid that its exactly 10 and does nothing:

state = self.get_state("switch.plug_158d0001a65815", "load_power")
if state = <10: 
  self.set_state("fan.living_room_fan", state = on)
else:
  self.set_state("fan.living_room_fan", state = off)

I like it :slight_smile:

Thanks Rene, I’ll give this a shot

@ReneTode I got a syntax error for if state = <10:

Do I need to call 10 out as an integer perhaps?

what is the error?
could be an indention problem.
and i didnt correct it but it is “<=” and not “=<”
also state could be not an integer that can be corrected by "int(state)"if that is the case.

There’s also a space in the comparison operator in your example above.

It should be if state <= 10, not if state = <10.

1 Like

So I actually have it the following ‘fully’ working :slight_smile:
It’s just missing a large listening piece :stuck_out_tongue:

class FanSync(appapi.AppDaemon):
 
  def initialize(self):
    state = self.get_state("switch.plug_158d0001a65815", "load_power")
    print(state)
    if state < 10: 
      self.set_state("fan.living_room_fan", state = "off")
    else:
      self.set_state("fan.living_room_fan", state = "on")

It works if the load power changes and I restart addaemon to initialise the check and it will correct the switch to how it should be :slight_smile: Thank you both :slight_smile:

So now I just have to work in listen_state and try and find a way to poll the load power reading more often (currently take a couple of mins).

Do I have to log the states in order for it to calculate a change?

now you want to add a listen_state to the initialize and move that stuff to a function.

i advice you to read my tutorial :wink:

but ill give you a starting clue (you may take out the errors)

class FanSync(appapi.AppDaemon):
 
  def initialize(self):
    self.listen_state(self.blablabla, "switch.plug_158d0001a65815")

  function(self, put here what is needed):
    state = self.get_state("switch.plug_158d0001a65815", "load_power")
    sel.log(state) #dont use print(state)
    if state < 10: 
      self.set_state("fan.living_room_fan", state = "off")
    else:
      self.set_state("fan.living_room_fan", state = "on")    

Reading away. Thanks Rene :slight_smile:

1 Like

ugh, very frustrating that this isnt possible without using a hack (AppDeamon) and not available within standard configs.