docs: replace real MAC addresses in examples with placeholders

The maintainer's two test-speaker MACs (A81B6A536A98 / A81B6A849D99,
plus colon-separated forms) appeared throughout documentation, runbooks,
and example READMEs. Public repo — same hygiene argument as the LAN-IP
sweep in 787c4fa.

Mapping:
  A81B6A536A98          → AABBCCDDEEFF
  A81B6A849D99          → AABBCCDDEE01
  A8:1B:6A:53:6A:98     → AA:BB:CC:DD:EE:FF
  A8:1B:6A:84:9D:99     → AA:BB:CC:DD:EE:01

The placeholders use the IANA-reserved AA:BB:CC:DD:EE:FF address that's
clearly synthetic, matching the convention the earlier anonymisation
pass had already adopted. 13 .md files touched; no tests, no code.

ANONYMIZATION-SUMMARY.md left for a dedicated rewrite commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tobias Gesellchen
2026-05-17 22:05:13 +02:00
co-authored by Claude Opus 4.7
parent 51d196dd03
commit fa51a6f610
13 changed files with 62 additions and 62 deletions
+4 -4
View File
@@ -143,7 +143,7 @@ Browse stored/local music library.
**Example:**
```go
library, err := client.GetStoredMusicLibrary("A81B6A536A98/0")
library, err := client.GetStoredMusicLibrary("AABBCCDDEEFF/0")
```
**Validation:**
@@ -526,7 +526,7 @@ Search for stations and content.
**Response Body:**
```xml
<results deviceID="A81B6A536A98" source="PANDORA" sourceAccount="user123">
<results deviceID="AABBCCDDEEFF" source="PANDORA" sourceAccount="user123">
<songs>
<searchResult source="PANDORA" sourceAccount="user123" token="S123">
<name>Love Story</name>
@@ -707,7 +707,7 @@ Navigation and station operations generate WebSocket events:
Generated when stations are added/removed that affect presets.
```xml
<presetsUpdated deviceID="A81B6A536A98">
<presetsUpdated deviceID="AABBCCDDEEFF">
<presets>
<!-- Updated preset list -->
</presets>
@@ -719,7 +719,7 @@ Generated when stations are added/removed that affect presets.
Generated when station operations affect current playback.
```xml
<nowPlayingUpdated deviceID="A81B6A536A98">
<nowPlayingUpdated deviceID="AABBCCDDEEFF">
<nowPlaying source="PANDORA">
<ContentItem source="PANDORA" location="R456" sourceAccount="user123" isPresetable="true">
<itemName>Taylor Swift Radio</itemName>
+5 -5
View File
@@ -15,14 +15,14 @@ The current request recording system has fundamental issues when dealing with re
**Local Recording** (complete):
```http
### POST /v1/scmudc/A81B6A536A98
POST /v1/scmudc/A81B6A536A98
### POST /v1/scmudc/AABBCCDDEEFF
POST /v1/scmudc/AABBCCDDEEFF
Host: events.api.bosecm.com
Content-Type: text/json; charset=utf-8
Content-Length: 587
Authorization: Bearer jGwEmFWr...
{"envelope":{"monoTime":234906,"payloadProtocolVersion":"3.1","payloadType":"scmudc","protocolVersion":"1.0","time":"2026-02-25T23:03:14.976349+00:00","uniqueId":"A81B6A536A98"},"payload":{"deviceInfo":{"boseID":"3230304","deviceID":"A81B6A536A98","deviceType":"SoundTouch 10","serialNumber":"I6332527703739342000020","softwareVersion":"27.0.6.46330.5043500 epdbuild.trunk.hepdswbld04.2022-08-04T11:20:29","systemSerialNumber":"069231P63364828AE"},"events":[{"data":{"play-state":"PAUSE_STATE"},"monoTime":234904,"time":"2026-02-25T23:03:14.973466+00:00","type":"play-state-changed"}]}}
{"envelope":{"monoTime":234906,"payloadProtocolVersion":"3.1","payloadType":"scmudc","protocolVersion":"1.0","time":"2026-02-25T23:03:14.976349+00:00","uniqueId":"AABBCCDDEEFF"},"payload":{"deviceInfo":{"boseID":"3230304","deviceID":"AABBCCDDEEFF","deviceType":"SoundTouch 10","serialNumber":"I6332527703739342000020","softwareVersion":"27.0.6.46330.5043500 epdbuild.trunk.hepdswbld04.2022-08-04T11:20:29","systemSerialNumber":"069231P63364828AE"},"events":[{"data":{"play-state":"PAUSE_STATE"},"monoTime":234904,"time":"2026-02-25T23:03:14.973466+00:00","type":"play-state-changed"}]}}
{% raw %}
> {%
@@ -33,8 +33,8 @@ Authorization: Bearer jGwEmFWr...
**Mirror Recording** (missing body):
```http
### POST /v1/scmudc/A81B6A536A98
POST /v1/scmudc/A81B6A536A98
### POST /v1/scmudc/AABBCCDDEEFF
POST /v1/scmudc/AABBCCDDEEFF
Host: events.api.bosecm.com
Content-Type: text/json; charset=utf-8
Content-Length: 587
+4 -4
View File
@@ -59,8 +59,8 @@ Based on analysis of recorded data:
### Before (Raw)
```http
### POST /v1/scmudc/A81B6A536A98
POST /v1/scmudc/A81B6A536A98
### POST /v1/scmudc/AABBCCDDEEFF
POST /v1/scmudc/AABBCCDDEEFF
Host: events.api.bosecm.com
...
@@ -69,7 +69,7 @@ Host: events.api.bosecm.com
### After (Enriched)
```http
### POST /v1/scmudc/A81B6A536A98
### POST /v1/scmudc/AABBCCDDEEFF
// Origin: Internal System (device)
// Action: play-item
// Command: Billie Eilish - bad guy (instrumental version)
@@ -87,7 +87,7 @@ Host: events.api.bosecm.com
// <itemName>Billie Eilish - bad guy (instrumental version)</itemName>
// <containerArt>https://i.scdn.co/image/ab67616d0000b273...</containerArt>
// </ContentItem>
POST /v1/scmudc/A81B6A536A98
POST /v1/scmudc/AABBCCDDEEFF
...
{% raw %}
+1 -1
View File
@@ -178,7 +178,7 @@ One row per device tested. Once two devices on different firmware confirm the sa
- Date: 2026-05-13
- Firmware: 27.0.6.46330.5043500 (build epdbuild.trunk.hepdswbld04.2022-08-04T11:20:29)
- Model: SoundTouch 10 (deviceID A81B6A536A98)
- Model: SoundTouch 10 (deviceID AABBCCDDEEFF)
- Bare setMargeAccount accepted: **yes** — pre-/info margeAccountUUID="" → post-/info margeAccountUUID="1111111"
- Persistence written: **yes** — device materialized 14-entry Sources.xml on its own
- Survives reboot: **yes**`setup inspect` after `setup reboot` shows margeAccountUUID still 1111111
+1 -1
View File
@@ -6,7 +6,7 @@ This document provides a comprehensive analysis of the `/supportedURLs` endpoint
**Test Devices:**
- Device 1: `192.0.2.11:8090` (deviceID: `08DF1F0BA325`)
- Device 2: `192.0.2.10:8090` (deviceID: `A81B6A536A98`)
- Device 2: `192.0.2.10:8090` (deviceID: `AABBCCDDEEFF`)
**Key Findings:**
- Both devices return identical endpoint lists
+10 -10
View File
@@ -368,14 +368,14 @@ POST /api/v1/accounts/{account_id}/devices
Content-Type: application/json
{
"device_id": "A81B6A536A98",
"device_id": "AABBCCDDEEFF",
"name": "Living Room Speaker",
"registration_type": "fresh"
}
Response: 201 Created
{
"device_id": "A81B6A536A98",
"device_id": "AABBCCDDEEFF",
"account_id": "acc_12345",
"state": "registering",
"created_at": "2024-01-20T10:00:00Z"
@@ -388,7 +388,7 @@ GET /api/v1/accounts/{account_id}/devices/{device_id}/state
Response: 200 OK
{
"device_id": "A81B6A536A98",
"device_id": "AABBCCDDEEFF",
"account_id": "acc_12345",
"state": "active",
"metadata": {
@@ -555,7 +555,7 @@ Response: 200 OK
```json
{
"version": "1.0",
"device_id": "A81B6A536A98",
"device_id": "AABBCCDDEEFF",
"account_id": "acc_12345",
"state": "active",
"created_at": "2024-01-20T10:00:00Z",
@@ -585,7 +585,7 @@ Response: 200 OK
"type": "SoundTouch 30",
"serial_number": "I6332527703739342000020",
"firmware_version": "4.8.1.25341.2677643.1597353330",
"mac_address": "A8:1B:6A:53:6A:98",
"mac_address": "AA:BB:CC:DD:EE:FF",
"ip_address": "192.168.1.100",
"last_seen": "2024-01-20T15:30:00Z",
"is_legacy_id": false,
@@ -615,7 +615,7 @@ Response: 200 OK
### Event Log Format (events.log)
```
# SoundTouch Service Event Log - Device A81B6A536A98
# SoundTouch Service Event Log - Device AABBCCDDEEFF
# Format: TIMESTAMP|EVENT_ID|EVENT_TYPE|SOURCE|DATA_JSON
# Version: 1.0
@@ -632,8 +632,8 @@ Response: 200 OK
# Format: TIMESTAMP|DISPARITY_ID|DEVICE_ID|ACCOUNT_ID|ENDPOINT|TYPE|SEVERITY|DETAILS_JSON
# Version: 1.0
2024-01-20T15:31:15.012Z|disp_12345|A81B6A536A98|acc_12345|/v1/presets|count_mismatch|medium|{"field_path":"preset_count","local_value":5,"upstream_value":4,"description":"Local has one additional preset"}
2024-01-20T15:32:45.678Z|disp_12346|A81B6A536A98|acc_12345|/v1/recents|timestamp_format|low|{"field_path":"recent[0].utc_time","local_value":"2024-01-20T15:30:00Z","upstream_value":"1705761000","description":"Timestamp format difference"}
2024-01-20T15:31:15.012Z|disp_12345|AABBCCDDEEFF|acc_12345|/v1/presets|count_mismatch|medium|{"field_path":"preset_count","local_value":5,"upstream_value":4,"description":"Local has one additional preset"}
2024-01-20T15:32:45.678Z|disp_12346|AABBCCDDEEFF|acc_12345|/v1/recents|timestamp_format|low|{"field_path":"recent[0].utc_time","local_value":"2024-01-20T15:30:00Z","upstream_value":"1705761000","description":"Timestamp format difference"}
2024-01-20T15:35:20.901Z|disp_12347|B92C7B647B09|acc_12345|/v1/account/full|structure_diff|high|{"field_path":"device[1].ip_address","local_value":"present","upstream_value":"missing","description":"IP address field missing in upstream response"}
```
@@ -925,12 +925,12 @@ type ServiceError struct {
{
"error": {
"code": "DEVICE_NOT_FOUND",
"message": "Device with ID 'A81B6A536A98' not found in account 'acc_12345'",
"message": "Device with ID 'AABBCCDDEEFF' not found in account 'acc_12345'",
"category": "validation",
"timestamp": "2024-01-20T15:30:00Z",
"context": {
"account_id": "acc_12345",
"device_id": "A81B6A536A98",
"device_id": "AABBCCDDEEFF",
"request_id": "req_67890"
},
"retryable": false,
+7 -7
View File
@@ -111,7 +111,7 @@ data/
```json
{
"device_id": "A81B6A536A98",
"device_id": "AABBCCDDEEFF",
"account_id": "account-12345",
"state": "active",
"created_at": "2024-01-15T10:30:00Z",
@@ -137,7 +137,7 @@ data/
"type": "SoundTouch 30",
"serial_number": "I6332527703739342000020",
"firmware_version": "4.8.1.25341.2677643.1597353330",
"mac_address": "A8:1B:6A:53:6A:98",
"mac_address": "AA:BB:CC:DD:EE:FF",
"ip_address": "192.168.1.100",
"last_seen": "2024-01-20T16:20:00Z",
"is_legacy_id": false
@@ -159,7 +159,7 @@ data/
### Event Log Format
```
# Device Events Log - A81B6A536A98
# Device Events Log - AABBCCDDEEFF
# Format: TIMESTAMP|EVENT_TYPE|SOURCE|DATA
2024-01-20T16:15:00Z|now_playing|websocket|{"source":"SPOTIFY","track":"Song Name","artist":"Artist Name"}
@@ -175,9 +175,9 @@ data/
# Parity Analysis Log
# Format: TIMESTAMP|ENDPOINT|DEVICE|ACCOUNT|DISPARITY_TYPE|DETAILS
2024-01-20T16:18:00Z|/v1/account/full|A81B6A536A98|account-12345|content_mismatch|preset_count:local=5,upstream=4
2024-01-20T16:19:15Z|/v1/presets|A81B6A536A98|account-12345|xml_structure|missing_container_art_in_local
2024-01-20T16:20:30Z|/v1/recents|A81B6A536A98|account-12345|timestamp_format|local=RFC3339,upstream=custom
2024-01-20T16:18:00Z|/v1/account/full|AABBCCDDEEFF|account-12345|content_mismatch|preset_count:local=5,upstream=4
2024-01-20T16:19:15Z|/v1/presets|AABBCCDDEEFF|account-12345|xml_structure|missing_container_art_in_local
2024-01-20T16:20:30Z|/v1/recents|AABBCCDDEEFF|account-12345|timestamp_format|local=RFC3339,upstream=custom
```
## Implementation Strategy
@@ -268,7 +268,7 @@ POST /api/v1/accounts/{account-id}/devices
Content-Type: application/json
{
"device_id": "A81B6A536A98",
"device_id": "AABBCCDDEEFF",
"name": "Living Room Speaker",
"registration_type": "fresh"
}
@@ -169,7 +169,7 @@ The `/power_on` endpoint receives comprehensive device data that could replace m
```xml
<device-data>
<device id="A81B6A536A98">
<device id="AABBCCDDEEFF">
<serialnumber>I6332527703739342000020</serialnumber>
<firmware-version>27.0.6.46330.5043500 epdbuild.trunk.hepdswbld04.2022-08-04T11:20:29</firmware-version>
<product product_code="SoundTouch 10 sm2" type="5">
@@ -181,8 +181,8 @@ The `/power_on` endpoint receives comprehensive device data that could replace m
<rssi>Excellent</rssi>
<gateway-ip-address>192.0.2.1</gateway-ip-address>
<macaddresses>
<macaddress>A81B6A536A98</macaddress>
<macaddress>A81B6A849D99</macaddress>
<macaddress>AABBCCDDEEFF</macaddress>
<macaddress>AABBCCDDEE01</macaddress>
</macaddresses>
<ip-address>192.0.2.10</ip-address>
<network-connection-type>Wireless</network-connection-type>
+3 -3
View File
@@ -23,7 +23,7 @@ The `/power_on` endpoint provides rich device data that could eliminate network
### Current /power_on Data
```xml
<device-data>
<device id="A81B6A536A98"> <!-- ✅ Device MAC -->
<device id="AABBCCDDEEFF"> <!-- ✅ Device MAC -->
<serialnumber>I6332527703739342000020</serialnumber> <!-- ✅ Serial -->
<firmware-version>27.0.6.46330.5043500...</firmware-version> <!-- ✅ FW -->
<product product_code="SoundTouch 10 sm2" type="5"> <!-- ✅ Model -->
@@ -35,8 +35,8 @@ The `/power_on` endpoint provides rich device data that could eliminate network
<rssi>Excellent</rssi> <!-- ✅ Signal -->
<gateway-ip-address>192.0.2.1</gateway-ip-address> <!-- ✅ Network -->
<macaddresses> <!-- ✅ All MACs -->
<macaddress>A81B6A536A98</macaddress>
<macaddress>A81B6A849D99</macaddress>
<macaddress>AABBCCDDEEFF</macaddress>
<macaddress>AABBCCDDEE01</macaddress>
</macaddresses>
<ip-address>192.0.2.10</ip-address> <!-- ✅ Current IP -->
<network-connection-type>Wireless</network-connection-type> <!-- ✅ Connection -->
+17 -17
View File
@@ -8,7 +8,7 @@ This guide explains how the SoundTouch service handles device identification thr
The SoundTouch service uses two different identifiers for devices:
- **MAC Address** (`A81B6A536A98`) - Used in HTTP API requests and UPnP discovery
- **MAC Address** (`AABBCCDDEEFF`) - Used in HTTP API requests and UPnP discovery
- **Serial Number** (`I6332527703739342000020`) - Used for internal file storage
The service automatically maps between these identifiers so that API requests using MAC addresses can access files stored using serial numbers.
@@ -17,8 +17,8 @@ The service automatically maps between these identifiers so that API requests us
### Request Flow
```
1. HTTP Request: GET /streaming/account/3230304/device/A81B6A536A98/presets
2. MAC Resolution: A81B6A536A98 → I6332527703739342000020
1. HTTP Request: GET /streaming/account/3230304/device/AABBCCDDEEFF/presets
2. MAC Resolution: AABBCCDDEEFF → I6332527703739342000020
3. File Access: accounts/3230304/devices/I6332527703739342000020/Presets.xml
```
@@ -26,12 +26,12 @@ The service automatically maps between these identifiers so that API requests us
The service extracts MAC addresses from UPnP device descriptions:
```xml
<!-- From http://192.168.1.100:8091/XD/BO5EBO5E-F00D-F00D-FEED-A81B6A536A98.xml -->
<!-- From http://192.168.1.100:8091/XD/BO5EBO5E-F00D-F00D-FEED-AABBCCDDEEFF.xml -->
<root xmlns="urn:schemas-upnp-org:device-1-0">
<device>
<friendlyName>Sound Machinery</friendlyName>
<modelName>SoundTouch 10</modelName>
<serialNumber>A81B6A536A98</serialNumber> <!-- MAC address here -->
<serialNumber>AABBCCDDEEFF</serialNumber> <!-- MAC address here -->
</device>
</root>
```
@@ -51,12 +51,12 @@ The service handles all common MAC address formats automatically:
| Format | Example | Status |
|-------------|---------------------|-------------|
| Standard | `A81B6A536A98` | ✅ Supported |
| Standard | `AABBCCDDEEFF` | ✅ Supported |
| Lowercase | `a81b6a536a98` | ✅ Supported |
| With Colons | `A8:1B:6A:53:6A:98` | ✅ Supported |
| With Colons | `AA:BB:CC:DD:EE:FF` | ✅ Supported |
| With Dashes | `A8-1B-6A-53-6A-98` | ✅ Supported |
| Mixed Case | `a81B6a536A98` | ✅ Supported |
| With Spaces | ` A81B6A536A98 ` | ✅ Supported |
| With Spaces | ` AABBCCDDEEFF ` | ✅ Supported |
## 🔧 **Troubleshooting**
@@ -64,9 +64,9 @@ The service handles all common MAC address formats automatically:
**Symptoms:**
```
GET /streaming/account/3230304/device/A81B6A536A98/presets
GET /streaming/account/3230304/device/AABBCCDDEEFF/presets
→ 500 Internal Server Error
→ Log: "open .../devices/A81B6A536A98/Presets.xml: no such file or directory"
→ Log: "open .../devices/AABBCCDDEEFF/Presets.xml: no such file or directory"
```
**Diagnosis:**
@@ -96,7 +96,7 @@ Ensure the MAC address is present:
```xml
<info deviceID="I6332527703739342000020">
<networkInfo type="SCM">
<macAddress>A81B6A536A98</macAddress> <!-- Must be present -->
<macAddress>AABBCCDDEEFF</macAddress> <!-- Must be present -->
<ipAddress>192.0.2.10</ipAddress>
</networkInfo>
</info>
@@ -114,7 +114,7 @@ cat > data/accounts/3230304/devices/I6332527703739342000020/DeviceInfo.xml << EO
<info deviceID="I6332527703739342000020">
<name>My SoundTouch Device</name>
<networkInfo type="SCM">
<macAddress>A81B6A536A98</macAddress>
<macAddress>AABBCCDDEEFF</macAddress>
<ipAddress>192.168.1.100</ipAddress>
</networkInfo>
</info>
@@ -126,7 +126,7 @@ EOF
**Check UPnP accessibility:**
```bash
# Test UPnP endpoint directly
curl http://192.168.1.100:8091/XD/BO5EBO5E-F00D-F00D-FEED-A81B6A536A98.xml
curl http://192.168.1.100:8091/XD/BO5EBO5E-F00D-F00D-FEED-AABBCCDDEEFF.xml
# Should return XML with <serialNumber> field
```
@@ -144,9 +144,9 @@ This should be handled automatically, but you can verify:
**Test different formats:**
```bash
# All of these should work the same:
curl http://localhost:8000/streaming/account/3230304/device/A81B6A536A98/presets
curl http://localhost:8000/streaming/account/3230304/device/AABBCCDDEEFF/presets
curl http://localhost:8000/streaming/account/3230304/device/a81b6a536a98/presets
curl http://localhost:8000/streaming/account/3230304/device/A8:1B:6A:53:6A:98/presets
curl http://localhost:8000/streaming/account/3230304/device/AA:BB:CC:DD:EE:FF/presets
```
## 📊 **Monitoring and Diagnostics**
@@ -186,8 +186,8 @@ For developers interested in the technical details:
// 1. Removing spaces, colons, and dashes
// 2. Converting to uppercase
// Examples:
// "a8:1b:6a:53:6a:98" → "A81B6A536A98"
// "A8-1B-6A-53-6A-98" → "A81B6A536A98"
// "a8:1b:6a:53:6a:98" → "AABBCCDDEEFF"
// "A8-1B-6A-53-6A-98" → "AABBCCDDEEFF"
```
### Lookup Process
+3 -3
View File
@@ -1008,9 +1008,9 @@ Use this checklist to systematically troubleshoot issues:
**Symptoms:**
```
GET /streaming/account/3230304/device/A81B6A536A98/presets
GET /streaming/account/3230304/device/AABBCCDDEEFF/presets
→ 500 Internal Server Error
→ Log: "open .../devices/A81B6A536A98/Presets.xml: no such file or directory"
→ Log: "open .../devices/AABBCCDDEEFF/Presets.xml: no such file or directory"
```
**Cause:** The service uses MAC addresses in API requests but stores files using device serial numbers. A mapping system resolves MAC addresses to serial numbers automatically.
@@ -1026,7 +1026,7 @@ sudo systemctl restart soundtouch-service
```bash
# Files should be stored by serial number, not MAC
ls data/accounts/3230304/devices/
# Should show: I6332527703739342000020/ (not A81B6A536A98/)
# Should show: I6332527703739342000020/ (not AABBCCDDEEFF/)
```
3. **Verify DeviceInfo.xml contains MAC address**:
+3 -3
View File
@@ -504,15 +504,15 @@ func TestHandleMargePowerOnEnhanced(t *testing.T) {
}{
{
name: "new_device_registration",
requestBody: `<device-data><device id="A81B6A536A98">...</device></device-data>`,
requestBody: `<device-data><device id="AABBCCDDEEFF">...</device></device-data>`,
existingDevice: nil,
expectedStatus: "ok",
expectMigration: false,
},
{
name: "existing_device_update",
requestBody: `<device-data><device id="A81B6A536A98">...</device></device-data>`,
existingDevice: &models.ServiceDeviceInfo{DeviceID: "A81B6A536A98"},
requestBody: `<device-data><device id="AABBCCDDEEFF">...</device></device-data>`,
existingDevice: &models.ServiceDeviceInfo{DeviceID: "AABBCCDDEEFF"},
expectedStatus: "ok",
expectMigration: true,
},