All notable changes to HAP-Revival will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning once we ship a versioned release.
Only add new filesmode (GUI checkbox, off by default; CLI--new-onlyonplan/sync). The local library is the source of truth, so a normal sync faithfully mirrors it — a "changed" file (path already on the HAP but byte size differs, e.g. a re-tag or re-encode) is pushed by default; no exceptions. The opt-in add-only mode is for the rare case of adding files without overwriting anything already there. New engine helperhap_sync.actionable(scan)centralizes the filter;scan_maprecords the intent so the plan and the transfer stay in sync.- Plan now shows everything, grouped and explained. Output is split into CHANGED (with
local X vs HAP Y, Δ±Zper file, so it's obvious whether the audio really differs or it's just metadata) and NEW, sorted, no longer truncated at 12 lines. The GUI also writes the complete plan tohap_plan_<share>.txtnext to the config every analysis, so nothing is ever hidden behind a cap. Fixes the "it says 100 files changed and I don't know what they are" confusion.
tools/smb_doctor.py— a shared engine that diagnoses SMB access to the HAP and can repair the Windows-side breakage that OS updates keep reintroducing. Two independent concerns, kept distinct so users aren't misled:- Authoritative transfer probe — opens the HAP's anonymous SMB1 share via
pysmbexactly like the transfer does. If it connects, syncing works regardless of any Windows SMB setting. - Native-path checks (Windows only) —
RequireSecuritySignature(the 24H2/25H2 default that blocks the HAP),EnableInsecureGuestLogons/AllowInsecureGuestAuth, the SMB1 client feature (read from themrxsmb10driver, no admin), and genuinely broken mapped drives. The last is verified by actively probing each mapping withTest-Pathrather than trustingGet-SmbMapping's Status field — an idle persistent mapping reports "Disconnected" yet reconnects fine, so trusting Status would tell users to delete working drives. - One-click fix — non-admin fixes (clearing stale mappings) run in the user session; admin fixes are bundled into a single self-elevating PowerShell (one UAC prompt). The split matters: an elevated process sees a different drive-letter namespace and wouldn't find the user's maps.
- Authoritative transfer probe — opens the HAP's anonymous SMB1 share via
- Wired into both surfaces: the GUI's Check button now shows the full diagnosis and reveals
a Fix Windows access button when there's something to repair (
tools/hap_gui.py); the CLI gainshap_sync check(rich report) andhap_sync check --fix(tools/hap_sync.py).
- Expanded
docs/04-smb.mdwith a "Windows updates keep re-breaking access" section. Each Win10/11 update can silently flip an SMB client default and lock you out of the anonymous HAP share even though nothing changed on the device. Documents the four knobs with check + elevated-PowerShell fix commands — SMB signing now required by default on Win11 24H2/25H2 (RequireSecuritySignature, the most recent regression), insecure guest logons (EnableInsecureGuestLogons/AllowInsecureGuestAuth), and the SMB1 client feature — plus the stale persistent-mapping gotcha (aDisconnected/Unavailablemapped drive keeps forcing a bogus credential prompt;net use * /delete /ythen reconnect as guest). Reiterates the two clean escapes: flip the device to SMB3 via Special Mode, or usetools/hap_sync.py(pysmb, bypasses the Windows SMB stack entirely).
- Expanded
docs/10-uart-console.mdinto a ready-to-run session guide while waiting for the USB-serial adapter:- Re-verified the console pins against the authoritative IC101 pin table (p79): M1 = CSI0_DAT10 (TX),
M3 = CSI0_DAT11 (RX), UART1 /
ttymxc0@ 115200 — confirmed correct (the LCD RGB bus uses other CSI0_DAT balls in the N/P/R/T/U rows; don't confuse them). - Board-level candidate
CN4008— the unqualified TXD/RXD console nets route to connectorCN4008(MAIN schematic p47), which also appears on the MAIN PWB (p40): the likely factory debug header. Confirm its pinout empirically. - Disassembly order to reach the MAIN board (it sits under the FPGA-DSP board).
- Dump runbook: interrupt U-Boot →
cat /proc/mtd→ddeach partition off via netcat over Ethernet or the SMB share;mtd2= the JFFS2 rootfs. Receiver (nc) confirmed available.
- Re-verified the console pins against the authoritative IC101 pin table (p79): M1 = CSI0_DAT10 (TX),
M3 = CSI0_DAT11 (RX), UART1 /
tools/hap_sync.py— actually transfers music to the HAP and keeps it in sync incrementally (copies only new/changed files), over the device's SMB1 share viapysmb— so you do not have to enable the insecure SMB1 client in Windows. Handles the two-share layout in one run: separate PC folders →HAP_InternalandHAP_External, configured in a smallhap_sync.json(tools/hap_sync.json.exampleprovided; the real one is git-ignored). Auto-skips junk (.ffs_tmp,Thumbs.db,._*…) and unsupported formats, preserves<Artist>/<Album>/, and offersplan(dry-run),sync,list,wake(WoL),check.- On-disk remote-index cache so we never re-list tens of thousands of files every run: the
first run scans the share, then
plan/syncread the cache instantly, and asyncfolds the files it just uploaded into the cache (steady-state = no re-scan).--refresh/ therefreshcommand force a full re-listing. Cache lives in.hap_sync_cache/(git-ignored). - Live-tested end-to-end against the device: anonymous SMB1 connect, full recursive listing (67k files), and a verified upload round-trip.
- Robustness fix discovered in testing: a long SMB1 recursive listing can desync pysmb's session
(breaking the next write) —
hap_syncreconnects on any listing error and uploads on a fresh connection, which also made the remote listing complete/consistent.
- On-disk remote-index cache so we never re-list tens of thousands of files every run: the
first run scans the share, then
tools/hap_companion.py— makes any file-copy tool (FreeFileSync, rsync, drag-and-drop) HAP-aware, without replacing it. Stdlib only, read-only.validate <folder>— pre-flight a music folder: flags unsupported codecs/containers, junk that pollutes the library (.ffs_tmp,.part,Thumbs.db,._*…), PCM over 192 kHz (the Forza PCM-path cap — reads FLAC/WAV headers to check real rates), and album folders missing cover art.diff <hdd_browse.db> <folder>— semantic new-vs-already-on-HAP comparison of a local<Artist>/<Album>/tree against the device's own SQLite catalog (so you transfer only what's actually missing, by content). Validated against a real library (24,404 artist/album pairs).wake <mac>(Wake-on-LAN) andcheck <ip>(reachability).
- Fix: both
hap_companion.pyandlibrary_browser.pynow tolerate the non-UTF-8 (latin-1) text that exists in some on-device DB rows (e.g. "Zé Roberto"), which previously crashed the SQLite read.
tools/library_browser.py— a stdlib-only web browser for a HAP library, reading the on-device SQLite catalog (hdd_browse.db) directly: artists → albums → tracks, with cover art (served from thePROP78D9thumbnail BLOB), codec, sample-rate/bit-depth, durations, and search. Read-only (DB opened immutable), data never leaves the machine. It's the reference decoder for theFTxx02/PROPxxxxschema documented in09-disk-layout.md, and the foundation for a control-app library view (the live API can't list HDD content;downloadByDiffis blocked — but the SQLite is all we need). Validated against a real 77k-track library; it immediately surfaced ~68 orphan "tracks" that were actually FreeFileSync.ffs_tmptemp files the indexer had picked up.
- New
docs/11-audio-path.md: the full signal chain, read from the GPLforza_snd_driversource. The FPGA is an Altera PCIe device (0x1172:0xE001); the SoC DMA's audio into its FIFO. Decoded the two DSPs' actual jobs and mapped them to the app's sound settings: ADSP-21488 SHARC = "HEQ"/DSEE-HX restoration + digital filter (the "DSEE" toggle), Cirrus CS48L10 = oversampling/SRC (firmware4up/2up/nonSRC↔ the "Oversampling" setting), plus the DSD-remastering mode machine (Direct.PCM / Direct.DSD / DSD_ReMaster.PCM). Documented the/dev/forzaioctl ABI — the lever a Phase-4 daemon uses to drive the chain while preserving Sony's analog path — and that DSP firmware lives on the rootfs at/sony/lib/modules/dspfw/.
A full audit of every doc against the 2026-06-02/03 ground truth, to make the repo a reliable reference for newcomers and specialists alike. Purged the claims that had become false and wired up the new docs everywhere:
- README: named the DSPs (ADSP-21488 SHARC + CS48L10), corrected the status/roadmap (firmware is OTA-only — no "format-analyze the blob"; the OS path is UART → NAND dump), reflected that the full library DB is now in hand, and added docs 09/10 to the reading order (they were missing).
- Killed the "firmware is downloadable" falsehood in
07-firmware.md,00-overview.md,CONTRIBUTING.md,08-prior-art.md, andarchive/README.md— it is OTA-only with no public copy. - Removed the last "Tokyo Cabinet = library DB" relics (
06-hdd-swap.md,08-prior-art.md) and the "SHARC part not published" / "NAND not pinned down" hedges (01-hardware.md,02-software-stack.md): rootfs is/dev/mtdblock2JFFS2 on NAND (GPMI), SPI-NOR is an M25P32. 04-smb.mdgained a "Security boundary" section (anonymous read/write confirmed; symlink + HTTP traversal blocked; no safe Samba RCE) and the real on-disk share paths.03-network-api.mddocuments the vestigial/sony/contentdb/v100+ MusicConnect endpoints.api-method-catalog.mdreframesdownloadByDiffas no-longer-a-blocker (DB obtained off-disk).- Added dated correction banners to the superseded 2026-05 research notes (iOS postmortem, mitmproxy, database-service, downloadByDiff deep-dive) pointing forward to the 2026-06 findings.
tools/hap_client.pydoc/bug pass, verified live against the device (2026-06-03): the paused state wire value isPAUSED_PLAYBACK(notPAUSED) — fixed the now-playing CLI so a paused device renders correctly; corrected the repeat/shuffletargetdocstrings (canonical'track'; Spotify is'', not'spotify'); documented thatgetSoundSettingsreturns the value incurrentValue(catalog + confirmed the client already reads it).
- UART serial console pinned down at the SoC — new doc
docs/10-uart-console.md. From the IC101 pin-function table (service manual p75–79): the i.MX6 UART1 console (ttymxc0 @ 115200) is ball M1 = CSI0_DAT10 (TX) and ball M3 = CSI0_DAT11 (RX); CSI0_DAT12/13 is the U-COM MCU link, CSI0_DAT14/15 the remote-learning link. Boot-mode straps hardwired for NAND. Full shopping list, 3.3 V safety rules, and the U-Boot→NAND-dump procedure included. - Audio DSPs identified from the GPL
forza_snd_driversource (downloaded): ADSP-21488 SHARC (adsp_21488.c) + Cirrus CS48L10 (cdsp_cs48l10.c). Updated01-hardware.md(were "not published"). - Full session record:
research/notes/2026-06-03-os-acquisition-recon.md— firmware confirmed unobtainable publicly (99-agent sweep), GPL bundle fetched, and live-device software recon: Samba 3.0.37 anon RW to music shares but symlink traversal blocked, lighttpd path traversal blocked. /sony/contentdb/v100REST API: confirmed NOT implemented on 19404R (GET times out, POST 404 while the same:60200ScalarWebAPI answers) — vestigial like MusicConnect; don't re-chase.- Flash layout learned from the GPL kernel (pre-UART): cmdline
console=ttymxc0,115200 root=/dev/mtdblock2 … rootfstype=jffs2; rootfs is writable JFFS2 on NAND mtd2; SPI-NOR M25P32 (4 MB) holds U-Boot+kernel. Documented in10-uart-console.md.
- First direct read of a HAP-Z1ES internal disk (pulled, attached over USB, imaged + mounted
read-only via WSL2). New canonical doc
docs/09-disk-layout.mdand full forensic noteresearch/notes/2026-06-02-hdd-direct-read-ondisk-findings.md. - Ground-truth DB schema committed under
research/db-schema/—.schemadumps of every on-device database (schema only, no library data). Confirms the schema reverse-engineered from the APK on 2026-05-25, with real row counts (77 668 tracks on the reference unit) and decoded enums (codecPROP304B: 49=FLAC/81=MP3/97=AAC/65=ALAC/129=WMA/17=WAV/33=AIFF;PROP6844=year;PROP3047=seconds). - Disk architecture established: two ext4 partitions —
/data(3 GB, the SQLite catalog, formatver 14.00) and/mnt/internal(928 GB, music understorage/<Artist>/<Album>/+ adb_storage/cover_artcache). Files areroot:root 0700; the indexer runs as root.
- Library metadata store is SQLite, not Tokyo Cabinet — corrected in
02-software-stack.mdand06-hdd-swap.md. Tokyo Cabinet is in the GPL bundle but is not the library DB. - The HDD holds no rootfs — only
/data+/mnt/internal. Partially answers Open Question #1 in02-software-stack.md; the OS lives on internal flash. Audio-path diagram paths corrected (storage/notMusic/;/data/*.dbnotlibrary.tch).
- Gear panel is now a full control surface, not just a theme picker. New sections:
- Display — Minimal mode toggle (hides the header "HAP-Revival · firmware · active" and the bottom footer for a stripped-down look). Choice persisted in
localStorage. - Sound — pill toggles for DSEE (auto/off), DSD remastering (on/off), Gapless (auto/off), Volume normalization (auto/off), Oversampling (precision/normal). Each setting has a plain-language caption directly under it explaining what it actually does, plus a longer hover tooltip on the label. All five round-trip validated against the live device via
audio.setSoundSettingsv1.1. - Playback — Volume slider (auto-disabled on HAP-Z1ES, enabled on HAP-S1 with the device's min/max/step), Sleep timer dropdown auto-populated from
getSleepTimercandidate seconds (Off + 10/20/30/40/50/60/90/120 min). - Current track — Favorite buttons (♥ / — / 👎) using
editContentInfowithtagUri:"meta:favorite". Auto-disabled when the current source is not an HDD track (Spotify Connect, radio, etc.) because Sony's editContentInfo only works onaudio:track?id=NURIs.
- Display — Minimal mode toggle (hides the header "HAP-Revival · firmware · active" and the bottom footer for a stripped-down look). Choice persisted in
- Backend new endpoints to back the above:
/api/set-sound,/api/set-volume,/api/mute-toggle,/api/set-sleep-timer,/api/set-favorite./api/statenow also returns sleep_timer, volume, and favorite_type in the now_playing block. Each sub-fetch is try-wrapped so a partial device failure doesn't blank the whole UI. - Live-reload of HTML template (commit a94d5d7) means editing CSS/JS in
webui.pyno longer needs a server restart — the HTML is re-read from disk on each GET. Cache-Control: no-store + Pragma + Expires so the browser never holds a stale copy. Adding new Python endpoints still needs a server restart since the Python class is loaded once at start. - Permanent archive of technical PDFs under
archive/:- HAP-Z1ES Service Manual (8.3 MB, SHA-256 documented in
archive/README.md) - HAP-S1 Service Manual (10.4 MB)
- HAP-Z1ES end-user Help Guide (1.3 MB)
- HAP-S1 end-user Help Guide (1.4 MB)
Total ~21 MB. Three docs that previously cited the now-dead
riverparkinc.commirror updated to point at the local archive. Documents legal stance + manual-download procedure for contributors who want to add more (e.g. the Reference Manual, Quick Start, RM-ANU183 remote manual).
- HAP-Z1ES Service Manual (8.3 MB, SHA-256 documented in
Building on the first web UI commit (b7e3eb4), a focused polish round driven by live user feedback during the session:
- Ambient cover background (Apple Music / Tidal style). The current cover image fills the viewport, blurred to 60 px and saturated 1.8×, behind the now-playing card. Cards switch to frosted-glass over it. The cover element itself gets a soft glow tinted by the HAP-extracted dominant color.
- Bug fix:
bodywas opaque, hidingbody::before(the ambient layer) completely. Split thehtml, bodyshorthand sohtmlkeeps the dark fallback andbodybecomes transparent. The ambient mode actually shows up now — earlier "ambient" screenshots were pure black because of this. - Theme switcher (⚙ icon top-right). Four modes:
- Ambient cover (default)
- Solid (from cover) — flat color = the RGB the HAP itself extracts from the cover
- Dark — the original
- Custom — native HTML5 color picker, choice persisted via
localStorageActive selection visually highlighted (accent-tinted row + border). Selected theme + custom color survive reload (per-browser).
- Adaptive text contrast: when the background is bright (perceptual luminance > 0.6 via Rec. 601 weights), the UI switches to dark text + light frosted-glass cards. Auto-flipping
--fg,--muted,--card-bg,--hover, and--text-shadowCSS variables. Header + footer also get an adaptivetext-shadowfor the worst-case mid-luminance covers. Recomputed both on cover change and on theme change. pausePlayingContentis a TOGGLE, not just pause — discovered when the user reported play not working after pause. The "naming-true"pause()/resume()library methods now check state first; the web UI uses/api/toggle-playback(direct toggle, single round-trip).setPowerStatus({status:"play"})does NOT reliably resume Spotify Connect playback — only thepausePlayingContenttoggle does. The library'sresume()documents this and uses the toggle.- Web UI live-reload: the HTML template is re-read from the source file on every request via sentinel comments. Means iterating on CSS / JS no longer requires bouncing the server — F5 in the browser is enough. Cache-Control no-store + Pragma no-cache + Expires 0 on the HTML response so the browser cannot cache between reloads.
- Server-side initial-cover URL: the
--cover-urlCSS variable is now pre-populated server-side from the currentgetPlayingContentInfo, so the ambient background renders on the very first paint instead of waiting for the JS refresh tick.
- 5 setter methods live-validated via round-trip ("set to current value = no net change"):
audio.setSoundSettingsv1.1[{settings:[{target,value}]}]avContent.setBufferTimev1.0[{bufferTimeSec:N}]avContent.setRepeatTypev1.0[{target,type}]avContent.setShuffleTypev1.0[{target,type}]system.setSleepTimerv1.0[{status,sleepTimerSec}]
- Favorites unlocked via
editContentInfov1.0 with{method:"editTrackInfo", target:[{uri,tagUri:"meta:favorite",value:"favorite"|"dislike"|"normal"}]}— Sony'ssetFavoritedoes not exist as a separate call. - Per-source repeat/shuffle:
target:"track"for HDD/USB,target:""for Spotify (Sony's canonical values from the APK). x-hap-device-idheader now sent by default on everyhap_client.pyrequest (matching Sony's Android client; optional in practice but good hygiene).- New library methods:
set_sound_setting,set_repeat,set_shuffle,set_buffer_time,set_sleep_timer,set_volume,mute_toggle,set_favorite,toggle_playback.
/sony/databaseservice confirmed live.checkSameDatabasev1.0 returns{isSameVersion, isSameName, type}with the correctdatabase:<short_uuid>?dbType=hdd&...URI.downloadByDiffv1.0: same shape; live still returns emptylocationeven with Sony's exact request (header +originalVersion=-1+ preflightcheckSameDatabase). Pending mitmproxy capture of Sony's Android client during a real sync.- Complete on-device DB schema decoded from
assets/demo_browse.db(79 KB SQLite shipped in the Android APK, never publicly extracted before). 11 tables —FT0000(root),FT0002(tracks, 37+ columns),FT000A(albums with thumbnail BLOB),FT4502(genres),FT5202(artists),FT6F02(composers),FT7002(lyricists),FTF003(playlists),FTF004(playlist contents). ~60 PROP-code hex constants decoded (PROP3601 = id, PROP304B = codec, PROP3048 = sample rate, PROP10DE = bit width, PROP6844 = release date, etc.). Full breakdown inresearch/notes/2026-05-25-database-service-and-db-schema.md. recfilegeneric transport mechanism discovered. Some JSON-RPC methods (getPlaylistInfo,downloadByDiff, probably others) return{location: "http://<ip>:60200/sony/avContent/recfile/requestN.data"}instead of the payload itself. A plain HTTP GET on that URL returns the binary/text payload asapplication/x-www-form-urlencodeddata (e.g.newVersion=9&types=2&ids=-1&positions=...). Confirmed viagetPlaylistInfoon a freshly-created playlist.- APK deep-dive #2 (research/notes/2026-05-25-apk-deep-dive-downloadbydiff.md, ~600 lines): full Java code paths for
downloadByDiff,getRichMetaInfo,editContentInfodispatch, the polling state machine, etc.
tools/hap_client.py— clean Python client library wrapping every confirmed API method. Stdlib-only (norequests). Typed dataclasses (SystemInfo,NowPlaying,SoundSettings,SleepTimer). Doubles as a CLI:python tools/hap_client.py <ip> now-playing | pause | resume | seek N | play-track N | system | sound | sleep-timer | next | prev.tools/webui.py— minimal stdlib HTTP server (no Flask, no aiohttp) serving an HTML5 single-page control panel athttp://localhost:8080. Features: now-playing with cover art, dynamic accent color from the device's RGB hint, seek by clicking the progress bar, pause/resume/next/previous/standby buttons, live sound-settings display, 3-second polling matching Sony's own app. The first working third-party HAP control web app ever shipped.- Live-validated against firmware 19404R: end-to-end functional with Spotify Connect playback (cover art from Spotify CDN renders correctly).
- Decompiled
com.sony.HAP.HDDAudioRemotev4.3.1 (12.88 MB APK from APKCombo). First public decompile of this client. Full findings:research/notes/2026-05-25-apk-decompile-findings.mdplus a deep-dive atresearch/notes/2026-05-25-apk-deep-dive-downloadbydiff.md(~1100 lines combined). Toolchain: OpenJDK 21 (winget) + jadx 1.5.5. - Live-validated 3 new methods with Sony shapes:
system.setPowerStatus v1.1[{status:"play"}]✅ resumes playback (wake + play, 4th status value)avContent.setPlayContent v1.1[{positionSec:N}]✅ seek-within-track (NOT a separateseekStreamingContent)avContent.createPlayingListAndQuickPlay v1.0[{uri,listIndex,listCount,playbackControlMode}]✅ THE HDD playback start primitive (Sony's UI calls this when you tap a track)
- Discovered new service
/sony/database(live-confirmed exists, responds tocheckSameDatabase). Sony uses it to sync the entire on-device music DB to a local SQLite mirror viacheckSameDatabase+downloadByDiff. Highest-leverage target for unlocking HDD content browsing. - APK reveals 15+ new methods Sony's client uses that we hadn't catalogued:
getSleepTimer/setSleepTimer,getSupportedFileType,createPlaylist/updatePlaylist/deletePlaylist/getPlaylistInfo,getStorageInformation,getBufferTime/setBufferTime,setAudioInput,getRichMetaInfo,editContentInfo,registerDevice,setRepeatType/getRepeatType,setShuffleType/getShuffleType. - APK reveals 🟡 method shapes for all previously-unknown methods. Notable corrections to our prior guesses:
deleteContent.uriis a JSON array of URI strings, not a scalar.- Pause/next/previous need
params:[{}](empty object inside array), not[]. scanPlayingContentis FF/REW with{direction:"fwd"|"bwd"}— NOT scrub-to-position.getContentList v1.3is for internet radio (netService) only — HDD content is browsed via thedatabaseservice's local SQLite cache, not via getContentList.
- Confirmed: HAP has no WebSocket notifications. Sony's app uses 4 polling threads at 5 s cadence. Our client design should do the same — stop investigating push mechanisms.
- Corrections vs APK agent's report (live tested 2026-05-25):
/sony/<service>IS required on firmware 19404R (agent claimed otherwise — wrong).x-hap-device-idheader is optional (agent claimed mandatory — wrong, our calls work without)./turnOn,/turnOffplain HTTP endpoints return 404 on firmware 19404R (agent claimed they exist — wrong on this firmware; possibly HAP-S1 only or removed).
- Side effect documented: my own probing during the session accidentally paused user's music (the 🟡 setPlayContent calls returned
[1, "Any"]errors but had side effects). Recovered viasetPowerStatus({status:"play"}). Lesson:[1, "Any"]does not mean "no effect" — some methods partially succeed even when reporting an error. Test only with disposable content going forward.
- First
tools/api-fuzzer.pyrun on a live HAP-Z1ES (firmware 19404R) — 53 method+service candidates tested, up to 8 versions each. 24 methods confirmed to exist on the device (up from 10 previously known). Output:research/captures/fuzz-192_168_1_28-20260525T184419Z.json. - New methods discovered to exist (parameters TBD):
system.setPowerStatusv1.1,audio.setAudioMutev1.1,avContent.setPlayContentv1.1 (was Unsupported at v1.0),avContent.stopPlayingContentv1.0,avContent.scanPlayingContentv1.0,avContent.getContentInfov1.1,avContent.getContentListv1.3 (was Unsupported at 1.0/1.2),avContent.deleteContentv1.1 (flagged dangerous),guide.getServiceProtocolsv1.0. - New methods confirmed working with empty params:
audio.setSoundSettingsv1.1 andavContent.setPlaybackModeSettingsv1.0 — both reply with empty result (noop with no params). - New error codes documented: code
1 "Any"(generic / invalid value) and code3 "illegal Argument"(missing/wrong parameter), in addition to the previously known5/12/14. Gives finer-grained method-existence detection. - Settled negatives: HAP cannot self-update via API (no
getSWUpdateInfo/actSWUpdate), seek within track not exposed (noseekStreamingContent), favorites and Bluetooth not exposed.
- Network surface mapped on a live HAP-Z1ES (firmware 19404R, 2026-05-25):
- Confirmed SSDP banner
Linux/3.0 UPnP/1.0 Sony-HAP/1.0 - Confirmed open TCP ports: 139, 445, 60100 (lighttpd / UPnP description), 60200 (ScalarWebAPI JSON-RPC)
- Confirmed alternate Sony API ports (10000, 54480, 52323) are closed on HAP — settled the python-songpal#29 ambiguity
- Captured full
/hap.xmldevice descriptor withMusicConnect:1+ScalarWebAPI:1service entries - Verified working methods:
system.getSystemInformationv1.2,system.getPowerStatusv1.1,audio.getVolumeInformationv1.1,audio.getSoundSettingsv1.1,avContent.getPlayingContentInfov1.2,avContent.pausePlayingContentv1.0
- Confirmed SSDP banner
- Hardware confirmed: SoC is NXP i.MX6 Dual (
MCIMX6D5EYM10AC, Cortex-A9 dual @ 1 GHz) per Sony service manualIC101part number. Earlier i.MX53 inference (Cortex-A8 single) corrected. - Software stack confirmed from Sony's oss.sony.net GPL release:
- OpenWrt trunk r35385 base
- Linux 3.0.35, U-Boot 2012.04.01
- Samba 3.0.37, Dropbear 2012.55, lighttpd 1.4.35
- GStreamer 0.10.36 + Freescale plugins
- Custom
forza_snd_driverkernel module (Sony codename "forza") — source available in GPL bundle - Control daemon is Python 2.7 + web.py 0.37 + lighttpd, not C
- Front-panel UI is DirectFB 1.4.17 (no X11)
- Service DIAG menu entry corrected: requires HOME + BACK held, then PLAY then POWER (4-key combo, not 2).
- HDD swap recipe documented: sector-clone via KURO-DACHI/CLONE/U3 preserves DB; Crucial MX500 / KIOXIA recommended; avoid Samsung 860/870 EVO.
- Exhaustive prior-art inventory completed — entire public corpus consists of one Swift app (HAPxFer), one 10-line gist (frazei), one Python file organizer (music-organizer), one stuck issue (python-songpal#29), Sony's GPL drop, a Crestron module, and the JP hardware-mod blogs. See
docs/08-prior-art.md.
- Initial repository structure, README, license split (MIT code / CC-BY-SA 4.0 docs), CONTRIBUTING, CHANGELOG.
- Documentation set (
docs/00–08) covering overview, hardware, software stack, network API, SMB, DIAG modes, HDD swap, firmware, and prior art. - Tools:
tools/discover.py(SSDP + API probe),tools/api-fuzzer.py(method×version brute force),tools/apk-decompile.md(recipe). - Issue templates for API method discoveries, hardware findings, and bug reports.
- Living API method catalog at
research/api-method-catalog.md.