LinkPlay Integration

The entity attributes in HA developer tools:

‘Media Duration’ and ‘Media Position’ attributes are updating as Spotify is playing, which is why I believe communication between the device and HA across VLANs is working fine. Should there be attributes here for media metadata too?

Yes it should. Media duration and position are queried via httpapi, media metadata is gathered through UPnP. You should first do a test when HA and Linkplays are on the same network, if they work fine like that, it’s likely a problem of firewalling between your vlans.

Added preliminary support for Home Assistant’s new Media Browser capability, for media files present on a USB stick plugged into the Linkplay device.

For devices with an USB port, make sure that in the sources configuration you have specified a udisk entry. Plug in a USB stick with MP3s on it, and switch to that source in Home Assistant. The Media Browser will populate with the list of files present on the stick, clicking a file will start playing it.

There may be cases when some models switch to USB and start playing automatically as soon as you connect a USB drive - it looks like the device doesn’t report the whole track list in that moment. In those cases, just select USB source again in HA and the list will be re-read from de device.
Currently working and tested with USB disks. SD/TF cards may work, I don’t have such a device to do tests with.

A quick tip : if you experience temporary Unavailable status on the slaves afer unjoining from a multiroom group in router mode, run once the Linkplay-specific command RouterMultiroomEnable. It’s described in the documentation.

Hey @robi,

Can you check to make sure that TTS is working on your end with linkplay media players? I haven’t been able to get TTS to work lately, and after troubleshooting today the only thing that works for me is downgrading the custom component to version 2.0.14 or earlier.

I have no errors in the logs (either TTS component or linkplay component). I know the issue is not with TTS because I was able to play TTS through a non-linkplay media player without error.

The ‘snapshot’ and ‘restore’ functions are also not working for me while playing spotify. I checked the list of presets after running snapshot and there are none saved.

Hi @robi - looks like this may be my error again. I set the logging to debug and it seems like, at least the snapshot error, is another UPnP issue. Let me see if I can get UPnP working like you previously mentioned.

I have to ask - what is the reasoning behind moving functionality to UPnP? My understanding is that this protocol is a severe security trade off for convenience. It’s not unheard of for system owners to segment networks into multiple VLANS for security. I do not want WiFi devices to have direct access to home assistant or other critical infrastructure like switches, web backend, etc.

The httpapi is incomplete and not functioning very well. It responds OK even for deliberately wrong commands, it’s missing functionality present in the UPnP api. It looks like the SOC manufacturer doesn’t really care about httpapi as the Android/Ios apps are all only working via UPnP and all the functionality is implemented there. It’s a mess to have some parts of the communication via one protocol and some parts via other. I think it’s better to have everything uniformized.

I myself have separated VLANs for all the stuff I use, but I prefer Linkplay devices with Ethernet connections thus they don’t connect via WiFi.

TTS broke by the recently introduced Media Browser functionality - I’m so sorry about this. Pushed an update with a fix for it.

Just tested snapshot and restore, with Spotify and they do work fine for me, when Linkplay device, Home Assistant and Android client are on the same VLAN. As I’ve explained earlier, this requires very special permissions to be synced between Linkplay device and the Spotify app. It might be very well possible that snapshot fails because the app is not present/running in the network at that moment, as the app also uses UPnP to discuss with the Linkplay module. The playlist name comes from the app, and Linkplay stores the preset by the playlist name… as the normal workflow is that both Spotify and 4Stream app are running on the same device or in the same time… you simply can’t exclude Spotify app from the ecosystem.

That’s a reason why I won’t renew my subscription with Spotify. It’s too closed system.

Found a Spotify metadata forwarding bug. Check with the latest version if that fixes your issue.

Thank you, I had no idea there was such a discrepancy between UPnP functionality and HTTPAPI. That makes complete sense.

I have the Muzo cobblestones that do have an ethernet port. I have found that, even when connected hardwired, the linkplay devices still want to be ‘set up’ with a wifi connection. It’s a bit weird. I also don’t have ethernet connections in every room that I have these. Maybe i’ll fiddle around with that today.

The update you pushed fixed TTS, thank you very much! There also is a change in the metadata, I now have a “media_title” that says “Spotify” when it is playing Spotify music. No track name/artist/artwork though.

Are you planning on moving to another music service that is more open? Just curious.

Edit: Here is my debug log when trying to snapshot on the latest version:

2020-09-23 07:38:40 DEBUG (SyncWorker_25) [custom_components.linkplay] service_handle from id: ['media_player.linkplay_den']
2020-09-23 07:38:40 DEBUG (SyncWorker_25) [custom_components.linkplay] **SNAPSHOT** entity: media_player.linkplay_den;
2020-09-23 07:38:40 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection.139727252032384] local variable 'result' referenced before assignment
Traceback (most recent call last):
  File "/config/custom_components/linkplay/media_player.py", line 1370, in _preset_snap_via_upnp
    result = self._upnp_device.PlayQueue.SetSpotifyPreset(KeyIndex=presetnum)
AttributeError: 'NoneType' object has no attribute 'PlayQueue'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 137, in handle_call_service
    await hass.services.async_call(
  File "/usr/src/homeassistant/homeassistant/core.py", line 1315, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1354, in _execute_service
    await self._hass.async_add_executor_job(handler.func, service_call)
  File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/linkplay/__init__.py", line 131, in service_handle
    device.snapshot(switchinput)
  File "/config/custom_components/linkplay/media_player.py", line 1092, in snapshot
    self._preset_snap_via_upnp(str(self._preset_key))
  File "/config/custom_components/linkplay/media_player.py", line 1372, in _preset_snap_via_upnp
    _LOGGER.debug("SetSpotifyPreset UPNP error: %s, %s, result: %s", self.entity_id, presetnum, result)
UnboundLocalError: local variable 'result' referenced before assignment

Linkplay devices have wifi buillt-in, which currently cannot be disabled (but I am trying to contact manufacturer to provide us a command to disable WiFi). I had no problems with devices without any setup, just connect through LAN and that’s it. Or you could set up to a dummy SSID which will never be accessible later for the device, if you use LAN.

Personally I like to listen normal radio stations, rather than music services. I tried Tidal, Deezer etc but none of them was good enough for my style.

Your device is not detected by HA’s UPnP system.
I’ll fix the error handling for this, however that won’t make it work for you…

Looks like still a networking issue: firewall in between or your UPnP proxy is not working correctly. What are you using for forwarding UPnP packets between vlans?

Get this testing version. Restart HA, and look in device attributes, what does debug_info say?

Using that testing version you posted, I get this result:

debug_info: UPnP not detected

I am using UPnP on my OPNsense router but it’s not working correctly and I don’t have the networking know-how to fix it… networking is not really my forte.

I appreciate you helping me debug this. Is there somewhere I can donate to you to buy you a coffee or something?

To be honest I’m not too worried about the snapshot/restore functionality not working, I think I have some workarounds in my lovelace UI and a node red flow that still provides the same functionality, I’ve been working on it all week instead of actually working :smiley:


The top two media player cards are media_player.spotify players for myself and my wife, and the next four are media_player.linkplayer players for each device.

In terms of automation, here is my node-red flow if anyone else is interested. I have three subflows: the first checks if media is playing either on any rokus or two spotify instances for myself or my wife and saves the state of each device to a variable. The second subflow does all of the checks (am I on a conference call, is an input_boolean for TTS notifications on, etc.) and actually calls the service to send the TTS notification. The final subflow checks each device’s previous state and restarts playback if it was playing previously.

Note that in the living room, both the roku and linkplay are attached to the same sound bar as different sources. I have to change the source on the soundbar (vizio soundcast plugin) before sending the TTS notification and then change the source back before resuming any playback.

Flow:

Check Media Status Subflow:

[{"id":"a85d05ef.d790d8","type":"switch","z":"b422b1d5.42072","name":"Check LR Roku","property":"lr_roku_status","propertyType":"global","rules":[{"t":"eq","v":"playing","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":800,"y":140,"wires":[["1faa15a5.3e8292"],["42a0d435.d7d094"]]},{"id":"1faa15a5.3e8292","type":"api-call-service","z":"b422b1d5.42072","name":"Pause Roku Playback","server":"9e1e946a.079518","version":1,"debugenabled":false,"service_domain":"remote","service":"send_command","entityId":"remote.roku_lr","data":"{\"command\":\"play\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1020,"y":100,"wires":[["82488a23.ca0858"]]},{"id":"82488a23.ca0858","type":"api-call-service","z":"b422b1d5.42072","name":"Set Soundbar Source - AUX","server":"9e1e946a.079518","version":1,"debugenabled":false,"service_domain":"media_player","service":"select_source","entityId":"media_player.vizio_living_room","data":"{\"entity_id\":\"media_player.vizio_living_room\",\"source\":\"AUX\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1280,"y":140,"wires":[["42a0d435.d7d094"]]},{"id":"e01492fb.8ed9c8","type":"switch","z":"b422b1d5.42072","name":"Check Bedroom Roku","property":"bedroom_roku_status","propertyType":"global","rules":[{"t":"eq","v":"playing","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":820,"y":320,"wires":[["1601e892.14b10f"],["42a0d435.d7d094"]]},{"id":"1601e892.14b10f","type":"api-call-service","z":"b422b1d5.42072","name":"Pause Roku Playback","server":"9e1e946a.079518","version":1,"debugenabled":false,"service_domain":"remote","service":"send_command","entityId":"remote.roku_bedroom","data":"{\"command\":\"play\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1040,"y":280,"wires":[["42a0d435.d7d094"]]},{"id":"29d7faf3.bbe8ce","type":"switch","z":"b422b1d5.42072","name":"Check Den Roku","property":"den_roku_status","propertyType":"global","rules":[{"t":"eq","v":"playing","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":810,"y":240,"wires":[["734115cd.d71e44"],["42a0d435.d7d094"]]},{"id":"734115cd.d71e44","type":"api-call-service","z":"b422b1d5.42072","name":"Pause Roku Playback","server":"9e1e946a.079518","version":1,"debugenabled":false,"service_domain":"remote","service":"send_command","entityId":"remote.40_tcl_roku_tv","data":"{\"command\":\"play\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1020,"y":200,"wires":[["42a0d435.d7d094"]]},{"id":"24ebc1c4.c1fc8e","type":"change","z":"b422b1d5.42072","name":"Set LR Roku Status Context","rules":[{"t":"set","p":"lr_roku_status","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":140,"wires":[["a85d05ef.d790d8"]]},{"id":"288a8029.edf77","type":"change","z":"b422b1d5.42072","name":"Set Den Roku Status Context","rules":[{"t":"set","p":"den_roku_status","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":240,"wires":[["29d7faf3.bbe8ce"]]},{"id":"ef5f3be7.39e1d8","type":"change","z":"b422b1d5.42072","name":"Set Bedroom Roku Status Context","rules":[{"t":"set","p":"bedroom_roku_status","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":320,"wires":[["e01492fb.8ed9c8"]]},{"id":"f9284486.f8355","type":"api-current-state","z":"b422b1d5.42072","name":"Get LR Roku State","server":"9e1e946a.079518","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"media_player.roku_lr","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":270,"y":140,"wires":[["24ebc1c4.c1fc8e"]]},{"id":"614980b9.515ca","type":"api-current-state","z":"b422b1d5.42072","name":"Get Den Roku State","server":"9e1e946a.079518","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"media_player.40_tcl_roku_tv","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":280,"y":240,"wires":[["288a8029.edf77"]]},{"id":"28b1288e.9bd438","type":"api-current-state","z":"b422b1d5.42072","name":"Get Bedroom Roku State","server":"9e1e946a.079518","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"media_player.roku_bedroom","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":290,"y":320,"wires":[["ef5f3be7.39e1d8"]]},{"id":"42a0d435.d7d094","type":"join","z":"b422b1d5.42072","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"5","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":1690,"y":260,"wires":[[]]},{"id":"f3995341.d045c","type":"api-current-state","z":"b422b1d5.42072","name":"Get peetipablo Spotify State","server":"9e1e946a.079518","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"media_player.spotify_peetipablo","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":300,"y":400,"wires":[["b995f7fd.485b38"]]},{"id":"434d3201.8b6344","type":"api-current-state","z":"b422b1d5.42072","name":"Get theheartsublime Spotify State","server":"9e1e946a.079518","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"media_player.spotify_theheartsublime","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":320,"y":480,"wires":[["f595926b.e3295"]]},{"id":"b995f7fd.485b38","type":"change","z":"b422b1d5.42072","name":"Set Spotify Status Context","rules":[{"t":"set","p":"sp_peetipablo_status","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":550,"y":400,"wires":[["6c15148d.20accc"]]},{"id":"f595926b.e3295","type":"change","z":"b422b1d5.42072","name":"Set Spotify Status Context","rules":[{"t":"set","p":"sp_theheartsublime_status","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":590,"y":480,"wires":[["bf56ba46.902a8"]]},{"id":"6c15148d.20accc","type":"switch","z":"b422b1d5.42072","name":"Check Peetipablo Spotify","property":"sp_peetipablo_status","propertyType":"global","rules":[{"t":"eq","v":"playing","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":830,"y":400,"wires":[["87e42ea5.163ae"],["42a0d435.d7d094"]]},{"id":"87e42ea5.163ae","type":"api-call-service","z":"b422b1d5.42072","name":"Pause Playback","server":"9e1e946a.079518","version":1,"debugenabled":false,"service_domain":"media_player","service":"media_pause","entityId":"media_player.spotify_peetipablo","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1040,"y":360,"wires":[["42a0d435.d7d094"]]},{"id":"bf56ba46.902a8","type":"switch","z":"b422b1d5.42072","name":"Check theheartsublime Spotify","property":"sp_theheartsublime_status","propertyType":"global","rules":[{"t":"eq","v":"playing","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":850,"y":480,"wires":[["2cf48478.8f6ad4"],["42a0d435.d7d094"]]},{"id":"2cf48478.8f6ad4","type":"api-call-service","z":"b422b1d5.42072","name":"Pause Playback","server":"9e1e946a.079518","version":1,"debugenabled":false,"service_domain":"media_player","service":"media_pause","entityId":"media_player.spotify_theheartsublime","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1060,"y":420,"wires":[["42a0d435.d7d094"]]},{"id":"9e1e946a.079518","type":"server","z":"","name":"Home Assistant","addon":true}]

TTS Notification Subflow:

[{"id":"60db8635.f62a58","type":"function","z":"7b7f94f1.e3eb14","name":"Set Speech Payload","func":"const message = (msg.payload && msg.payload.message) || \"Automation provided no message\";\nvar now = new Date().toLocaleString(\"en-GB\");\n\nnode.status({ fill: \"green\", shape: \"dot\", text: \"TTS message: \" + message + \" - \" + now });\nreturn {\n    payload:{\n        data: {\n            message: message,\n            language: \"en\"\n        }\n    }\n};","outputs":1,"noerr":0,"initialize":"","finalize":"","x":740,"y":100,"wires":[["f4701f1f.e8ceb"]]},{"id":"2a0ab5b9.1994ba","type":"api-current-state","z":"7b7f94f1.e3eb14","name":"Speech Notifications?","server":"9e1e946a.079518","version":1,"outputs":2,"halt_if":"true","halt_if_type":"bool","halt_if_compare":"is","override_topic":false,"entity_id":"input_boolean.voice_notifications","state_type":"habool","state_location":"","override_payload":"none","entity_location":"","override_data":"none","blockInputOverrides":false,"x":420,"y":140,"wires":[["e08969a9.63ee6"],[]],"outputLabels":["","enabled"]},{"id":"d647562e.8d1398","type":"function","z":"7b7f94f1.e3eb14","name":"Check for overrides","func":"const alwaysSpeak = msg.payload && msg.payload.urgent\nnode.status({ fill: \"green\", shape: \"dot\", text: alwaysSpeak });\nif (alwaysSpeak) {\n    return [msg, null];\n} else {\n    return [null, msg];\n}","outputs":2,"noerr":0,"initialize":"","finalize":"","x":210,"y":100,"wires":[["60db8635.f62a58"],["2a0ab5b9.1994ba"]],"outputLabels":["Bypass notification","Check for notifications"]},{"id":"e08969a9.63ee6","type":"api-current-state","z":"7b7f94f1.e3eb14","name":"Work Mode OFF?","server":"9e1e946a.079518","version":1,"outputs":2,"halt_if":"off","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"input_boolean.work_mode","state_type":"str","state_location":"","override_payload":"none","entity_location":"","override_data":"none","blockInputOverrides":false,"x":410,"y":240,"wires":[["60db8635.f62a58"],[]],"outputLabels":["","enabled"]},{"id":"f4701f1f.e8ceb","type":"api-call-service","z":"7b7f94f1.e3eb14","name":"Send Speech Notification","server":"9e1e946a.079518","version":1,"debugenabled":false,"service_domain":"tts","service":"google_translate_say","entityId":"media_player.linkplay_den","data":"","dataType":"json","mergecontext":"","output_location":"payload","output_location_type":"msg","mustacheAltTags":false,"x":1010,"y":100,"wires":[["d269dacd.b09318"]]},{"id":"d269dacd.b09318","type":"delay","z":"7b7f94f1.e3eb14","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":1220,"y":100,"wires":[[]]},{"id":"9e1e946a.079518","type":"server","z":"","name":"Home Assistant","addon":true}]

Resume Media Subflow:

[{"id":"86b35f79.2e90d8","type":"switch","z":"9949c1df.df6f2","name":"Check LR Roku","property":"lr_roku_status","propertyType":"global","rules":[{"t":"eq","v":"unavailable","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":580,"y":60,"wires":[["b66303f0.cdd35"],["a0283b78.191db8"]]},{"id":"e47e5c89.f11f1","type":"api-call-service","z":"9949c1df.df6f2","name":"Resume Roku Playback","server":"9e1e946a.079518","version":1,"debugenabled":false,"service_domain":"remote","service":"send_command","entityId":"remote.roku_lr","data":"{\"command\":\"play\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1190,"y":260,"wires":[["b66303f0.cdd35"]]},{"id":"ee7173c.5de159","type":"delay","z":"9949c1df.df6f2","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":1000,"y":200,"wires":[["e47e5c89.f11f1"]]},{"id":"50c4e7e7.3f8818","type":"switch","z":"9949c1df.df6f2","name":"Check Bedroom Roku","property":"bedroom_roku_status","propertyType":"global","rules":[{"t":"eq","v":"unavailable","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":600,"y":400,"wires":[["b66303f0.cdd35"],["225af727.f3d438"]]},{"id":"225af727.f3d438","type":"api-call-service","z":"9949c1df.df6f2","name":"Resume Roku Playback","server":"9e1e946a.079518","version":1,"debugenabled":false,"service_domain":"remote","service":"send_command","entityId":"remote.roku_bedroom","data":"{\"command\":\"play\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":830,"y":440,"wires":[["b66303f0.cdd35"]]},{"id":"6f2e9ecb.2ef1b","type":"switch","z":"9949c1df.df6f2","name":"Check Den Roku","property":"den_roku_status","propertyType":"global","rules":[{"t":"eq","v":"unavailable","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":590,"y":300,"wires":[["b66303f0.cdd35"],["83428750.baba6"]]},{"id":"83428750.baba6","type":"api-call-service","z":"9949c1df.df6f2","name":"Resume Roku Playback","server":"9e1e946a.079518","version":1,"debugenabled":false,"service_domain":"remote","service":"send_command","entityId":"remote.40_tcl_roku_tv","data":"{\"command\":\"play\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":830,"y":340,"wires":[["b66303f0.cdd35"]]},{"id":"a0283b78.191db8","type":"api-call-service","z":"9949c1df.df6f2","name":"Set Soundbar Source - Optical","server":"9e1e946a.079518","version":1,"debugenabled":false,"service_domain":"media_player","service":"select_source","entityId":"media_player.vizio_living_room","data":"{\"entity_id\":\"media_player.vizio_living_room\",\"source\":\"Optical\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":810,"y":140,"wires":[["ee7173c.5de159"]]},{"id":"b66303f0.cdd35","type":"join","z":"9949c1df.df6f2","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"5","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":1850,"y":320,"wires":[[]]},{"id":"55c4d5ff.bb4794","type":"switch","z":"9949c1df.df6f2","name":"Check Peetipablo Spotify","property":"sp_peetipablo_status","propertyType":"global","rules":[{"t":"eq","v":"playing","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":630,"y":640,"wires":[["2043704a.222f6"],["b66303f0.cdd35"]]},{"id":"2dbaf8a5.b9335","type":"switch","z":"9949c1df.df6f2","name":"Check Theheartsublime Spotify","property":"sp_theheartsublime_status","propertyType":"global","rules":[{"t":"eq","v":"playing","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":670,"y":880,"wires":[["ec067ee.fe4ca"],["b66303f0.cdd35"]]},{"id":"d6613646.f62158","type":"api-call-service","z":"9949c1df.df6f2","name":"Resume Spotify Playback","server":"9e1e946a.079518","version":1,"debugenabled":false,"service_domain":"media_player","service":"media_play","entityId":"media_player.spotify_peetipablo","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":910,"y":520,"wires":[["b66303f0.cdd35"]]},{"id":"e2fff7bb.1c6d08","type":"api-call-service","z":"9949c1df.df6f2","name":"Resume Spotify Playback","server":"9e1e946a.079518","version":1,"debugenabled":false,"service_domain":"media_player","service":"media_play","entityId":"media_player.spotify_theheartsublime","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":910,"y":720,"wires":[["b66303f0.cdd35"]]},{"id":"ec067ee.fe4ca","type":"delay","z":"9949c1df.df6f2","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":720,"y":720,"wires":[["e2fff7bb.1c6d08"]]},{"id":"2043704a.222f6","type":"delay","z":"9949c1df.df6f2","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":720,"y":520,"wires":[["d6613646.f62158"]]},{"id":"8172f4c0.1f7fd8","type":"change","z":"9949c1df.df6f2","name":"Clear Payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":300,"y":460,"wires":[["6f2e9ecb.2ef1b","86b35f79.2e90d8","50c4e7e7.3f8818","55c4d5ff.bb4794","2dbaf8a5.b9335"]]},{"id":"9e1e946a.079518","type":"server","z":"","name":"Home Assistant","addon":true}]

See, that’s the problem. Home Assistant can’t connect to Linkplay unit with UPnP.
There’s an issue on your OPNsense system, it doesn’t forward UPnP packets correctly.
Try switching to pfSense (the base of OPNsense) and install Avahi package, see if that fixes your problem.

Yeah, I’m just going to leave it for now… maybe that’ll be my weekend project. Again I appreciate all your help.

Hey @robi,

I wanted to clarify my last post. It seems like certain TTS messages are working with the linkplay entities and some are not.

Very simple commands work - “Someone is at the door”
Adding punctuation or increasing sentence complexity causes the notification to not play - “Hey - Someone is at the door” or “Hey - someone is at the door. Get off your butt.

I verified the messages that are giving me trouble work with other TTS players, so I think it’s still something wonky with the custom linkplay component.

It’s not the component problem. It looks like either the TTS audio file has something, or the webserver of HA, or a Linkplay SOC issue because the HTTPAPI called directly won’t play those messages either.

Can you please try in a browser this:
http://your.player.ip/httpapi.asp?command=setPlayerCmd:play:URL
where URL is the link of your TTS file. If you enabled debug on the component, you should see in the logs the message Trying to play media. with the URL in it. Copy that URL and replace it in the link above, and paste it in a browser on your PC, something like this:

http://your.player.ip/httpapi.asp?command=setPlayerCmd:play:http://hassio.ip:8123/api/tts_proxy/98551e2e3ddc89213a34c84ff492e615e7e13418_en_-_google_translate.mp3

Try with both type messages. Short and long. See if the player plays them. Mine doesn’t play the long ones so as I said, this is an issue of either audio file format or Linkplay modules not liking it…
(another reason to stay away from HTTPAPI)

What TTS integration do you use?

Long Message (“The dryer is done, time to go fold laundry. Don’t wait for tomorrow!”):

http://<LINKPLAY URL>/httpapi.asp?command=setPlayerCmd:play:http://<HA URL>/api/tts_proxy/e6401ffa70b376bad34b5a3713bef6e9bc2dbc7a_en_-_google_translate.mp3

I get ‘OK’ as a response but no media plays on the linkplay.

Short Message (“Someone rang the doorbell”):

http://<LINKPLAY URL>/httpapi.asp?command=setPlayerCmd:play:http://<HA URL>/api/tts_proxy/fdd8bafd4babd5c7fedd40eaca764765595df004_en_-_google_translate.mp3

I get ‘OK’ as a response and the media plays on the linkplay.

If I go to both audio URLs directly in firefox the sound files play in the firefox tab no problem. I can PM you links to download the audio files if it’s helpful.

I use google_translate TTS integration, no issues with any other devices.