Skip to content

Commit 683a362

Browse files
authored
Merge pull request #50 from timcharper/tharper/fix-battery-reporting-for-devices
Add and direct implementors to use LowBatteryStatusAccessory
2 parents 50d0a4d + 819a5c2 commit 683a362

File tree

10 files changed

+174
-75
lines changed

10 files changed

+174
-75
lines changed

src/main/java/com/beowulfe/hap/accessories/BatteryAccessory.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package com.beowulfe.hap.accessories;
22

3-
import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
4-
53
import java.util.concurrent.CompletableFuture;
64

5+
import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
6+
77
/**
8-
* An accessory that runs on batteries. Accessories that run on batteries are able to report
9-
* battery level.
8+
* Do not use. Devices that have battery levels should implement LowBatteryStatusAccessory.
109
*
1110
* @author Gaston Dombiak
1211
*/
12+
@Deprecated
1313
public interface BatteryAccessory {
1414

1515
/**
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.beowulfe.hap.accessories;
2+
3+
import java.util.concurrent.CompletableFuture;
4+
5+
import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
6+
7+
/**
8+
* An accessory that runs on batteries. Accessories that run on batteries are able to report
9+
* battery level.
10+
*
11+
* @author Tim Harper
12+
*/
13+
public interface BatteryStatusAccessory {
14+
15+
/**
16+
* Queries if the device battery level is low; returning a value of true
17+
* will cause a low-battery status to appear in Home for the device.
18+
*
19+
* @return a future that will contain the accessory's low battery state
20+
*/
21+
CompletableFuture<Boolean> getLowBatteryState();
22+
23+
/**
24+
* Subscribes to changes in the battery level.
25+
*
26+
* @param callback the function to call when low battery state changes.
27+
*/
28+
void subscribeLowBatteryState(HomekitCharacteristicChangeCallback callback);
29+
30+
/**
31+
* Unsubscribes from changes in the low battery state.
32+
*/
33+
void unsubscribeLowBatteryState();
34+
}

src/main/java/com/beowulfe/hap/accessories/CarbonMonoxideSensor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* <p>A carbon monoxide sensor reports whether carbon monoxide has been detected or not.</p>
1515
*
1616
* <p>Carbon monoxide sensors that run on batteries will need to implement this interface
17-
* and also implement {@link BatteryAccessory}.</p>
17+
* and also implement {@link BatteryStatusAccessory}.</p>
1818
*
1919
* @author Gaston Dombiak
2020
*/

src/main/java/com/beowulfe/hap/accessories/ContactSensor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* that the door/window is closed.</p>
1717
*
1818
* <p>Contact sensors that run on batteries will need to implement this interface
19-
* and also implement {@link BatteryAccessory}.</p>
19+
* and also implement {@link BatteryStatusAccessory}.</p>
2020
*
2121
* @author Gaston Dombiak
2222
*/

src/main/java/com/beowulfe/hap/accessories/LockMechanism.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* {@link LockableLockMechanism}.</p>
1616
*
1717
* <p>Locks that run on batteries will need to implement this interface and also
18-
* implement {@link BatteryAccessory}.</p>
18+
* implement {@link BatteryStatusAccessory}.</p>
1919
*
2020
* @author Andy Lintner
2121
*/

src/main/java/com/beowulfe/hap/accessories/MotionSensor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* <p>A motion sensor that reports whether motion has been detected.</p>
1414
*
1515
* <p>Motion sensors that run on batteries will need to implement this interface
16-
* and also implement {@link BatteryAccessory}.</p>
16+
* and also implement {@link BatteryStatusAccessory}.</p>
1717
*
1818
* @author Gaston Dombiak
1919
*/

src/main/java/com/beowulfe/hap/accessories/SmokeSensor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* <p>A smoke sensor reports whether smoke has been detected or not.</p>
1515
*
1616
* <p>Smoke sensors that run on batteries will need to implement this interface
17-
* and also implement {@link BatteryAccessory}.</p>
17+
* and also implement {@link BatteryStatusAccessory}.</p>
1818
*
1919
* @author Gaston Dombiak
2020
*/

src/main/java/com/beowulfe/hap/impl/characteristics/common/BatteryLevelCharacteristic.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
package com.beowulfe.hap.impl.characteristics.common;
22

3-
import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
4-
import com.beowulfe.hap.characteristics.EventableCharacteristic;
5-
import com.beowulfe.hap.characteristics.IntegerCharacteristic;
6-
73
import java.util.concurrent.CompletableFuture;
84
import java.util.function.Consumer;
95
import java.util.function.Supplier;
106

7+
import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
8+
import com.beowulfe.hap.characteristics.EventableCharacteristic;
9+
import com.beowulfe.hap.characteristics.IntegerCharacteristic;
10+
11+
/**
12+
* This characteristic is used by a stand-alone BatteryService, which describes
13+
* a stand-alone battery device, not the battery status of a battery operated
14+
* device such as a motion sensor.
15+
*/
1116
public class BatteryLevelCharacteristic extends IntegerCharacteristic implements EventableCharacteristic {
1217

1318
private final Supplier<CompletableFuture<Integer>> getter;
1419
private final Consumer<HomekitCharacteristicChangeCallback> subscriber;
1520
private final Runnable unsubscriber;
1621

1722
public BatteryLevelCharacteristic(Supplier<CompletableFuture<Integer>> getter,
18-
Consumer<HomekitCharacteristicChangeCallback> subscriber, Runnable unsubscriber) {
23+
Consumer<HomekitCharacteristicChangeCallback> subscriber, Runnable unsubscriber) {
1924
super("00000068-0000-1000-8000-0026BB765291", false, true, "Battery Level", 0, 100, "%");
2025
this.getter = getter;
2126
this.subscriber = subscriber;
@@ -29,7 +34,7 @@ protected CompletableFuture<Integer> getValue() {
2934

3035
@Override
3136
protected void setValue(Integer value) throws Exception {
32-
//Read Only
37+
// Read Only
3338
}
3439

3540
@Override
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.beowulfe.hap.impl.characteristics.common;
2+
3+
import java.util.concurrent.CompletableFuture;
4+
import java.util.function.Consumer;
5+
import java.util.function.Supplier;
6+
7+
import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
8+
import com.beowulfe.hap.characteristics.BooleanCharacteristic;
9+
import com.beowulfe.hap.characteristics.EventableCharacteristic;
10+
11+
public class LowBatteryStatusCharacteristic extends BooleanCharacteristic implements EventableCharacteristic {
12+
13+
private final Supplier<CompletableFuture<Boolean>> getter;
14+
private final Consumer<HomekitCharacteristicChangeCallback> subscriber;
15+
private final Runnable unsubscriber;
16+
17+
public LowBatteryStatusCharacteristic(Supplier<CompletableFuture<Boolean>> getter,
18+
Consumer<HomekitCharacteristicChangeCallback> subscriber, Runnable unsubscriber) {
19+
super("00000079-0000-1000-8000-0026BB765291", false, true, "Status Low Battery");
20+
this.getter = getter;
21+
this.subscriber = subscriber;
22+
this.unsubscriber = unsubscriber;
23+
}
24+
25+
@Override
26+
protected CompletableFuture<Boolean> getValue() {
27+
return getter.get();
28+
}
29+
30+
@Override
31+
protected void setValue(Boolean value) throws Exception {
32+
// Read Only
33+
}
34+
35+
@Override
36+
public void subscribe(HomekitCharacteristicChangeCallback callback) {
37+
subscriber.accept(callback);
38+
}
39+
40+
@Override
41+
public void unsubscribe() {
42+
unsubscriber.run();
43+
}
44+
}
Lines changed: 76 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,93 @@
11
package com.beowulfe.hap.impl.services;
22

3+
import java.util.Collections;
4+
import java.util.LinkedList;
5+
import java.util.List;
6+
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
310
import com.beowulfe.hap.HomekitAccessory;
411
import com.beowulfe.hap.Service;
512
import com.beowulfe.hap.accessories.BatteryAccessory;
13+
import com.beowulfe.hap.accessories.BatteryStatusAccessory;
614
import com.beowulfe.hap.characteristics.Characteristic;
715
import com.beowulfe.hap.impl.characteristics.common.BatteryLevelCharacteristic;
16+
import com.beowulfe.hap.impl.characteristics.common.LowBatteryStatusCharacteristic;
817
import com.beowulfe.hap.impl.characteristics.common.Name;
918

10-
import java.util.Collections;
11-
import java.util.LinkedList;
12-
import java.util.List;
13-
1419
abstract class AbstractServiceImpl implements Service {
15-
16-
private final String type;
17-
private final List<Characteristic> characteristics = new LinkedList<>();
20+
private final Logger logger = LoggerFactory.getLogger(this.getClass());
21+
private final String type;
22+
private final List<Characteristic> characteristics = new LinkedList<>();
1823

19-
/**
20-
* This constructor has been deprecated and replaced with
21-
* {@link #AbstractServiceImpl(String, HomekitAccessory, String)}. Usages of
22-
* this constructor will need to manually configure {@link Name} characteristic
23-
* and {@link BatteryLevelCharacteristic} if needed.
24-
*
25-
* @param type unique UUID of the service. This information can be obtained from HomeKit Accessory Simulator.
26-
*/
27-
@Deprecated
28-
public AbstractServiceImpl(String type) {
29-
this(type, null, null);
30-
}
24+
/**
25+
* This constructor has been deprecated and replaced with
26+
* {@link #AbstractServiceImpl(String, HomekitAccessory, String)}. Usages of
27+
* this constructor will need to manually configure {@link Name} characteristic
28+
* and {@link BatteryLevelCharacteristic} if needed.
29+
*
30+
* @param type unique UUID of the service. This information can be obtained from HomeKit Accessory Simulator.
31+
*/
32+
@Deprecated
33+
public AbstractServiceImpl(String type) {
34+
this(type, null, null);
35+
}
3136

32-
/**
33-
* <p>Creates a new instance of this class with the specified UUID and {@link HomekitAccessory}.
34-
* Download and install <i>HomeKit Accessory Simulator</i> to discover the corresponding UUID for
35-
* the specific service.</p>
36-
*
37-
* <p>The new service will automatically add {@link Name} characteristic. If the accessory
38-
* is battery operated then it must implement {@link BatteryAccessory} and {@link BatteryLevelCharacteristic}
39-
* will be added too.</p>
40-
*
41-
* @param type unique UUID of the service. This information can be obtained from HomeKit Accessory Simulator.
42-
* @param accessory HomeKit accessory exposed as a service.
43-
* @param serviceName name of the service. This information is usually the name of the accessory.
37+
/**
38+
* <p>
39+
* Creates a new instance of this class with the specified UUID and {@link HomekitAccessory}.
40+
* Download and install <i>HomeKit Accessory Simulator</i> to discover the corresponding UUID for
41+
* the specific service.
42+
* </p>
43+
*
44+
* <p>
45+
* The new service will automatically add {@link Name} characteristic. If the accessory
46+
* is battery operated then it must implement {@link BatteryAccessory} and {@link BatteryLevelCharacteristic}
47+
* will be added too.
48+
* </p>
49+
*
50+
* @param type unique UUID of the service. This information can be obtained from HomeKit Accessory Simulator.
51+
* @param accessory HomeKit accessory exposed as a service.
52+
* @param serviceName name of the service. This information is usually the name of the accessory.
4453
*/
45-
public AbstractServiceImpl(String type, HomekitAccessory accessory, String serviceName) {
46-
this.type = type;
54+
public AbstractServiceImpl(String type, HomekitAccessory accessory, String serviceName) {
55+
this.type = type;
56+
57+
if (accessory != null) {
58+
// Add name characteristic
59+
addCharacteristic(new Name(serviceName));
60+
61+
// If battery operated accessory then add BatteryLevelCharacteristic
62+
if (accessory instanceof BatteryAccessory) {
63+
logger.warn(
64+
"Accessory {} implements BatteryAccessory, which was incorrectly used to advertise battery state and is not recognized by HomeKit. "
65+
+ "Battery-powered devices should report their battery status using LowBatteryStatusAccessory",
66+
accessory.getClass());
67+
}
68+
69+
// If battery operated accessory then add LowBatteryStatusAccessory
70+
if (accessory instanceof BatteryStatusAccessory) {
71+
BatteryStatusAccessory batteryStatusAccessory = (BatteryStatusAccessory) accessory;
72+
addCharacteristic(new LowBatteryStatusCharacteristic(batteryStatusAccessory::getLowBatteryState,
73+
batteryStatusAccessory::subscribeLowBatteryState,
74+
batteryStatusAccessory::unsubscribeLowBatteryState));
75+
76+
}
77+
}
78+
}
4779

48-
if (accessory != null) {
49-
// Add name characteristic
50-
addCharacteristic(new Name(serviceName));
80+
@Override
81+
public List<Characteristic> getCharacteristics() {
82+
return Collections.unmodifiableList(characteristics);
83+
}
5184

52-
// If battery operated accessory then add BatteryLevelCharacteristic
53-
if (accessory instanceof BatteryAccessory) {
54-
BatteryAccessory batteryAccessory = (BatteryAccessory) accessory;
55-
addCharacteristic(new BatteryLevelCharacteristic(
56-
batteryAccessory::getBatteryLevelState,
57-
batteryAccessory::subscribeBatteryLevelState,
58-
batteryAccessory::unsubscribeBatteryLevelState
59-
));
60-
}
61-
}
62-
}
85+
@Override
86+
public String getType() {
87+
return type;
88+
}
6389

64-
@Override
65-
public List<Characteristic> getCharacteristics() {
66-
return Collections.unmodifiableList(characteristics);
67-
}
68-
69-
@Override
70-
public String getType() {
71-
return type;
72-
}
73-
74-
protected void addCharacteristic(Characteristic characteristic) {
75-
this.characteristics.add(characteristic);
76-
}
90+
protected void addCharacteristic(Characteristic characteristic) {
91+
this.characteristics.add(characteristic);
92+
}
7793
}

0 commit comments

Comments
 (0)