-
Notifications
You must be signed in to change notification settings - Fork 115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Passing a 'flags' dictionary to 'write_value' in GATT.py ends in exception #413
Comments
Do you have a minimal reproducible example piece of code I could use for testing? Looking at this now, it doesn't seem to be well documented in the library, but shouldn't it be something like: write_value(b'\x02\x00...', {'type': 'command'}) |
I don't have a minimal example yet. Will try to come up with it..
And it seems that dbus.Array() loses the values of the dictionary.
|
I agree with you. It looks like it should be: dbus.Dictionary({'type': 'command'}, signature=dbus.Signature('sv')) I've looked through the test cases in Bluezero and there doesn't seem to be anything that tests this. Are you able to take a look on your setup as to what works? |
Minimal example to catch exception: from bluezero import adapter, central, constants, peripheral
dongle = next(adapter.Adapter.available())
dongle.nearby_discovery()
device_addr = 'SOME_ADDR'
service_uuid = 'SOME_SERV_UUI'
write_uuid = 'SOME_WRITE_UUI'
monitor = central.Central(device_addr=device_addr)
monitor.connect()
write_char = monitor.add_characteristic(service_uuid, write_uuid)
monitor.load_gatt()
write_char.write_value(b'asdad', flags={'type': 'command'}) Changing |
I've spent a little time on this issue and considering how this should look and fit with the API complexity goals of Bluezero I'm not sure I'm happy for this to be a final solution, but to give visibility of what I've tried. I created a little script to exercise some different values using a Micro:Bit I had laying around. from random import randint
import dbus
from bluezero import central
ubit_addr = 'E1:4B:6C:22:56:F0'
temperature_srvc = 'e95d6100-251d-470a-a062-fa1922dfa9a8'
temperature_period = 'e95d1b25-251d-470a-a062-fa1922dfa9a8'
def get_rand_period():
rand_value = randint(1000, 1500)
return int(rand_value).to_bytes(2, byteorder='little', signed=False)
ubit = central.Central(device_addr=ubit_addr)
rw_char = ubit.add_characteristic(temperature_srvc, temperature_period)
ubit.connect()
test_write_options = [
None,
{},
{'type': 'request', 'offset': 0},
{'type': dbus.String('request'), 'offset': dbus.UInt16(0)},
]
print('Test write flags:')
for flags in test_write_options:
period_rand = get_rand_period()
print(f"\twriting {int.from_bytes(period_rand, byteorder='little', signed=False)} with {flags}")
rw_char.write_value(period_rand, flags=flags)
test_read_options = [
None,
{},
{'offset': 0},
{'offset': dbus.UInt16(0)}
]
print("Test read flags")
for flags in test_read_options:
result = rw_char.read_raw_value(flags=flags)
print(f"\tRead value: {int.from_bytes(result, byteorder='little', signed=False)} with {flags}")
ubit.disconnect()
And then changed the functions in GATT.py to be consistent with this: def read_raw_value(self, flags=None):
"""
Return this characteristic's value (if allowed).
:param flags: "offset": Start offset
"device": Device path (Server only)
:return:
Possible Errors: org.bluez.Error.Failed
org.bluez.Error.InProgress
org.bluez.Error.NotPermitted
org.bluez.Error.InvalidValueLength
org.bluez.Error.NotAuthorized
org.bluez.Error.NotSupported
"""
_flags = {}
if flags is None:
flags = {}
else:
for k, v in flags.items():
if k in ['offset', 'mtu']:
_flags[k] = dbus.UInt16(v)
if k == 'device':
_flags[k] = dbus.ObjectPath(v)
try:
return self.characteristic_methods.ReadValue(dbus.Dictionary(_flags))
except AttributeError:
logger.error('Service: %s with Characteristic: %s not defined on '
'device: %s', self.srv_uuid, self.chrc_uuid,
self.device_addr)
return [] def write_value(self, value, flags=None):
"""
Write a new value to the characteristic.
:param value: A list of byte values
:param flags: Optional dictionary.
Typically empty. Values defined at:
https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/gatt-api.txt
"""
_flags = {}
if flags is None:
_flags = {}
else:
for k, v in flags.items():
if k in ['offset', 'mtu']:
_flags[k] = dbus.UInt16(v)
if k == ['type', 'link']:
_flags[k] = dbus.String(v)
if k == 'device':
_flags[k] = dbus.ObjectPath(v)
try:
self.characteristic_methods.WriteValue(value, dbus.Dictionary(_flags))
except AttributeError:
logger.error('Service: %s with Characteristic: %s not defined '
'on device: %s. Cannot write_value', self.srv_uuid,
self.chrc_uuid, self.device_addr) I have not looked at what would be required for localGATT.py Example oputput from test run:
|
Thank you for the investigation! So you would feel reluctant introducing this change? Another approach that would satisfy my needs would be to pass the same |
I'm reluctant to make it a permanent change to the API at this time without getting more feedback on it.
Values for I guess there are two different needs here.
|
Could I possibly provide more feedback/testing? And please disregard my suggestion about |
Absolutely! I'm pushed the changes to GATT.py to the read_write_options branch. The feedback I'm interested in:
|
I think the following |
Added fix with 86afd98 |
Thanks for the fixes!
Since in my experience passing anything to 'flags' on main branch leads to an exception, I'd assume every existing user of the library is not passing anything to 'flags'. |
python-bluezero/bluezero/GATT.py
Line 204 in e120285
Passing any flags specified in https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/org.bluez.GattCharacteristic.rst to 'write_value' in GATT.py as a python dictionary leads to an exception:
The text was updated successfully, but these errors were encountered: