]> git.basschouten.com Git - openhab-addons.git/blob
a0620334014a69321ccca339e47b741bb83a92e8
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.bluetooth;
14
15 import java.util.ArrayList;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.UUID;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23
24 /**
25  * The {@link BluetoothCharacteristic} class defines the Bluetooth characteristic.
26  * <p>
27  * Characteristics are defined attribute types that contain a single logical value.
28  * <p>
29  * https://www.bluetooth.com/specifications/gatt/characteristics
30  *
31  * @author Chris Jackson - Initial contribution
32  * @author Kai Kreuzer - Cleaned up code
33  * @author Peter Rosenberg - Improve properties support
34  */
35 @NonNullByDefault
36 public class BluetoothCharacteristic {
37     public static final int PROPERTY_BROADCAST = 0x01;
38     public static final int PROPERTY_READ = 0x02;
39     public static final int PROPERTY_WRITE_NO_RESPONSE = 0x04;
40     public static final int PROPERTY_WRITE = 0x08;
41     public static final int PROPERTY_NOTIFY = 0x10;
42     public static final int PROPERTY_INDICATE = 0x20;
43     public static final int PROPERTY_SIGNED_WRITE = 0x40;
44     public static final int PROPERTY_EXTENDED_PROPS = 0x80;
45
46     public static final int PERMISSION_READ = 0x01;
47     public static final int PERMISSION_READ_ENCRYPTED = 0x02;
48     public static final int PERMISSION_READ_ENCRYPTED_MITM = 0x04;
49     public static final int PERMISSION_WRITE = 0x10;
50     public static final int PERMISSION_WRITE_ENCRYPTED = 0x20;
51     public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 0x40;
52     public static final int PERMISSION_WRITE_SIGNED = 0x80;
53     public static final int PERMISSION_WRITE_SIGNED_MITM = 0x100;
54
55     public static final int WRITE_TYPE_DEFAULT = 0x02;
56     public static final int WRITE_TYPE_NO_RESPONSE = 0x01;
57     public static final int WRITE_TYPE_SIGNED = 0x04;
58
59     /**
60      * The {@link UUID} for this characteristic
61      */
62     protected UUID uuid;
63
64     /**
65      * The handle for this characteristic
66      */
67     protected int handle;
68
69     /**
70      * A map of {@link BluetoothDescriptor}s applicable to this characteristic
71      */
72     protected Map<UUID, BluetoothDescriptor> gattDescriptors = new HashMap<>();
73     protected int instance;
74     protected int properties;
75     protected int permissions;
76     protected int writeType;
77
78     /**
79      * The {@link BluetoothService} to which this characteristic belongs
80      */
81     protected @Nullable BluetoothService service;
82
83     /**
84      * Create a new BluetoothCharacteristic.
85      *
86      * @param uuid the {@link UUID} of the new characteristic
87      * @param handle
88      */
89     public BluetoothCharacteristic(UUID uuid, int handle) {
90         this.uuid = uuid;
91         this.handle = handle;
92     }
93
94     /**
95      * Adds a descriptor to this characteristic.
96      *
97      * @param descriptor {@link BluetoothDescriptor} to be added to this characteristic.
98      * @return true, if the descriptor was added to the characteristic
99      */
100     public boolean addDescriptor(BluetoothDescriptor descriptor) {
101         if (gattDescriptors.get(descriptor.getUuid()) != null) {
102             return false;
103         }
104
105         gattDescriptors.put(descriptor.getUuid(), descriptor);
106         return true;
107     }
108
109     /**
110      * Returns the {@link UUID} of this characteristic
111      *
112      * @return UUID of this characteristic
113      */
114     public UUID getUuid() {
115         return uuid;
116     }
117
118     /**
119      * Returns the instance ID for this characteristic.
120      *
121      * If a remote device offers multiple characteristics with the same UUID, the instance ID is used to distinguish
122      * between characteristics.
123      *
124      * @return Instance ID of this characteristic
125      */
126     public int getInstanceId() {
127         return instance;
128     }
129
130     /**
131      * Set the raw properties. The individual properties are represented as bits inside
132      * of this int value.
133      *
134      * @param properties of this Characteristic
135      */
136     public void setProperties(int properties) {
137         this.properties = properties;
138     }
139
140     /**
141      * Returns the properties of this characteristic.
142      *
143      * The properties contain a bit mask of property flags indicating the features of this characteristic.
144      *
145      */
146     public int getProperties() {
147         return properties;
148     }
149
150     /**
151      * Returns if the given characteristics property is enabled or not.
152      *
153      * @param property one of the Constants BluetoothCharacteristic.PROPERTY_XX
154      * @return true if this characteristic has the given property enabled, false if properties not set or
155      *         the given property is not enabled.
156      */
157     public boolean hasPropertyEnabled(int property) {
158         return (properties & property) != 0;
159     }
160
161     /**
162      * Returns if notifications can be enabled on this characteristic.
163      *
164      * @return true if notifications can be enabled, false if notifications are not supported, characteristic is missing
165      *         on device or notifications are not supported.
166      */
167     public boolean canNotify() {
168         return hasPropertyEnabled(BluetoothCharacteristic.PROPERTY_NOTIFY);
169     }
170
171     /**
172      * Returns if the value can be read on this characteristic.
173      *
174      * @return true if the value can be read, false otherwise.
175      */
176     public boolean canRead() {
177         return hasPropertyEnabled(BluetoothCharacteristic.PROPERTY_READ);
178     }
179
180     /**
181      * Returns if the value can be written on this characteristic.
182      *
183      * @return true if the value can be written with of without a response, false otherwise.
184      */
185     public boolean canWrite() {
186         return hasPropertyEnabled(BluetoothCharacteristic.PROPERTY_WRITE)
187                 || hasPropertyEnabled(BluetoothCharacteristic.PROPERTY_WRITE_NO_RESPONSE);
188     }
189
190     /**
191      * Returns the permissions for this characteristic.
192      */
193     public int getPermissions() {
194         return permissions;
195     }
196
197     /**
198      * Gets the write type for this characteristic.
199      *
200      */
201     public int getWriteType() {
202         return writeType;
203     }
204
205     /**
206      * Set the write type for this characteristic
207      *
208      * @param writeType
209      */
210     public void setWriteType(int writeType) {
211         this.writeType = writeType;
212     }
213
214     /**
215      * Get the service to which this characteristic belongs
216      *
217      * @return the {@link BluetoothService}
218      */
219     public @Nullable BluetoothService getService() {
220         return service;
221     }
222
223     /**
224      * Returns the handle for this characteristic
225      *
226      * @return the handle for the characteristic
227      */
228     public int getHandle() {
229         return handle;
230     }
231
232     /**
233      * Get the service to which this characteristic belongs
234      *
235      * @return the {@link BluetoothService}
236      */
237     public void setService(BluetoothService service) {
238         this.service = service;
239     }
240
241     /**
242      * Returns a list of descriptors for this characteristic.
243      *
244      */
245     public List<BluetoothDescriptor> getDescriptors() {
246         return new ArrayList<>(gattDescriptors.values());
247     }
248
249     /**
250      * Returns a descriptor with a given UUID out of the list of
251      * descriptors for this characteristic.
252      *
253      * @return the {@link BluetoothDescriptor}
254      */
255     public @Nullable BluetoothDescriptor getDescriptor(UUID uuid) {
256         return gattDescriptors.get(uuid);
257     }
258
259     @Override
260     public int hashCode() {
261         BluetoothService btService = service;
262         final int prime = 31;
263         int result = 1;
264         result = prime * result + instance;
265         result = prime * result + ((btService == null) ? 0 : btService.hashCode());
266         result = prime * result + uuid.hashCode();
267         return result;
268     }
269
270     @Override
271     public boolean equals(@Nullable Object obj) {
272         if (this == obj) {
273             return true;
274         }
275         if (obj == null) {
276             return false;
277         }
278         if (getClass() != obj.getClass()) {
279             return false;
280         }
281         BluetoothCharacteristic other = (BluetoothCharacteristic) obj;
282         if (instance != other.instance) {
283             return false;
284         }
285         BluetoothService btService = service;
286         if (btService == null) {
287             if (other.service != null) {
288                 return false;
289             }
290         } else if (!btService.equals(other.service)) {
291             return false;
292         }
293
294         return uuid.equals(other.uuid);
295     }
296
297     public @Nullable GattCharacteristic getGattCharacteristic() {
298         return GattCharacteristic.getCharacteristic(uuid);
299     }
300
301     public enum GattCharacteristic {
302         // Characteristic
303         ALERT_CATEGORY_ID(0x2A43),
304         ALERT_CATEGORY_ID_BIT_MASK(0x2A42),
305         ALERT_LEVEL(0x2A06),
306         ALERT_NOTIFICATION_CONTROL_POINT(0x2A44),
307         ALERT_STATUS(0x2A3F),
308         APPEARANCE(0x2A01),
309         BATTERY_LEVEL(0x2A19),
310         BLOOD_PRESSURE_FEATURE(0x2A49),
311         BLOOD_PRESSURE_MEASUREMENT(0x2A35),
312         BODY_SENSOR_LOCATION(0x2A38),
313         BOOT_KEYOBARD_INPUT_REPORT(0x2A22),
314         BOOT_KEYOBARD_OUTPUT_REPORT(0x2A32),
315         BOOT_MOUSE_INPUT_REPORT(0x2A33),
316         CSC_FEATURE(0x2A5C),
317         CSC_MEASUREMENT(0x2A5B),
318         CURRENT_TIME(0x2A2B),
319         CYCLING_POWER_CONTROL_POINT(0x2A66),
320         CYCLING_POWER_FEATURE(0x2A65),
321         CYCLING_POWER_MEASUREMENT(0x2A63),
322         CYCLING_POWER_VECTOR(0x2A64),
323         DATE_TIME(0x2A08),
324         DAY_DATE_TIME(0x2A0A),
325         DAY_OF_WEEK(0x2A09),
326         DEVICE_NAME(0x2A00),
327         DST_OFFSET(0x2A0D),
328         EXACT_TIME_256(0x2A0C),
329         FIRMWARE_REVISION_STRING(0x2A26),
330         GLUCOSE_FEATURE(0x2A51),
331         GLUCOSE_MEASUREMENT(0x2A18),
332         GLUCOSE_MEASUREMENT_CONTROL(0x2A34),
333         HARDWARE_REVISION_STRING(0x2A27),
334         HEART_RATE_CONTROL_POINT(0x2A39),
335         HEART_RATE_MEASUREMENT(0x2A37),
336         HID_CONTROL_POINT(0x2A4C),
337         HID_INFORMATION(0x2A4A),
338         IEEE11073_20601_REGULATORY_CERTIFICATION_DATA_LIST(0x2A2A),
339         INTERMEDIATE_CUFF_PRESSURE(0x2A36),
340         INTERMEDIATE_TEMPERATURE(0x2A1E),
341         LN_CONTROL_POINT(0x2A6B),
342         LN_FEATURE(0x2A6A),
343         LOCAL_TIME_INFORMATION(0x2A0F),
344         LOCATION_AND_SPEED(0x2A67),
345         MANUFACTURER_NAME_STRING(0x2A29),
346         MEASUREMENT_INTERVAL(0x2A21),
347         MODEL_NUMBER_STRING(0x2A24),
348         NAVIGATION(0x2A68),
349         NEW_ALERT(0x2A46),
350         PERIPERAL_PREFFERED_CONNECTION_PARAMETERS(0x2A04),
351         PERIPHERAL_PRIVACY_FLAG(0x2A02),
352         PN_PID(0x2A50),
353         POSITION_QUALITY(0x2A69),
354         PROTOCOL_MODE(0x2A4E),
355         RECONNECTION_ADDRESS(0x2A03),
356         RECORD_ACCESS_CONTROL_POINT(0x2A52),
357         REFERENCE_TIME_INFORMATION(0x2A14),
358         REPORT(0x2A4D),
359         REPORT_MAP(0x2A4B),
360         RINGER_CONTROL_POINT(0x2A40),
361         RINGER_SETTING(0x2A41),
362         RSC_FEATURE(0x2A54),
363         RSC_MEASUREMENT(0x2A53),
364         SC_CONTROL_POINT(0x2A55),
365         SCAN_INTERVAL_WINDOW(0x2A4F),
366         SCAN_REFRESH(0x2A31),
367         SENSOR_LOCATION(0x2A5D),
368         SERIAL_NUMBER_STRING(0x2A25),
369         SERVICE_CHANGED(0x2A05),
370         SOFTWARE_REVISION_STRING(0x2A28),
371         SUPPORTED_NEW_ALERT_CATEGORY(0x2A47),
372         SUPPORTED_UNREAD_ALERT_CATEGORY(0x2A48),
373         SYSTEM_ID(0x2A23),
374         TEMPERATURE_MEASUREMENT(0x2A1C),
375         TEMPERATURE_TYPE(0x2A1D),
376         TIME_ACCURACY(0x2A12),
377         TIME_SOURCE(0x2A13),
378         TIME_UPDATE_CONTROL_POINT(0x2A16),
379         TIME_UPDATE_STATE(0x2A17),
380         TIME_WITH_DST(0x2A11),
381         TIME_ZONE(0x2A0E),
382         TX_POWER_LEVEL(0x2A07),
383         UNREAD_ALERT_STATUS(0x2A45),
384         AGGREGATE_INPUT(0x2A5A),
385         ANALOG_INPUT(0x2A58),
386         ANALOG_OUTPUT(0x2A59),
387         DIGITAL_INPUT(0x2A56),
388         DIGITAL_OUTPUT(0x2A57),
389         EXACT_TIME_100(0x2A0B),
390         NETWORK_AVAILABILITY(0x2A3E),
391         SCIENTIFIC_TEMPERATURE_IN_CELSIUS(0x2A3C),
392         SECONDARY_TIME_ZONE(0x2A10),
393         STRING(0x2A3D),
394         TEMPERATURE_IN_CELSIUS(0x2A1F),
395         TEMPERATURE_IN_FAHRENHEIT(0x2A20),
396         TIME_BROADCAST(0x2A15),
397         BATTERY_LEVEL_STATE(0x2A1B),
398         BATTERY_POWER_STATE(0x2A1A),
399         PULSE_OXIMETRY_CONTINUOUS_MEASUREMENT(0x2A5F),
400         PULSE_OXIMETRY_CONTROL_POINT(0x2A62),
401         PULSE_OXIMETRY_FEATURES(0x2A61),
402         PULSE_OXIMETRY_PULSATILE_EVENT(0x2A60),
403         PULSE_OXIMETRY_SPOT_CHECK_MEASUREMENT(0x2A5E),
404         RECORD_ACCESS_CONTROL_POINT_TESTVERSION(0x2A52),
405         REMOVABLE(0x2A3A),
406         SERVICE_REQUIRED(0x2A3B);
407
408         private static @Nullable Map<UUID, GattCharacteristic> uuidToServiceMapping;
409
410         private UUID uuid;
411
412         private GattCharacteristic(long key) {
413             this.uuid = BluetoothBindingConstants.createBluetoothUUID(key);
414         }
415
416         public static @Nullable GattCharacteristic getCharacteristic(UUID uuid) {
417             Map<UUID, GattCharacteristic> localServiceMapping = uuidToServiceMapping;
418             if (localServiceMapping == null) {
419                 localServiceMapping = new HashMap<>();
420                 for (GattCharacteristic s : values()) {
421                     localServiceMapping.put(s.uuid, s);
422                 }
423                 uuidToServiceMapping = localServiceMapping;
424             }
425             return localServiceMapping.get(uuid);
426         }
427
428         /**
429          * @return the key
430          */
431         public UUID getUUID() {
432             return uuid;
433         }
434     }
435 }