And did it work with previous versions of HA?
Actually today is the first time I tried it and I updated earlier this evening, so I’m not sure…
hm… error message points inside states.get function… strange!
it works fine on 0.104.2, haven’t updated to 0.105 yet (but will over the weekend)
that should work, did you use to have it configured like this:
- service: python_script.set_state
entity_id:
- sensor.last_known_version
data_template:
state: "{{states('sensor.current_version')}}"
If so, that would make it a list. Which would propagate error in question all the way down in the hass.states.get() in line 13.
change the code to this and it should always work.
inputEntity = data.get('entity_id')
if inputEntity is None:
logger.warning("===== entity_id is required if you want to set something.")
else:
if isinstance(inputEntity, list) and len(inputEntity) >= 1:
inputEntity = inputEntity[0]
if isinstance(inputEntity, str) and inputEntity:
inputStateObject = hass.states.get(inputEntity)
inputState = inputStateObject.state
inputAttributesObject = inputStateObject.attributes.copy()
for item in data:
newAttribute = data.get(item)
logger.debug("===== item = {0}; value = {1}".format(item,newAttribute))
if item == 'entity_id':
continue # already handled
elif item == 'state':
inputState = newAttribute
else:
inputAttributesObject[item] = newAttribute
hass.states.set(inputEntity, inputState, inputAttributesObject)
else:
logger.warning("===== entity_id is required if you want to set something.")
could you explain why it is a list?
and I think this makes sense
inputEntity = data.get('entity_id')
if isinstance(inputEntity, list) and len(inputEntity) >= 1:
inputEntity = inputEntity[0]
if isinstance(inputEntity, str) and inputEntity:
inputStateObject = hass.states.get(inputEntity)
inputState = inputStateObject.state
inputAttributesObject = inputStateObject.attributes.copy()
for item in data:
newAttribute = data.get(item)
logger.debug("===== item = {0}; value = {1}".format(item,newAttribute))
if item == 'entity_id':
continue # already handled
elif item == 'state':
inputState = newAttribute
else:
inputAttributesObject[item] = newAttribute
hass.states.set(inputEntity, inputState, inputAttributesObject)
else:
logger.warning("===== entity_id is required if you want to set something.")
Seems like it is a list looking at the square brackets in the log. I will play with it tonight.
I’d also like to know why it’s being input as a list.
So yaml is pretty smart. It takes your configuration and converts it on load into python objects.
If you have this as a configuration in yaml:
foo:
- a
python recieves {'foo':['a']}
So if you were to get foo, you’d get ['a']
which is a list.
Same goes for a mapping object with a dict
foo:
bar: a
python gets {'foo':{'bar':'a'}}
or if you were to just use a single value:
foo: a
python gets {'foo':'a'}
So with that knowledge, and the flow of the program, you could deduce where this list would be coming from in get() because it’s only accepting what the user puts inside ‘entity_id’)
Well, I use a little bit modified script(which apparently does not do any list->str conversions) in my setup and there is at least one place where I call in from automation.yaml
service: python_script.set_state
data_template:
entity_id: binary_sensor.wallpanel_entrance_sensor_motion
state: >
{% if trigger.to_state.state == 'off' %}
Unavailable
{% else %}
{% set sensor_state = states('binary_sensor.wallpanel_entrance_sensor_motion') %}
{{ 'Clear' if sensor_state == 'Unavailable' else sensor_state }}
{% endif %}
and it does not produce errors, I wonder what’s the difference between my and @stuart-i-m-smith automations.
My assumption is that his original configuration was:
entity_id:
- binary_sensor.wallpanel_entrance_sensor_motion
instead of
entity_id: binary_sensor.wallpanel_entrance_sensor_motion
I see now (was focusing on the state
attribute for some reason). Looking at his code it sounds reasonable
- service: python_script.set_state
entity_id:
- sensor.last_known_version
So actually there is no need to change the script code, he just have to remove that dash and this should work
- service: python_script.set_state
entity_id: sensor.last_known_version
data_template:
state: "{{states('sensor.current_version')}}"
The only trouble is he says it doesn’t… 8()
Yeah, but the script should probably have some added safety. Never underestimate users. I didn’t test the changes I made but it should work for all non-string cases. It still doesn’t verify the entity_id is correct but that can always be added.
Yeah I saw that, but you can never be sure. Always good to point out things they could have done to cause the issue.
This is (and always has been) the automation action.
- service: python_script.set_state
entity_id: sensor.last_known_version
data_template:
state: "{{states('sensor.current_version')}}"
Moreover, your amendment to detect a list doesn’t work, perhaps theres a missing import? Error is
name ‘list’ is not defined
It’s ok because this is the only place this script is used so for now I have just commented the check and assume it is always a list.
Sorry my python is not very good.
nope. this works for me:
if type(inputEntity) is list and len(inputEntity) >= 1:
list is a type in python, it’s impossible for it to not exist.
Try putting entity_id inside data_template
- service: python_script.set_state
data_template:
entity_id: sensor.last_known_version
state: "{{states('sensor.current_version')}}"
neither list
not type
are recognised in python_script
because it’s RestrictedPython.
Here’s what’s available - list
is a wrapper and I can see no .isinstance
I think I can explain what’s wrong with the OP’s code.
First of all, it is not related to HA version (at least it behaves the same in 0.104.2).
It is also not related to the set_state.py
script - I was able to get the error in question by changing the automation only.
Apparently the reason behind the error is the way data was passed to the service call and this suggestion should solve the issue. (I do remember at least one topic discussing different integrations allowing entity_id
only outside/inside data
)
Here is how it should be - basically, everything that you want to pass to your service must be inside data{_template}
or you may get any types of errors.
I’m not a HA developer but the fact is that we get a string if entity_id
is inside data_template
and a list that contains the very same string if it’s outside. Maybe that’s because result of every template is a string, it cannot be an object?
I can only say that everything that we consider a string (like {{states('sensor.current_version')}}
) is actually a list because that’s the way strings are represented in python - basically they are all lists of characters.
The bottom line is read the docs!
Psh, who does that!
I just want to thank you for this amazing solution, it just made my day!
My use case as a new comer to H-A is a little different to most of what is posted here.
I have a python script that returns a numeric value from sqliteDB. I want to pass that numeric value to an entity state to update the state value and do this on a pattern or cron job every couple of hours. The idea is just to display the entity state value in a lovelace card.
Can this set_state.py script be used to achieve this?