-
-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Example code for a GattServer #63
Comments
Providing a Gatt-Server is not really straight forward using bluez and dbus. package com.github.hypfvieh.sandbox.bluez;
import org.bluez.GattCharacteristic1;
import org.bluez.GattDescriptor1;
import org.bluez.GattManager1;
import org.bluez.GattService1;
import org.bluez.datatypes.TwoTuple;
import org.bluez.exceptions.*;
import org.freedesktop.dbus.DBusPath;
import org.freedesktop.dbus.FileDescriptor;
import org.freedesktop.dbus.connections.impl.DBusConnection;
import org.freedesktop.dbus.connections.impl.DBusConnectionBuilder;
import org.freedesktop.dbus.interfaces.DBusInterface;
import org.freedesktop.dbus.interfaces.Properties;
import org.freedesktop.dbus.types.UInt16;
import org.freedesktop.dbus.types.Variant;
import java.util.*;
public class GattExample {
static final String FLAG_READ = "read";
static final String FLAG_WRITE = "write";
public static void main(String[] args) {
MyGattApplication myGattApplication = new MyGattApplication();
SampleService sampleService = new SampleService();
SampleCharacteristics sampleCharacteristics = new SampleCharacteristics(sampleService);
SampleGattDescriptor sampleDescriptor = new SampleGattDescriptor(sampleCharacteristics);
sampleCharacteristics.getDescriptors().add(sampleDescriptor);
myGattApplication.addService(sampleService);
sampleService.getCharacteristics().add(sampleCharacteristics);
try (DBusConnection dbus = DBusConnectionBuilder.forSystemBus().build()) {
dbus.exportObject(myGattApplication);
GattManager1 gattMgr = dbus.getRemoteObject("org.bluez", "/org/bluez/hci0", GattManager1.class);
Map<String, Variant<?>> opts = new HashMap<>();
gattMgr.RegisterApplication(new DBusPath(myGattApplication.getObjectPath()), opts);
Thread.sleep(50000000L); // do something useful or a proper wait loop
} catch (Exception _ex) {
// TODO Auto-generated catch block
_ex.printStackTrace();
}
}
public static class MyGattApplication implements GattServiceApp {
private final List<SampleService> services = new ArrayList<>();
@Override
public String getObjectPath() {
return "/";
}
public void addService(SampleService _service) {
services.add(_service);
}
@Override
public Map<DBusPath, Map<String, Map<String, Variant<?>>>> GetManagedObjects() {
Map<DBusPath, Map<String, Map<String, Variant<?>>>> result = new LinkedHashMap<>();
for (SampleService svc : services) {
result.put(new DBusPath(svc.getObjectPath()), svc.getProps());
for (SampleCharacteristics chr : svc.getCharacteristics()) {
result.put(new DBusPath(chr.getObjectPath()), chr.getProps());
for (SampleGattDescriptor descriptor : chr.getDescriptors()) {
result.put(new DBusPath(descriptor.getObjectPath()), descriptor.getProps());
}
}
}
return result;
}
}
public static class SampleService implements GattService1, PropertiesHelper {
static final String BASE_PATH = "/mygatt/application/";
// This should be a static value, not a random one
private final String uuid = UUID.randomUUID().toString();
private final Boolean primary = true;
private final List<SampleCharacteristics> characteristics = new ArrayList<>();
public List<SampleCharacteristics> getCharacteristics() {
return characteristics;
}
@Override
public String getObjectPath() {
return BASE_PATH + "service0";
}
public String getUuid() {
return uuid;
}
public boolean isPrimary() {
return primary;
}
@SuppressWarnings("unchecked")
@Override
public Variant<?> Get(String _interfaceName, String _propertyName) {
if (!getBluezInterface().getName().equals(_interfaceName)) {
throw new IllegalArgumentException();
}
if ("UUID".equals(_propertyName)) {
return new Variant<>(uuid);
} else if ("Primary".equals(_propertyName)) {
return new Variant<>(primary);
} else if ("Characteristics".equals(_propertyName)) {
return getCharacteristicsAsVariantArray();
}
return null;
}
@Override
public <A> void Set(String _interfaceName, String _propertyName, A _value) {
throw new UnsupportedOperationException();
}
@Override
public Map<String, Variant<?>> GetAll(String _interfaceName) {
return Map.of("UUID", new Variant<>(uuid),
"Primary", new Variant<>(primary),
"Characteristics", getCharacteristicsAsVariantArray()
);
}
@Override
public Class<? extends DBusInterface> getBluezInterface() {
return GattService1.class;
}
private Variant<List<DBusPath>> getCharacteristicsAsVariantArray() {
List<DBusPath> pathes = new ArrayList<>();
getCharacteristics().stream().map(d -> new DBusPath(d.getObjectPath())).forEach(pathes::add);
return new Variant<>(pathes, "ao");
}
}
public static class SampleCharacteristics implements GattCharacteristic1, PropertiesHelper {
private final String uuid = UUID.randomUUID().toString();
private final SampleService service;
private final List<String> flags = new ArrayList<>();
private final List<SampleGattDescriptor> descriptors = new ArrayList<>();
public SampleCharacteristics(SampleService _service) {
service = _service;
flags.add(FLAG_READ);
}
public String getUuid() {
return uuid;
}
public SampleService getService() {
return service;
}
public List<SampleGattDescriptor> getDescriptors() {
return descriptors;
}
@Override
public Class<? extends DBusInterface> getBluezInterface() {
return GattCharacteristic1.class;
}
@Override
public String getObjectPath() {
return service.getObjectPath() + "/char0";
}
@Override
public byte[] ReadValue(Map<String, Variant<?>> _options)
throws BluezFailedException, BluezInProgressException, BluezNotPermittedException, BluezNotAuthorizedException, BluezInvalidOffsetException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@Override
public void WriteValue(byte[] _value, Map<String, Variant<?>> _options)
throws BluezFailedException, BluezInProgressException, BluezNotPermittedException, BluezInvalidValueLengthException, BluezNotAuthorizedException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@Override
public TwoTuple<FileDescriptor, UInt16> AcquireWrite(Map<String, Variant<?>> _options) throws BluezFailedException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@Override
public TwoTuple<FileDescriptor, UInt16> AcquireNotify(Map<String, Variant<?>> _options) throws BluezFailedException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@Override
public void StartNotify() throws BluezFailedException, BluezNotPermittedException, BluezInProgressException, BluezNotConnectedException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@Override
public void StopNotify() throws BluezFailedException {
throw new UnsupportedOperationException("Implement if needed");
}
@Override
public void Confirm() throws BluezFailedException {
throw new UnsupportedOperationException("Implement if needed");
}
@SuppressWarnings("unchecked")
@Override
public Variant<?> Get(String _interfaceName, String _propertyName) {
if (!getBluezInterface().getName().equals(_interfaceName)) {
throw new IllegalArgumentException();
}
if ("UUID".equals(_propertyName)) {
return new Variant<>(uuid);
} else if ("Service".equals(_propertyName)) {
return new Variant<>(new DBusPath(service.getObjectPath()));
} else if ("Descriptors".equals(_propertyName)) {
return getDescriptorsAsVariantArray();
} else if ("Flags".equals(_propertyName)) {
return new Variant<>(flags, "as");
}
return null;
}
@Override
public <A> void Set(String _interfaceName, String _propertyName, A _value) {
throw new UnsupportedOperationException();
}
@Override
public Map<String, Variant<?>> GetAll(String _interfaceName) {
return Map.of("UUID", new Variant<>(uuid),
"Service", new Variant<>(new DBusPath(service.getObjectPath())),
"Descriptors", getDescriptorsAsVariantArray(),
"Flags", new Variant<>(flags, "as"));
}
private Variant<List<DBusPath>> getDescriptorsAsVariantArray() {
List<DBusPath> pathes = new ArrayList<>();
getDescriptors().stream().map(d -> new DBusPath(d.getObjectPath())).forEach(pathes::add);
return new Variant<>(pathes, "ao");
}
}
public static class SampleGattDescriptor implements GattDescriptor1, PropertiesHelper {
private final String uuid = UUID.randomUUID().toString();
private final SampleCharacteristics characteristic;
private final List<String> flags = new ArrayList<>();
public SampleGattDescriptor(SampleCharacteristics _characteristics) {
characteristic = _characteristics;
flags.add(FLAG_READ);
}
public String getUuid() {
return uuid;
}
public SampleCharacteristics getCharacteristic() {
return characteristic;
}
@Override
public Class<? extends DBusInterface> getBluezInterface() {
return GattDescriptor1.class;
}
@Override
public String getObjectPath() {
return characteristic.getObjectPath() + "/desc0";
}
@Override
public byte[] ReadValue(Map<String, Variant<?>> _flags)
throws BluezFailedException, BluezInProgressException, BluezNotPermittedException, BluezNotAuthorizedException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@Override
public void WriteValue(byte[] _value, Map<String, Variant<?>> _flags)
throws BluezFailedException, BluezInProgressException, BluezNotPermittedException, BluezInvalidValueLengthException, BluezNotAuthorizedException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@SuppressWarnings("unchecked")
@Override
public Variant<?> Get(String _interfaceName, String _propertyName) {
if ("UUID".equals(_propertyName)) {
return new Variant<>(uuid);
} else if ("Characteristic ".equals(_propertyName)) {
return new Variant<>(characteristic);
} else if ("Flags".equals(_propertyName)) {
return new Variant<>(flags, "as");
}
return null;
}
@Override
public <A> void Set(String _interfaceName, String _propertyName, A _value) {
throw new UnsupportedOperationException();
}
@Override
public Map<String, Variant<?>> GetAll(String _interfaceName) {
return Map.of("UUID", new Variant<>(uuid),
"Characteristic", new Variant<>(new DBusPath(characteristic.getObjectPath())),
"Flags", new Variant<>(flags, "as"));
}
}
public interface GattServiceApp extends DBusInterface {
Map<DBusPath, Map<String, Map<String, Variant<?>>>> GetManagedObjects();
}
public interface PropertiesHelper extends Properties {
Class<? extends DBusInterface> getBluezInterface();
default Map<String, Map<String, Variant<?>>> getProps() {
Map<String, Map<String, Variant<?>>> result = new LinkedHashMap<>();
result.put(getBluezInterface().getName(), GetAll(null));
return result;
}
}
}
|
Wow, thank you so much for providing this sketch. I guess I will need some time to work through it. This is exactly what I was looking for.
Regards, Markus.
… Am 15.08.2024 um 21:08 schrieb David M. ***@***.***>:
Providing a Gatt-Server is not really straight forward using bluez and dbus.
Without any warranty, here is some sample code, maybe you can start with that. Other samples in Python and C can be found in the bluez.git <https://github.com/bluez/bluez/> Repository (see tools and test directory).
package com.github.hypfvieh.sandbox.bluez;
import org.bluez.GattCharacteristic1;
import org.bluez.GattDescriptor1;
import org.bluez.GattManager1;
import org.bluez.GattService1;
import org.bluez.datatypes.TwoTuple;
import org.bluez.exceptions.*;
import org.freedesktop.dbus.DBusPath;
import org.freedesktop.dbus.FileDescriptor;
import org.freedesktop.dbus.connections.impl.DBusConnection;
import org.freedesktop.dbus.connections.impl.DBusConnectionBuilder;
import org.freedesktop.dbus.interfaces.DBusInterface;
import org.freedesktop.dbus.interfaces.Properties;
import org.freedesktop.dbus.types.UInt16;
import org.freedesktop.dbus.types.Variant;
import java.util.*;
public class GattExample {
static final String FLAG_READ = "read";
static final String FLAG_WRITE = "write";
public static void main(String[] args) {
MyGattApplication myGattApplication = new MyGattApplication();
SampleService sampleService = new SampleService();
SampleCharacteristics sampleCharacteristics = new SampleCharacteristics(sampleService);
SampleGattDescriptor sampleDescriptor = new SampleGattDescriptor(sampleCharacteristics);
sampleCharacteristics.getDescriptors().add(sampleDescriptor);
myGattApplication.addService(sampleService);
sampleService.getCharacteristics().add(sampleCharacteristics);
try (DBusConnection dbus = DBusConnectionBuilder.forSystemBus().build()) {
dbus.exportObject(myGattApplication);
GattManager1 gattMgr = dbus.getRemoteObject("org.bluez", "/org/bluez/hci0", GattManager1.class);
Map<String, Variant<?>> opts = new HashMap<>();
gattMgr.RegisterApplication(new DBusPath(myGattApplication.getObjectPath()), opts);
Thread.sleep(50000000L); // do something useful or a proper wait loop
} catch (Exception _ex) {
// TODO Auto-generated catch block
_ex.printStackTrace();
}
}
public static class MyGattApplication implements GattServiceApp {
private final List<SampleService> services = new ArrayList<>();
@OverRide
public String getObjectPath() {
return "/";
}
public void addService(SampleService _service) {
services.add(_service);
}
@OverRide
public Map<DBusPath, Map<String, Map<String, Variant<?>>>> GetManagedObjects() {
Map<DBusPath, Map<String, Map<String, Variant<?>>>> result = new LinkedHashMap<>();
for (SampleService svc : services) {
result.put(new DBusPath(svc.getObjectPath()), svc.getProps());
for (SampleCharacteristics chr : svc.getCharacteristics()) {
result.put(new DBusPath(chr.getObjectPath()), chr.getProps());
for (SampleGattDescriptor descriptor : chr.getDescriptors()) {
result.put(new DBusPath(descriptor.getObjectPath()), descriptor.getProps());
}
}
}
return result;
}
}
public static class SampleService implements GattService1, PropertiesHelper {
static final String BASE_PATH = "/mygatt/application/";
// This should be a static value, not a random one
private final String uuid = UUID.randomUUID().toString();
private final Boolean primary = true;
private final List<SampleCharacteristics> characteristics = new ArrayList<>();
public List<SampleCharacteristics> getCharacteristics() {
return characteristics;
}
@OverRide
public String getObjectPath() {
return BASE_PATH + "service0";
}
public String getUuid() {
return uuid;
}
public boolean isPrimary() {
return primary;
}
@SuppressWarnings("unchecked")
@OverRide
public Variant<?> Get(String _interfaceName, String _propertyName) {
if (!getBluezInterface().getName().equals(_interfaceName)) {
throw new IllegalArgumentException();
}
if ("UUID".equals(_propertyName)) {
return new Variant<>(uuid);
} else if ("Primary".equals(_propertyName)) {
return new Variant<>(primary);
} else if ("Characteristics".equals(_propertyName)) {
return getCharacteristicsAsVariantArray();
}
return null;
}
@OverRide
public <A> void Set(String _interfaceName, String _propertyName, A _value) {
throw new UnsupportedOperationException();
}
@OverRide
public Map<String, Variant<?>> GetAll(String _interfaceName) {
return Map.of("UUID", new Variant<>(uuid),
"Primary", new Variant<>(primary),
"Characteristics", getCharacteristicsAsVariantArray()
);
}
@OverRide
public Class<? extends DBusInterface> getBluezInterface() {
return GattService1.class;
}
private Variant<List<DBusPath>> getCharacteristicsAsVariantArray() {
List<DBusPath> pathes = new ArrayList<>();
getCharacteristics().stream().map(d -> new DBusPath(d.getObjectPath())).forEach(pathes::add);
return new Variant<>(pathes, "ao");
}
}
public static class SampleCharacteristics implements GattCharacteristic1, PropertiesHelper {
private final String uuid = UUID.randomUUID().toString();
private final SampleService service;
private final List<String> flags = new ArrayList<>();
private final List<SampleGattDescriptor> descriptors = new ArrayList<>();
public SampleCharacteristics(SampleService _service) {
service = _service;
flags.add(FLAG_READ);
}
public String getUuid() {
return uuid;
}
public SampleService getService() {
return service;
}
public List<SampleGattDescriptor> getDescriptors() {
return descriptors;
}
@OverRide
public Class<? extends DBusInterface> getBluezInterface() {
return GattCharacteristic1.class;
}
@OverRide
public String getObjectPath() {
return service.getObjectPath() + "/char0";
}
@OverRide
public byte[] ReadValue(Map<String, Variant<?>> _options)
throws BluezFailedException, BluezInProgressException, BluezNotPermittedException, BluezNotAuthorizedException, BluezInvalidOffsetException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@OverRide
public void WriteValue(byte[] _value, Map<String, Variant<?>> _options)
throws BluezFailedException, BluezInProgressException, BluezNotPermittedException, BluezInvalidValueLengthException, BluezNotAuthorizedException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@OverRide
public TwoTuple<FileDescriptor, UInt16> AcquireWrite(Map<String, Variant<?>> _options) throws BluezFailedException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@OverRide
public TwoTuple<FileDescriptor, UInt16> AcquireNotify(Map<String, Variant<?>> _options) throws BluezFailedException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@OverRide
public void StartNotify() throws BluezFailedException, BluezNotPermittedException, BluezInProgressException, BluezNotConnectedException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@OverRide
public void StopNotify() throws BluezFailedException {
throw new UnsupportedOperationException("Implement if needed");
}
@OverRide
public void Confirm() throws BluezFailedException {
throw new UnsupportedOperationException("Implement if needed");
}
@SuppressWarnings("unchecked")
@OverRide
public Variant<?> Get(String _interfaceName, String _propertyName) {
if (!getBluezInterface().getName().equals(_interfaceName)) {
throw new IllegalArgumentException();
}
if ("UUID".equals(_propertyName)) {
return new Variant<>(uuid);
} else if ("Service".equals(_propertyName)) {
return new Variant<>(new DBusPath(service.getObjectPath()));
} else if ("Descriptors".equals(_propertyName)) {
return getDescriptorsAsVariantArray();
} else if ("Flags".equals(_propertyName)) {
return new Variant<>(flags, "as");
}
return null;
}
@OverRide
public <A> void Set(String _interfaceName, String _propertyName, A _value) {
throw new UnsupportedOperationException();
}
@OverRide
public Map<String, Variant<?>> GetAll(String _interfaceName) {
return Map.of("UUID", new Variant<>(uuid),
"Service", new Variant<>(new DBusPath(service.getObjectPath())),
"Descriptors", getDescriptorsAsVariantArray(),
"Flags", new Variant<>(flags, "as"));
}
private Variant<List<DBusPath>> getDescriptorsAsVariantArray() {
List<DBusPath> pathes = new ArrayList<>();
getDescriptors().stream().map(d -> new DBusPath(d.getObjectPath())).forEach(pathes::add);
return new Variant<>(pathes, "ao");
}
}
public static class SampleGattDescriptor implements GattDescriptor1, PropertiesHelper {
private final String uuid = UUID.randomUUID().toString();
private final SampleCharacteristics characteristic;
private final List<String> flags = new ArrayList<>();
public SampleGattDescriptor(SampleCharacteristics _characteristics) {
characteristic = _characteristics;
flags.add(FLAG_READ);
}
public String getUuid() {
return uuid;
}
public SampleCharacteristics getCharacteristic() {
return characteristic;
}
@OverRide
public Class<? extends DBusInterface> getBluezInterface() {
return GattDescriptor1.class;
}
@OverRide
public String getObjectPath() {
return characteristic.getObjectPath() + "/desc0";
}
@OverRide
public byte[] ReadValue(Map<String, Variant<?>> _flags)
throws BluezFailedException, BluezInProgressException, BluezNotPermittedException, BluezNotAuthorizedException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@OverRide
public void WriteValue(byte[] _value, Map<String, Variant<?>> _flags)
throws BluezFailedException, BluezInProgressException, BluezNotPermittedException, BluezInvalidValueLengthException, BluezNotAuthorizedException, BluezNotSupportedException {
throw new UnsupportedOperationException("Implement if needed");
}
@SuppressWarnings("unchecked")
@OverRide
public Variant<?> Get(String _interfaceName, String _propertyName) {
if ("UUID".equals(_propertyName)) {
return new Variant<>(uuid);
} else if ("Characteristic ".equals(_propertyName)) {
return new Variant<>(characteristic);
} else if ("Flags".equals(_propertyName)) {
return new Variant<>(flags, "as");
}
return null;
}
@OverRide
public <A> void Set(String _interfaceName, String _propertyName, A _value) {
throw new UnsupportedOperationException();
}
@OverRide
public Map<String, Variant<?>> GetAll(String _interfaceName) {
return Map.of("UUID", new Variant<>(uuid),
"Characteristic", new Variant<>(new DBusPath(characteristic.getObjectPath())),
"Flags", new Variant<>(flags, "as"));
}
}
public interface GattServiceApp extends DBusInterface {
Map<DBusPath, Map<String, Map<String, Variant<?>>>> GetManagedObjects();
}
public interface PropertiesHelper extends Properties {
Class<? extends DBusInterface> getBluezInterface();
default Map<String, Map<String, Variant<?>>> getProps() {
Map<String, Map<String, Variant<?>>> result = new LinkedHashMap<>();
result.put(getBluezInterface().getName(), GetAll(null));
return result;
}
}
}
—
Reply to this email directly, view it on GitHub <#63 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAN4OIOD63IMU2IEHXV3ZQDZRT4CJAVCNFSM6AAAAABMR5KBISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEOJSGAYTKMRWGA>.
You are receiving this because you authored the thread.
|
# for free
to join this conversation on GitHub.
Already have an account?
# to comment
Hi,
we are trying to implement Bluetooth as an additional path to control an IoT-Device.
Our current set-up regarding the compute hardware is a Raspberry Pi (may changed later) but will still be Linux ;)
Our functionality is already accessible via REST-calls provided by a micronaut-based Java program.
I struggle in setting-up a GattServer with this library.
I would appreciate it if a simple example code could be provided showing how to provide a read function on a property (incl. advertsing it).
Regards, Markus.
The text was updated successfully, but these errors were encountered: