Closed alexsahka closed 2 years ago
This is the built-in example for an ingress function:
// msg & attribute objects are
// passed to function
return msg.payload;
...and this is the example for an egress function:
// msg & attribute objects are
// passed to function
return msg;
Spot the difference? ;)
I should add a line or two to the example code to better highlight the difference. The ingress is supposed to return a single value, "return msg.payload;" but the egress returns a complete msg object "return msg;". The reasoning behind this is that it might be necessary for the egress to manipulate other parts of the msg object, like msg.topic or msg.url or anything else, so the egress needs to return the whole object.
Looks like you only return msg.payload which is probably the reason it doesn't work for you.
Is this is correct for Egress? This returns nothing.
msg.payload = (msg.payload.contact == true) ? '1' : '0'; return msg;
Also tried Pass-through
return msg;
returns nothing.
Seems to be working. Maybe a bit strange to user payload.contact as an input to the action? Try the example below:
[
{
"id": "453f525291d30f5c",
"type": "hal2Thing",
"z": "d9b62b0.9ebbfd8",
"eventHandler": "e228014191d14be6",
"thingType": "3bbd5e2d12efd9a0",
"name": "Test thing",
"attributes": [],
"topicFilter": "",
"topicFilterType": "mqtt",
"topicPrefix": "",
"notes": "",
"outputs": "1",
"x": 420,
"y": 3520,
"wires": [
[
"3f29d3d9a955dcb6"
]
]
},
{
"id": "3f29d3d9a955dcb6",
"type": "debug",
"z": "d9b62b0.9ebbfd8",
"name": "Output",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 570,
"y": 3520,
"wires": []
},
{
"id": "3e9c82d75accf248",
"type": "inject",
"z": "d9b62b0.9ebbfd8",
"name": "contact = true",
"props": [
{
"p": "payload.contact",
"v": "true",
"vt": "bool"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 230,
"y": 3580,
"wires": [
[
"017dad059d5fdf2d"
]
]
},
{
"id": "017dad059d5fdf2d",
"type": "hal2Action",
"z": "d9b62b0.9ebbfd8",
"eventHandler": "e228014191d14be6",
"name": "Test action",
"commandset": [
{
"category": "hal2Thing",
"thing": "453f525291d30f5c",
"item": "db49b125.6ae54",
"value": "payload",
"type": "msg"
}
],
"ratelimit": 0,
"x": 430,
"y": 3580,
"wires": []
},
{
"id": "12cba9878bba6772",
"type": "inject",
"z": "d9b62b0.9ebbfd8",
"name": "contact = false",
"props": [
{
"p": "payload.contact",
"v": "false",
"vt": "bool"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 240,
"y": 3620,
"wires": [
[
"017dad059d5fdf2d"
]
]
},
{
"id": "e228014191d14be6",
"type": "hal2EventHandler",
"name": "Event handler",
"maxlisteners": "50",
"heartbeat": "60"
},
{
"id": "3bbd5e2d12efd9a0",
"type": "hal2ThingType",
"name": "Test",
"contextStore": "memory",
"nodestatus": "",
"items": [
{
"name": "Test egress",
"id": "db49b125.6ae54",
"topicFilterType": "str",
"topicFilterValue": "",
"topicSuffix": "",
"type": "command",
"ingress": "748151a2.840f9",
"egress": "293406ea.fc48da",
"notes": "",
"output": "1"
}
],
"attributes": [],
"ingress": [
{
"name": "Pass-through",
"id": "748151a2.840f9",
"fn": "// msg & attribute objects are\n// passed to function\n\nreturn msg.payload;"
},
{
"name": "Convert to Number",
"id": "9243d3c4.f5753",
"fn": "// msg & attribute objects are\n// passed to function\n\nmsg.payload = Number(msg.payload);\nreturn msg.payload;"
},
{
"name": "Convert to Boolean",
"id": "21bf578f.d98df8",
"fn": "// msg & attribute objects are\n// passed to function\n\nmsg.payload = (msg.payload === 'true');\nreturn msg.payload;"
}
],
"egress": [
{
"name": "Pass-through",
"id": "8fd76278.c7a82",
"fn": "// msg & attribute objects are\n// passed to function\n\nreturn msg;"
},
{
"name": "Test",
"id": "293406ea.fc48da",
"fn": "msg.payload = (msg.payload.contact == true) ? '1' : '0';\nreturn msg;"
}
],
"thingStatus": false,
"thingCommand": true,
"thingOutput": true,
"hbCheck": false,
"hbType": "lwt",
"hbTTL": "",
"hbFilterVal": "",
"hbFilterType": "str",
"filterFunction": "0",
"outputs": "1"
}
]
Thanks, your example works. But when I tried this: nothing returns to output, same time ingress work.
Can you export and post an example?
Okay, got it.
The input on the Thing node is for ingress only. To get anything out of the output (egress) side you need to use an Action or Group node. Take a look at my example, I send msg.payload.contact true/false to an Action node, not to the Thing input.
I was under the impression that what I got on Ingress I can output try Egress function same time.
What I want to achieve is:
Z2M sensor contact: False/True
Ingress function converts it to Opened/Closed (easy to read for humans)
Egress function converts it to 0/1 for database use.
Well, I can see a couple of different ways to do that. I would probably not use an egress function, although that will work. Take a look at the example below. I would recommend example 2, that's what I would use.
[
{
"id": "2097573d5a616c9d",
"type": "inject",
"z": "e33735cb57f4c372",
"name": "Door true",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "{\"battery\":100,\"contact\":true,\"linkquality\":68,\"voltage\":3.04}",
"payloadType": "json",
"x": 240,
"y": 120,
"wires": [
[
"ca1d645f1bcf7440"
]
]
},
{
"id": "ca1d645f1bcf7440",
"type": "mqtt out",
"z": "e33735cb57f4c372",
"name": "",
"topic": "zigbee2mqtt/tttttttttt",
"qos": "1",
"retain": "false",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "5aeb1c10233e4cc2",
"x": 520,
"y": 140,
"wires": []
},
{
"id": "ca4226481ef8bce7",
"type": "inject",
"z": "e33735cb57f4c372",
"name": "Door false",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "{\"battery\":100,\"contact\":false,\"linkquality\":68,\"voltage\":3.04}",
"payloadType": "json",
"x": 240,
"y": 160,
"wires": [
[
"ca1d645f1bcf7440"
]
]
},
{
"id": "e6efe10ab218e082",
"type": "hal2Thing",
"z": "e33735cb57f4c372",
"eventHandler": "488bfca26161ef73",
"thingType": "1067281e08cac1b6",
"name": "Z2M test",
"attributes": [],
"topicFilter": "zigbee2mqtt/tttttttttt",
"topicFilterType": "mqtt",
"topicPrefix": "",
"notes": "",
"outputs": "1",
"x": 320,
"y": 220,
"wires": [
[
"e9a696d6b6cb6e58"
]
]
},
{
"id": "e9a696d6b6cb6e58",
"type": "debug",
"z": "e33735cb57f4c372",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 510,
"y": 220,
"wires": []
},
{
"id": "bc26aa1879b223d2",
"type": "mqtt in",
"z": "e33735cb57f4c372",
"name": "zigbee2mqtt",
"topic": "zigbee2mqtt/#",
"qos": "1",
"datatype": "json",
"broker": "5aeb1c10233e4cc2",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 150,
"y": 220,
"wires": [
[
"0142f143f41938e0",
"e6efe10ab218e082"
]
]
},
{
"id": "0142f143f41938e0",
"type": "hal2Action",
"z": "e33735cb57f4c372",
"eventHandler": "e228014191d14be6",
"name": "Contact out action",
"commandset": [
{
"category": "hal2Thing",
"thing": "e6efe10ab218e082",
"item": "2be75f55.195c4",
"value": "payload",
"type": "msg"
}
],
"ratelimit": 0,
"x": 350,
"y": 340,
"wires": []
},
{
"id": "9a46b6321f6613a3",
"type": "hal2Event",
"z": "e33735cb57f4c372",
"eventHandler": "e228014191d14be6",
"name": "Event on contact change",
"topic": "",
"thing": "e6efe10ab218e082",
"typeSel": "hal2Thing",
"item": "af0460be.09d73",
"operator": "always",
"change": "1",
"compareValue": "",
"compareType": "num",
"outputValue": "payload",
"outputType": "state",
"x": 370,
"y": 440,
"wires": [
[
"d0a62cd05b8c3b65"
]
]
},
{
"id": "30ed894a10f24da0",
"type": "comment",
"z": "e33735cb57f4c372",
"name": "Example 1",
"info": "",
"x": 320,
"y": 300,
"wires": []
},
{
"id": "e83393bb875ae5b0",
"type": "comment",
"z": "e33735cb57f4c372",
"name": "Example 2",
"info": "",
"x": 320,
"y": 400,
"wires": []
},
{
"id": "d0a62cd05b8c3b65",
"type": "function",
"z": "e33735cb57f4c372",
"name": "Convert to 1/0",
"func": "msg.payload = (msg.payload == 'closed') ? '1' : '0';\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 600,
"y": 440,
"wires": [
[
"87ea1a07174f5321"
]
]
},
{
"id": "87ea1a07174f5321",
"type": "debug",
"z": "e33735cb57f4c372",
"name": "To DB",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 770,
"y": 440,
"wires": []
},
{
"id": "5aeb1c10233e4cc2",
"type": "mqtt-broker",
"name": "MQTT 100",
"broker": "10.90.0.100",
"port": "1883",
"clientid": "",
"autoConnect": true,
"usetls": false,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willPayload": "",
"willMsg": {},
"sessionExpiry": ""
},
{
"id": "488bfca26161ef73",
"type": "hal2EventHandler",
"name": "Windows Doors",
"maxlisteners": "50",
"heartbeat": "3600"
},
{
"id": "1067281e08cac1b6",
"type": "hal2ThingType",
"name": "Z2M Xiaomi MCCGQ11LM door / window sensor",
"contextStore": "file",
"nodestatus": " 🚪%Contact%⏳%Contact Open Delay%⏳%Contact Delay%🌡️%Temperature%°F📶%Linkquality%🔋%Battery%%⚡%Voltage%V🕢%LastSeen%",
"items": [
{
"name": "Battery",
"id": "38773bb6.1923d4",
"topicFilterType": "StrEnd",
"topicFilterValue": "",
"topicSuffix": "",
"type": "status",
"ingress": "488ff997.1fae98",
"egress": "5a6ab0b3.43636",
"notes": "",
"output": "1"
},
{
"name": "Voltage",
"id": "a308050c.ec17f8",
"topicFilterType": "StrEnd",
"topicFilterValue": "",
"topicSuffix": "",
"type": "status",
"ingress": "b891197f.d119c8",
"egress": "5a6ab0b3.43636",
"notes": "",
"output": "1"
},
{
"name": "Linkquality",
"id": "977167c1.ae6448",
"topicFilterType": "StrEnd",
"topicFilterValue": "",
"topicSuffix": "",
"type": "status",
"ingress": "7838e8e7.d95508",
"egress": "5a6ab0b3.43636",
"notes": "",
"output": "1"
},
{
"name": "Temperature",
"id": "df60e448.dfe898",
"topicFilterType": "StrEnd",
"topicFilterValue": "",
"topicSuffix": "",
"type": "status",
"ingress": "5306119b.55bd2",
"egress": "5a6ab0b3.43636",
"notes": "",
"output": "1"
},
{
"name": "Contact",
"id": "af0460be.09d73",
"topicFilterType": "StrEnd",
"topicFilterValue": "",
"topicSuffix": "",
"type": "both",
"ingress": "d2515770.de6b18",
"egress": "acd4d5b2.e46cf8",
"notes": "",
"output": "1"
},
{
"name": "LastSeen",
"id": "800ca8b7.4b7328",
"topicFilterType": "str",
"topicFilterValue": "",
"topicSuffix": "",
"type": "status",
"ingress": "9f7dd133.3df26",
"egress": "5a6ab0b3.43636",
"notes": "",
"output": "1"
},
{
"name": "Contact Delay",
"id": "cd3d788f.2a4dd8",
"topicFilterType": "str",
"topicFilterValue": "",
"topicSuffix": "",
"type": "status",
"ingress": "43e4e408.dfb08c",
"egress": "5a6ab0b3.43636",
"notes": "",
"output": "1"
},
{
"name": "Contact Open Delay",
"id": "5a23656.d93b79c",
"topicFilterType": "str",
"topicFilterValue": "",
"topicSuffix": "",
"type": "status",
"ingress": "6e073250.e8a16c",
"egress": "5a6ab0b3.43636",
"notes": "",
"output": "1"
},
{
"name": "contact out",
"id": "2be75f55.195c4",
"topicFilterType": "str",
"topicFilterValue": "",
"topicSuffix": "",
"type": "command",
"ingress": "c7ccebbd.016228",
"egress": "acd4d5b2.e46cf8",
"notes": "",
"output": "1"
},
{
"name": "Alive",
"id": "1",
"topicFilterType": "StrEnd",
"topicFilterValue": "",
"topicSuffix": "",
"readOnly": true,
"ingress": "c7ccebbd.016228",
"egress": ""
}
],
"attributes": [],
"ingress": [
{
"name": "Pass-through",
"id": "c7ccebbd.016228",
"fn": "// msg object is passed to function\n\nreturn msg.payload;"
},
{
"name": "Battery",
"id": "488ff997.1fae98",
"fn": "// msg object is passed to function\nif (msg.payload.battery) {\n msg.payload = Number(msg.payload.battery);\n return msg.payload;\n}\n"
},
{
"name": "Voltage",
"id": "b891197f.d119c8",
"fn": "// msg object is passed to function\nif (msg.payload.voltage) {\n msg.payload = Number(msg.payload.voltage);\n return msg.payload * 0.01;\n}"
},
{
"name": "Linkquality",
"id": "7838e8e7.d95508",
"fn": "// msg object is passed to function\nif (msg.payload.linkquality) {\n msg.payload = Number(msg.payload.linkquality);\n return msg.payload;\n}"
},
{
"name": "Temperature",
"id": "5306119b.55bd2",
"fn": "// msg object is passed to function\nif (msg.payload.temperature) {\n tempc = Number(msg.payload.temperature);\n tempf = tempc * 9/5 + 32;\n msg.payload = Math.round(tempf* 10) / 10;\n return msg.payload\n}"
},
{
"name": "Contact",
"id": "d2515770.de6b18",
"fn": "// msg object is passed to function\n//msg.payload = (msg.payload.contact == 1);\n//return msg.payload;\n\n// msg object is passed to function\nmsg.payload = (msg.payload.contact == true) ? 'closed' : 'opened';\nreturn msg.payload;"
},
{
"name": "LastSeen",
"id": "9f7dd133.3df26",
"fn": "// msg object is passed to function\nif (msg.payload.last_seen) {\n msg.payload = String(msg.payload.last_seen);\n return msg.payload;\n}"
},
{
"name": "Contact_Delay",
"id": "43e4e408.dfb08c",
"fn": "// msg object is passed to function\nif (msg.payload.delay) {\n msg.payload = String(msg.payload.delay);\n return msg.payload;\n}"
},
{
"name": "Open_Delay",
"id": "6e073250.e8a16c",
"fn": "// msg object is passed to function\nif (msg.payload.open) {\n msg.payload = String(msg.payload.open);\n return msg.payload;\n}"
}
],
"egress": [
{
"name": "Pass-through",
"id": "5a6ab0b3.43636",
"fn": "// msg object is passed to function\n\nreturn msg;"
},
{
"name": "Contact 2 DB",
"id": "acd4d5b2.e46cf8",
"fn": "msg.payload = (msg.payload.contact == true) ? '1' : '0';\nreturn msg;"
}
],
"thingStatus": true,
"thingCommand": true,
"thingOutput": true,
"hbCheck": true,
"hbType": "ttl",
"hbTTL": "3600",
"hbLWT": "c7ccebbd.016228",
"hbFilterVal": "",
"hbFilterType": "StrEnd",
"filterFunction": "0",
"outputs": "1"
},
{
"id": "e228014191d14be6",
"type": "hal2EventHandler",
"name": "Event handler",
"maxlisteners": "50",
"heartbeat": "10"
}
]
I thought about this, even have this in my flows, but I thought to have a simple out from the hal2Thing with internal conversion would be a nice feature. Thank you!
Yeah that might be worth considering, maybe add a separate output option. Thanks.
Used Ingress function for while and it works great, here is an example for Z2M door/window sensor:
msg.payload = (msg.payload.contact == true) ? 'closed' : 'opened'; return msg.payload;
While started using the Egress function nothing came out of output no matter what I have tryed.
msg.payload = (msg.payload.contact == true) ? '1' : '0'; return msg.payload;
Question if the Egress function works at all? I have tried an example with the Egress function and it is not working as well.