Fix BlueZ GATT server registration and OBD-II mode 03/04 parsing
Add @dbus_property(PropertyAccess.READ) to GattServiceIface, GattCharacteristicIface, and GattDescriptorIface so BlueZ can validate objects via the standard Properties interface — fixes "No valid service object found" error on RegisterApplication. Also fix ELM327 emulator rejecting 2-char OBD commands (mode 03 for DTCs and mode 04 for clear) by padding to 4 chars.
This commit is contained in:
parent
d0f0565e62
commit
5dc5f640c7
@ -24,7 +24,7 @@ from typing import Any
|
||||
|
||||
from dbus_fast import BusType, Message, MessageType, Variant
|
||||
from dbus_fast.aio import MessageBus
|
||||
from dbus_fast.service import ServiceInterface, dbus_property, method
|
||||
from dbus_fast.service import PropertyAccess, ServiceInterface, dbus_property, method
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -130,11 +130,22 @@ class GattApplication(ServiceInterface):
|
||||
class GattServiceIface(ServiceInterface):
|
||||
"""org.bluez.GattService1 — exported at each service path.
|
||||
|
||||
No D-Bus methods; properties served via GetManagedObjects only.
|
||||
Properties must be exposed via @dbus_property so BlueZ can validate
|
||||
the service object through the standard Properties interface.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, uuid: str, primary: bool):
|
||||
super().__init__("org.bluez.GattService1")
|
||||
self._uuid = uuid
|
||||
self._primary = primary
|
||||
|
||||
@dbus_property(PropertyAccess.READ)
|
||||
def UUID(self) -> "s": # noqa: F821
|
||||
return self._uuid
|
||||
|
||||
@dbus_property(PropertyAccess.READ)
|
||||
def Primary(self) -> "b": # noqa: F821
|
||||
return self._primary
|
||||
|
||||
|
||||
class GattCharacteristicIface(ServiceInterface):
|
||||
@ -142,6 +153,7 @@ class GattCharacteristicIface(ServiceInterface):
|
||||
|
||||
ReadValue returns the stored value. WriteValue stores the value AND
|
||||
records a WriteEvent for LLM polling (like agent.py's pending_requests).
|
||||
Properties exposed via @dbus_property for BlueZ introspection.
|
||||
"""
|
||||
|
||||
def __init__(self, char: ServerCharacteristic, manager: "GattServerManager"):
|
||||
@ -149,6 +161,18 @@ class GattCharacteristicIface(ServiceInterface):
|
||||
self._char = char
|
||||
self._manager = manager
|
||||
|
||||
@dbus_property(PropertyAccess.READ)
|
||||
def UUID(self) -> "s": # noqa: F821
|
||||
return self._char.uuid
|
||||
|
||||
@dbus_property(PropertyAccess.READ)
|
||||
def Service(self) -> "o": # noqa: F821
|
||||
return f"{APP_BASE_PATH}/{self._char.service_id}"
|
||||
|
||||
@dbus_property(PropertyAccess.READ)
|
||||
def Flags(self) -> "as": # noqa: F821
|
||||
return self._char.flags
|
||||
|
||||
@method()
|
||||
def ReadValue(self, options: "a{sv}") -> "ay": # noqa: F821
|
||||
offset = 0
|
||||
@ -189,12 +213,27 @@ class GattCharacteristicIface(ServiceInterface):
|
||||
|
||||
|
||||
class GattDescriptorIface(ServiceInterface):
|
||||
"""org.bluez.GattDescriptor1 — handles reads/writes on descriptors."""
|
||||
"""org.bluez.GattDescriptor1 — handles reads/writes on descriptors.
|
||||
|
||||
Properties exposed via @dbus_property for BlueZ introspection.
|
||||
"""
|
||||
|
||||
def __init__(self, desc: ServerDescriptor):
|
||||
super().__init__("org.bluez.GattDescriptor1")
|
||||
self._desc = desc
|
||||
|
||||
@dbus_property(PropertyAccess.READ)
|
||||
def UUID(self) -> "s": # noqa: F821
|
||||
return self._desc.uuid
|
||||
|
||||
@dbus_property(PropertyAccess.READ)
|
||||
def Characteristic(self) -> "o": # noqa: F821
|
||||
return f"{APP_BASE_PATH}/{self._desc.char_id}"
|
||||
|
||||
@dbus_property(PropertyAccess.READ)
|
||||
def Flags(self) -> "as": # noqa: F821
|
||||
return self._desc.flags
|
||||
|
||||
@method()
|
||||
def ReadValue(self, options: "a{sv}") -> "ay": # noqa: F821
|
||||
offset = 0
|
||||
@ -226,15 +265,15 @@ class LEAdvertisementIface(ServiceInterface):
|
||||
def Release(self) -> None:
|
||||
log.info("GATT server: advertisement released by BlueZ")
|
||||
|
||||
@dbus_property()
|
||||
@dbus_property(PropertyAccess.READ)
|
||||
def Type(self) -> "s": # noqa: F821
|
||||
return self._type
|
||||
|
||||
@dbus_property()
|
||||
@dbus_property(PropertyAccess.READ)
|
||||
def LocalName(self) -> "s": # noqa: F821
|
||||
return self._local_name
|
||||
|
||||
@dbus_property()
|
||||
@dbus_property(PropertyAccess.READ)
|
||||
def ServiceUUIDs(self) -> "as": # noqa: F821
|
||||
return self._service_uuids
|
||||
|
||||
@ -277,7 +316,7 @@ class GattServerManager:
|
||||
uuid=uuid,
|
||||
primary=primary,
|
||||
)
|
||||
svc.dbus_obj = GattServiceIface()
|
||||
svc.dbus_obj = GattServiceIface(uuid, primary)
|
||||
self._services[service_id] = svc
|
||||
|
||||
log.info("GATT server: added service %s (UUID=%s)", service_id, uuid)
|
||||
|
||||
@ -231,7 +231,10 @@ class ELM327Emulator:
|
||||
cr = "\r\n" if self.linefeed else "\r"
|
||||
cmd = cmd.replace(" ", "")
|
||||
|
||||
if len(cmd) < 4:
|
||||
# Modes 03/04 don't require a PID — pad to 4 chars
|
||||
if len(cmd) == 2:
|
||||
cmd += "00"
|
||||
elif len(cmd) < 4:
|
||||
return f"?{cr}{cr}>"
|
||||
|
||||
try:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user