From f2562732e94d222c9f64379d4016b15809d73c7f Mon Sep 17 00:00:00 2001
From: Tim Harper
Date: Wed, 2 Jan 2019 01:28:25 -0700
Subject: [PATCH] Add and direct implementors to use LowBatteryStatusAccessory
BatteryAccessory is used only by BatteryService and does not apply to
MotionSensor, SmokeSensor, etc.
Deprecate BatteryAccessory and leave the implementation for BatteryService /
Battery for a future date. Log a warning for accessories that are still trying
to use it.
---
.../hap/accessories/BatteryAccessory.java | 8 +-
.../hap/accessories/CarbonMonoxideSensor.java | 2 +-
.../hap/accessories/ContactSensor.java | 2 +-
.../hap/accessories/LockMechanism.java | 2 +-
.../LowBatteryStatusAccessory.java | 33 +++++
.../hap/accessories/MotionSensor.java | 2 +-
.../beowulfe/hap/accessories/SmokeSensor.java | 2 +-
.../common/BatteryLevelCharacteristic.java | 17 ++-
.../LowBatteryStatusCharacteristic.java | 44 ++++++
.../impl/services/AbstractServiceImpl.java | 136 ++++++++++--------
10 files changed, 173 insertions(+), 75 deletions(-)
create mode 100644 src/main/java/com/beowulfe/hap/accessories/LowBatteryStatusAccessory.java
create mode 100644 src/main/java/com/beowulfe/hap/impl/characteristics/common/LowBatteryStatusCharacteristic.java
diff --git a/src/main/java/com/beowulfe/hap/accessories/BatteryAccessory.java b/src/main/java/com/beowulfe/hap/accessories/BatteryAccessory.java
index 1e7914dad..b69bdf7e3 100644
--- a/src/main/java/com/beowulfe/hap/accessories/BatteryAccessory.java
+++ b/src/main/java/com/beowulfe/hap/accessories/BatteryAccessory.java
@@ -1,15 +1,15 @@
package com.beowulfe.hap.accessories;
-import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
-
import java.util.concurrent.CompletableFuture;
+import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
+
/**
- * An accessory that runs on batteries. Accessories that run on batteries are able to report
- * battery level.
+ * Do not use. Devices that have battery levels should implement LowBatteryStatusAccessory.
*
* @author Gaston Dombiak
*/
+@Deprecated
public interface BatteryAccessory {
/**
diff --git a/src/main/java/com/beowulfe/hap/accessories/CarbonMonoxideSensor.java b/src/main/java/com/beowulfe/hap/accessories/CarbonMonoxideSensor.java
index 6133f4ac6..6bac40d45 100644
--- a/src/main/java/com/beowulfe/hap/accessories/CarbonMonoxideSensor.java
+++ b/src/main/java/com/beowulfe/hap/accessories/CarbonMonoxideSensor.java
@@ -14,7 +14,7 @@
* A carbon monoxide sensor reports whether carbon monoxide has been detected or not.
*
* Carbon monoxide sensors that run on batteries will need to implement this interface
- * and also implement {@link BatteryAccessory}.
+ * and also implement {@link LowBatteryStatusAccessory}.
*
* @author Gaston Dombiak
*/
diff --git a/src/main/java/com/beowulfe/hap/accessories/ContactSensor.java b/src/main/java/com/beowulfe/hap/accessories/ContactSensor.java
index e74edf1c6..61670e579 100644
--- a/src/main/java/com/beowulfe/hap/accessories/ContactSensor.java
+++ b/src/main/java/com/beowulfe/hap/accessories/ContactSensor.java
@@ -16,7 +16,7 @@
* that the door/window is closed.
*
* Contact sensors that run on batteries will need to implement this interface
- * and also implement {@link BatteryAccessory}.
+ * and also implement {@link LowBatteryStatusAccessory}.
*
* @author Gaston Dombiak
*/
diff --git a/src/main/java/com/beowulfe/hap/accessories/LockMechanism.java b/src/main/java/com/beowulfe/hap/accessories/LockMechanism.java
index c44ebb6ac..99e9f97b9 100644
--- a/src/main/java/com/beowulfe/hap/accessories/LockMechanism.java
+++ b/src/main/java/com/beowulfe/hap/accessories/LockMechanism.java
@@ -15,7 +15,7 @@
* {@link LockableLockMechanism}.
*
* Locks that run on batteries will need to implement this interface and also
- * implement {@link BatteryAccessory}.
+ * implement {@link LowBatteryStatusAccessory}.
*
* @author Andy Lintner
*/
diff --git a/src/main/java/com/beowulfe/hap/accessories/LowBatteryStatusAccessory.java b/src/main/java/com/beowulfe/hap/accessories/LowBatteryStatusAccessory.java
new file mode 100644
index 000000000..6532f6438
--- /dev/null
+++ b/src/main/java/com/beowulfe/hap/accessories/LowBatteryStatusAccessory.java
@@ -0,0 +1,33 @@
+package com.beowulfe.hap.accessories;
+
+import java.util.concurrent.CompletableFuture;
+
+import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
+
+/**
+ * An accessory that runs on batteries. Accessories that run on batteries are able to report
+ * battery level.
+ *
+ * @author Tim Harper
+ */
+public interface LowBatteryStatusAccessory {
+
+ /**
+ * Retrieves the battery level of the accessory.
+ *
+ * @return a future that will contain the accessory's low battery state
+ */
+ CompletableFuture getLowBatteryState();
+
+ /**
+ * Subscribes to changes in the battery level.
+ *
+ * @param callback the function to call when low battery state changes.
+ */
+ void subscribeLowBatteryState(HomekitCharacteristicChangeCallback callback);
+
+ /**
+ * Unsubscribes from changes in the low battery state.
+ */
+ void unsubscribeLowBatteryState();
+}
diff --git a/src/main/java/com/beowulfe/hap/accessories/MotionSensor.java b/src/main/java/com/beowulfe/hap/accessories/MotionSensor.java
index afa3b605d..37ebaf5d5 100644
--- a/src/main/java/com/beowulfe/hap/accessories/MotionSensor.java
+++ b/src/main/java/com/beowulfe/hap/accessories/MotionSensor.java
@@ -13,7 +13,7 @@
* A motion sensor that reports whether motion has been detected.
*
* Motion sensors that run on batteries will need to implement this interface
- * and also implement {@link BatteryAccessory}.
+ * and also implement {@link LowBatteryStatusAccessory}.
*
* @author Gaston Dombiak
*/
diff --git a/src/main/java/com/beowulfe/hap/accessories/SmokeSensor.java b/src/main/java/com/beowulfe/hap/accessories/SmokeSensor.java
index ff575dec7..c41f34249 100644
--- a/src/main/java/com/beowulfe/hap/accessories/SmokeSensor.java
+++ b/src/main/java/com/beowulfe/hap/accessories/SmokeSensor.java
@@ -14,7 +14,7 @@
* A smoke sensor reports whether smoke has been detected or not.
*
* Smoke sensors that run on batteries will need to implement this interface
- * and also implement {@link BatteryAccessory}.
+ * and also implement {@link LowBatteryStatusAccessory}.
*
* @author Gaston Dombiak
*/
diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/common/BatteryLevelCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/common/BatteryLevelCharacteristic.java
index a6c6eebcf..f0cd9aa4f 100644
--- a/src/main/java/com/beowulfe/hap/impl/characteristics/common/BatteryLevelCharacteristic.java
+++ b/src/main/java/com/beowulfe/hap/impl/characteristics/common/BatteryLevelCharacteristic.java
@@ -1,13 +1,18 @@
package com.beowulfe.hap.impl.characteristics.common;
-import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
-import com.beowulfe.hap.characteristics.EventableCharacteristic;
-import com.beowulfe.hap.characteristics.IntegerCharacteristic;
-
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
+import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
+import com.beowulfe.hap.characteristics.EventableCharacteristic;
+import com.beowulfe.hap.characteristics.IntegerCharacteristic;
+
+/**
+ * This characteristic is used by a stand-alone BatteryService, which describes
+ * a stand-alone battery device, not the battery status of a battery operated
+ * device such as a motion sensor.
+ */
public class BatteryLevelCharacteristic extends IntegerCharacteristic implements EventableCharacteristic {
private final Supplier> getter;
@@ -15,7 +20,7 @@ public class BatteryLevelCharacteristic extends IntegerCharacteristic implements
private final Runnable unsubscriber;
public BatteryLevelCharacteristic(Supplier> getter,
- Consumer subscriber, Runnable unsubscriber) {
+ Consumer subscriber, Runnable unsubscriber) {
super("00000068-0000-1000-8000-0026BB765291", false, true, "Battery Level", 0, 100, "%");
this.getter = getter;
this.subscriber = subscriber;
@@ -29,7 +34,7 @@ protected CompletableFuture getValue() {
@Override
protected void setValue(Integer value) throws Exception {
- //Read Only
+ // Read Only
}
@Override
diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/common/LowBatteryStatusCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/common/LowBatteryStatusCharacteristic.java
new file mode 100644
index 000000000..ad44c51e2
--- /dev/null
+++ b/src/main/java/com/beowulfe/hap/impl/characteristics/common/LowBatteryStatusCharacteristic.java
@@ -0,0 +1,44 @@
+package com.beowulfe.hap.impl.characteristics.common;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
+import com.beowulfe.hap.characteristics.BooleanCharacteristic;
+import com.beowulfe.hap.characteristics.EventableCharacteristic;
+
+public class LowBatteryStatusCharacteristic extends BooleanCharacteristic implements EventableCharacteristic {
+
+ private final Supplier> getter;
+ private final Consumer subscriber;
+ private final Runnable unsubscriber;
+
+ public LowBatteryStatusCharacteristic(Supplier> getter,
+ Consumer subscriber, Runnable unsubscriber) {
+ super("00000079-0000-1000-8000-0026BB765291", false, true, "Status Low Battery");
+ this.getter = getter;
+ this.subscriber = subscriber;
+ this.unsubscriber = unsubscriber;
+ }
+
+ @Override
+ protected CompletableFuture getValue() {
+ return getter.get();
+ }
+
+ @Override
+ protected void setValue(Boolean value) throws Exception {
+ // Read Only
+ }
+
+ @Override
+ public void subscribe(HomekitCharacteristicChangeCallback callback) {
+ subscriber.accept(callback);
+ }
+
+ @Override
+ public void unsubscribe() {
+ unsubscriber.run();
+ }
+}
diff --git a/src/main/java/com/beowulfe/hap/impl/services/AbstractServiceImpl.java b/src/main/java/com/beowulfe/hap/impl/services/AbstractServiceImpl.java
index 21bebcec8..ce5793af0 100644
--- a/src/main/java/com/beowulfe/hap/impl/services/AbstractServiceImpl.java
+++ b/src/main/java/com/beowulfe/hap/impl/services/AbstractServiceImpl.java
@@ -1,77 +1,93 @@
package com.beowulfe.hap.impl.services;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.beowulfe.hap.HomekitAccessory;
import com.beowulfe.hap.Service;
import com.beowulfe.hap.accessories.BatteryAccessory;
+import com.beowulfe.hap.accessories.LowBatteryStatusAccessory;
import com.beowulfe.hap.characteristics.Characteristic;
import com.beowulfe.hap.impl.characteristics.common.BatteryLevelCharacteristic;
+import com.beowulfe.hap.impl.characteristics.common.LowBatteryStatusCharacteristic;
import com.beowulfe.hap.impl.characteristics.common.Name;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-
abstract class AbstractServiceImpl implements Service {
-
- private final String type;
- private final List characteristics = new LinkedList<>();
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+ private final String type;
+ private final List characteristics = new LinkedList<>();
- /**
- * This constructor has been deprecated and replaced with
- * {@link #AbstractServiceImpl(String, HomekitAccessory, String)}. Usages of
- * this constructor will need to manually configure {@link Name} characteristic
- * and {@link BatteryLevelCharacteristic} if needed.
- *
- * @param type unique UUID of the service. This information can be obtained from HomeKit Accessory Simulator.
- */
- @Deprecated
- public AbstractServiceImpl(String type) {
- this(type, null, null);
- }
+ /**
+ * This constructor has been deprecated and replaced with
+ * {@link #AbstractServiceImpl(String, HomekitAccessory, String)}. Usages of
+ * this constructor will need to manually configure {@link Name} characteristic
+ * and {@link BatteryLevelCharacteristic} if needed.
+ *
+ * @param type unique UUID of the service. This information can be obtained from HomeKit Accessory Simulator.
+ */
+ @Deprecated
+ public AbstractServiceImpl(String type) {
+ this(type, null, null);
+ }
- /**
- * Creates a new instance of this class with the specified UUID and {@link HomekitAccessory}.
- * Download and install HomeKit Accessory Simulator to discover the corresponding UUID for
- * the specific service.
- *
- * The new service will automatically add {@link Name} characteristic. If the accessory
- * is battery operated then it must implement {@link BatteryAccessory} and {@link BatteryLevelCharacteristic}
- * will be added too.
- *
- * @param type unique UUID of the service. This information can be obtained from HomeKit Accessory Simulator.
- * @param accessory HomeKit accessory exposed as a service.
- * @param serviceName name of the service. This information is usually the name of the accessory.
+ /**
+ *
+ * Creates a new instance of this class with the specified UUID and {@link HomekitAccessory}.
+ * Download and install HomeKit Accessory Simulator to discover the corresponding UUID for
+ * the specific service.
+ *
+ *
+ *
+ * The new service will automatically add {@link Name} characteristic. If the accessory
+ * is battery operated then it must implement {@link BatteryAccessory} and {@link BatteryLevelCharacteristic}
+ * will be added too.
+ *
+ *
+ * @param type unique UUID of the service. This information can be obtained from HomeKit Accessory Simulator.
+ * @param accessory HomeKit accessory exposed as a service.
+ * @param serviceName name of the service. This information is usually the name of the accessory.
*/
- public AbstractServiceImpl(String type, HomekitAccessory accessory, String serviceName) {
- this.type = type;
+ public AbstractServiceImpl(String type, HomekitAccessory accessory, String serviceName) {
+ this.type = type;
+
+ if (accessory != null) {
+ // Add name characteristic
+ addCharacteristic(new Name(serviceName));
+
+ // If battery operated accessory then add BatteryLevelCharacteristic
+ if (accessory instanceof BatteryAccessory) {
+ logger.warn(
+ "Accessory {} implements BatteryAccessory, which was incorrectly used to advertise battery state and is not recognized by HomeKit. "
+ + "Battery-powered devices should report their battery status using LowBatteryStatusAccessory",
+ accessory.getClass());
+ }
+
+ // If battery operated accessory then add LowBatteryStatusAccessory
+ if (accessory instanceof LowBatteryStatusAccessory) {
+ LowBatteryStatusAccessory lowBatteryStatusAccessory = (LowBatteryStatusAccessory) accessory;
+ addCharacteristic(new LowBatteryStatusCharacteristic(lowBatteryStatusAccessory::getLowBatteryState,
+ lowBatteryStatusAccessory::subscribeLowBatteryState,
+ lowBatteryStatusAccessory::unsubscribeLowBatteryState));
+
+ }
+ }
+ }
- if (accessory != null) {
- // Add name characteristic
- addCharacteristic(new Name(serviceName));
+ @Override
+ public List getCharacteristics() {
+ return Collections.unmodifiableList(characteristics);
+ }
- // If battery operated accessory then add BatteryLevelCharacteristic
- if (accessory instanceof BatteryAccessory) {
- BatteryAccessory batteryAccessory = (BatteryAccessory) accessory;
- addCharacteristic(new BatteryLevelCharacteristic(
- batteryAccessory::getBatteryLevelState,
- batteryAccessory::subscribeBatteryLevelState,
- batteryAccessory::unsubscribeBatteryLevelState
- ));
- }
- }
- }
+ @Override
+ public String getType() {
+ return type;
+ }
- @Override
- public List getCharacteristics() {
- return Collections.unmodifiableList(characteristics);
- }
-
- @Override
- public String getType() {
- return type;
- }
-
- protected void addCharacteristic(Characteristic characteristic) {
- this.characteristics.add(characteristic);
- }
+ protected void addCharacteristic(Characteristic characteristic) {
+ this.characteristics.add(characteristic);
+ }
}