ESPresense Follow-me Music Assistant - Solved

Currently in ideation status. Will update thread with solution. Looking to see if anyone has accomplished this already and can share thoughts on approach

High level idea - Have the music playing on music assistant follow me as I move around the house.

Existing Capabilities:

  • ESPresense located and tuned in each room where music is to be played
  • ESPresense sensors configured for phone and watch
  • Whole house audio WIIM via Airplay
  • Music assistant configured with player in each room
  • Node Red used extensively for lighting presence control

New Capabilities

  • Use action music_assistant.transfer_queue

Solution Ideas:

  1. Create helper input boolean to turn on/off music tracking “input_boolean.music_follow_paul”
  2. Create node red flow to poll for room change via sensor.iphonepvc when “input_boolean.music_follow_paul” is on.
  3. Create a function node, or switch node to capture the from/to state change.
  4. Create a function node to call the action “music_assistant.transfer_queue” based upon the from/to change (This is really where I need ideas)

I’m diving in and would apricate any ideas or guidance.

Cheers - Paul

  1. Format your config correctly: https://community.home-assistant.io/t/how-to-help-us-help-you-or-how-to-ask-a-good-question/114371#oneone-format-it-properly-16

  2. Reminder: do not use LLMs to help others. You are free to use them yourself but do not use them to answer questions from other people.

This node red flow works.

  1. ESPresense phone sensor
  2. Change node to only pass room changes that have music capabilities
  3. Change node to store flow data with old room and new room
  4. Current state node to check if “follow music” input boolean is on
  5. Function node to create action payload
  6. Action code to call change queue service.

Probably going to add a limiter to eliminate quick changes in a row, like going to the kitchen for less than 2 mins

[{"id":"filter","type":"switch","z":"2ace8abbbc7448db","name":"Room Changed?","property":"data.new_state.state","propertyType":"msg","rules":[{"t":"neq","v":"msg.data.old_state.state","vt":"msg"},{"t":"neq","v":"not_home","vt":"str"},{"t":"neq","v":"office","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":250,"y":160,"wires":[["set_vars"],[],[]]},{"id":"trigger","type":"server-state-changed","z":"2ace8abbbc7448db","name":"iPhonePVC","server":"2a12269e.94634a","version":6,"outputs":1,"exposeAsEntityConfig":"","entities":{"entity":["sensor.iphonepvc"],"substring":[],"regex":[]},"outputInitially":false,"stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":false,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":70,"y":160,"wires":[["filter"]]},{"id":"set_vars","type":"change","z":"2ace8abbbc7448db","name":"Set Locations","rules":[{"t":"set","p":"old_location","pt":"flow","to":"msg.data.old_state.state","tot":"msg"},{"t":"set","p":"new_location","pt":"flow","to":"msg.data.new_state.state","tot":"msg"}],"x":480,"y":160,"wires":[["37ac6641e0135e8c"]]},{"id":"37ac6641e0135e8c","type":"api-current-state","z":"2ace8abbbc7448db","name":"music follow paul","server":"2a12269e.94634a","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.music_follow_paul","state_type":"str","blockInputOverrides":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":670,"y":160,"wires":[["function"]]},{"id":"function","type":"function","z":"2ace8abbbc7448db","name":"Transfer Queue","func":"// =============================================================================\n// MUSIC ASSISTANT QUEUE TRANSFER - Node-RED Function\n// Based on: music_assistant.transfer_queue\n// =============================================================================\n\n// Extract old/new locations from flow context (set by previous change node)\nvar old_location = flow.get('old_location');\nvar new_location = flow.get('new_location');\n\n// VALIDATION: Skip invalid transfers\nif (!old_location || !new_location || old_location === new_location || new_location === 'not_home') {\n    node.warn(`❌ Skipping: ${old_location || 'none'} → ${new_location || 'none'}`);\n    return null;\n}\n\n// 🎵 BUILD EXACT Home Assistant Service Format\nmsg.payload = {\n    // REQUIRED: Action (for Node-RED api-call-service)\n    \"action\": \"music_assistant.transfer_queue\",\n    \n    // REQUIRED: Target entity (matches your HA example)\n    \"target\": {\n        \"entity_id\": \"media_player.ma_\" + new_location\n    },\n    \n    // REQUIRED: Music Assistant data (matches your HA example)\n    \"data\": {\n        \"source_player\": \"media_player.ma_\" + old_location\n        //\"target_player\": \"media_player.ma_\" + new_location\n    }\n};\n\n// DEBUG INFO\nnode.log(`🎵 Transferring: ${old_location} → ${new_location}`);\nmsg.debugInfo = {\n    from: old_location,\n    to: new_location,\n    source: \"media_player.ma_\" + old_location,\n    target: \"media_player.ma_\" + new_location,\n    timestamp: new Date().toISOString()\n};\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":160,"wires":[["service"]]},{"id":"service","type":"api-call-service","z":"2ace8abbbc7448db","name":"Music Assistant","server":"2a12269e.94634a","version":7,"debugenabled":true,"action":"music_assistant.transfer_queue","floorId":[],"areaId":[],"deviceId":[],"entityId":[],"labelId":[],"data":"$payload","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","blockInputOverrides":false,"domain":"music_assistant","service":"transfer_queue","x":1040,"y":160,"wires":[["debug"]]},{"id":"debug","type":"debug","z":"2ace8abbbc7448db","name":"Transfer Details","tosidebar":true,"complete":"debugInfo","statusVal":"","statusType":"auto","x":1220,"y":160,"wires":[]},{"id":"2a12269e.94634a","type":"server","name":"Hingham Home","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":true,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]