Fix empty Bluetooth lists in web mixer; advertise it over Bonjour

busctl cannot convert some BlueZ advertisement data (Apple
ManufacturerData, a{qv}) to JSON, so GetManagedObjects failed as soon as
an iPad was paired and the web showed no devices at all. Read only the
needed Device1/Adapter1 properties per object instead. Also publish the
web mixer as an _http._tcp Avahi service.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jsahn
2026-10-12 21:54:38 +09:00
co-authored by Claude Opus 5.5
parent 5e8906b43d
commit 7fa372e801
5 changed files with 63 additions and 8 deletions
+16 -3
View File
@@ -58,13 +58,26 @@ class WebTests(unittest.TestCase):
{'action':'discoverable','on':'yes','seconds':300},{'action':'discoverable','on':True,'seconds':True}]:
with self.subTest(data=data), self.assertRaises(ValueError): w.validate_action(data)
def test_devices_skip_unreadable_and_tolerate_missing_uuids(self):
out={'/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF':'{"type":"s","data":"AA:BB:CC:DD:EE:FF"}\n{"type":"s","data":"QCY"}\n'
'{"type":"b","data":true}\n{"type":"b","data":true}\n{"type":"b","data":false}'}
def command(*args):
if 'tree' in args: return '/org/bluez\n/org/bluez/hci0\n/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF\n/org/bluez/hci0/dev_11_22_33_44_55_66\n'
path=args[5]
if path not in out or 'UUIDs' in args: raise ValueError('No such property')
return out[path]
with patch.object(a,'command',side_effect=command):
self.assertEqual(a.devices(),[{'address':'AA:BB:CC:DD:EE:FF','name':'QCY','bonded':True,'paired':True,
'connected':False,'output':False}])
def test_pairing_state_reports_remaining_only_when_discoverable(self):
adapter={'/org/bluez/hci0':{'org.bluez.Adapter1':{'Discoverable':True,'Alias':'Radxa Audio Bluetooth'}}}
with patch.object(a,'objects',return_value=adapter), patch.object(a,'PAIRING_UNTIL') as until, \
adapter={'Discoverable':True,'Alias':'Radxa Audio Bluetooth'}
with patch.object(a,'bluez_paths',return_value=['/org/bluez/hci0']), \
patch.object(a,'properties',return_value=adapter), patch.object(a,'PAIRING_UNTIL') as until, \
patch.object(a.time,'time',return_value=1000.0):
until.read_text.return_value='1120.0'
self.assertEqual(a.pairing(),{'discoverable':True,'remaining':120,'alias':'Radxa Audio Bluetooth'})
adapter['/org/bluez/hci0']['org.bluez.Adapter1']['Discoverable']=False
adapter['Discoverable']=False
self.assertEqual(a.pairing()['remaining'],0)
def test_dac_selection_is_one_atomic_cli_command(self):