Hi all,
I’ve been using MyStrom buttons which make a HTTP GET or POST to a specific URL, where one can only can configure the GET params or the POST body. Thus I had to rethink my whole integration after the api_password URL parameter support was removed in v0.101.
The easiest way is to create a webhook and let it do a POST request there. However, this only works for HA automation.
What I wanted was the Node RED automation thing. As I found no solution how to let a HA webhook trigger something in HA, I looked for a solution which I want to show here. Of course I could’ve simply opened the Node RED port and use this as kind of a webhook endpoint, but why adding another possible security hole.
So first I created a rest_command like this, which simply sends all incoming data to a Node Red HTTP endpoint. I’ve used the same secret
vars for the Hass.io node username+password, so if you’ve configured it differently, you need to set your own user+pass of the Node RED HTTP node:
rest_command:
node_red:
url: http://localhost:1880/endpoint/inbound
method: POST
username: !secret node_red_http_node_username
password: !secret node_red_http_node_password
payload: '{{ data | tojson }}'
content_type: 'application/json; charset=utf-8'
Secondly, I’ve added the following automation which sends the webhook id, the request data or json as well as the query params.
There are 2 things to note here:
- data+query are of type
MultiDictProxy
, that’s why I need to convert it to JSON manually. This is not fool proof, so if you have some quotes in your keys or values, it’s not encoded - the “json” content is no valid JSON. It uses single quotes instead of double quotes around keys and values. I’ve opened an issue for this and you’ll see later, that I do a stupid but simple “replace single quotes with double quotes” string replacement.
- alias: Node Red
trigger:
- platform: webhook
webhook_id: PLEASESETYOUROWNUNIQUEANDSECRETID
action:
- data_template:
data:
data: '{ {% for key, value in trigger.data.items() %} {% if not loop.first
%} , {% endif %} "{{ key|e }}": "{{ value|e }}" {% endfor %} }'
webhook_id: '{{trigger.webhook_id}}'
json: '{{trigger.json}}'
query: '{ {% for key, value in trigger.query.items() %} {% if not loop.first
%} , {% endif %} "{{ key|e }}": "{{ value|e }}" {% endfor %} }'
service: rest_command.node_red
Last but not least, I’ve added a subflow in Node Red. Please find a screenshot as well as the flow JSON below.
[{"id":"3c3edf43.a7172","type":"subflow","name":"HA webhook","info":"# Payload:\n\n* json (object containing body json)\n* query (object containing GET parameters)\n* webhook_id (string)\n* data (object containing form data body)","category":"","in":[],"out":[{"x":540,"y":80,"wires":[{"id":"a39b3afc.3ba0f8","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"a412c92e.cac678","type":"http in","z":"3c3edf43.a7172","name":"","url":"/inbound","method":"post","upload":false,"swaggerDoc":"","x":200,"y":80,"wires":[["a39b3afc.3ba0f8","4e6bf1c.a50661"]]},{"id":"a39b3afc.3ba0f8","type":"function","z":"3c3edf43.a7172","name":"parse JSON","func":"[\"json\",\"query\", \"data\"].forEach(key => {\n if(msg.payload[key] && msg.payload[key].length > 1) {\n // the replacement is necessary as no valid JSON is received from HA\n const jsonStr = msg.payload[key].replace(/'/g, '\"');\n msg.payload[key] = JSON.parse(jsonStr);\n }\n});\nreturn msg;","outputs":1,"noerr":0,"x":410,"y":80,"wires":[[]]},{"id":"4e6bf1c.a50661","type":"http response","z":"3c3edf43.a7172","name":"","statusCode":"204","headers":{},"x":580,"y":140,"wires":[]},{"id":"f99841cd.e6753","type":"subflow:3c3edf43.a7172","z":"df65cebf.0ae0e","name":"HA Webhook","env":[],"x":210,"y":760,"wires":[["48b9895.1da0c78"]]},{"id":"48b9895.1da0c78","type":"debug","z":"df65cebf.0ae0e","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":380,"y":760,"wires":[]}]
Subflow screenshot:
So then your payload includes the id and some objects, containing the query (key: value) as well as the data with form data (key: value) or the json content (please note again that single quotes might’ve been replaced by double quotes due to the HA issue).
I hope it also helps one or the other to migrate away from api_password
.
Let me know if you have suggestions about how to improve the code and/or share it below