This repository has been archived by the owner on May 7, 2020. It is now read-only.
/
BeaconBluetoothHandler.java
176 lines (150 loc) · 5.87 KB
/
BeaconBluetoothHandler.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/**
* Copyright (c) 2014,2018 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.smarthome.binding.bluetooth;
import java.util.concurrent.locks.ReentrantLock;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.binding.bluetooth.notification.BluetoothConnectionStatusNotification;
import org.eclipse.smarthome.binding.bluetooth.notification.BluetoothScanNotification;
import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.thing.Bridge;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.thing.ThingStatus;
import org.eclipse.smarthome.core.thing.ThingStatusDetail;
import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
import org.eclipse.smarthome.core.thing.binding.BridgeHandler;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.RefreshType;
import org.eclipse.smarthome.core.types.UnDefType;
/**
* This is a handler for generic Bluetooth devices in beacon-mode (i.e. not connected), which at the same time can be
* used as a base implementation for more specific thing handlers.
*
* @author Kai Kreuzer - Initial contribution and API
*/
@NonNullByDefault
public class BeaconBluetoothHandler extends BaseThingHandler implements BluetoothDeviceListener {
@NonNullByDefault({} /* non-null if initialized */)
protected BluetoothAdapter adapter;
@NonNullByDefault({} /* non-null if initialized */)
protected BluetoothAddress address;
@NonNullByDefault({} /* non-null if initialized */)
protected BluetoothDevice device;
protected final ReentrantLock deviceLock;
public BeaconBluetoothHandler(Thing thing) {
super(thing);
deviceLock = new ReentrantLock();
}
@Override
public void initialize() {
try {
address = new BluetoothAddress(getConfig().get(BluetoothBindingConstants.CONFIGURATION_ADDRESS).toString());
} catch (IllegalArgumentException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getLocalizedMessage());
return;
}
Bridge bridge = getBridge();
if (bridge == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Not associated with any bridge");
return;
}
BridgeHandler bridgeHandler = bridge.getHandler();
if (!(bridgeHandler instanceof BluetoothAdapter)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Associated with an unsupported bridge");
return;
}
adapter = (BluetoothAdapter) bridgeHandler;
try {
deviceLock.lock();
device = adapter.getDevice(address);
device.addListener(this);
} finally {
deviceLock.unlock();
}
updateStatus(ThingStatus.UNKNOWN);
}
@Override
public void dispose() {
try {
deviceLock.lock();
if (device != null) {
device.removeListener(this);
device = null;
}
} finally {
deviceLock.unlock();
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command == RefreshType.REFRESH && channelUID.getId().equals(BluetoothBindingConstants.CHANNEL_TYPE_RSSI)) {
updateRSSI();
}
}
/**
* Updates the RSSI channel and the Thing status according to the new received rssi value
*/
protected void updateRSSI() {
if (device != null) {
Integer rssi = device.getRssi();
if (rssi != null && rssi != 0) {
updateState(BluetoothBindingConstants.CHANNEL_TYPE_RSSI, new DecimalType(rssi));
updateStatusBasedOnRssi(true);
} else {
updateState(BluetoothBindingConstants.CHANNEL_TYPE_RSSI, UnDefType.NULL);
updateStatusBasedOnRssi(false);
}
}
}
/**
* This method sets the Thing status based on whether or not we can receive a signal from it.
* This is the best logic for beacons, but connected devices might want to deactivate this by overriding the method.
*
* @param receivedSignal true, if the device is in reach
*/
protected void updateStatusBasedOnRssi(boolean receivedSignal) {
if (receivedSignal) {
updateStatus(ThingStatus.ONLINE);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
}
}
@Override
public void onScanRecordReceived(BluetoothScanNotification scanNotification) {
int rssi = scanNotification.getRssi();
if (rssi != Integer.MIN_VALUE) {
device.setRssi(rssi);
updateRSSI();
}
}
@Override
public void onConnectionStateChange(BluetoothConnectionStatusNotification connectionNotification) {
}
@Override
public void onServicesDiscovered() {
}
@Override
public void onCharacteristicReadComplete(BluetoothCharacteristic characteristic, BluetoothCompletionStatus status) {
}
@Override
public void onCharacteristicWriteComplete(BluetoothCharacteristic characteristic,
BluetoothCompletionStatus status) {
}
@Override
public void onCharacteristicUpdate(BluetoothCharacteristic characteristic) {
}
@Override
public void onDescriptorUpdate(BluetoothDescriptor bluetoothDescriptor) {
}
}