Extracting a value from a http request

I am trying to extract a value (string) obtained by a http request. This is the payload I am receiving (partially)

<?xml version="1.0" ?>
<command_result>
<param name="protocol_version" value="6"/>
<param name="phv_md5" value="D41D8CD98F00B204E9800998ECF8427E"/>
<param name="android_app_active" value="0"/>
<param name="android_md5" value="8607D73529871E25EB08F15E8B88BDF8"/>
<param name="player_state" value="navigator"/>
<param name="playback_volume" value="80"/>
<param name="playback_mute" value="0"/>

I am trying to extract the player state (that will then show me how to extract other values I might need)

If the XML string is in msg.payload, first use an "xml" node to convert XML to a JavaScript object.

Then in a function node:

let params = msg.payload.command_result.param;

let playerState = params.find(p => p.$.name === "player_state").$.value;

msg.payload = playerState;
return msg;
1 Like

That works well. But I am now trying to expand the function node to extract 2 values, and send them to 2 different outputs. One for player state, the other for playback state.
I get an error from the function node: TypeError: Cannot read properties of undefined (reading '$')
Ideally I wanted the output as a object, and in payload. If thats not possible it could be in payload.status
This is my function node

let params = msg.payload.command_result.param;

let playerState = params.find(p => p.$.name === "player_state").$.value;
let playbackState = params.find(p => p.$.name === "playback_state").$.value;

var msg1 = { payload: {status: playerState }};
var msg2 = { payload: {status: playbackState }};
return [msg1,msg2]

The error you're getting means that
params.find(p => p.$.name === "player_state")
or
params.find(p => p.$.name === "playback_state")
is returning undefined — in other words, it didn't find a matching element, and then you're trying to access undefined.$.value.

I assume you did insert an XML node in your NR flow before the function node?

Possible steps to tryout...

You need to:

  1. Ensure the .find(...) call actually finds an element.
  2. Add checks before accessing properties.

Try this JS in the function node.

let params = msg.payload.command_result.param;

// Find player_state and playback_state objects safely
let playerStateObj = params.find(p => p.$ && p.$.name === "player_state");
let playbackStateObj = params.find(p => p.$ && p.$.name === "playback_state");

// Extract values safely
let playerState = playerStateObj?.$?.value || "unknown";
let playbackState = playbackStateObj?.$?.value || "unknown";

var msg1 = { payload: { status: playerState }};
var msg2 = { payload: { status: playbackState }};

return [msg1, msg2];

It would help if you can share the NR flow you have created and a sample XML string.

Using your demo data from post 1, there is no playback_state so without error checking or error handling, you will see that.

If I add that entry into the test data, it works with this:

const param = msg.payload.command_result.param
const player_state = param?.find(e => e.$.name === "player_state")
const playback_state = param?.find(e => e.$.name === "playback_state")

if (!player_state || !player_state.$) {
    throw new Error('player_state not found')
}
if (!playback_state || !playback_state.$) {
    throw new Error('playback_state not found')
}

const msg1 = { topic: "player", payload: { status:  player_state.$.value }};
const msg2 = { topic: "playback", payload: { status: playback_state.$.value }};

return [msg1, msg2];

Test flow

[{"id":"4ad53da770f3dd0b","type":"group","z":"7a7a72bd5ef89e06","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["ed635d75dbfbadce","07412dcdd28bea9f","5c297e6faa3bf049","89c2bff228087709","e1a5554947e128b7","06c46dbadab39a09","ed96549876a942c7","9cb41e9bf2af8433","5b60ae43c433be62","6212f5a283e0a2d6","183feac69cb0b228"],"x":514,"y":119,"w":732,"h":322},{"id":"ed635d75dbfbadce","type":"inject","z":"7a7a72bd5ef89e06","g":"4ad53da770f3dd0b","name":"good data","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":620,"y":160,"wires":[["07412dcdd28bea9f"]]},{"id":"07412dcdd28bea9f","type":"template","z":"7a7a72bd5ef89e06","g":"4ad53da770f3dd0b","name":"test data","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"<?xml version=\"1.0\" ?>\n<command_result>\n    <param name=\"protocol_version\" value=\"6\" />\n    <param name=\"phv_md5\" value=\"D41D8CD98F00B204E9800998ECF8427E\" />\n    <param name=\"android_app_active\" value=\"0\" />\n    <param name=\"android_md5\" value=\"8607D73529871E25EB08F15E8B88BDF8\" />\n    <param name=\"player_state\" value=\"navigator\" />\n    <param name=\"playback_state\" value=\"paused\" />\n    <param name=\"playback_volume\" value=\"80\" />\n    <param name=\"playback_mute\" value=\"0\" />\n</command_result>","output":"str","x":770,"y":160,"wires":[["5c297e6faa3bf049"]]},{"id":"5c297e6faa3bf049","type":"xml","z":"7a7a72bd5ef89e06","g":"4ad53da770f3dd0b","name":"","property":"payload","attr":"","chr":"","x":950,"y":160,"wires":[["89c2bff228087709","e1a5554947e128b7"]]},{"id":"89c2bff228087709","type":"debug","z":"7a7a72bd5ef89e06","g":"4ad53da770f3dd0b","name":"debug 1","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1140,"y":160,"wires":[]},{"id":"e1a5554947e128b7","type":"function","z":"7a7a72bd5ef89e06","g":"4ad53da770f3dd0b","name":"get player and playback state","func":"const param = msg.payload.command_result.param\nconst player_state = param?.find(e => e.$.name === \"player_state\")\nconst playback_state = param?.find(e => e.$.name === \"playback_state\")\n\nif (!player_state || !player_state.$) {\n    throw new Error('player_state not found')\n}\nif (!playback_state || !playback_state.$) {\n    throw new Error('playback_state not found')\n}\n\nconst msg1 = { topic: \"player\", payload: { status:  player_state.$.value }};\nconst msg2 = { topic: \"playback\", payload: { status: playback_state.$.value }};\n\nreturn [msg1, msg2];","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":920,"y":280,"wires":[["06c46dbadab39a09"],["183feac69cb0b228"]]},{"id":"06c46dbadab39a09","type":"debug","z":"7a7a72bd5ef89e06","g":"4ad53da770f3dd0b","name":"player","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1130,"y":240,"wires":[]},{"id":"ed96549876a942c7","type":"inject","z":"7a7a72bd5ef89e06","g":"4ad53da770f3dd0b","name":"bad data","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":620,"y":200,"wires":[["9cb41e9bf2af8433"]]},{"id":"9cb41e9bf2af8433","type":"template","z":"7a7a72bd5ef89e06","g":"4ad53da770f3dd0b","name":"test data","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"<?xml version=\"1.0\" ?>\n<command_result>\n\n</command_result>","output":"str","x":770,"y":200,"wires":[["5c297e6faa3bf049"]]},{"id":"5b60ae43c433be62","type":"catch","z":"7a7a72bd5ef89e06","g":"4ad53da770f3dd0b","name":"","scope":"group","uncaught":false,"x":630,"y":400,"wires":[["6212f5a283e0a2d6"]]},{"id":"6212f5a283e0a2d6","type":"debug","z":"7a7a72bd5ef89e06","g":"4ad53da770f3dd0b","name":"error","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1130,"y":400,"wires":[]},{"id":"183feac69cb0b228","type":"debug","z":"7a7a72bd5ef89e06","g":"4ad53da770f3dd0b","name":"playback","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1140,"y":320,"wires":[]}]
1 Like

I am not getting errors now with the updated function. I think it might be throwing a error when the player is on standby, as then there is no playback state.

This is a sample of the xml when the player is on standby

<?xml version="1.0" ?>
<command_result>
<param name="protocol_version" value="6"/>
<param name="phv_md5" value="D41D8CD98F00B204E9800998ECF8427E"/>
<param name="android_app_active" value="0"/>
<param name="android_md5" value="8607D73529871E25EB08F15E8B88BDF8"/>
<param name="player_state" value="navigator"/>
<param name="playback_volume" value="80"/>
<param name="playback_mute" value="0"/>
<param name="md5" value="F4BEE7914810BB1A60A53F349AFC8076"/>
<param name="product_id" value="tv188b"/>
<param name="serial_number" value="***"/>
<param name="firmware_version" value="250622_1149_r22"/>
<param name="commercial_serial_number" value="***"/>
<param name="app_version" value="1.0.1-13-250622_1149"/>
<param name="product_name" value="Pro 8K Plus"/>
</command_result>

This is one when playing

<param name="protocol_version" value="6"/>
<param name="phv_md5" value="D41D8CD98F00B204E9800998ECF8427E"/>
<param name="android_app_active" value="0"/>
<param name="android_md5" value="8607D73529871E25EB08F15E8B88BDF8"/>
<param name="player_state" value="file_playback"/>
<param name="playback_state" value="playing"/>
<param name="previous_playback_state" value="buffering"/>
<param name="last_playback_event" value="no_event"/>
<param name="playback_url" value="/tmp/mnt/smb/2/Videos/Unbroken (2014)/Unbroken-(2014)-1080p-Atmos-8bit.mkv"/>
<param name="playback_speed" value="256"/>
<param name="playback_duration" value="8248"/>
<param name="playback_position" value="497"/>
<param name="playback_position_version" value="134"/>
<param name="playback_repeat" value="0"/>
<param name="playback_shuffle" value="0"/>
<param name="playback_current_bitrate" value="28061000"/>
<param name="playback_is_buffering" value="0"/>
<param name="playback_volume" value="80"/>
<param name="playback_mute" value="0"/>
<param name="playback_video_width" value="1920"/>
<param name="playback_video_height" value="1080"/>
<param name="audio_track" value="0"/>
<param name="subtitles_track" value="-1"/>
<param name="playback_window_fullscreen" value="0"/>
<param name="playback_window_rect_x" value="0"/>
<param name="playback_window_rect_y" value="0"/>
<param name="playback_window_rect_width" value="0"/>
<param name="playback_window_rect_height" value="0"/>
<param name="playback_clip_rect_x" value="0"/>
<param name="playback_clip_rect_y" value="0"/>
<param name="playback_clip_rect_width" value="0"/>
<param name="playback_clip_rect_height" value="0"/>
<param name="playback_video_source_rect_x" value="0"/>
<param name="playback_video_source_rect_y" value="0"/>
<param name="playback_video_source_rect_width" value="0"/>
<param name="playback_video_source_rect_height" value="0"/>
<param name="osd_width" value="0"/>
<param name="osd_height" value="0"/>
<param name="video_enabled" value="0"/>
<param name="video_on_top" value="0"/>
<param name="video_zoom" value="normal"/>
<param name="is_video" value="1"/>
<param name="pause_is_available" value="0"/>
<param name="teletext_available" value="0"/>
<param name="teletext_enabled" value="0"/>
<param name="teletext_mix_mode" value="0"/>
<param name="teletext_page_number" value="0"/>
<param name="scrambling_detected" value="0"/>
<param name="hangup_watchdog_activations" value="0"/>
<param name="hls_first_sequence" value="0"/>
<param name="segment_length" value="0"/>
<param name="item_id" value="0"/>
<param name="audio_track.0.lang" value="eng"/>
<param name="audio_track.0.pid" value="1"/>
<param name="audio_track.0.codec" value="TrueHD"/>
<param name="audio_track.0.type" value="normal"/>
<param name="subtitles_track.0.lang" value="eng"/>
<param name="subtitles_track.0.pid" value="2"/>
<param name="subtitles_track.0.codec" value="PGS"/>
<param name="subtitles_track.0.type" value="normal"/>
<param name="subtitles_track.0.offset_ms" value="0"/>
<param name="subtitles_track.1.lang" value="fre"/>
<param name="subtitles_track.1.pid" value="3"/>
<param name="subtitles_track.1.codec" value="PGS"/>
<param name="subtitles_track.1.type" value="normal"/>
<param name="subtitles_track.1.offset_ms" value="0"/>
<param name="pltv_enabled" value="0"/>
<param name="playback_caption" value="Unbroken (1 of 20)"/>
<param name="playback_extra_caption" value="Chapter 01"/>
<param name="md5" value="9E41BD80B32849C6E536C5A3A65D4A8F"/>
<param name="product_id" value="tv188b"/>
<param name="serial_number" value="***"/>
<param name="firmware_version" value="250622_1149_r22"/>
<param name="commercial_serial_number" value="***"/>
<param name="app_version" value="1.0.1-13-250622_1149"/>
<param name="product_name" value="Pro 8K Plus"/>

This is my current flow. The change node for the player state and following nodes should really be processed in the function node too, but not sure yet of how to do that

[
    {
        "id": "0ef1f12f95a3d503",
        "type": "http request",
        "z": "51ebdd733328bee0",
        "name": "",
        "method": "GET",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "http://192.168.0.177/cgi-bin/do?cmd=status",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 270,
        "y": 4000,
        "wires": [
            [
                "e873c1cbc9d093f5"
            ]
        ]
    },
    {
        "id": "8a1213070c83837a",
        "type": "inject",
        "z": "51ebdd733328bee0",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 100,
        "y": 4000,
        "wires": [
            [
                "0ef1f12f95a3d503"
            ]
        ]
    },
    {
        "id": "63813081fdd613b9",
        "type": "debug",
        "z": "51ebdd733328bee0",
        "name": "debug 180",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 890,
        "y": 4000,
        "wires": []
    },
    {
        "id": "e873c1cbc9d093f5",
        "type": "xml",
        "z": "51ebdd733328bee0",
        "name": "",
        "property": "payload",
        "attr": "",
        "chr": "",
        "x": 430,
        "y": 4000,
        "wires": [
            [
                "d4e24881c6f41e4a"
            ]
        ]
    },
    {
        "id": "d4e24881c6f41e4a",
        "type": "function",
        "z": "51ebdd733328bee0",
        "name": "function 33",
        "func": "let params = msg.payload.command_result.param;\n\n// Find player_state and playback_state objects safely\nlet playerStateObj = params.find(p => p.$ && p.$.name === \"player_state\");\nlet playbackStateObj = params.find(p => p.$ && p.$.name === \"playback_state\");\n\n// Extract values safely\nlet playerState = playerStateObj?.$?.value || \"unknown\";\nlet playbackState = playbackStateObj?.$?.value || \"unknown\";\n\nvar msg1 = { payload: { status: playerState } };\nvar msg2 = { payload: { status: playbackState } };\n\nreturn [msg1, msg2];\n",
        "outputs": 2,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 190,
        "y": 4200,
        "wires": [
            [
                "63813081fdd613b9",
                "9e084cb49ada6936",
                "af5cc1acf96817f0"
            ],
            [
                "701b0538133c89d3"
            ]
        ]
    },
    {
        "id": "9e084cb49ada6936",
        "type": "change",
        "z": "51ebdd733328bee0",
        "name": "update Dune Player State",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "update",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "payload.value",
                "pt": "msg",
                "to": "payload.value",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 230,
        "y": 4100,
        "wires": [
            []
        ]
    },
    {
        "id": "4596367cf960dbef",
        "type": "hs-device",
        "z": "51ebdd733328bee0",
        "name": "AV Lounge Dune Player State",
        "device": "4461",
        "server": "e2626888dadf1c4f",
        "feature": 0,
        "reportonstartup": false,
        "x": 850,
        "y": 4200,
        "wires": [
            []
        ]
    },
    {
        "id": "701b0538133c89d3",
        "type": "change",
        "z": "51ebdd733328bee0",
        "name": "update Dune Playback State",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "update",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "payload.value",
                "pt": "msg",
                "to": "payload.value",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 240,
        "y": 4320,
        "wires": [
            [
                "cef5da6143b81564"
            ]
        ]
    },
    {
        "id": "cef5da6143b81564",
        "type": "hs-device",
        "z": "51ebdd733328bee0",
        "name": "AV Lounge Dune Playback State",
        "device": "4459",
        "server": "e2626888dadf1c4f",
        "feature": 0,
        "reportonstartup": false,
        "x": 550,
        "y": 4320,
        "wires": [
            []
        ]
    },
    {
        "id": "c069fe5f0c2da476",
        "type": "debug",
        "z": "51ebdd733328bee0",
        "name": "debug 182",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 890,
        "y": 4040,
        "wires": []
    },
    {
        "id": "af5cc1acf96817f0",
        "type": "switch",
        "z": "51ebdd733328bee0",
        "name": "",
        "property": "payload.status",
        "propertyType": "msg",
        "rules": [
            {
                "t": "cont",
                "v": "standby",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "navigator",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "file_playback",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 3,
        "x": 430,
        "y": 4180,
        "wires": [
            [
                "1d9791817b0b3d3a"
            ],
            [
                "e8cac50b776cbef1"
            ],
            [
                "c34cb02cf6c4a18f"
            ]
        ]
    },
    {
        "id": "1d9791817b0b3d3a",
        "type": "change",
        "z": "51ebdd733328bee0",
        "name": "Standby",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "{\"value\":\"0\"}",
                "tot": "json"
            },
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "control",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 600,
        "y": 4160,
        "wires": [
            [
                "4596367cf960dbef",
                "c069fe5f0c2da476"
            ]
        ]
    },
    {
        "id": "e8cac50b776cbef1",
        "type": "change",
        "z": "51ebdd733328bee0",
        "name": "Navigator",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "{\"value\":\"1\"}",
                "tot": "json"
            },
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "control",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 600,
        "y": 4200,
        "wires": [
            [
                "4596367cf960dbef"
            ]
        ]
    },
    {
        "id": "c34cb02cf6c4a18f",
        "type": "change",
        "z": "51ebdd733328bee0",
        "name": "File playback",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "{\"value\":\"2\"}",
                "tot": "json"
            },
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "control",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 610,
        "y": 4240,
        "wires": [
            [
                "4596367cf960dbef"
            ]
        ]
    },
    {
        "id": "e2626888dadf1c4f",
        "type": "hs-server",
        "name": "new HS4",
        "host": "192.168.0.7",
        "port": "81"
    }
]

Here's a quickly cleaned-up and merged version of the last NR flow you posted.

Key changes...

  • Merged multiple change nodes into a single function
  • Combined player state mapping into one logic block
  • Output messages include proper topic and payload.value formatting for HomeSeer
  • Optional: keeps a single debug for clarity
[{"id":"ebf08de78ddb1c68","type":"tab","label":"Flow 14","disabled":false,"info":"","env":[]},{"id":"inject_get_status","type":"inject","z":"ebf08de78ddb1c68","name":"Trigger","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":170,"y":260,"wires":[["http_get_status"]]},{"id":"http_get_status","type":"http request","z":"ebf08de78ddb1c68","name":"GET Dune Status","method":"GET","ret":"txt","paytoqs":"ignore","url":"http://192.168.0.177/cgi-bin/do?cmd=status","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":350,"y":260,"wires":[["xml_parse"]]},{"id":"xml_parse","type":"xml","z":"ebf08de78ddb1c68","name":"Parse XML","property":"payload","attr":"","chr":"","x":550,"y":260,"wires":[["extract_states"]]},{"id":"extract_states","type":"function","z":"ebf08de78ddb1c68","name":"Extract States","func":"// Extract from XML\nlet params = msg.payload.command_result.param;\n\nlet playerStateObj = params.find(p => p.$?.name === \"player_state\");\nlet playbackStateObj = params.find(p => p.$?.name === \"playback_state\");\n\nlet playerState = playerStateObj?.$?.value || \"unknown\";\nlet playbackState = playbackStateObj?.$?.value || \"unknown\";\n\nreturn [\n    { payload: { value: playerState }, topic: \"update\", status: playerState },\n    { payload: { value: playbackState }, topic: \"update\" }\n];","outputs":2,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":740,"y":260,"wires":[["map_player_state","debug_output"],["hs_playback_state"]]},{"id":"map_player_state","type":"function","z":"ebf08de78ddb1c68","name":"Map Player State","func":"let state = msg.status;\nlet value;\n\nif (state.includes(\"standby\")) {\n    value = \"0\";\n} else if (state.includes(\"navigator\")) {\n    value = \"1\";\n} else if (state.includes(\"file_playback\")) {\n    value = \"2\";\n} else {\n    return null;\n}\n\nmsg.payload = { value };\nmsg.topic = \"control\";\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":970,"y":180,"wires":[["hs_player_state"]]},{"id":"hs_player_state","type":"hs-device","z":"ebf08de78ddb1c68","name":"AV Lounge Dune Player State","device":"4461","server":"hs4_server","feature":0,"reportonstartup":false,"x":1190,"y":180,"wires":[]},{"id":"hs_playback_state","type":"hs-device","z":"ebf08de78ddb1c68","name":"AV Lounge Dune Playback State","device":"4459","server":"hs4_server","feature":0,"reportonstartup":false,"x":970,"y":300,"wires":[]},{"id":"debug_output","type":"debug","z":"ebf08de78ddb1c68","name":"Debug Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":960,"y":240,"wires":[]}]

Note: I haven't got the HomeSeer (hs) nodes, so they are showing as 'unknown'.

Yes that works perfectly now. How would I change the function node 'extract states', if I only wanted a output if playerstate or playbck state changes ? The reason is I want to change my lights, but do not want to send a command if the lights are already set to that mode

I have found a solution to only output when there is a change. Thanks all for the help, much appreciated !

To only output from the extract_states function node if player_state or playback_state has changed, you can store the previous values in context and compare them with the current ones. If neither has changed, return null.

Here’s the modified extract_states function with that logic:

let params = msg.payload.command_result.param;

let playerStateObj = params.find(p => p.$?.name === "player_state");
let playbackStateObj = params.find(p => p.$?.name === "playback_state");

let playerState = playerStateObj?.$?.value || "unknown";
let playbackState = playbackStateObj?.$?.value || "unknown";

// Get previous states from context
let prevPlayerState = context.get("playerState");
let prevPlaybackState = context.get("playbackState");

// Check if either value has changed
let changedPlayer = playerState !== prevPlayerState;
let changedPlayback = playbackState !== prevPlaybackState;

// Store current states for next time
context.set("playerState", playerState);
context.set("playbackState", playbackState);

// Only output if something changed
if (changedPlayer || changedPlayback) {
    return [
        changedPlayer ? { payload: { value: playerState }, topic: "update", status: playerState } : null,
        changedPlayback ? { payload: { value: playbackState }, topic: "update" } : null
    ];
} else {
    return [null, null];
}