Signal Messenger Add-On + NodeRed

Signal Messenger Add-On

The How-To Explanation that I never found anywhere else

So, you want to integrate a Signal Messenger account into your Home Assistant instance, and you got to the point where you could send, but not receive, or were entirely disappointed with the lag and how slow it is.

Read on!

Signal Messenger Add-On

The instructions are simple and easy to follow. But don’t do it!

Skip ahead to the Signal CLI REST API installation instructions.

Once you have the Signal Messenger Add-On installed, go into the Configuration.

Choose the mode: json-rpc.

Toggle OFF Auto_Receive

Change the External Port number if necessary. My instance is already using 8080 somewhere else. So I changed the Signal Docker port to 7465. (That’s SGNL on a touchtone phone.)

Go to Info and Start the Signal Messenger Add-On.

Have a look at the Log on Start Up. It should look like this:

The next few steps are required to associate your Signal Add-On with a phone number. This can be a totally new number on Signal (probably the best option), or it can be an existing number (that will be shared with your phone). The downside of linking your HA Signal is that you would just be sending messages to yourself.

The instructions are straight forward and have all the necessary steps in detail, should you run into issues. Do all of these from a Terminal, and remember to use the IP of your HA Instance (the external IP, or hostname/domain name), and the port number you defined in the configuration.

Once you have successfully registered your HA with Signal and have completed some of the preliminary checks, and the logs are not throwing any 400 or 404 errors.

Lucky for you, I have Noded out a full Signal CLI REST API Flow for you to import. It’s fully Commented and will provide most of the commands listed. Some of the API calls just didn’t succeed, and I don’t know why. But it’s not really a problem because the main functions of sending and receiving should be working.

The most important piece of information that is not at all mentioned in the official documentations found on HA or the Signal CLI REST API, or the Signal-CLI githubs is this: when in json-rpc mode, all interactions with the Add-On are sent by HTTP, with the exception of RECEIVING MESSAGES, which is available only on a WebSocket connection.

In modes “normal” or “native”, sending and receiving are often delayed and quite sluggish, as the engine spins up for each service call. But in json-rpc mode, the receiving of messages is through the always-on always-connected WebSocket.

After importing the Flow into your NodeRed, be sure to add the REQUIRED Global Env Variables; these are used throughout the Nodes in the Flow.

Also be sure to edit the WebSocket Node in the Messages group to reflect your Signal resource, port, and Signal Phone Number.

When you are using Terminal to do the initial setup, it will be to your HA external IP.

However, when NodeRed is communicating with Signal, on http:// REST API calls or on the ws:// WebSocket, this is all happening inside the Docker network in HA. Therefore the URL in NodeRed is the hostname of the Signal Docker. This is viewable on the Info tab of the add-on.

Even if you have set a different port for Signal, the internal network of Docker maintains the default port of 8080 for communicating with the Signal Messenger host.

Once you’ve come this far… Just start with sending and receiving messages and watching the debug. You should be able to expand the json objects and locate the paths with which you will build your automations and notifications in NodeRed.

The Flow is too long for a single post. I will post it in two replies.

1 Like

This is Part 1 of the Flow

[{"id":"3240b1abdd2b9cc0","type":"tab","label":"Signal Messenger","disabled":false,"info":"","env":[]},{"id":"d09b4bf0ac40a1dc","type":"group","z":"3240b1abdd2b9cc0","name":"Messages","style":{"stroke":"#000000","fill":"#c8e7a7","label":true,"color":"#000000","label-position":"ne"},"nodes":["6d93e88b1e70eb79","a8bf417e2fb1d44c","399891f08c181bbf","97005b3edc34119d","44e4482edd7b0bbc","d416b6b2783e0d95","3c7b6b7dfc073e13","f24961571f4ca048","f9e1c2353e30f3da","01dd4f0ba1caa84b","f84a642126c6f401","216864cd48324378","1c1966db6bdd1151","ab541d059c27634e","acd36385bf216bc3","320c907ae16bd118"],"x":54,"y":579,"w":732,"h":482},{"id":"66db6ed8538aa25a","type":"group","z":"3240b1abdd2b9cc0","name":"Group Actions","style":{"stroke":"#000000","fill":"#ffdf7f","label":true,"color":"#001f60"},"nodes":["1077d1a6a70caeb1","37791c81deae0edb","46bcf90a0c8c5e14","0444b4fdb1a44883","4bf25e1da4c3cf2f","080435febec3faa7","3d4d7ad29478f56f","7463dd958cad9c7d","eacf128896ef1d75","5ce5f6ac9ccecc3f","1883c673cc7fd875","05901559b046735e","9fd5cc8da301bb2a","400e1991256db001","578358ebd81506ab","b314a6dd55b70dfc","3f9204a78046e854","7108f971c36a609b","3692f4e607a89fc3","33076447e5040d7f","03d90bdba7100ff3","0569fd357eb939ce","3086665b284694cf","64d3c119e5a4bed6","df6e6efe7336b61d","71592ea3d174d75e","2df2d27a5788fd44","a197340e95bff72d","868d717057115bfc","c63177f56c67d4de","68eaded31b51bfc3","426b58641c07dab0","45b5f4df745f0df8","6d02d61fbfc0fbb6","2762a409bd366916","b1cc87736ccc0151","2d65fa8550e0938f","7d8a22d94d17f39f","655ba30a30919e17","7277a91a2681e24f","f03880a97c602c24","5928816a80a090eb","bcade1473470f263","cb36c6bc822b38cf","4eb442f87a5a74a3","70708a6092ef09b0","cc329acbaba3b3a7","bae8df465e5bef69","bec501a8bbdfca40"],"x":814,"y":99,"w":852,"h":1282},{"id":"9960202b1208ef7b","type":"group","z":"3240b1abdd2b9cc0","name":"General","style":{"stroke":"#000000","fill":"#7fb7df","label":true,"label-position":"ne","color":"#000000"},"nodes":["17ecccb972234070","3335a5836a1f1d6f","552a23c432b48a2f","a06e918627829672","eece0e5e26bc8f93","e0aae9e41e8b04fe","80dfeddd3f3a95a7","761ba4aade07aff0","4d4ba6ef3330ae84","95bdf43c41020987","e8b592c436e335b9","82e969976e44571f","c680452b6921318c","a55e92518369399f","8a7e0e2728dd3cf7","3a0880a3662d0445"],"x":54,"y":99,"w":732,"h":422},{"id":"44f2778d817fd3a9","type":"group","z":"3240b1abdd2b9cc0","name":"Trust Identities","style":{"stroke":"#000000","fill":"#d1d1d1","label":true,"label-position":"ne","color":"#000000"},"nodes":["b2f5dd6e03a136f3","eb8fe74b94ee0f79","7a915afc8c35fc67","9bb14c15cb8a65d9","41b98669873ded1b","9d90428694ebd6f5","ee38b66a74042f61","5a8096c460ab3555","c6dbc0b68361dd92"],"x":74,"y":1099,"w":692,"h":282},{"id":"7f3749c392037095","type":"group","z":"3240b1abdd2b9cc0","name":"Contacts","style":{"stroke":"#000000","fill":"#ffff7f","label":true,"label-position":"ne","color":"#000000"},"nodes":["c8f1cc833c2218a9","ba5d158fce2fd0c4","bd54b84bc8341dba","4c8bc2f9ab0b8fe1","f969efddaf409890","8fef4d9e01276f7f","dfc9a9321740fd56","154cf7a88fd8de54","766b3aef36c93507"],"x":54,"y":1419,"w":992,"h":282},{"id":"6d93e88b1e70eb79","type":"inject","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"PUT Typing Indicator","props":[{"p":"url","v":"$env('signal_url') & '/v1/typing-indicator/' & $env('signal_num')","vt":"jsonata"},{"p":"method","v":"PUT","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"recipient\":$env('signal_snd')}","payloadType":"jsonata","x":200,"y":660,"wires":[["a8bf417e2fb1d44c"]]},{"id":"a8bf417e2fb1d44c","type":"http request","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":430,"y":660,"wires":[["399891f08c181bbf"]]},{"id":"399891f08c181bbf","type":"debug","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"Typing Indicator","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":660,"y":660,"wires":[]},{"id":"97005b3edc34119d","type":"comment","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"Turn ON Typing Indicator for Specified Recipient","info":"","x":320,"y":700,"wires":[]},{"id":"44e4482edd7b0bbc","type":"inject","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"DELETE Typing Indicator","props":[{"p":"url","v":"$env('signal_url') & '/v1/typing-indicator/' & $env('signal_num')","vt":"jsonata"},{"p":"method","v":"DELETE","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"recipient\":$env('signal_snd')}","payloadType":"jsonata","x":210,"y":760,"wires":[["d416b6b2783e0d95"]]},{"id":"d416b6b2783e0d95","type":"http request","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":430,"y":760,"wires":[["3c7b6b7dfc073e13"]]},{"id":"3c7b6b7dfc073e13","type":"debug","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"Typing Indicator","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":660,"y":760,"wires":[]},{"id":"f24961571f4ca048","type":"comment","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"Turn OFF Typing Indicator for Specified Recipient","info":"","x":320,"y":800,"wires":[]},{"id":"f9e1c2353e30f3da","type":"inject","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"POST Send a Message","props":[{"p":"url","v":"$env('signal_url') & '/v2/send'","vt":"jsonata"},{"p":"method","v":"POST","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\t   \"number\": $env('signal_num'),\t   \"recipients\":[$env('signal_snd')],\t   \"message\":\"Sending a Test Message.\"\t}","payloadType":"jsonata","x":200,"y":860,"wires":[["01dd4f0ba1caa84b"]]},{"id":"01dd4f0ba1caa84b","type":"http request","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":430,"y":860,"wires":[["f84a642126c6f401"]]},{"id":"f84a642126c6f401","type":"debug","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"Typing Indicator","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":660,"y":860,"wires":[]},{"id":"216864cd48324378","type":"comment","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"Send a Message to the Defined Recipient(s)","info":"","x":310,"y":900,"wires":[]},{"id":"1077d1a6a70caeb1","type":"inject","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"PUT Update Group","props":[{"p":"url","v":"$env('signal_url') & '/v1/groups/' & $env('signal_num') & '/' & $env('signal_grp')","vt":"jsonata"},{"p":"method","v":"PUT","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"description\":\"Update Description HERE\",\"name\":\"Update Name HERE\"}","payloadType":"json","x":950,"y":500,"wires":[["37791c81deae0edb"]]},{"id":"37791c81deae0edb","type":"http request","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":1210,"y":500,"wires":[["46bcf90a0c8c5e14"]]},{"id":"46bcf90a0c8c5e14","type":"debug","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Update Group Name & Description","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1480,"y":500,"wires":[]},{"id":"0444b4fdb1a44883","type":"comment","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Update Group Name and Description.","info":"","x":1050,"y":540,"wires":[]},{"id":"4bf25e1da4c3cf2f","type":"inject","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"DELETE Group","props":[{"p":"url","v":"$env('signal_url') & '/v1/groups/' & $env('signal_num') & '/' & $env('signal_grp')","vt":"jsonata"},{"p":"method","v":"DELETE","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":940,"y":600,"wires":[["080435febec3faa7"]]},{"id":"080435febec3faa7","type":"http request","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":1210,"y":600,"wires":[["3d4d7ad29478f56f"]]},{"id":"3d4d7ad29478f56f","type":"debug","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Delete Group by ID","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1530,"y":600,"wires":[]},{"id":"7463dd958cad9c7d","type":"comment","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Delete Group by ID.","info":"","x":990,"y":640,"wires":[]},{"id":"eacf128896ef1d75","type":"inject","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"POST Add Group Admins","props":[{"p":"url","v":"$env('signal_url') & '/v1/groups/' & $env('signal_num') & '/' & $env('signal_grp') & '/admins'","vt":"jsonata"},{"p":"method","v":"POST","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"admins\":[\"add admins by phone number here\",\"like this --->\",\"+CountryCodeAreaCodePhoneNumber\",\"+12125551234\"]}","payloadType":"json","x":970,"y":700,"wires":[["5ce5f6ac9ccecc3f"]]},{"id":"5ce5f6ac9ccecc3f","type":"http request","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":1210,"y":700,"wires":[["1883c673cc7fd875"]]},{"id":"1883c673cc7fd875","type":"debug","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Add Group Admins","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1530,"y":700,"wires":[]},{"id":"05901559b046735e","type":"comment","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Add Admins to existing Group","info":"","x":1020,"y":740,"wires":[]},{"id":"9fd5cc8da301bb2a","type":"inject","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"DELETE Group Admins","props":[{"p":"url","v":"$env('signal_url') & '/v1/groups/' & $env('signal_num') & '/' & $env('signal_grp') & '/admins'","vt":"jsonata"},{"p":"method","v":"DELETE","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"admins\":[\"delete admins by phone number here\",\"like this --->\",\"+CountryCodeAreaCodePhoneNumber\",\"+12125551234\"]}","payloadType":"json","x":960,"y":800,"wires":[["400e1991256db001"]]},{"id":"400e1991256db001","type":"http request","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":1210,"y":800,"wires":[["578358ebd81506ab"]]},{"id":"578358ebd81506ab","type":"debug","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Delete Group Admins","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1520,"y":800,"wires":[]},{"id":"b314a6dd55b70dfc","type":"comment","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Add Admins to existing Group","info":"","x":1020,"y":840,"wires":[]},{"id":"3f9204a78046e854","type":"inject","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"POST Block Group","props":[{"p":"url","v":"$env('signal_url') & '/v1/groups/' & $env('signal_num') & '/' & $env('signal_grp') & '/block'","vt":"jsonata"},{"p":"method","v":"POST","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":950,"y":900,"wires":[["7108f971c36a609b"]]},{"id":"7108f971c36a609b","type":"http request","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":1210,"y":900,"wires":[["3692f4e607a89fc3"]]},{"id":"3692f4e607a89fc3","type":"debug","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Block Group","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1550,"y":900,"wires":[]},{"id":"33076447e5040d7f","type":"comment","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Block the Specified Group","info":"","x":1010,"y":940,"wires":[]},{"id":"03d90bdba7100ff3","type":"inject","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"POST Join Group","props":[{"p":"url","v":"$env('signal_url') & '/v1/groups/' & $env('signal_num') & '/' & $env('signal_grp') & '/join'","vt":"jsonata"},{"p":"method","v":"POST","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":940,"y":1000,"wires":[["0569fd357eb939ce"]]},{"id":"0569fd357eb939ce","type":"http request","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":1210,"y":1000,"wires":[["3086665b284694cf"]]},{"id":"3086665b284694cf","type":"debug","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Join Group","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1550,"y":1000,"wires":[]},{"id":"64d3c119e5a4bed6","type":"comment","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Join the Specified Group","info":"","x":1010,"y":1040,"wires":[]},{"id":"df6e6efe7336b61d","type":"inject","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"POST Add Group Members","props":[{"p":"url","v":"$env('signal_url') & '/v1/groups/' & $env('signal_num') & '/' & $env('signal_grp') & '/members'","vt":"jsonata"},{"p":"method","v":"POST","vt":"str"},{"p":"payoad","v":"{\"members\":[\"add members by phone number here\",\"like this --->\",\"+CountryCodeAreaCodePhoneNumber\",\"+12125551234\"]}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":980,"y":1100,"wires":[["71592ea3d174d75e"]]},{"id":"71592ea3d174d75e","type":"http request","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":1210,"y":1100,"wires":[["2df2d27a5788fd44"]]},{"id":"2df2d27a5788fd44","type":"debug","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Add Group Members","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1520,"y":1100,"wires":[]},{"id":"a197340e95bff72d","type":"comment","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Add new Members to the Specified Group","info":"","x":1060,"y":1140,"wires":[]},
1 Like

This is Part Two of the Flow
Combine them in order in a json file and import to NodeRed

{"id":"868d717057115bfc","type":"inject","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"DELETE Group Members","props":[{"p":"url","v":"$env('signal_url') & '/v1/groups/' & $env('signal_num') & '/' & $env('signal_grp') & '/members'","vt":"jsonata"},{"p":"method","v":"DELETE","vt":"str"},{"p":"payoad","v":"{\"members\":[\"delete members by phone number here\",\"like this --->\",\"+CountryCodeAreaCodePhoneNumber\",\"+12125551234\"]}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":970,"y":1200,"wires":[["c63177f56c67d4de"]]},{"id":"c63177f56c67d4de","type":"http request","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":1210,"y":1200,"wires":[["68eaded31b51bfc3"]]},{"id":"68eaded31b51bfc3","type":"debug","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Remove Group Members","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1510,"y":1200,"wires":[]},{"id":"426b58641c07dab0","type":"comment","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Remove Members from the Specified Group","info":"","x":1070,"y":1240,"wires":[]},{"id":"45b5f4df745f0df8","type":"inject","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"POST Quit Group","props":[{"p":"url","v":"$env('signal_url') & '/v1/groups/' & $env('signal_num') & '/' & $env('signal_grp') & '/quit'","vt":"jsonata"},{"p":"method","v":"POST","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":940,"y":1300,"wires":[["6d02d61fbfc0fbb6"]]},{"id":"6d02d61fbfc0fbb6","type":"http request","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":1210,"y":1300,"wires":[["2762a409bd366916"]]},{"id":"2762a409bd366916","type":"debug","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Quit Group","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1550,"y":1300,"wires":[]},{"id":"b1cc87736ccc0151","type":"comment","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Quit the Specified Group","info":"","x":1010,"y":1340,"wires":[]},{"id":"2d65fa8550e0938f","type":"inject","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"GET Groups","props":[{"p":"url","v":"$env('signal_url') & '/v1/groups/' & $env('signal_num')","vt":"jsonata"},{"p":"method","v":"GET","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":930,"y":200,"wires":[["7d8a22d94d17f39f"]]},{"id":"7d8a22d94d17f39f","type":"http request","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":1210,"y":200,"wires":[["655ba30a30919e17"]]},{"id":"655ba30a30919e17","type":"debug","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"List All Groups","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1420,"y":200,"wires":[]},{"id":"7277a91a2681e24f","type":"comment","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"List all Signal Groups","info":"","x":1000,"y":240,"wires":[]},{"id":"f03880a97c602c24","type":"inject","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"POST Groups","props":[{"p":"url","v":"$env('signal_url') & '/v1/groups/' & $env('signal_num')","vt":"jsonata"},{"p":"method","v":"POST","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"members\":[\"ADD\",\"NEW\",\"MEMBERS\",\"HERE\",\"FORMATTED AS:\",\"+CountryCodeAreaCodePhoneNumber\",\"+12125551234\"],\"name\":\"Test Group\"}","payloadType":"json","x":930,"y":300,"wires":[["5928816a80a090eb"]]},{"id":"5928816a80a090eb","type":"http request","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":1210,"y":300,"wires":[["bcade1473470f263"]]},{"id":"bcade1473470f263","type":"debug","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Create New Group","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1430,"y":300,"wires":[]},{"id":"cb36c6bc822b38cf","type":"comment","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Create New Group.  Edit POST Group Inject Node msg.data as necesssary.","info":"","x":1160,"y":340,"wires":[]},{"id":"4eb442f87a5a74a3","type":"inject","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"GET Group List","props":[{"p":"url","v":"$env('signal_url') & '/v1/groups/' & $env('signal_num') & '/' & $env('signal_grp')","vt":"jsonata"},{"p":"method","v":"GET","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":940,"y":400,"wires":[["70708a6092ef09b0"]]},{"id":"70708a6092ef09b0","type":"http request","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":1210,"y":400,"wires":[["cc329acbaba3b3a7"]]},{"id":"cc329acbaba3b3a7","type":"debug","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"List Defined Group","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1430,"y":400,"wires":[]},{"id":"bae8df465e5bef69","type":"comment","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"List Group Information","info":"","x":1000,"y":440,"wires":[]},{"id":"17ecccb972234070","type":"debug","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"About","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":690,"y":140,"wires":[]},{"id":"3335a5836a1f1d6f","type":"http request","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":430,"y":140,"wires":[["17ecccb972234070"]]},{"id":"552a23c432b48a2f","type":"inject","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"GET About","props":[{"p":"url","v":"$env('signal_url') & '/v1/about'","vt":"jsonata"},{"p":"method","v":"GET","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":160,"y":140,"wires":[["3335a5836a1f1d6f"]]},{"id":"a06e918627829672","type":"inject","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"GET Account Configuration","props":[{"p":"url","v":"$env('signal_url') & '/v1/configuration/' & $env('signal_num') & '/settings'","vt":"jsonata"},{"p":"method","v":"GET","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":220,"y":240,"wires":[["eece0e5e26bc8f93"]]},{"id":"eece0e5e26bc8f93","type":"http request","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":430,"y":240,"wires":[["e0aae9e41e8b04fe"]]},{"id":"e0aae9e41e8b04fe","type":"debug","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"Account Configuration","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":640,"y":240,"wires":[]},{"id":"80dfeddd3f3a95a7","type":"inject","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"GET Health","props":[{"p":"url","v":"$env('signal_url') & '/v1/health'","vt":"jsonata"},{"p":"method","v":"GET","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":170,"y":440,"wires":[["761ba4aade07aff0"]]},{"id":"761ba4aade07aff0","type":"http request","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":430,"y":440,"wires":[["4d4ba6ef3330ae84"]]},{"id":"4d4ba6ef3330ae84","type":"debug","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"Health Check","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":660,"y":440,"wires":[]},{"id":"95bdf43c41020987","type":"comment","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"General information about the Signal API","info":"","x":280,"y":180,"wires":[]},{"id":"e8b592c436e335b9","type":"comment","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"Account specific settings","info":"","x":230,"y":280,"wires":[]},{"id":"82e969976e44571f","type":"comment","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"Health Check : responds 204 when healthy","info":"","x":280,"y":480,"wires":[]},{"id":"c680452b6921318c","type":"inject","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"GET Accounts","props":[{"p":"url","v":"$env('signal_url') & '/v1/accounts'","vt":"jsonata"},{"p":"method","v":"GET","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":170,"y":340,"wires":[["a55e92518369399f"]]},{"id":"a55e92518369399f","type":"http request","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":430,"y":340,"wires":[["8a7e0e2728dd3cf7"]]},{"id":"8a7e0e2728dd3cf7","type":"debug","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"Accounts","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":680,"y":340,"wires":[]},{"id":"3a0880a3662d0445","type":"comment","z":"3240b1abdd2b9cc0","g":"9960202b1208ef7b","name":"List all accounts linked or registered.","info":"","x":280,"y":380,"wires":[]},{"id":"b2f5dd6e03a136f3","type":"inject","z":"3240b1abdd2b9cc0","g":"44f2778d817fd3a9","name":"GET Identities","props":[{"p":"url","v":"$env('signal_url') & '/v1/identities/' & $env('signal_num')","vt":"jsonata"},{"p":"method","v":"GET","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":190,"y":1200,"wires":[["eb8fe74b94ee0f79"]]},{"id":"eb8fe74b94ee0f79","type":"http request","z":"3240b1abdd2b9cc0","g":"44f2778d817fd3a9","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":450,"y":1200,"wires":[["7a915afc8c35fc67"]]},{"id":"7a915afc8c35fc67","type":"debug","z":"3240b1abdd2b9cc0","g":"44f2778d817fd3a9","name":"Identities","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":660,"y":1200,"wires":[]},{"id":"9bb14c15cb8a65d9","type":"comment","z":"3240b1abdd2b9cc0","g":"44f2778d817fd3a9","name":"List all Identities","info":"","x":240,"y":1240,"wires":[]},{"id":"41b98669873ded1b","type":"inject","z":"3240b1abdd2b9cc0","g":"44f2778d817fd3a9","name":"PUT Trust Identity","props":[{"p":"url","v":"$env('signal_url') & '/v1/identities/' & $env('signal_num') & '/trust/' & $env('signal_snd')","vt":"jsonata"},{"p":"method","v":"PUT","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\t   \"trust_all_known_keys\": false,\t   \"verified_safety_number\": $env('safety_num')\t}","payloadType":"jsonata","x":210,"y":1300,"wires":[["9d90428694ebd6f5"]]},{"id":"9d90428694ebd6f5","type":"http request","z":"3240b1abdd2b9cc0","g":"44f2778d817fd3a9","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":450,"y":1300,"wires":[["ee38b66a74042f61"]]},{"id":"ee38b66a74042f61","type":"debug","z":"3240b1abdd2b9cc0","g":"44f2778d817fd3a9","name":"Trust Identity","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":650,"y":1300,"wires":[]},{"id":"5a8096c460ab3555","type":"comment","z":"3240b1abdd2b9cc0","g":"44f2778d817fd3a9","name":"Trust Specified Identity with Safety Number","info":"","x":330,"y":1340,"wires":[]},{"id":"c8f1cc833c2218a9","type":"comment","z":"3240b1abdd2b9cc0","g":"7f3749c392037095","name":"Search for Specified User","info":"","x":250,"y":1560,"wires":[]},{"id":"ba5d158fce2fd0c4","type":"inject","z":"3240b1abdd2b9cc0","g":"7f3749c392037095","name":"POST Synchronize Contacts","props":[{"p":"url","v":"$env('signal_url') & '/v1/contacts/' & $env('signal_num') & '/sync'","vt":"jsonata"},{"p":"method","v":"POST","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":220,"y":1520,"wires":[["bd54b84bc8341dba"]]},{"id":"bd54b84bc8341dba","type":"http request","z":"3240b1abdd2b9cc0","g":"7f3749c392037095","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":450,"y":1520,"wires":[["4c8bc2f9ab0b8fe1"]]},{"id":"4c8bc2f9ab0b8fe1","type":"debug","z":"3240b1abdd2b9cc0","g":"7f3749c392037095","name":"Synchronize Contacts","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":640,"y":1520,"wires":[]},{"id":"f969efddaf409890","type":"comment","z":"3240b1abdd2b9cc0","g":"7f3749c392037095","name":"Add a New Contact or Update Existing Contact","info":"","x":320,"y":1660,"wires":[]},{"id":"8fef4d9e01276f7f","type":"inject","z":"3240b1abdd2b9cc0","g":"7f3749c392037095","name":"PUT Add New or Update Contact","props":[{"p":"url","v":"$env('signal_url') & '/v1/contacts/' & $env('signal_num')","vt":"jsonata"},{"p":"method","v":"PUT","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\t   \"expiration_in_seconds\": 7200,\t   \"name\": $env('contact_name'),\t   \"recipient\": $env('signal_snd')\t}","payloadType":"jsonata","x":230,"y":1620,"wires":[["dfc9a9321740fd56"]]},{"id":"dfc9a9321740fd56","type":"http request","z":"3240b1abdd2b9cc0","g":"7f3749c392037095","name":"Signal API","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":450,"y":1620,"wires":[["154cf7a88fd8de54"]]},{"id":"154cf7a88fd8de54","type":"debug","z":"3240b1abdd2b9cc0","g":"7f3749c392037095","name":"Update Contacts","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":650,"y":1620,"wires":[]},{"id":"b1bdc6b343aae5ec","type":"comment","z":"3240b1abdd2b9cc0","name":"REQUIRED: Define Global Environmental Variables: \"signal_url\" = \"http://1315902c-signal-messenger:8080\", \"signal_num\" = {{your registered Signal phone number}}","info":"","x":610,"y":60,"wires":[]},{"id":"bec501a8bbdfca40","type":"comment","z":"3240b1abdd2b9cc0","g":"66db6ed8538aa25a","name":"REQUIRED: Define Global Environmental Variable: \"signal_grp\" = {{group.ID}}","info":"","x":1130,"y":140,"wires":[]},{"id":"1c1966db6bdd1151","type":"comment","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"REQUIRED: Define Global Environmental Variable: \"signal_snd\" = {{phone number of recipient}}","info":"","x":430,"y":620,"wires":[]},{"id":"c6dbc0b68361dd92","type":"comment","z":"3240b1abdd2b9cc0","g":"44f2778d817fd3a9","name":"REQUIRED: Define Global Environmental Variable: \"safety_num\" = {{safety number}}","info":"","x":390,"y":1140,"wires":[]},{"id":"766b3aef36c93507","type":"comment","z":"3240b1abdd2b9cc0","g":"7f3749c392037095","name":"REQUIRED: Define Global Environmental Variables: \"signal_snd\" = {{phone number of recipient}}, \"contact_name\" = {{name of your contact}}","info":"","x":550,"y":1460,"wires":[]},{"id":"ab541d059c27634e","type":"websocket in","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"Signal Receive","server":"","client":"c7bcef6ada6d3c7f","x":280,"y":960,"wires":[["acd36385bf216bc3"]]},{"id":"acd36385bf216bc3","type":"debug","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"Signal Messages Received","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":560,"y":960,"wires":[]},{"id":"320c907ae16bd118","type":"comment","z":"3240b1abdd2b9cc0","g":"d09b4bf0ac40a1dc","name":"Open this WebSocket Node and edit the URL to include your Signal Number","info":"","x":430,"y":1020,"wires":[]},{"id":"c7bcef6ada6d3c7f","type":"websocket-client","path":"ws://1315902c-signal-messenger:8080/v1/receive/+yourSignalPhoneNumberHere","tls":"","wholemsg":"true","hb":"0","subprotocol":""}]
1 Like

Hi Lewis, a beginners question… REQUIRED: Define Global Environmental Variables: “signal_url” = “http://1315902c-signal-messenger:8080”, “signal_num” = {{your registered Signal phone number}}… where to define… can i have a sample ?

When in the Node-RED dashboard, click on the hamburger menu in the upper right, then click on Settings.

In the pop-up window there are four stacked tabs on the left side, View, Palette, Keyboard, Environment

Select Environment

Add key value (str) pairs to match what I’ve entered in the comment bubbles.

Start here:

Signal for HA on GitHub

Follow the installation instructions.

Hi Lewis,
yes, thank you
Part 1 is working now.
1.- added in REPOSITORIE: the URL: GitHub - haberda/hassio_addons: hopefully useful hassio addons
then i can see the add-on Signal-Messenger

Hi Lewis,
when i correct you understand,
i set the value in “Environment”
Now how can do a basic test that i received the message?

Hi Lewis,
i add the configuration for notify.signal and tried a test, but i don’t receive again anything :frowning:
Any suggestion for me?

SORRY, i cannot more add new reply. - i reached the limit

Hi Lewis,
thank you very much for your quickly reply.
when you wrote: Use the inject nodes to send yourself a message, and then reply to that message from your phone. → i need to add a new “inject nodes” in CANVAS and configure my phone number OR i need to use a specific “inject node” that already are in CANVAS.
Sorry my questions, today is my first day with Node RED :slight_smile:

Assuming you have successfully registered a phone number with Signal, then you should be able to test everything from my Flow within Node-Red.

When you are in Node-Red, be sure to have the debug window in view (on the right side of the screen, the little bug icon).

Use the inject nodes to send yourself a message, and then reply to that message from your phone.

The debug window/console will log all the messages for sending and receiving, and also show errors if there are any.

1 Like

Lewis - This is great stuff! I just wanted to send a quick thanks for posting.