How to pass trigger.value_json (Python dict) to python_script?

Hi All,

I have a simple mqtt demultiplexer (from OMG Pilight to individual mqtt sensors).
Its goal is convert messages like this

{“message”:{“unit”:50555,“battery”:1,“state”:“closed”},“protocol”:“GS-iwds07”,“length”:“”,“repeats”:2,“status”:2}

to this

home/contacts/1st_floor/window Closed
home/contacts/1st_floor/window/attribute {“battery”: “Normal”}

Currently I pass the data to my python_script individually:

- service: python_script.pilight2mqtt_contact_demux
      data_template:
        protocol: "{{ trigger.payload_json.protocol }}"
        code:     "{{ trigger.payload_json.message.unit if trigger.payload_json.protocol == 'GS-iwds07' else trigger.payload_json.message.unitcode }}"
        state:    "{{ trigger.payload_json.message.state }}"
        battery:  "{{ trigger.payload_json.message.battery if trigger.payload_json.protocol == 'GS-iwds07' else '1' }}"

As you can see, I had to add some logic when passing code and battery variables.
I would like to do all the processing in the script by passing the whole trigger.payload_json.message to it like this:

- service: python_script.pilight2mqtt_contact_demux
      data_template:
        protocol: "{{ trigger.payload_json.protocol }}"
        message:  "{{ trigger.payload_json.message }}"

but it doesn’t work, seems like variables’ content gets converted to a string because I can see the following in the HA log

Executing pilight2mqtt_contact_demux.py: {‘protocol’: ‘GS-iwds07’, ‘message’: “{‘unit’: 50555, ‘battery’: 1, ‘state’: ‘closed’}”}

and obviously anything like message.unit in the script yellds None.

So I wonder if there is a way to pass a Python dict (as far as I understand what trigger.payload_json is) to python_script as a dict, intact?
Or is there another approach to achieve my goal?

UPDATE:
it works if I DO NOT use template in automation, i.e

- service: python_script.pilight2mqtt_contact_demux
      data_template:
        protocol: "{{ trigger.payload_json.protocol }}"
        message:  {'state':'closed'}

Apparently the result of every template is a string (and dicts get converted to strings) and there is no way to pass run-time dict into a script without templates.
There is also no easy way to convert that string into a dict as import and eval are prohibited within python_script.

Is that it then? :frowning:

Im not sure if you can use it in python_scripts but you could try json.loads on the string to convert to a python dict

AFAIK you cannot import anything in python_scripts so the answer is no… :\

Has anyone found an answer? This restriction is so terribly annoying. I also have to process a webhook JSON data including calling HA services and change states and there is no way to do this within a python script…:frowning:
I think ast.literal_eval should be allowed as it’s considered safe. But it would require an import thus this is not an option… :frowning:
Shame HA services do not return values as it would be possible to make a custom_component with a service that converts a dictionary string into dictionary. Then we could call it in python_script. But as services return no values - this is again not an option.

The only solution I see is to modify component python_script, make it a custom component and allow at least ast.eval_literal call. But then we would need to maintain such component to catch up with the HA version…

I hope someone has an idea. An alternative could be to write a dictionary string parser, but this is a lot of work without using any imports…

Any other ideas anyone??

2 Likes

Ugh, same issue here, I’m trying to pass a JSON string to a python script so I can standardise/map the device id. I was hoping to be able to just pass the JSON values back with the mapped ID via a new MQTT message, but this isn’t possible.

It feels like overkill to have to use AppDaemon for this and it’s a lot less flexible having to pass individual values and do the mapping in the automation.