MacLoggerDX

MacLoggerDX is a fantastic logging application for MacOS.  It has a lot of cool features and we can use some of them to do some fun stuff.  Inside the preferences of MacLoggerDX is a setting under Station called "UDP Broadcast".  Enabling this option will cause the application to send data for radio settings, logging, and spots via UDP to the local broadcast address.  I thought this sounded like something I could put to some kind of use so I had to think of something.  

After a little bit of thought, I decided I wanted to pass this information to my home automation system, Home Assistant.  There are a lot of different ways I could have done this, but bar far the easiest way that I could think of was to use Node-Red.  If you haven't used Home Assistant or Node-Red yet, I highly recommend looking into it if you have any interest in home automation at all.  

I won't go into setting up or programming Home Assistant or Node-Red.  There is just too much to cover here so I will assume you are already familiar with them going forward.  The setup is pretty simple so I'll just go over what I did to set it up.  If anyone has a better way to accomplish this, I would love to know.

The first thing I did was to set up a "UDP in" node set to listen on port 9932, which is the default port for MacLoggerDX.  From there, we need to split the data into three different payloads.  One is for radio settings, one is for spotting, and one is for logging.  For that you can just use a switch node that to check whether the payload contains "Radio", "Spot", or "Log".  From there, you can split each of the new payloads with a comma followed by a space to break it up from one string.  Then, you can use another switch node to select any of the field you want like Band, Mode, Power, Call, TxMhz, etc.  

At this point, you can simply pass 99% of the data directly to home assistant by whatever means you have setup.  The issue is that fields at the beginning or end of the message will have a square bracket or other text as part of the message which we don't want to pass along.  There are probably better ways to do this, but what I did.  If there is data that is at the beginning,  you can use another split node and split it on the message type (Radio: or Report:) to split the beginning of the message containing the info we don't want with the info we do want.  This will split off all the preceding information in the message that we don't care about.  Now we can just use another switch node to select the payload we want.  If there is a square bracket is at the end of the message, it's a little bit easier as we can just use a change node and search for the bracket and replace it with nothing.

I will copy my flow below if anyone is interested in doing something similar, but hopefully this is of use to someone out there.

Node-Red Flow

[{"id":"492e0a22632c979a","type":"udp in","z":"ba4a265d561d9675","name":"MacloggerDX","iface":"","port":"9932","ipv":"udp4","multicast":"false","group":"","datatype":"utf8","x":70,"y":300,"wires":[["188d2bb31b6a02f1"]]},{"id":"21f8ad6882a7aeaf","type":"debug","z":"ba4a265d561d9675","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1160,"y":560,"wires":[]},{"id":"e58e59c8a646de6a","type":"split","z":"ba4a265d561d9675","name":"Split Radio","splt":", ","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":430,"y":60,"wires":[["6fa34b8b43e6ec7e"]]},{"id":"188d2bb31b6a02f1","type":"switch","z":"ba4a265d561d9675","name":"Report Type","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"Radio","vt":"str"},{"t":"cont","v":"Spot","vt":"str"},{"t":"cont","v":"Log","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":250,"y":300,"wires":[["e58e59c8a646de6a"],["9c2abfb85e9b6750"],["c91e795c917958ad"]]},{"id":"9c2abfb85e9b6750","type":"split","z":"ba4a265d561d9675","name":"Split Spot","splt":", ","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":440,"y":300,"wires":[["6e013199ef9b7e40","69e31becace3d1cf"]]},{"id":"c91e795c917958ad","type":"split","z":"ba4a265d561d9675","name":"Split Log","splt":", ","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":440,"y":520,"wires":[["d93b125df81be6f3","8671be0b3dd26fb5"]]},{"id":"6fa34b8b43e6ec7e","type":"switch","z":"ba4a265d561d9675","name":"Which Radio Sensor","property":"$substringBefore(payload,\":\")","propertyType":"jsonata","rules":[{"t":"cont","v":"Band","vt":"str"},{"t":"cont","v":"Mode","vt":"str"},{"t":"cont","v":"Power","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":680,"y":60,"wires":[["b083e6cadbb39fe7"],["aa678417c64f40fc"],["9130f37fb4e6d91c"]]},{"id":"b083e6cadbb39fe7","type":"ha-entity","z":"ba4a265d561d9675","name":"Radio Band","server":"9405c3fe.d0a6c","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Radio Band"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"$substringAfter(payload,\":\")","stateType":"jsonata","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1090,"y":20,"wires":[[]]},{"id":"aa678417c64f40fc","type":"ha-entity","z":"ba4a265d561d9675","name":"Radio Mode","server":"9405c3fe.d0a6c","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Radio Mode"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"$substringAfter(payload,\":\")","stateType":"jsonata","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1090,"y":60,"wires":[[]]},{"id":"6f58f399c21b4bc4","type":"ha-entity","z":"ba4a265d561d9675","name":"Radio Power","server":"9405c3fe.d0a6c","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Radio Power"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"$substring(payload,6,3)","stateType":"jsonata","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1090,"y":100,"wires":[[]]},{"id":"9130f37fb4e6d91c","type":"change","z":"ba4a265d561d9675","name":"","rules":[{"t":"change","p":"payload","pt":"msg","from":"]","fromt":"str","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":900,"y":100,"wires":[["6f58f399c21b4bc4"]]},{"id":"6e013199ef9b7e40","type":"switch","z":"ba4a265d561d9675","name":"Which Spot Sensor","property":"$substringBefore(payload,\":\")","propertyType":"jsonata","rules":[{"t":"cont","v":"Mode","vt":"str"},{"t":"cont","v":"Call","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":670,"y":300,"wires":[["26041c1a3b080b88"],["694cdb1e751a20e3"]]},{"id":"ea6b12a3950c97e5","type":"ha-entity","z":"ba4a265d561d9675","name":"Spot Freq","server":"9405c3fe.d0a6c","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Spot Freq"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"$substringAfter(payload,\":\")","stateType":"jsonata","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":960,"y":240,"wires":[[]]},{"id":"26041c1a3b080b88","type":"ha-entity","z":"ba4a265d561d9675","name":"Spot Mode","server":"9405c3fe.d0a6c","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Spot Mode"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"$substringAfter(payload,\":\")","stateType":"jsonata","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":970,"y":280,"wires":[[]]},{"id":"694cdb1e751a20e3","type":"ha-entity","z":"ba4a265d561d9675","name":"Spot Call","server":"9405c3fe.d0a6c","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Spot Call"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"$substringAfter(payload,\":\")","stateType":"jsonata","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":960,"y":320,"wires":[[]]},{"id":"d93b125df81be6f3","type":"switch","z":"ba4a265d561d9675","name":"Which Log Sensor","property":"$substringBefore(payload,\":\")","propertyType":"jsonata","rules":[{"t":"cont","v":"TxMHz","vt":"str"},{"t":"cont","v":"Mode","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":670,"y":520,"wires":[["de1ecfbd6aa5b2aa"],["a6546439d52f9086"]]},{"id":"de1ecfbd6aa5b2aa","type":"ha-entity","z":"ba4a265d561d9675","name":"Log Freq","server":"9405c3fe.d0a6c","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Log Freq"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"$substringAfter(payload,\":\")","stateType":"jsonata","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":900,"y":500,"wires":[[]]},{"id":"a6546439d52f9086","type":"ha-entity","z":"ba4a265d561d9675","name":"Log Mode","server":"9405c3fe.d0a6c","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Log Mode"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"$substringAfter(payload,\":\")","stateType":"jsonata","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":910,"y":540,"wires":[[]]},{"id":"2a09d15752e56b05","type":"ha-entity","z":"ba4a265d561d9675","name":"Log Call","server":"9405c3fe.d0a6c","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Log Call"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"$substringAfter(payload,\":\")","stateType":"jsonata","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":900,"y":580,"wires":[[]]},{"id":"69e31becace3d1cf","type":"split","z":"ba4a265d561d9675","name":"Split RxMhz","splt":"Report:","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":610,"y":260,"wires":[["ae83dc93e26d87eb"]]},{"id":"ae83dc93e26d87eb","type":"switch","z":"ba4a265d561d9675","name":"Select RxMHz","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"RxMHz","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":780,"y":260,"wires":[["ea6b12a3950c97e5"]]},{"id":"8671be0b3dd26fb5","type":"split","z":"ba4a265d561d9675","name":"Split Call","splt":"Report:","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":600,"y":580,"wires":[["1b3ba8fb46562af7"]]},{"id":"1b3ba8fb46562af7","type":"switch","z":"ba4a265d561d9675","name":"Select Call","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"Call","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":750,"y":580,"wires":[["2a09d15752e56b05"]]},{"id":"9405c3fe.d0a6c","type":"server","name":"Home Assistant","version":4,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m"}]