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