]> git.basschouten.com Git - openhab-addons.git/blob
485299031bdabb5d0cc65ec1e40cb6545f219a62
[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      * Set the service to which this characteristic belongs
234      */
235     public void setService(BluetoothService service) {
236         this.service = service;
237     }
238
239     /**
240      * Returns a list of descriptors for this characteristic.
241      *
242      */
243     public List<BluetoothDescriptor> getDescriptors() {
244         return new ArrayList<>(gattDescriptors.values());
245     }
246
247     /**
248      * Returns a descriptor with a given UUID out of the list of
249      * descriptors for this characteristic.
250      *
251      * @return the {@link BluetoothDescriptor}
252      */
253     public @Nullable BluetoothDescriptor getDescriptor(UUID uuid) {
254         return gattDescriptors.get(uuid);
255     }
256
257     @Override
258     public int hashCode() {
259         BluetoothService btService = service;
260         final int prime = 31;
261         int result = 1;
262         result = prime * result + instance;
263         result = prime * result + ((btService == null) ? 0 : btService.hashCode());
264         result = prime * result + uuid.hashCode();
265         return result;
266     }
267
268     @Override
269     public boolean equals(@Nullable Object obj) {
270         if (this == obj) {
271             return true;
272         }
273         if (obj == null) {
274             return false;
275         }
276         if (getClass() != obj.getClass()) {
277             return false;
278         }
279         BluetoothCharacteristic other = (BluetoothCharacteristic) obj;
280         if (instance != other.instance) {
281             return false;
282         }
283         BluetoothService btService = service;
284         if (btService == null) {
285             if (other.service != null) {
286                 return false;
287             }
288         } else if (!btService.equals(other.service)) {
289             return false;
290         }
291
292         return uuid.equals(other.uuid);
293     }
294
295     public @Nullable GattCharacteristic getGattCharacteristic() {
296         return GattCharacteristic.getCharacteristic(uuid);
297     }
298
299     public enum GattCharacteristic {
300         // Characteristic
301         ALERT_CATEGORY_ID(0x2A43),
302         ALERT_CATEGORY_ID_BIT_MASK(0x2A42),
303         ALERT_LEVEL(0x2A06),
304         ALERT_NOTIFICATION_CONTROL_POINT(0x2A44),
305         ALERT_STATUS(0x2A3F),
306         APPEARANCE(0x2A01),
307         BATTERY_LEVEL(0x2A19),
308         BLOOD_PRESSURE_FEATURE(0x2A49),
309         BLOOD_PRESSURE_MEASUREMENT(0x2A35),
310         BODY_SENSOR_LOCATION(0x2A38),
311         BOOT_KEYOBARD_INPUT_REPORT(0x2A22),
312         BOOT_KEYOBARD_OUTPUT_REPORT(0x2A32),
313         BOOT_MOUSE_INPUT_REPORT(0x2A33),
314         CSC_FEATURE(0x2A5C),
315         CSC_MEASUREMENT(0x2A5B),
316         CURRENT_TIME(0x2A2B),
317         CYCLING_POWER_CONTROL_POINT(0x2A66),
318         CYCLING_POWER_FEATURE(0x2A65),
319         CYCLING_POWER_MEASUREMENT(0x2A63),
320         CYCLING_POWER_VECTOR(0x2A64),
321         DATE_TIME(0x2A08),
322         DAY_DATE_TIME(0x2A0A),
323         DAY_OF_WEEK(0x2A09),
324         DEVICE_NAME(0x2A00),
325         DST_OFFSET(0x2A0D),
326         EXACT_TIME_256(0x2A0C),
327         FIRMWARE_REVISION_STRING(0x2A26),
328         GLUCOSE_FEATURE(0x2A51),
329         GLUCOSE_MEASUREMENT(0x2A18),
330         GLUCOSE_MEASUREMENT_CONTROL(0x2A34),
331         HARDWARE_REVISION_STRING(0x2A27),
332         HEART_RATE_CONTROL_POINT(0x2A39),
333         HEART_RATE_MEASUREMENT(0x2A37),
334         HID_CONTROL_POINT(0x2A4C),
335         HID_INFORMATION(0x2A4A),
336         IEEE11073_20601_REGULATORY_CERTIFICATION_DATA_LIST(0x2A2A),
337         INTERMEDIATE_CUFF_PRESSURE(0x2A36),
338         INTERMEDIATE_TEMPERATURE(0x2A1E),
339         LN_CONTROL_POINT(0x2A6B),
340         LN_FEATURE(0x2A6A),
341         LOCAL_TIME_INFORMATION(0x2A0F),
342         LOCATION_AND_SPEED(0x2A67),
343         MANUFACTURER_NAME_STRING(0x2A29),
344         MEASUREMENT_INTERVAL(0x2A21),
345         MODEL_NUMBER_STRING(0x2A24),
346         NAVIGATION(0x2A68),
347         NEW_ALERT(0x2A46),
348         PERIPERAL_PREFFERED_CONNECTION_PARAMETERS(0x2A04),
349         PERIPHERAL_PRIVACY_FLAG(0x2A02),
350         PN_PID(0x2A50),
351         POSITION_QUALITY(0x2A69),
352         PROTOCOL_MODE(0x2A4E),
353         RECONNECTION_ADDRESS(0x2A03),
354         RECORD_ACCESS_CONTROL_POINT(0x2A52),
355         REFERENCE_TIME_INFORMATION(0x2A14),
356         REPORT(0x2A4D),
357         REPORT_MAP(0x2A4B),
358         RINGER_CONTROL_POINT(0x2A40),
359         RINGER_SETTING(0x2A41),
360         RSC_FEATURE(0x2A54),
361         RSC_MEASUREMENT(0x2A53),
362         SC_CONTROL_POINT(0x2A55),
363         SCAN_INTERVAL_WINDOW(0x2A4F),
364         SCAN_REFRESH(0x2A31),
365         SENSOR_LOCATION(0x2A5D),
366         SERIAL_NUMBER_STRING(0x2A25),
367         SERVICE_CHANGED(0x2A05),
368         SOFTWARE_REVISION_STRING(0x2A28),
369         SUPPORTED_NEW_ALERT_CATEGORY(0x2A47),
370         SUPPORTED_UNREAD_ALERT_CATEGORY(0x2A48),
371         SYSTEM_ID(0x2A23),
372         TEMPERATURE_MEASUREMENT(0x2A1C),
373         TEMPERATURE_TYPE(0x2A1D),
374         TIME_ACCURACY(0x2A12),
375         TIME_SOURCE(0x2A13),
376         TIME_UPDATE_CONTROL_POINT(0x2A16),
377         TIME_UPDATE_STATE(0x2A17),
378         TIME_WITH_DST(0x2A11),
379         TIME_ZONE(0x2A0E),
380         TX_POWER_LEVEL(0x2A07),
381         UNREAD_ALERT_STATUS(0x2A45),
382         AGGREGATE_INPUT(0x2A5A),
383         ANALOG_INPUT(0x2A58),
384         ANALOG_OUTPUT(0x2A59),
385         DIGITAL_INPUT(0x2A56),
386         DIGITAL_OUTPUT(0x2A57),
387         EXACT_TIME_100(0x2A0B),
388         NETWORK_AVAILABILITY(0x2A3E),
389         SCIENTIFIC_TEMPERATURE_IN_CELSIUS(0x2A3C),
390         SECONDARY_TIME_ZONE(0x2A10),
391         STRING(0x2A3D),
392         TEMPERATURE_IN_CELSIUS(0x2A1F),
393         TEMPERATURE_IN_FAHRENHEIT(0x2A20),
394         TIME_BROADCAST(0x2A15),
395         BATTERY_LEVEL_STATE(0x2A1B),
396         BATTERY_POWER_STATE(0x2A1A),
397         PULSE_OXIMETRY_CONTINUOUS_MEASUREMENT(0x2A5F),
398         PULSE_OXIMETRY_CONTROL_POINT(0x2A62),
399         PULSE_OXIMETRY_FEATURES(0x2A61),
400         PULSE_OXIMETRY_PULSATILE_EVENT(0x2A60),
401         PULSE_OXIMETRY_SPOT_CHECK_MEASUREMENT(0x2A5E),
402         RECORD_ACCESS_CONTROL_POINT_TESTVERSION(0x2A52),
403         REMOVABLE(0x2A3A),
404         SERVICE_REQUIRED(0x2A3B);
405
406         private static @Nullable Map<UUID, GattCharacteristic> uuidToServiceMapping;
407
408         private UUID uuid;
409
410         private GattCharacteristic(long key) {
411             this.uuid = BluetoothBindingConstants.createBluetoothUUID(key);
412         }
413
414         public static @Nullable GattCharacteristic getCharacteristic(UUID uuid) {
415             Map<UUID, GattCharacteristic> localServiceMapping = uuidToServiceMapping;
416             if (localServiceMapping == null) {
417                 localServiceMapping = new HashMap<>();
418                 for (GattCharacteristic s : values()) {
419                     localServiceMapping.put(s.uuid, s);
420                 }
421                 uuidToServiceMapping = localServiceMapping;
422             }
423             return localServiceMapping.get(uuid);
424         }
425
426         /**
427          * @return the key
428          */
429         public UUID getUUID() {
430             return uuid;
431         }
432     }
433 }