Skip to content

Latest commit

 

History

History
195 lines (151 loc) · 9.9 KB

File metadata and controls

195 lines (151 loc) · 9.9 KB

Network API

How the HAP-Z1ES talks to the world over the LAN.

Open ports (factory firmware 19404R)

Port Proto Service Notes
139 TCP NetBIOS Session Samba 3.0.37
445 TCP SMB Samba 3.0.37 — see 04-smb.md
1900 UDP SSDP UPnP discovery, server banner Linux/3.0 UPnP/1.0 Sony-HAP/1.0
60100 TCP HTTP (lighttpd) UPnP device description + embedded web UI
60200 TCP HTTP (lighttpd) JSON-RPC ScalarWebAPI — the control plane

Not open (verified empirically): 22 (SSH), 23 (telnet), 80 (HTTP), 443 (HTTPS), 5000, 8000, 8080, 8443, 10000 (Sony Home Audio API on cousin devices), 54480 (Sony Personal Audio API), 52323 (BRAVIA).

Implication: the alternate Sony ports referenced in python-songpal#29 are not used by the HAP — the HAP family is its own generation with its own port assignment. Don't waste time probing those.

SSDP discovery

A standard M-SEARCH * HTTP/1.1 to 239.255.255.250:1900 returns five replies, one for each advertised service:

HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1800
LOCATION: http://192.168.1.28:60100/hap.xml
SERVER: Linux/3.0 UPnP/1.0 Sony-HAP/1.0
ST: upnp:rootdevice
USN: uuid:00000000-0000-1010-8000-<wifi-mac-no-colons>::upnp:rootdevice

Also advertised:

  • urn:schemas-upnp-org:device:Basic:1
  • urn:schemas-sony-com:service:ScalarWebAPI:1
  • urn:schemas-sony-com:service:MusicConnect:1

The UUID format is 00000000-0000-1010-8000-<12 hex chars>. The last 12 hex chars are the Wi-Fi MAC (without colons), not the Ethernet MAC.

UPnP device description (port 60100)

GET http://<ip>:60100/hap.xml returns the standard UPnP root device document, including the X_ScalarWebAPI extension:

<av:X_ScalarWebAPI_DeviceInfo xmlns:av="urn:schemas-sony-com:av">
  <av:X_ScalarWebAPI_Version>1.0</av:X_ScalarWebAPI_Version>
  <av:X_ScalarWebAPI_BaseURL>http://<ip>:60200/sony</av:X_ScalarWebAPI_BaseURL>
  <av:X_ScalarWebAPI_ServiceList>
    <av:X_ScalarWebAPI_ServiceType>guide</av:X_ScalarWebAPI_ServiceType>
    <av:X_ScalarWebAPI_ServiceType>system</av:X_ScalarWebAPI_ServiceType>
    <av:X_ScalarWebAPI_ServiceType>audio</av:X_ScalarWebAPI_ServiceType>
    <av:X_ScalarWebAPI_ServiceType>avContent</av:X_ScalarWebAPI_ServiceType>
  </av:X_ScalarWebAPI_ServiceList>
</av:X_ScalarWebAPI_DeviceInfo>
<av:X_HAP_DeviceInfo xmlns:av="urn:schemas-sony-com:av">
  <av:X_HAP_Version>0019404R</av:X_HAP_Version>
  <av:X_HAP_MACAddr>80:56:f2:85:0e:27</av:X_HAP_MACAddr>
</av:X_HAP_DeviceInfo>

Other endpoints on port 60100:

  • /HAP.html → 301 to /HAP_app.html — a 272 KB HTML/JS embedded admin UI (CSS comments in Japanese — internal Sony tooling, not designed for end users).
  • /ScalarWebAPI_SCPD.xml — UPnP SCPD descriptor (essentially empty — the real API is the JSON-RPC below).
  • /MusicConnect_SCPD.xml — declares TransportState (STOPPED/PLAYING/PAUSED_PLAYBACK/NO_MEDIA_PRESENT) and LastChange evented variables.
  • /HAP-Z1ES_120.png, /HAP-Z1ES_48.png, etc. — device icons.

Vestigial / advertised-but-unimplemented endpoints (don't waste time on these)

Firmware 19404R advertises a few endpoints that the daemon does not actually serve — leftovers from a shared Sony codebase. Confirmed dead on 19404R:

  • MusicConnect — declared in the UPnP description, but POST /MusicConnect/control returns 404.
  • /sony/contentdb/v100/... (a REST-style content API the embedded HAP_app.html admin UI calls — audio/{albums,artists,genres,tracks,playlists}, contentplayer/v100/...). On 19404R a GET hangs and times out (0 bytes) and a POST returns 404, while the same :60200 answers a normal ScalarWebAPI getPowerStatus. So HAP_app.html is a generic/older UI pointed at a backend this firmware lacks. The library is reachable via the JSON-RPC avContent.* methods (or read directly off disk — 09-disk-layout.md), not this REST surface.

JSON-RPC ScalarWebAPI (port 60200)

This is the real control plane. Every endpoint is POST http://<ip>:60200/sony/<service> with a JSON-RPC body:

{
  "method": "<methodName>",
  "id": 1,
  "params": [...],
  "version": "<version>"
}

Services exposed:

  • /sony/system — power, system info, network settings
  • /sony/audio — volume, sound settings (DSEE, DSD remastering, gapless, oversampling)
  • /sony/avContent — playback control, library browse, now-playing info
  • /sony/guide — API introspection (mostly disabled on HAP — getMethodTypes returns {"results": []})

Quirks observed

  • Per-method versioning is non-uniform. Each method advertises its own version, and the server returns error: [14, "Unsupported Version"] if you call the wrong one. There is no 1.0 for everything. See research/api-method-catalog.md for the working version of each known method.
  • HTTP Expect: 100-continue triggers 417 Expectation Failed. Most Python and PowerShell clients send this header by default; you must disable it. In Python with requests: session = requests.Session(); session.headers.update({'Expect': ''}).
  • Introspection is neutered. getMethodTypes returns {"results": []} at every version on every service, and getSupportedApiInfo returns [12, "No Such Method"]. The full method dictionary has been recovered via APK decompile (see research/notes/2026-05-25-apk-decompile-findings.md and research/notes/2026-05-25-apk-deep-dive-downloadbydiff.md) plus live fuzzing.
  • Response bytes are UTF-8 JSON. Some libraries return them as byte[] — decode with UTF-8 before parsing.

Sample working call

curl -X POST http://192.168.1.28:60200/sony/avContent \
  -H 'Content-Type: application/json' \
  --data '{"method":"getPlayingContentInfo","id":1,"params":[],"version":"1.2"}'

Returns (formatted):

{
  "id": 1,
  "result": [{
    "title": "Dan té dinyé la",
    "artist": "Nahawa Doumbia",
    "albumName": "La grande cantatrice Malienne vol. 3",
    "fileName": "02 - Nahawa Doumbia - Dan té dinyé la.flac",
    "uri": "audio:track?id=163756",
    "albumID": "audio:album?id=11781",
    "playlistUri": "audio:playinglist?id=69",
    "storageUri": "storage:usb1",
    "audioInfo": [{"codec":"flac","frequency":"44100","bandwidth":"16","bitrate":"1001000"}],
    "audioCodec": ["flac"],
    "audioFrequency": ["44100"],
    "bandwidth": "16",
    "bitrate": "1001000",
    "durationMsec": 274000,
    "positionMsec": 110000,
    "state": "PLAYING",
    "shuffleType": "off",
    "repeatType": "off",
    "playbackControlMode": "folder",
    "playlistModifiedVersion": 7,
    "favoriteType": "normal",
    "listCount": 4,
    "listIndex": 1,
    "coverArtUrl": "http://192.168.1.28:60200/sony/avContent/storage/cover_art/A0002E05",
    "backgroundColorR": 93,
    "backgroundColorG": 160,
    "backgroundColorB": 80,
    "backgroundColorA": 255,
    "composer": "Nahawa Doumbia"
  }]
}

Notice the typo playinglist (instead of playlist) — preserved here verbatim because that's the actual URI scheme. Future code that parses this must match the typo.

URI schemes observed

Scheme Example Meaning
audio:track?id=NNN audio:track?id=163756 A single track in the library DB
audio:album?id=NNN audio:album?id=11781 An album in the library DB
audio:artist?id=NNN (inferred) An artist
audio:playinglist?id=NNN audio:playinglist?id=69 A playlist (note typo)
storage:usb1 storage:usb1 The USB-attached external drive
storage:internal (inferred) The internal HDD

Cover art

http://<ip>:60200/sony/avContent/storage/cover_art/<8-hex-id> returns the album art as JPEG (probably). The 8-hex ID is opaque — it does not match the album ID in audio:album?id=NNN directly.

Real-time updates — polling, not WebSocket

The HAP exposes no push-notification mechanism. Confirmed via APK decompile (2026-05-25): Sony's own Android client uses four background polling threads at 5 s cadence rather than subscribing to events. There is no switchNotifications call anywhere in the client. No ws:// URLs. No WebSocket upgrade handshake. The phrase "WebSocket" appears in zero decompiled source files. Our earlier WebSocket upgrade probe on port 60200 returned 405 because the device doesn't speak WebSocket on that port at all.

Sony's polling endpoints (replicate this model in any third-party client):

Thread Endpoint Method Cadence
Volume + mute POST /sony/audio getVolumeInformation v1.1 5 s
Now-playing POST /sony/avContent getPlayingContentInfo v1.2 5 s
Power POST /sony/system getPowerStatus v1.1 5 s
Library sync state POST /sony/database checkSameDatabase v1.0 5 s

Sony's "official example code" repo (sonydevworld/audio_control_api_examples) does demonstrate switchNotifications over WebSocket, but for cousin devices (BRAVIA TVs, STR-DN receivers, SRS speakers). The HAP family is a different generation and never picked up that capability.

Methods we've confirmed working

See research/api-method-catalog.md for the living catalog with exact versions and parameter shapes.

Reference: cousin-device documentation we can transpose