Smart Approach to Email Alerts

Greetings,

I have been using a door reed switch to notify via mqtt when a door is open or closed. My node-red code has worked really well with one reed switch. Now that I want to add more reed switches I need to modify my code, but I am unsure the best approach. With a single door I wrote my code to have wording for just that door, but for multiple doors I am thinking I will need code that sends alerts absed upon the door alerting.

Here's my code...

[
    {
        "id": "f24af96c839adf16",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": ""
    },
    {
        "id": "bce559e2bcf01975",
        "type": "mqtt in",
        "z": "f24af96c839adf16",
        "name": "Studio Door Status",
        "topic": "HomeAssistant/Studio/Door/Status",
        "qos": "0",
        "datatype": "utf8",
        "broker": "f1621f1e.35326",
        "x": 170,
        "y": 400,
        "wires": [
            [
                "13d92fc5e5a8357d"
            ]
        ]
    },
    {
        "id": "2d1e24499952a054",
        "type": "blynk-ws-out-write",
        "z": "f24af96c839adf16",
        "name": "DoorStatus",
        "pin": "6",
        "pinmode": 0,
        "client": "e2371786.305248",
        "x": 930,
        "y": 520,
        "wires": []
    },
    {
        "id": "ec9ac712a27e6e78",
        "type": "blynk-ws-out-notify",
        "z": "f24af96c839adf16",
        "name": "Studio Door Open Notify",
        "client": "e2371786.305248",
        "queue": false,
        "rate": 5,
        "x": 1210,
        "y": 380,
        "wires": []
    },
    {
        "id": "7271816e933f2255",
        "type": "change",
        "z": "f24af96c839adf16",
        "name": "Convert Door Status",
        "rules": [
            {
                "t": "change",
                "p": "payload",
                "pt": "msg",
                "from": "1",
                "fromt": "num",
                "to": "0",
                "tot": "num"
            },
            {
                "t": "change",
                "p": "payload",
                "pt": "msg",
                "from": "0",
                "fromt": "str",
                "to": "255",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 620,
        "y": 440,
        "wires": [
            [
                "2d1e24499952a054"
            ]
        ]
    },
    {
        "id": "750f0ca47adfc748",
        "type": "function",
        "z": "f24af96c839adf16",
        "name": "Door Open Email",
        "func": "msg = {\n    payload : \"The Studio Door is OPEN!! \" + Date().toString() + \", Door Status \" +\n    msg.payload,\n    topic : \"WARNING!! DOOR STATUS\"\n};\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 910,
        "y": 420,
        "wires": [
            []
        ]
    },
    {
        "id": "13d92fc5e5a8357d",
        "type": "rbe",
        "z": "f24af96c839adf16",
        "name": "",
        "func": "rbe",
        "gap": "",
        "start": "",
        "inout": "out",
        "property": "payload",
        "x": 430,
        "y": 400,
        "wires": [
            [
                "7271816e933f2255",
                "b33070f839a44b63"
            ]
        ]
    },
    {
        "id": "b33070f839a44b63",
        "type": "switch",
        "z": "f24af96c839adf16",
        "name": "Door Status Check",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "0",
                "vt": "num"
            },
            {
                "t": "eq",
                "v": "1",
                "vt": "num"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 2,
        "x": 610,
        "y": 360,
        "wires": [
            [
                "60187f35357b3506",
                "d975bb60d8ce0667"
            ],
            [
                "750f0ca47adfc748",
                "84834fd9eb2dec3c"
            ]
        ]
    },
    {
        "id": "60187f35357b3506",
        "type": "function",
        "z": "f24af96c839adf16",
        "name": "Door Closed Email",
        "func": "msg = {\n    payload : \"The Studio Door is CLOSED!! \" + Date().toString() + \", Door Status \" +\n    msg.payload,\n    topic : \"WARNING!! DOOR STATUS\"\n};\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 910,
        "y": 380,
        "wires": [
            []
        ]
    },
    {
        "id": "84834fd9eb2dec3c",
        "type": "function",
        "z": "f24af96c839adf16",
        "name": "Door Open Notification",
        "func": "msg = {\n    payload : \"The Studio Door is OPEN!! \"\n};\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 920,
        "y": 460,
        "wires": [
            [
                "ec9ac712a27e6e78"
            ]
        ]
    },
    {
        "id": "d975bb60d8ce0667",
        "type": "function",
        "z": "f24af96c839adf16",
        "name": "Door Closed Notification",
        "func": "msg = {\n    payload : \"The Studio Door is CLOSED!! \"\n};\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 930,
        "y": 340,
        "wires": [
            [
                "ec9ac712a27e6e78"
            ]
        ]
    },
    {
        "id": "9a186ae478ba6066",
        "type": "mqtt in",
        "z": "f24af96c839adf16",
        "name": "Man Cave Door",
        "topic": "zigbee2mqtt/Man Cave Door",
        "qos": "0",
        "datatype": "json",
        "broker": "f1621f1e.35326",
        "nl": false,
        "rap": false,
        "x": 160,
        "y": 340,
        "wires": [
            [
                "b33070f839a44b63"
            ]
        ]
    },
    {
        "id": "f1621f1e.35326",
        "type": "mqtt-broker",
        "name": "Mosquitto",
        "broker": "<IP Redacted>",
        "port": "<Port Redacted>",
        "clientid": "",
        "usetls": false,
        "compatmode": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "sessionExpiry": ""
    },
    {
        "id": "<REDACTED>",
        "type": "blynk-ws-client",
        "name": "",
        "path": "ws://blynk-cloud.com/websockets",
        "key": "<REDACTED>",
        "dbg_all": false,
        "dbg_read": false,
        "dbg_write": false,
        "dbg_notify": false,
        "dbg_mail": false,
        "dbg_prop": false,
        "dbg_sync": false,
        "dbg_bridge": false,
        "dbg_low": false,
        "dbg_pins": "",
        "multi_cmd": false,
        "proxy_type": "no",
        "proxy_url": "",
        "enabled": true
    }
]

I would really like to have a method of alerting where the alert that is emailed out uses the node-red name assigned to the sensor(reed switch). I feel like I am not making this clear, apology.

Just use a Change node before the email node to alter the payload (email body) and topic (email subject) with the relevant sensor name.

Hi Bob,

Thanks for the advice. Imagine I am a complete novice, what might the change node look like? I am pretty good once I get the basic coding, so any tips would be appreciated. I figure if I can somehow use the name of the node (as in the door nodes below) it would be great... only I have no idea how that is done with a change node.

Screenshot_20220905_163226

Thanks, Mark

The input to the Change node would need to be your sensor name in some message format (eg msg.name or msg.payload.name). Then in the Change node set msg.payload (for the email body) to msg.name, and set msg.topic (for the email subject) to msg.name as well (or something else relevant to that particular door like door status, it can be anything you like obviously).

The info on what the email node accepts as input is in the help section.

Then connect the Change node to your configured email node.

Hope the above makes sense.

Hi Bob,

Not really following... Could I perhaps place a variable in this node that would replace the "The Studio Door is CLOSED!!" with something like "The $topic Door is CLOSED!!" which would then send the email with the topic name, or perhaps I could pull the name off the end of the MQTT topic?

For example... the MQTT topics are titled...

zigbee2mqtt/Man Cave Door
HomeAssistant/Studio/Door/Status

The MQTT topics are delivered via two difference sensors, one via Home Assistant and one via a zigbee sensor. I could and probably should standardise on naming.

Screenshot_20220905_170619

Is this where you are suggesting I concentrate my efforts?

Sure. I was trying to keep Function nodes out of the equation (for simplicity) but you can do a whole lot more with them so proceed with using it.

So if you add a msg.topic for the subject, then wire this into the email node, that should be job done!

Just think of it like this, the input to the email node needs to be msg.payload (for the email body) and msg.topic (for the email subject). That is all that is needed. So provided you convert whatever your mqtt nomenclature is to something meaningful and unique, then put it in msg.payload and msg.topic for the email node it should work fine.

You could add a change node right after each MQTT-in node to set msg.topic to what ever you want like ‘Mancave’ or ‘Studio’

If you change the MQTT topics output by your sensors so that all of them come under a single parent name such as reedswitch/Studio Door, reedswitch/Man Cave Door, etc. Then you can simplify the code a lot.

You can set your MQTT-in node to listen for reedswitch/#. Then with a change node, change the topic to replace reedswitch/ with an empty string.

Now your topic contains the text you need for your alerts. Another change entry in the same change node could create your standard output text message. No function node needed.

I like this approach, it sounds the most practical. Only thing, I am still confused on what I would enter into the change node?

Inside the mqtt node, I noticed it has a tag called Name. So I am wondering, is that something I could use to identify where the message is coming from?

Screenshot_20220905_210037

Could this be referenced via... msg.name or is that not how things work?

No, the msg.topic is for that. Name is only local to the Editor, not part of the message typically.

Thanks. I also found this... I assume if I place a change after the mqtt node I could reference this in a function?

if (msg.topic === "ManCave") {
   return [ No idea what goes here? ];
}

This is where I got stuck?

I assume I could have multiple 'if' statements that would output something different based on the mqtt node sending the message?

I've setup a simulated config to test everything... so far I have confirmation a 0 triggers the door is closed and a 1 is triggering the door is open.

Now I just need to understand what code needs to be added to the Door Closed Notification function node to extract the payload.topic...

This is really ugly... but appears to work?

[
    {
        "id": "1ab0469b9bafb6c1",
        "type": "tab",
        "label": "Flow 2",
        "disabled": false,
        "info": ""
    },
    {
        "id": "416245531dd98ad4",
        "type": "change",
        "z": "1ab0469b9bafb6c1",
        "name": "Topic change CLOSED",
        "rules": [
            {
                "t": "change",
                "p": "topic",
                "pt": "msg",
                "from": "ManCave",
                "fromt": "str",
                "to": "The Man Cave Door is CLOSED!!",
                "tot": "str"
            },
            {
                "t": "change",
                "p": "topic",
                "pt": "msg",
                "from": "Studio",
                "fromt": "str",
                "to": "The Studio Door is CLOSED!!",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 930,
        "y": 160,
        "wires": [
            [
                "dca8f86acdcb3d44"
            ]
        ]
    },
    {
        "id": "dca8f86acdcb3d44",
        "type": "debug",
        "z": "1ab0469b9bafb6c1",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1270,
        "y": 220,
        "wires": []
    },
    {
        "id": "176197c60728a5d8",
        "type": "inject",
        "z": "1ab0469b9bafb6c1",
        "name": "Inject 0",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "0",
        "payloadType": "str",
        "x": 130,
        "y": 220,
        "wires": [
            [
                "8a71583969f65231"
            ]
        ]
    },
    {
        "id": "06ab0fa29b63d68d",
        "type": "inject",
        "z": "1ab0469b9bafb6c1",
        "name": "Inject 1",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "1",
        "payloadType": "str",
        "x": 130,
        "y": 280,
        "wires": [
            [
                "8a71583969f65231"
            ]
        ]
    },
    {
        "id": "8a71583969f65231",
        "type": "change",
        "z": "1ab0469b9bafb6c1",
        "name": "Msg Topic Studio",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "Studio",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 370,
        "y": 240,
        "wires": [
            [
                "751e7dfd492e62b7"
            ]
        ]
    },
    {
        "id": "751e7dfd492e62b7",
        "type": "switch",
        "z": "1ab0469b9bafb6c1",
        "name": "Door Status Check",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "0",
                "vt": "num"
            },
            {
                "t": "eq",
                "v": "1",
                "vt": "num"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 2,
        "x": 630,
        "y": 200,
        "wires": [
            [
                "416245531dd98ad4"
            ],
            [
                "32d407222c828608"
            ]
        ]
    },
    {
        "id": "32d407222c828608",
        "type": "change",
        "z": "1ab0469b9bafb6c1",
        "name": "Topic change OPEN",
        "rules": [
            {
                "t": "change",
                "p": "topic",
                "pt": "msg",
                "from": "ManCave",
                "fromt": "str",
                "to": "The Man Cave Door is OPEN!!",
                "tot": "str"
            },
            {
                "t": "change",
                "p": "topic",
                "pt": "msg",
                "from": "Studio",
                "fromt": "str",
                "to": "The Studio Door is OPEN!!",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 920,
        "y": 220,
        "wires": [
            [
                "dca8f86acdcb3d44"
            ]
        ]
    },
    {
        "id": "8005636720fd2af6",
        "type": "inject",
        "z": "1ab0469b9bafb6c1",
        "name": "Inject 0",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "0",
        "payloadType": "str",
        "x": 130,
        "y": 80,
        "wires": [
            [
                "f493483d004ebd6b"
            ]
        ]
    },
    {
        "id": "4c8ac23fcb8a9115",
        "type": "inject",
        "z": "1ab0469b9bafb6c1",
        "name": "Inject 1",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "1",
        "payloadType": "str",
        "x": 130,
        "y": 140,
        "wires": [
            [
                "f493483d004ebd6b"
            ]
        ]
    },
    {
        "id": "f493483d004ebd6b",
        "type": "change",
        "z": "1ab0469b9bafb6c1",
        "name": "Msg Topic ManCave",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "ManCave",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 360,
        "y": 80,
        "wires": [
            [
                "751e7dfd492e62b7"
            ]
        ]
    }
]

No doubt there would be much better ways to do it?

Assuming you change your mqtt topics as totallyinformation suggests, you will have "reedswitch/Man Cave Door" or "reedswitch/Studio Door" (I assume spaces are ok in a topic, I'd probably avoid them)

So you might do something like this

[{"id":"b1c5f6463d7b05ca","type":"inject","z":"a00459fb50e37229","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"reedswitch/Man Cave Door","payload":"0","payloadType":"num","x":360,"y":100,"wires":[["357e055a197c40f7"]]},{"id":"357e055a197c40f7","type":"function","z":"a00459fb50e37229","name":"function 6","func":"msg.topic = msg.topic.split('/')[1];\nswitch (msg.payload) {\n    case 0:\n        msg.payload = msg.topic + \" is closed\";\n        break;\n    case 1:\n        msg.payload = msg.topic + \" is closed\";\n        break;\n    default:\n        msg.payload = \"'\" + msg.payload + \"' Is neither 0 nor 1\";\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":620,"y":140,"wires":[["7dd792b627161b6f","b1263569ee7741d7"]]},{"id":"7dd792b627161b6f","type":"debug","z":"a00459fb50e37229","name":"debug 31","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":820,"y":80,"wires":[]},{"id":"b1a112729ce41e48","type":"inject","z":"a00459fb50e37229","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"reedswitch/Studio Door","payload":"1","payloadType":"num","x":350,"y":140,"wires":[["357e055a197c40f7"]]},{"id":"2beb91bb252ace0b","type":"inject","z":"a00459fb50e37229","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"reedswitch/Studio Door","payload":"Something else","payloadType":"str","x":320,"y":180,"wires":[["357e055a197c40f7"]]},{"id":"b1263569ee7741d7","type":"e-mail","z":"a00459fb50e37229","server":"smtp.gmail.com","port":"465","secure":true,"tls":true,"name":"","dname":"","credentials":{},"x":810,"y":140,"wires":[]}]

Yes, they are, topics are just strings. Using spaces lets you simplify the logic quite a bit.

Hi @jbudd thanks for the help, that was awesome. I've modified my code (see below) based upon your example, and added a date/time stamp.

Question, is there a way to format the text and time stamp more neatly?

[
    {
        "id": "dca8f86acdcb3d44",
        "type": "debug",
        "z": "1ab0469b9bafb6c1",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1130,
        "y": 180,
        "wires": []
    },
    {
        "id": "176197c60728a5d8",
        "type": "inject",
        "z": "1ab0469b9bafb6c1",
        "name": "Inject 0",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "Grego/Studio",
        "payload": "0",
        "payloadType": "num",
        "x": 130,
        "y": 220,
        "wires": [
            [
                "b62cd3f3bf87d513"
            ]
        ]
    },
    {
        "id": "06ab0fa29b63d68d",
        "type": "inject",
        "z": "1ab0469b9bafb6c1",
        "name": "Inject 1",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "Grego/Studio",
        "payload": "1",
        "payloadType": "num",
        "x": 130,
        "y": 280,
        "wires": [
            [
                "b62cd3f3bf87d513"
            ]
        ]
    },
    {
        "id": "8005636720fd2af6",
        "type": "inject",
        "z": "1ab0469b9bafb6c1",
        "name": "Inject 0",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "Man Cave",
        "payload": "0",
        "payloadType": "num",
        "x": 130,
        "y": 80,
        "wires": [
            [
                "f493483d004ebd6b"
            ]
        ]
    },
    {
        "id": "4c8ac23fcb8a9115",
        "type": "inject",
        "z": "1ab0469b9bafb6c1",
        "name": "Inject 1",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "1",
        "payloadType": "num",
        "x": 130,
        "y": 140,
        "wires": [
            [
                "f493483d004ebd6b"
            ]
        ]
    },
    {
        "id": "f493483d004ebd6b",
        "type": "change",
        "z": "1ab0469b9bafb6c1",
        "name": "Msg Topic ManCave",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "Grego/ManCave",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 380,
        "y": 120,
        "wires": [
            [
                "b62cd3f3bf87d513"
            ]
        ]
    },
    {
        "id": "b62cd3f3bf87d513",
        "type": "function",
        "z": "1ab0469b9bafb6c1",
        "name": "function 6",
        "func": "msg.topic = msg.topic.split('/')[1];\nswitch (msg.payload) {\n    case 0:\n        msg.payload = msg.topic + \" door is CLOSED \" + Date().toString();\n        break;\n    case 1:\n        msg.payload = msg.topic + \" door is OPEN \" + Date().toString();\n        break;\n    default:\n        msg.payload = \"'\" + msg.payload + \"' Is neither 0 nor 1\";\n}\nreturn msg;\n\n\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 860,
        "y": 180,
        "wires": [
            [
                "dca8f86acdcb3d44"
            ]
        ]
    }
]

Thanks again, really appreciate the help. Mark

I don't really know if this is what you are looking for but there is a node to do date conversions.

Actually I don't use Moment myself.
Sadly, I find it easier to read and interpret "2022-09-06T13:42:37.286Z", mentally applying any browser/server timezone and daylight saving time variations than to understand how to make it work in Node-red and connected applications.

You don't need moment if you are using node.js v14+ (actually it goes back much further I think) and a function node since you can use Node.js's INTL library.

Intl - JavaScript | MDN (mozilla.org)