Lutron Caseta Pico Remotes and Node-Red

I have recently employed the Lutron Pro Hub and have several Pico remotes controlling non-Lutron lights. I have a few of the two switch models, that send a 0 when idle and a 1 and 4 when the top (on) and bottom (off) buttons are pushed respectively. I’m trying to make them dim the lights when held. I’ve figured out how to recognize a “short” and “long” push, but it doesn’t recognize it until the button is released and goes back to zero. That obviously won’t work very well for dimming. Does anyone have any suggestions or examples of a similar flow?

2 Likes

Here’s my flow, but it’s not very elegant and I’m sure there’s a much better better way to do it. It’s dims a preset amount each time it’s pressed.

Here is a subflow that I created for my Pico remotes, which handles various tap/hold combinations for each button, including adjustments while holding the dimmer buttons.

[{"id":"26fa9897.8dc708","type":"subflow","name":"Pico Remote - Lights","info":"","category":"","in":[{"x":30,"y":135,"wires":[{"id":"26e24595.347092"}]}],"out":[],"env":[]},{"id":"26e24595.347092","type":"switch","z":"26fa9897.8dc708","name":"Pico Sensor Switch","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"},{"t":"eq","v":"8","vt":"num"},{"t":"eq","v":"16","vt":"num"},{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"4","vt":"num"},{"t":"eq","v":"2","vt":"num"}],"checkall":"true","repair":false,"outputs":6,"x":195,"y":135,"wires":[["ed76edfe.b85ca","3cb9667a.6bd052"],["94a01109.d92dd"],["94a01109.d92dd"],[],[],[]],"outputLabels":["Idle","Up","Down","On","Off","Action"]},{"id":"94a01109.d92dd","type":"looptimer","z":"26fa9897.8dc708","duration":"1.5","units":"Second","maxloops":"6","maxtimeout":"1","maxtimeoutunits":"Minute","name":"","x":510,"y":120,"wires":[["73b940af.34f05"],["80b174c2.fc8938"]]},{"id":"ed76edfe.b85ca","type":"change","z":"26fa9897.8dc708","name":"Stop Loop","rules":[{"t":"set","p":"payload","pt":"msg","to":"STOP","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":210,"wires":[["94a01109.d92dd"]]},{"id":"73b940af.34f05","type":"function","z":"26fa9897.8dc708","name":"Hold Loop Counter","func":"// Get or create a context for this message\nvar msg_context = context.get(msg._msgid) || {}\n\n// Initialize the hold count if not message context\nif (msg_context.hold_count === undefined) {\n    msg_context.hold_count = 0;\n}\n\n// Update the hold count\nmsg_context.hold_count += 1;\nmsg.hold_count = msg_context.hold_count;\n\n// Save and return hold count\ncontext.set(msg._msgid, msg_context)\nreturn msg;\n","outputs":1,"noerr":0,"x":510,"y":75,"wires":[["41015b9d.8e10c4"]]},{"id":"41015b9d.8e10c4","type":"function","z":"26fa9897.8dc708","name":"service_dimmer_up_down","func":"let dim_step = 50;\nlet initial_brightness = msg.source_light.attributes.brightness || 0;\nvar dim_direction = 1;  // 1=dim_up, -1=dim_down\n\n// Only create payload for dimmer buttons\n// and pass it through the first output\nif (msg.payload != 16 && msg.payload != 8) {\n    return [null, msg];\n}\n\n\n// Payload is 8 for dim up, 16 for dim down\nif (msg.payload == 16) {\n    dim_direction = -1;\n}\n\nvar brightness = initial_brightness + (dim_direction * dim_step * msg.hold_count);\nif (brightness < 1) {\n    brightness = 1;\n}\n\nlet dimmer_service_data = {\n    \"data\" : {\n        \"entity_id\" : msg.target_light,\n        \"brightness\": brightness,\n        \"transition\": 1.00\n    }\n}\nmsg.dimmer_service_data = dimmer_service_data;\n\nmsg.payload = dimmer_service_data;\n\nreturn [msg, null];\n","outputs":2,"noerr":0,"x":825,"y":75,"wires":[["519a3f5a.7684e"],[]]},{"id":"519a3f5a.7684e","type":"api-call-service","z":"26fa9897.8dc708","name":"Dim Light","server":"af006389.170db","version":1,"service_domain":"light","service":"turn_on","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1530,"y":75,"wires":[[]]},{"id":"975e6050.5821e","type":"function","z":"26fa9897.8dc708","name":"Get Button Press Type","func":"// Map of sensor states to button names\nlet buttonMap = {\n    \"0\": \"idle\",\n    \"1\": \"on\",\n    \"2\": \"action\",\n    \"4\": \"off\",\n    \"8\": \"up\",\n    \"16\": \"down\"\n}\n\n//var pico = msg.data.pico || {};\nvar pico = {};\n\n// Identify the pressed button from previous state (before released)\npico.state = msg.data.old_state.state;\npico.button = buttonMap[pico.state.toString()];\n\n// Store number of rapid button taps from timed-counter\npico.tap_count = msg.count;\ndelete msg.count;\n\n// Calculate the hold duration of the last button press\nvar holdStart = new Date(msg.data.old_state.last_changed).getTime();\nvar holdEnd = new Date(msg.data.new_state.last_changed).getTime();\npico.hold_duration = holdEnd - holdStart;\n\n// Save the button press data in the message's pico object\nmsg.pico = pico;\n\n// Move the original message data\nmsg.sensor_data = msg.data\n\n// Replace message data with the target light data to support service calls\nmsg.payload.data  = {\n    \"entity_id\" : msg.target_light\n}\n\n// Output 3: Long Press\nif (pico.hold_duration >= 1000)\n    return [null, null, msg];\n    \n// Output 2: Double Tap\nelse if (pico.tap_count > 1)\n    return [null, msg, null];\n    \n// Output 1: Single Tap\nelse\n    return [msg, null, null];","outputs":3,"noerr":0,"x":520,"y":315,"wires":[["1b4304c0.755883"],["4eecc065.39adc"],["9f9b4370.50841"]],"inputLabels":["Pico Sensor Event"],"outputLabels":["Single Tap","Double Tap","Long Press"]},{"id":"3cb9667a.6bd052","type":"timed-counter","z":"26fa9897.8dc708","name":"Count Taps","timelimit":"350","timeunit":1,"withhold":true,"fixedtimeout":false,"pertopic":false,"x":490,"y":255,"wires":[["975e6050.5821e"]]},{"id":"1b4304c0.755883","type":"switch","z":"26fa9897.8dc708","name":"Button Tapped","property":"pico.button","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"off","vt":"str"},{"t":"eq","v":"up","vt":"str"},{"t":"eq","v":"down","vt":"str"},{"t":"eq","v":"action","vt":"str"}],"checkall":"true","repair":false,"outputs":5,"x":785,"y":240,"wires":[["5e468631.5b51c8"],["7073abb6.0d6b84"],["43ca083b.760358"],["43ca083b.760358"],["e7de0b16.3fc9d8"]],"outputLabels":["On","Off","Up","Down","Action"]},{"id":"4eecc065.39adc","type":"switch","z":"26fa9897.8dc708","name":"Button Double Tapped","property":"pico.button","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"off","vt":"str"},{"t":"eq","v":"up","vt":"str"},{"t":"eq","v":"down","vt":"str"},{"t":"eq","v":"action","vt":"str"}],"checkall":"true","repair":false,"outputs":5,"x":805,"y":390,"wires":[["3cc9a5ab.875c9a","43ca083b.760358"],["937f45c2.1e08f","43ca083b.760358"],[],[],["135a5b3d.df8b35"]],"outputLabels":["On","Off","Up","Down","Action"]},{"id":"9f9b4370.50841","type":"switch","z":"26fa9897.8dc708","name":"Button Long Pressed","property":"pico.button","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"off","vt":"str"},{"t":"eq","v":"up","vt":"str"},{"t":"eq","v":"down","vt":"str"},{"t":"eq","v":"action","vt":"str"}],"checkall":"true","repair":false,"outputs":5,"x":805,"y":540,"wires":[["31073fb7.41b068"],["9bdab28c.fbf96"],[],[],["9b98da6.c7494a8"]],"outputLabels":["On","Off","Up","Down","Action"]},{"id":"80b174c2.fc8938","type":"function","z":"26fa9897.8dc708","name":"Clear Msg Context","func":"// Get or create a context for this message\nvar msg_context = context.get(msg._msgid) || {}\n\n// TODO: Clear this message from the context to prevent memory leak\n\n\nreturn msg;\n","outputs":1,"noerr":0,"x":510,"y":165,"wires":[[]]},{"id":"e7de0b16.3fc9d8","type":"function","z":"26fa9897.8dc708","name":"Action Iterator - Single Tap","func":"// Get or create a context for the remote's scene index\nlet remote_name = msg.topic.split(/\\.(.+)/)[1];      // remove 'sensor' \nlet action_index_context = \"pico_remotes.\" + remote_name + \".action_index_single\";\n\n// Set action index to -1 if context not yet initialized\nvar action_index = context.get(action_index_context);\nif (typeof action_index === \"undefined\") {\n    action_index = -1\n}\n\n// A list of actions/service calls should be part of the msg\nvar actions = msg.service_action_tap_single || [];\n\n// Loop back to the first action if we've advanced too far\nif (action_index >= actions.length - 1) {\n    action_index = 0;\n} else {\n    action_index++;\n}\n\nvar service_payload = actions[action_index];\n\n// Update message details\nmsg[\"action_index\"] = action_index;\nmsg[\"service_payload\"] = service_payload;\n\n// Update context with the remote's action index\ncontext.set(action_index_context, action_index);\n\nmsg[\"sensor_payload\"] = msg.payload;\nmsg.payload = service_payload;\n\nreturn msg;\n","outputs":1,"noerr":0,"x":1110,"y":150,"wires":[["c2f4e603.1b9d18","d7581470.a427d"]]},{"id":"c2f4e603.1b9d18","type":"change","z":"26fa9897.8dc708","name":"Turn Off Both Circadian Switches","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\t   \"domain\": \"switch\",\t   \"service\": \"turn_off\",\t   \"data\": {\t       \"entity_id\": [msg.circadian_switch, msg.circadian_switch & \"_nobrightadj\"]\t   }\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1400,"y":150,"wires":[["d7581470.a427d"]]},{"id":"5e468631.5b51c8","type":"change","z":"26fa9897.8dc708","name":"service_on_tap_single","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_on_tap_single","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1090,"y":180,"wires":[["d7581470.a427d"]]},{"id":"7073abb6.0d6b84","type":"change","z":"26fa9897.8dc708","name":"service_off_tap_single","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_off_tap_single","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1090,"y":210,"wires":[["d7581470.a427d"]]},{"id":"6cd20bba.9d8514","type":"change","z":"26fa9897.8dc708","name":"service_up_tap_single","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_up_tap_single","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1090,"y":240,"wires":[["d7581470.a427d"]]},{"id":"d69fd6e4.dbbbf","type":"change","z":"26fa9897.8dc708","name":"service_down_tap_single","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_down_tap_single","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":270,"wires":[["d7581470.a427d"]]},{"id":"8484ddc2.6bd38","type":"change","z":"26fa9897.8dc708","name":"service_action_tap_single","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_action_tap_single","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":300,"wires":[["d7581470.a427d"]]},{"id":"3cc9a5ab.875c9a","type":"change","z":"26fa9897.8dc708","name":"service_on_tap_double","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_on_tap_double","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":330,"wires":[["d7581470.a427d"]]},{"id":"937f45c2.1e08f","type":"change","z":"26fa9897.8dc708","name":"service_off_tap_double","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_off_tap_double","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":360,"wires":[["d7581470.a427d"]]},{"id":"377e4fc.ed3bf3","type":"change","z":"26fa9897.8dc708","name":"service_up_tap_double","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_up_tap_double","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":390,"wires":[["d7581470.a427d"]]},{"id":"60ed4e1.afa313","type":"change","z":"26fa9897.8dc708","name":"service_down_tap_double","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_down_tap_double","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":420,"wires":[["d7581470.a427d"]]},{"id":"31073fb7.41b068","type":"change","z":"26fa9897.8dc708","name":"service_on_tap_hold","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_on_tap_hold","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1090,"y":480,"wires":[["d7581470.a427d"]]},{"id":"9bdab28c.fbf96","type":"change","z":"26fa9897.8dc708","name":"service_off_tap_hold","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_off_tap_hold","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1090,"y":510,"wires":[["d7581470.a427d"]]},{"id":"8f1e4d50.600a7","type":"change","z":"26fa9897.8dc708","name":"service_up_tap_hold","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_up_tap_hold","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1090,"y":540,"wires":[["d7581470.a427d"]]},{"id":"43071de1.ce27ac","type":"change","z":"26fa9897.8dc708","name":"service_down_tap_hold","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_down_tap_hold","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":570,"wires":[["d7581470.a427d"]]},{"id":"9b98da6.c7494a8","type":"change","z":"26fa9897.8dc708","name":"service_action_tap_hold","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_action_tap_hold","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":600,"wires":[["d7581470.a427d"]]},{"id":"d7581470.a427d","type":"api-call-service","z":"26fa9897.8dc708","name":"Call Service","server":"af006389.170db","version":1,"service_domain":"","service":"","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1525,"y":390,"wires":[[]]},{"id":"135a5b3d.df8b35","type":"change","z":"26fa9897.8dc708","name":"service_action_tap_double","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_action_tap_double","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1110,"y":450,"wires":[["d7581470.a427d"]]},{"id":"71af814a.898a3","type":"change","z":"26fa9897.8dc708","name":"Turn On \"No Brightness\" Circadian Switch","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\t   \"domain\": \"switch\",\t   \"service\": \"turn_on\",\t   \"data\": {\t       \"entity_id\": msg.circadian_switch & \"_nobrightadj\"\t   }\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1670,"y":705,"wires":[["d7581470.a427d"]]},{"id":"2f394085.7128c","type":"api-current-state","z":"26fa9897.8dc708","name":"Get State","server":"af006389.170db","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":1305,"y":705,"wires":[["b48eddb1.46b7e"]]},{"id":"43ca083b.760358","type":"change","z":"26fa9897.8dc708","name":"'Standard' Circiadian Switch","rules":[{"t":"delete","p":"payload","pt":"msg"},{"t":"set","p":"payload.entity_id","pt":"msg","to":"circadian_switch","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1110,"y":705,"wires":[["2f394085.7128c"]]},{"id":"b48eddb1.46b7e","type":"switch","z":"26fa9897.8dc708","name":"Is \"on\"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":1430,"y":705,"wires":[["71af814a.898a3"]]},{"id":"5fde6378.56544c","type":"comment","z":"26fa9897.8dc708","name":"If a brightness was adjusted while circadian is enabled, disable circadian brightess adjustments","info":"","x":1320,"y":675,"wires":[]},{"id":"af006389.170db","type":"server","z":"","name":"Home Assistant"}]

Dimming loop logic is at the top-center of diagram.

4 Likes

If you want to decipher all of the logic, the higher level flow is as follows. When there is a state change on the remote, there is a change node that is contains all of the configuration - mapping different button press types to service calls - before running that common subflow logic that all Picos use.

[{"id":"26fa9897.8dc708","type":"subflow","name":"Pico Remote - Lights","info":"","category":"","in":[{"x":30,"y":135,"wires":[{"id":"26e24595.347092"}]}],"out":[],"env":[]},{"id":"26e24595.347092","type":"switch","z":"26fa9897.8dc708","name":"Pico Sensor Switch","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"},{"t":"eq","v":"8","vt":"num"},{"t":"eq","v":"16","vt":"num"},{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"4","vt":"num"},{"t":"eq","v":"2","vt":"num"}],"checkall":"true","repair":false,"outputs":6,"x":195,"y":135,"wires":[["ed76edfe.b85ca","3cb9667a.6bd052"],["94a01109.d92dd"],["94a01109.d92dd"],[],[],[]],"outputLabels":["Idle","Up","Down","On","Off","Action"]},{"id":"94a01109.d92dd","type":"looptimer","z":"26fa9897.8dc708","duration":"1.5","units":"Second","maxloops":"6","maxtimeout":"1","maxtimeoutunits":"Minute","name":"","x":510,"y":120,"wires":[["73b940af.34f05"],["80b174c2.fc8938"]]},{"id":"ed76edfe.b85ca","type":"change","z":"26fa9897.8dc708","name":"Stop Loop","rules":[{"t":"set","p":"payload","pt":"msg","to":"STOP","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":210,"wires":[["94a01109.d92dd"]]},{"id":"73b940af.34f05","type":"function","z":"26fa9897.8dc708","name":"Hold Loop Counter","func":"// Get or create a context for this message\nvar msg_context = context.get(msg._msgid) || {}\n\n// Initialize the hold count if not message context\nif (msg_context.hold_count === undefined) {\n    msg_context.hold_count = 0;\n}\n\n// Update the hold count\nmsg_context.hold_count += 1;\nmsg.hold_count = msg_context.hold_count;\n\n// Save and return hold count\ncontext.set(msg._msgid, msg_context)\nreturn msg;\n","outputs":1,"noerr":0,"x":510,"y":75,"wires":[["41015b9d.8e10c4"]]},{"id":"41015b9d.8e10c4","type":"function","z":"26fa9897.8dc708","name":"service_dimmer_up_down","func":"let dim_step = 50;\nlet initial_brightness = msg.source_light.attributes.brightness || 0;\nvar dim_direction = 1;  // 1=dim_up, -1=dim_down\n\n// Only create payload for dimmer buttons\n// and pass it through the first output\nif (msg.payload != 16 && msg.payload != 8) {\n    return [null, msg];\n}\n\n\n// Payload is 8 for dim up, 16 for dim down\nif (msg.payload == 16) {\n    dim_direction = -1;\n}\n\nvar brightness = initial_brightness + (dim_direction * dim_step * msg.hold_count);\nif (brightness < 1) {\n    brightness = 1;\n}\n\nlet dimmer_service_data = {\n    \"data\" : {\n        \"entity_id\" : msg.target_light,\n        \"brightness\": brightness,\n        \"transition\": 1.00\n    }\n}\nmsg.dimmer_service_data = dimmer_service_data;\n\nmsg.payload = dimmer_service_data;\n\nreturn [msg, null];\n","outputs":2,"noerr":0,"x":825,"y":75,"wires":[["519a3f5a.7684e"],[]]},{"id":"519a3f5a.7684e","type":"api-call-service","z":"26fa9897.8dc708","name":"Dim Light","server":"af006389.170db","version":1,"service_domain":"light","service":"turn_on","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1530,"y":75,"wires":[[]]},{"id":"975e6050.5821e","type":"function","z":"26fa9897.8dc708","name":"Get Button Press Type","func":"// Map of sensor states to button names\nlet buttonMap = {\n    \"0\": \"idle\",\n    \"1\": \"on\",\n    \"2\": \"action\",\n    \"4\": \"off\",\n    \"8\": \"up\",\n    \"16\": \"down\"\n}\n\n//var pico = msg.data.pico || {};\nvar pico = {};\n\n// Identify the pressed button from previous state (before released)\npico.state = msg.data.old_state.state;\npico.button = buttonMap[pico.state.toString()];\n\n// Store number of rapid button taps from timed-counter\npico.tap_count = msg.count;\ndelete msg.count;\n\n// Calculate the hold duration of the last button press\nvar holdStart = new Date(msg.data.old_state.last_changed).getTime();\nvar holdEnd = new Date(msg.data.new_state.last_changed).getTime();\npico.hold_duration = holdEnd - holdStart;\n\n// Save the button press data in the message's pico object\nmsg.pico = pico;\n\n// Move the original message data\nmsg.sensor_data = msg.data\n\n// Replace message data with the target light data to support service calls\nmsg.payload.data  = {\n    \"entity_id\" : msg.target_light\n}\n\n// Output 3: Long Press\nif (pico.hold_duration >= 1000)\n    return [null, null, msg];\n    \n// Output 2: Double Tap\nelse if (pico.tap_count > 1)\n    return [null, msg, null];\n    \n// Output 1: Single Tap\nelse\n    return [msg, null, null];","outputs":3,"noerr":0,"x":520,"y":315,"wires":[["1b4304c0.755883"],["4eecc065.39adc"],["9f9b4370.50841"]],"inputLabels":["Pico Sensor Event"],"outputLabels":["Single Tap","Double Tap","Long Press"]},{"id":"3cb9667a.6bd052","type":"timed-counter","z":"26fa9897.8dc708","name":"Count Taps","timelimit":"350","timeunit":1,"withhold":true,"fixedtimeout":false,"pertopic":false,"x":490,"y":255,"wires":[["975e6050.5821e"]]},{"id":"1b4304c0.755883","type":"switch","z":"26fa9897.8dc708","name":"Button Tapped","property":"pico.button","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"off","vt":"str"},{"t":"eq","v":"up","vt":"str"},{"t":"eq","v":"down","vt":"str"},{"t":"eq","v":"action","vt":"str"}],"checkall":"true","repair":false,"outputs":5,"x":785,"y":240,"wires":[["5e468631.5b51c8"],["7073abb6.0d6b84"],["43ca083b.760358"],["43ca083b.760358"],["e7de0b16.3fc9d8"]],"outputLabels":["On","Off","Up","Down","Action"]},{"id":"4eecc065.39adc","type":"switch","z":"26fa9897.8dc708","name":"Button Double Tapped","property":"pico.button","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"off","vt":"str"},{"t":"eq","v":"up","vt":"str"},{"t":"eq","v":"down","vt":"str"},{"t":"eq","v":"action","vt":"str"}],"checkall":"true","repair":false,"outputs":5,"x":805,"y":390,"wires":[["3cc9a5ab.875c9a","43ca083b.760358"],["937f45c2.1e08f","43ca083b.760358"],[],[],["135a5b3d.df8b35"]],"outputLabels":["On","Off","Up","Down","Action"]},{"id":"9f9b4370.50841","type":"switch","z":"26fa9897.8dc708","name":"Button Long Pressed","property":"pico.button","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"off","vt":"str"},{"t":"eq","v":"up","vt":"str"},{"t":"eq","v":"down","vt":"str"},{"t":"eq","v":"action","vt":"str"}],"checkall":"true","repair":false,"outputs":5,"x":805,"y":540,"wires":[["31073fb7.41b068"],["9bdab28c.fbf96"],[],[],["9b98da6.c7494a8"]],"outputLabels":["On","Off","Up","Down","Action"]},{"id":"80b174c2.fc8938","type":"function","z":"26fa9897.8dc708","name":"Clear Msg Context","func":"// Get or create a context for this message\nvar msg_context = context.get(msg._msgid) || {}\n\n// TODO: Clear this message from the context to prevent memory leak\n\n\nreturn msg;\n","outputs":1,"noerr":0,"x":510,"y":165,"wires":[[]]},{"id":"e7de0b16.3fc9d8","type":"function","z":"26fa9897.8dc708","name":"Action Iterator - Single Tap","func":"// Get or create a context for the remote's scene index\nlet remote_name = msg.topic.split(/\\.(.+)/)[1];      // remove 'sensor' \nlet action_index_context = \"pico_remotes.\" + remote_name + \".action_index_single\";\n\n// Set action index to -1 if context not yet initialized\nvar action_index = context.get(action_index_context);\nif (typeof action_index === \"undefined\") {\n    action_index = -1\n}\n\n// A list of actions/service calls should be part of the msg\nvar actions = msg.service_action_tap_single || [];\n\n// Loop back to the first action if we've advanced too far\nif (action_index >= actions.length - 1) {\n    action_index = 0;\n} else {\n    action_index++;\n}\n\nvar service_payload = actions[action_index];\n\n// Update message details\nmsg[\"action_index\"] = action_index;\nmsg[\"service_payload\"] = service_payload;\n\n// Update context with the remote's action index\ncontext.set(action_index_context, action_index);\n\nmsg[\"sensor_payload\"] = msg.payload;\nmsg.payload = service_payload;\n\nreturn msg;\n","outputs":1,"noerr":0,"x":1110,"y":150,"wires":[["c2f4e603.1b9d18","d7581470.a427d"]]},{"id":"c2f4e603.1b9d18","type":"change","z":"26fa9897.8dc708","name":"Turn Off Both Circadian Switches","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\t   \"domain\": \"switch\",\t   \"service\": \"turn_off\",\t   \"data\": {\t       \"entity_id\": [msg.circadian_switch, msg.circadian_switch & \"_nobrightadj\"]\t   }\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1400,"y":150,"wires":[["d7581470.a427d"]]},{"id":"5e468631.5b51c8","type":"change","z":"26fa9897.8dc708","name":"service_on_tap_single","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_on_tap_single","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1090,"y":180,"wires":[["d7581470.a427d"]]},{"id":"7073abb6.0d6b84","type":"change","z":"26fa9897.8dc708","name":"service_off_tap_single","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_off_tap_single","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1090,"y":210,"wires":[["d7581470.a427d"]]},{"id":"6cd20bba.9d8514","type":"change","z":"26fa9897.8dc708","name":"service_up_tap_single","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_up_tap_single","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1090,"y":240,"wires":[["d7581470.a427d"]]},{"id":"d69fd6e4.dbbbf","type":"change","z":"26fa9897.8dc708","name":"service_down_tap_single","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_down_tap_single","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":270,"wires":[["d7581470.a427d"]]},{"id":"8484ddc2.6bd38","type":"change","z":"26fa9897.8dc708","name":"service_action_tap_single","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_action_tap_single","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":300,"wires":[["d7581470.a427d"]]},{"id":"3cc9a5ab.875c9a","type":"change","z":"26fa9897.8dc708","name":"service_on_tap_double","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_on_tap_double","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":330,"wires":[["d7581470.a427d"]]},{"id":"937f45c2.1e08f","type":"change","z":"26fa9897.8dc708","name":"service_off_tap_double","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_off_tap_double","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":360,"wires":[["d7581470.a427d"]]},{"id":"377e4fc.ed3bf3","type":"change","z":"26fa9897.8dc708","name":"service_up_tap_double","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_up_tap_double","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":390,"wires":[["d7581470.a427d"]]},{"id":"60ed4e1.afa313","type":"change","z":"26fa9897.8dc708","name":"service_down_tap_double","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_down_tap_double","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":420,"wires":[["d7581470.a427d"]]},{"id":"31073fb7.41b068","type":"change","z":"26fa9897.8dc708","name":"service_on_tap_hold","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_on_tap_hold","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1090,"y":480,"wires":[["d7581470.a427d"]]},{"id":"9bdab28c.fbf96","type":"change","z":"26fa9897.8dc708","name":"service_off_tap_hold","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_off_tap_hold","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1090,"y":510,"wires":[["d7581470.a427d"]]},{"id":"8f1e4d50.600a7","type":"change","z":"26fa9897.8dc708","name":"service_up_tap_hold","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_up_tap_hold","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1090,"y":540,"wires":[["d7581470.a427d"]]},{"id":"43071de1.ce27ac","type":"change","z":"26fa9897.8dc708","name":"service_down_tap_hold","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_down_tap_hold","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":570,"wires":[["d7581470.a427d"]]},{"id":"9b98da6.c7494a8","type":"change","z":"26fa9897.8dc708","name":"service_action_tap_hold","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_action_tap_hold","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1100,"y":600,"wires":[["d7581470.a427d"]]},{"id":"d7581470.a427d","type":"api-call-service","z":"26fa9897.8dc708","name":"Call Service","server":"af006389.170db","version":1,"service_domain":"","service":"","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1525,"y":390,"wires":[[]]},{"id":"135a5b3d.df8b35","type":"change","z":"26fa9897.8dc708","name":"service_action_tap_double","rules":[{"t":"move","p":"payload","pt":"msg","to":"sensor_payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"service_action_tap_double","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1110,"y":450,"wires":[["d7581470.a427d"]]},{"id":"71af814a.898a3","type":"change","z":"26fa9897.8dc708","name":"Turn On \"No Brightness\" Circadian Switch","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\t   \"domain\": \"switch\",\t   \"service\": \"turn_on\",\t   \"data\": {\t       \"entity_id\": msg.circadian_switch & \"_nobrightadj\"\t   }\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1670,"y":705,"wires":[["d7581470.a427d"]]},{"id":"2f394085.7128c","type":"api-current-state","z":"26fa9897.8dc708","name":"Get State","server":"af006389.170db","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":1305,"y":705,"wires":[["b48eddb1.46b7e"]]},{"id":"43ca083b.760358","type":"change","z":"26fa9897.8dc708","name":"'Standard' Circiadian Switch","rules":[{"t":"delete","p":"payload","pt":"msg"},{"t":"set","p":"payload.entity_id","pt":"msg","to":"circadian_switch","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1110,"y":705,"wires":[["2f394085.7128c"]]},{"id":"b48eddb1.46b7e","type":"switch","z":"26fa9897.8dc708","name":"Is \"on\"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":1430,"y":705,"wires":[["71af814a.898a3"]]},{"id":"5fde6378.56544c","type":"comment","z":"26fa9897.8dc708","name":"If a brightness was adjusted while circadian is enabled, disable circadian brightess adjustments","info":"","x":1320,"y":675,"wires":[]},{"id":"5d4606b3.9c246","type":"server-state-changed","z":"e54719d2.18a8f8","name":"","server":"af006389.170db","version":1,"entityidfilter":"sensor.pico_familyroom","entityidfiltertype":"substring","outputinitially":false,"state_type":"num","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"x":210,"y":105,"wires":[["e4a5b448.0a377"]]},{"id":"bb9e87f6.ba4848","type":"change","z":"e54719d2.18a8f8","name":"Configure Flow","rules":[{"t":"set","p":"source_remote_state","pt":"msg","to":"msg.payload","tot":"jsonata"},{"t":"set","p":"source_light","pt":"msg","to":"source_light[0]","tot":"msg"},{"t":"set","p":"target_light","pt":"msg","to":"light.familyroom_ceiling","tot":"str"},{"t":"set","p":"circadian_switch","pt":"msg","to":"switch.circadian_lighting_familyroom","tot":"str"},{"t":"set","p":"service_action_tap_single","pt":"msg","to":"[{\"domain\":\"hue\",\"service\":\"hue_activate_scene\",\"data\":{\"group_name\":\"FamilyRoom Ceiling\",\"scene_name\":\"Bright\"}},{\"domain\":\"hue\",\"service\":\"hue_activate_scene\",\"data\":{\"group_name\":\"FamilyRoom Ceiling\",\"scene_name\":\"Dimmed\"}},{\"domain\":\"hue\",\"service\":\"hue_activate_scene\",\"data\":{\"group_name\":\"FamilyRoom Ceiling\",\"scene_name\":\"Relax\"}}]","tot":"json"},{"t":"set","p":"service_action_tap_double","pt":"msg","to":"{\"domain\":\"switch\",\"service\":\"turn_on\",\"data\":{\"entity_id\":\"switch.circadian_lighting_familyroom\"}}","tot":"json"},{"t":"set","p":"service_on_tap_single","pt":"msg","to":"{\t   \"domain\": \"light\",\t   \"service\": \"turn_on\",\t   \"data\": {\t       \"entity_id\": msg.target_light\t   \t   }\t\t}","tot":"jsonata"},{"t":"set","p":"service_off_tap_single","pt":"msg","to":"{\t   \"domain\": \"light\",\t   \"service\": \"turn_off\",\t   \"data\": {\t       \"entity_id\": msg.target_light\t   }\t}","tot":"jsonata"},{"t":"set","p":"service_on_tap_double","pt":"msg","to":"{\t   \"domain\": \"light\",\t   \"service\": \"turn_on\",\t   \"data\": {\t       \"entity_id\": msg.target_light,\t       \"brightness\": 254\t   }\t}","tot":"jsonata"},{"t":"set","p":"service_off_tap_double","pt":"msg","to":"{\t   \"domain\": \"light\",\t   \"service\": \"turn_on\",\t   \"data\": {\t       \"entity_id\": msg.target_light,\t       \"brightness\": 1\t   }\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":890,"y":105,"wires":[["b0cdcf31.dfb4d"]]},{"id":"e4a5b448.0a377","type":"ha-get-entities","z":"e54719d2.18a8f8","server":"af006389.170db","name":"Get Source: light.familyroom_ceiling","rules":[{"property":"entity_id","logic":"is","value":"light.familyroom_ceiling","valueType":"str"}],"output_type":"array","output_empty_results":false,"output_location_type":"msg","output_location":"source_light","output_results_count":1,"x":615,"y":105,"wires":[["bb9e87f6.ba4848"]]},{"id":"b0cdcf31.dfb4d","type":"subflow:26fa9897.8dc708","z":"e54719d2.18a8f8","name":"Pico Remote - Lights","env":[],"x":1120,"y":105,"wires":[]},{"id":"af006389.170db","type":"server","z":"","name":"Home Assistant"}]
3 Likes

Oh wow! Now that is impressive. That’s a bit to chew on, but I really appreciate you posting that.

What do you use double taps for?

Double-tap on for max brightness, double-tap off for min brightness (not off).

1 Like

Seems that the pico has different button press logic for up and down; double-tapping those takes longer than double-tapping on, off, and action.

Thanks for sharing, finally got dimming via pico remote. And learned about using subflows.

One question, when you dim up or down does is dim smooth? Mine always dims two steps up or down with a single press.

It dims smoothly for me. A single press, as long as you don’t hold it down, should only increment a single step.

Okay, I was referring to holding down the the button to dim.

Got it. That is how it is designed. When holding down, it sends a sequence of brightness changing events. You can tweak the frequency of the loop and the transition time for each brightness step if you want to.

I will look into that, I have the dimming subflow working across 8 picos working with zigbee, hue and lifx lights.

@MizterB love what you did with the Pico set-up. I would love to use your flow in my set-up. Not being a node-red expert yet I see your higher-level flow and the subflow. Is there a pico complete flow or do I have to grab each one you posted in order to duplicate your config in my set-up?v Do I need to link the two flows together? Thanks for sharing and the help!

Yes, you would need both flows - the sub flow is a common button handling component used by the other flow, which handles the mapping of different remotes to different lights and customized button pressing behaviors.

For what it’s worth, I am no longer using node red for my Pico automations. I have converted to native HA automations. The following automation raises a ‘pico_buttonpress’ event for tap, doubletap, and hold events, which can then be consumed by other automations.

  automation:
    ################################################################################
    # AUTOMATION: pico_buttonpress_event 
    # This a common handler for any Pico button press, including lights and fans
    # which raises a custom 'pico_buttonpress' event containing:
    # entity_id: Pico remote
    # button_pressed: on|off|up|down|action
    # press_type: tap|doubletap|hold
    ################################################################################
    - alias: pico_buttonpress_event
      description: "Raise an event when a Pico remote button is pressed"
      mode: single
      # Trigger this when the remote state changes from 'idle'
      trigger:
        platform: event
        event_type: state_changed
      condition: "{{ trigger.event.data.entity_id in states['variable.pico_remotes'].attributes|list
                      and trigger.event.data.old_state.state|int == 0 
                      and trigger.event.data.new_state.state|int != 0 }}"
      action:
        - variables:
            hold_ms: 1000
            tap_ms: 250
            pico_id: "{{ trigger.event.data.entity_id }}"
            button_id: "{{ states(pico_id) }}"
            button_name: >
              {% if button_id|int == 1 %}
                on
              {% elif button_id|int == 2 %}
                action
              {% elif button_id|int == 4 %}
                off
              {% elif button_id|int == 8 %}
                up
              {% elif button_id|int == 16 %}
                down
              {% endif %}
            button_start: "{{ as_timestamp(now()) }}"
        # Wait for the button to be released
        # While pressed, trigger the 'hold' action every 'hold_ms' millesconds
        # Don't iterate more than 10 times if the sensor gets 'stuck' during a long hold
        - repeat:
            until: "{{ is_state(pico_id, '0') or repeat.index >= 10 }}"
            sequence:
              - wait_template: "{{ states(pico_id) == '0' }}"
                timeout:
                  milliseconds: "{{ hold_ms }}"
              - condition: template
                value_template: "{{ (((as_timestamp(now()) - button_start|float)*1000)|int) >= hold_ms }}"
              # Hold actions
              - service: system_log.write
                data:
                  message: "{{ pico_id }} - Holding button '{{ button_name }}'"
                  logger: pico_buttonpress
                  level: debug
              - event: pico_buttonpress
                event_data: 
                  entity_id: "{{ pico_id }}"
                  button_pressed: "{{ button_name }}"
                  press_type: hold
        # If we did not hold, then continue processing as a tap
        - condition: template
          value_template: "{{ (((as_timestamp(now()) - button_start|float)*1000)|int) < hold_ms }}"
        # Wait to see if we double tap
        - wait_template: "{{ states(pico_id) == button_id|string }}"
          timeout:
            milliseconds: "{{ tap_ms }}"
        - choose:
            # Double tap actions
            - conditions: "{{ wait.completed }}"
              sequence:
                - service: system_log.write
                  data:
                    message: "{{ pico_id }} - Double tap of '{{ button_name }}'"
                    logger: pico_buttonpress
                    level: debug
                - event: pico_buttonpress
                  event_data: 
                    entity_id: "{{ pico_id }}"
                    button_pressed: "{{ button_name }}"
                    press_type: doubletap
            # Single tap actions
            - conditions: "{{ not wait.completed }}"
              sequence:
                - service: system_log.write
                  data:
                    message: "{{ pico_id }} - Single tap of '{{ button_name }}'"
                    logger: pico_buttonpress
                    level: debug
                - event: pico_buttonpress
                  event_data: 
                    entity_id: "{{ pico_id }}"
                    button_pressed: "{{ button_name }}"
                    press_type: tap
1 Like

I should note that in the my automation, the condition is looking up remote names from the variable custom component. If you were to use it , the condition would need to be updated with the names of your own Pico sensors, something like:

      condition: "{{ trigger.event.data.entity_id in ['sensor.pico_remote_1', 'sensor.pico_remote_2', 'sensor.pico_remote_3']
                      and trigger.event.data.old_state.state|int == 0 
                      and trigger.event.data.new_state.state|int != 0 }}"
1 Like

Nice I was liking the Node-Red as it was visual and know that more native is always preferred so I really appreciate the assistance with the YAML. I figured to make up a file/list with the remote names and that was what your variable.pico_remotes was pointing to. Then I use the event data to make for example a hue light automation link to the events to dim or turn on or off?

Yes, that’s correct

1 Like

This is working great! did you ever solution something for the “is circadian switch enabled?” and if so disable it. Thinking I can add a condition as part of the automation but I like the simplicity you created with a master Pico event system and didn’t want to re-invent the wheel.

I moved from the Circadian component to Adaptive Lighting, which will be finding its way into HA Core soon. It has logic that will detect when a light was manually changed, and will stop making adjustments until the light has been turned off.

But you can create other automations that listen for pico_buttonpress events to further customize the behavior. For example, I have set up a double-click of the action button to remove the manual control that I mentioned above, and re-apply the adaptive lighting.

@MizterB Any chance you could share the automation you made that takes the double-click of the action switch to remove the manual control and re-apply the adaptive lighting? I gave the automation process a go and have it built out but unable to parse the event for some reason so thinking an example would be super helpful. Thanks again for all the help