Overview

These instructions outline how to create a homekit device to play an internet stream on your Sonos device.

These scripts are used with the CMD4 Plugin for Homebridge.

Cmd4 Script

Play Radio Paradise

playMusic.js
#!/usr/bin/env bash
# rp-sonos-cmd4.sh — Homebridge Cmd4 state_cmd to play/stop Radio Paradise on Sonos
# Usage from Cmd4:
#   playRadioParadise.sh "<AccessoryName>" on get
#   playRadioParadise.sh "<AccessoryName>" on set <0|1>
#
# accepts BOTH:
#   1) "<Accessory>" on get|set [0|1]
#   2) get|set "<Accessory>" on [0|1]

# SONOS_IP=192.168.1.29 ./playRadioParadise.sh "Radio Paradise (Sonos)" on set 1


set -euo pipefail

# --- Sonos target ---
SONOS_IP="${SONOS_IP:-${SONOS_HOST:-}}"
PORT="${PORT:-1400}"
if [[ -z "${SONOS_IP}" ]]; then
  echo "SONOS_IP/SONOS_HOST not set" >&2
  exit 2
fi

# --- Stream URL ---
RP_URL="${RP_URL:-http://stream.radioparadise.com/aac-320}"
SONOS_URI="x-rincon-mp3radio://${RP_URL}"
START_VOLUME="${START_VOLUME:-}"

# --- Parse args in either order ---
# Expect either:
# A) ACCESSORY=$1  CHAR=$2  ACTION=$3  VALUE=$4
# B) ACTION=$1     ACCESSORY=$2 CHAR=$3 VALUE=$4
A1="${1:-}"; A2="${2:-}"; A3="${3:-}"; A4="${4:-}"

lower() { echo "${1:-}" | tr '[:upper:]' '[:lower:]'; }

if [[ "$(lower "$A1")" == "get" || "$(lower "$A1")" == "set" ]]; then
  ACTION="$(lower "$A1")"
  ACCESSORY="$A2"
  CHAR="$(lower "$A3")"
  VALUE="${A4:-}"
else
  ACCESSORY="$A1"
  CHAR="$(lower "$A2")"
  ACTION="$(lower "$A3")"
  VALUE="${A4:-}"
fi

AVT_CTRL="http://${SONOS_IP}:${PORT}/MediaRenderer/AVTransport/Control"
REND_CTRL="http://${SONOS_IP}:${PORT}/MediaRenderer/RenderingControl/Control"

soap_avt() {
  local action="$1" body="$2"
  curl -sS --fail -X POST "$AVT_CTRL" \
    -H 'Content-Type: text/xml; charset="utf-8"' \
    -H "SOAPACTION: \"urn:schemas-upnp-org:service:AVTransport:1#${action}\"" \
    --data-binary "<?xml version=\"1.0\"?>
<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>${body}</s:Body></s:Envelope>"
}

soap_rc() {
  local action="$1" body="$2"
  curl -sS --fail -X POST "$REND_CTRL" \
    -H 'Content-Type: text/xml; charset="utf-8"' \
    -H "SOAPACTION: \"urn:schemas-upnp-org:service:RenderingControl:1#${action}\"" \
    --data-binary "<?xml version=\"1.0\"?>
<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body>${body}</s:Body></s:Envelope>"
}

is_playing() {
  local resp
  resp="$(soap_avt "GetTransportInfo" "<u:GetTransportInfo xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>0</InstanceID></u:GetTransportInfo>")" || return 1
  echo "$resp" | grep -q "<CurrentTransportState>PLAYING</CurrentTransportState>"
}

start_play() {
  soap_avt "SetAVTransportURI" "<u:SetAVTransportURI xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\">
    <InstanceID>0</InstanceID><CurrentURI>${SONOS_URI}</CurrentURI><CurrentURIMetaData></CurrentURIMetaData>
  </u:SetAVTransportURI>" >/dev/null

  if [[ -n "${START_VOLUME}" ]]; then
    soap_rc "SetVolume" "<u:SetVolume xmlns:u=\"urn:schemas-upnp-org:service:RenderingControl:1\">
      <InstanceID>0</InstanceID><Channel>Master</Channel><DesiredVolume>${START_VOLUME}</DesiredVolume>
    </u:SetVolume>" >/dev/null
  fi

  soap_avt "Play" "<u:Play xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\">
    <InstanceID>0</InstanceID><Speed>1</Speed>
  </u:Play>" >/dev/null
}

stop_play() {
  soap_avt "Stop" "<u:Stop xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\">
    <InstanceID>0</InstanceID>
  </u:Stop>" >/dev/null || true
}

if [[ "$CHAR" != "on" ]]; then
  echo "Unsupported characteristic: ${ACCESSORY}" >&2
  exit 1
fi

case "$ACTION" in
  get)
    if is_playing; then echo 1; else echo 0; fi
    ;;
  set)
    if [[ "${VALUE:-0}" == "1" ]]; then
      start_play
    else
      stop_play
    fi
    ;;
  *)
    echo "Unknown action: $ACTION" >&2; exit 1;;
esac


Homebridge Configuration


config.json
...
{
            "platform": "Cmd4",
            "name": "Cmd4",
            "accessories": [
                {
                    "type": "Lightbulb",
                    "displayName": "Kitchen Radio Paradise",
                    "on": "1",
                    "name": "Kitchen Radio Paradise",
                    "timeout": 30000,
                    "polling": true,
                    "interval": 1000,
                    "stateChangeResponseTime": 3,
                    "state_cmd": "SONOS_HOST=192.168.1.99 /homebridge/Cmd4Scripts/playRadioParadise.sh"
                }
             ]
}
...


References

ReferenceURL
Cmd4 Plugin for Homebridgehttps://github.com/ztalbot2000/homebridge-cmd4