Skip to content

Commit

Permalink
Add and direct implementors to use LowBatteryStatusAccessory
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
timcharper committed Jan 2, 2019
1 parent e64bf79 commit f256273
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -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 {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* <p>A carbon monoxide sensor reports whether carbon monoxide has been detected or not.</p>
*
* <p>Carbon monoxide sensors that run on batteries will need to implement this interface
* and also implement {@link BatteryAccessory}.</p>
* and also implement {@link LowBatteryStatusAccessory}.</p>
*
* @author Gaston Dombiak
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* that the door/window is closed.</p>
*
* <p>Contact sensors that run on batteries will need to implement this interface
* and also implement {@link BatteryAccessory}.</p>
* and also implement {@link LowBatteryStatusAccessory}.</p>
*
* @author Gaston Dombiak
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* {@link LockableLockMechanism}.</p>
*
* <p>Locks that run on batteries will need to implement this interface and also
* implement {@link BatteryAccessory}.</p>
* implement {@link LowBatteryStatusAccessory}.</p>
*
* @author Andy Lintner
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Boolean> 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();
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* <p>A motion sensor that reports whether motion has been detected.</p>
*
* <p>Motion sensors that run on batteries will need to implement this interface
* and also implement {@link BatteryAccessory}.</p>
* and also implement {@link LowBatteryStatusAccessory}.</p>
*
* @author Gaston Dombiak
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* <p>A smoke sensor reports whether smoke has been detected or not.</p>
*
* <p>Smoke sensors that run on batteries will need to implement this interface
* and also implement {@link BatteryAccessory}.</p>
* and also implement {@link LowBatteryStatusAccessory}.</p>
*
* @author Gaston Dombiak
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
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<CompletableFuture<Integer>> getter;
private final Consumer<HomekitCharacteristicChangeCallback> subscriber;
private final Runnable unsubscriber;

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

@Override
protected void setValue(Integer value) throws Exception {
//Read Only
// Read Only
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -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<CompletableFuture<Boolean>> getter;
private final Consumer<HomekitCharacteristicChangeCallback> subscriber;
private final Runnable unsubscriber;

public LowBatteryStatusCharacteristic(Supplier<CompletableFuture<Boolean>> getter,
Consumer<HomekitCharacteristicChangeCallback> 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<Boolean> 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();
}
}
136 changes: 76 additions & 60 deletions src/main/java/com/beowulfe/hap/impl/services/AbstractServiceImpl.java
Original file line number Diff line number Diff line change
@@ -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<Characteristic> characteristics = new LinkedList<>();
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final String type;
private final List<Characteristic> 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);
}

/**
* <p>Creates a new instance of this class with the specified UUID and {@link HomekitAccessory}.
* Download and install <i>HomeKit Accessory Simulator</i> to discover the corresponding UUID for
* the specific service.</p>
*
* <p>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.</p>
*
* @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.
/**
* <p>
* Creates a new instance of this class with the specified UUID and {@link HomekitAccessory}.
* Download and install <i>HomeKit Accessory Simulator</i> to discover the corresponding UUID for
* the specific service.
* </p>
*
* <p>
* 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.
* </p>
*
* @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<Characteristic> 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<Characteristic> 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);
}
}

0 comments on commit f256273

Please sign in to comment.