Skip to content

Add support for FilterMaintenanceAccessory #124

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 11, 2020
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

* Valid values are supported for enum characteristics instead of min and max values
* Supported valid states for Thermostat, SecuritySystem, HeaterCooler and HumidifierDehumidifier [#108] [#120](https://github.com/hap-java/HAP-Java/pull/120)
* Support for FilterMaintenance. Can be used as a linked service for an Air Purifier [#124](https://github.com/hap-java/HAP-Java/pull/124)

# HAP-Java 1.1.5

Expand All @@ -27,6 +28,7 @@
* Fix various spec violations and optimize communications to improve performance [#65](https://github.com/hap-java/HAP-Java/pull/65)
* Fix a pairing issue in which HAP-Java could listen on a different interface than that which it advertises [#67](https://github.com/hap-java/HAP-Java/pull/67)
* Allow window covering to be used without optional characteristics. The inclusion of `HoldPositionCharacteristic` did terrible things, and we're still not sure why. Addressed [#56](https://github.com/hap-java/HAP-Java/pull/56)
* Air Purifier didn't support rotation speed characteristics. [#124](https://github.com/hap-java/HAP-Java/pull/124)

## New and improved

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ After that, check out the [Sample](https://github.com/hap-java/HAP-Java/tree/sam
Supported HomeKit Accessories
=========

Current implementation fully supports 37 HomeKit accessory/services.
Current implementation fully supports 38 HomeKit accessory/services.

| HomeKit Accessory & Service type | Supported by Java-HAP |
|--------------------|--------------------|
Expand All @@ -41,7 +41,7 @@ Current implementation fully supports 37 HomeKit accessory/services.
| Doorbell | :white_check_mark: |
| Fan | :white_check_mark: |
| Faucet | :white_check_mark: |
| Filter Maintenance | :x: |
| Filter Maintenance | :white_check_mark: |
| Garage Door Opener | :white_check_mark: |
| HAP Protocol Information | :white_check_mark: |
| Heater Cooler | :white_check_mark: |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.github.hapjava.accessories;

import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.filtermaintenance.FilterChangeIndicationEnum;
import io.github.hapjava.services.Service;
import io.github.hapjava.services.impl.FilterMaintenanceService;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;

/**
* A Filter maintenance with mandatory characteristics.
*
* <p>The HomeKit app doesn't support a separate FilterMaintenance, but as a linked service to
* AirPurifier.
*/
public interface FilterMaintenanceAccessory extends HomekitAccessory {

/**
* The filter change indictaion. It's either yes or no.
*
* @return FilterChangeIndicationEnum
*/
CompletableFuture<FilterChangeIndicationEnum> getFilterChangeIndication();

/**
* Subscribes to changes in the filter change indication.
*
* @param callback the function to call when the state changes.
*/
void subscribeFilterChangeIndication(HomekitCharacteristicChangeCallback callback);

/** Unsubscribes from changes in the filter change indication. */
void unsubscribeFilterChangeIndication();

@Override
default Collection<Service> getServices() {
return Collections.singleton(new FilterMaintenanceService(this));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.github.hapjava.accessories.optionalcharacteristic;

import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import java.util.concurrent.CompletableFuture;

/** Accessory with filter level characteristics */
public interface AccessoryWithFilterLifeLevel {

/**
* what's the filter life level, percentage wise
*
* @return filter life level
*/
CompletableFuture<Double> getFilterLifeLevel();

/**
* Subscribes to changes in the filter life level.
*
* @param callback the function to call when the level changes.
*/
void subscribeFilterLifeLevel(HomekitCharacteristicChangeCallback callback);

/** Unsubscribes from changes in the current filter life level. */
void unsubscribeFilterLifeLevel();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.github.hapjava.accessories.optionalcharacteristic;

import java.util.concurrent.CompletableFuture;

/** Accessory with filter reset characteristics */
public interface AccessoryWithResetFilterIndication {

/**
* Request to reset the filter level
*
* @param indication always 1, by HomeKit protocol. (to be ignored)
* @return a future that completes when the change is made
* @throws Exception when the change cannot be made
*/
CompletableFuture<Void> resetFilterIndication(Integer indication) throws Exception;
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ protected CompletableFuture<JsonObjectBuilder> makeBuilder(int iid) {
return super.makeBuilder(iid)
.thenApply(
builder -> {
return builder
.add("minValue", minValue)
.add("maxValue", maxValue)
.add("minStep", 1)
.add("unit", unit);
builder.add("minValue", minValue).add("maxValue", maxValue).add("minStep", 1);
if (this.unit != null) {
builder.add("unit", unit);
}
return builder;
});
}

@Override
protected CompletableFuture<Integer> getValue() {
return getter.map(integerGetter -> integerGetter.get()).get();
return getter.map(integerGetter -> integerGetter.get()).orElse(null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.github.hapjava.characteristics.impl.filtermaintenance;

import io.github.hapjava.characteristics.EventableCharacteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class FilterChangeIndicationCharacteristic
extends EnumCharacteristic<FilterChangeIndicationEnum> implements EventableCharacteristic {

public FilterChangeIndicationCharacteristic(
Supplier<CompletableFuture<FilterChangeIndicationEnum>> getter,
Consumer<HomekitCharacteristicChangeCallback> subscriber,
Runnable unsubscriber) {
super(
"000000AC-0000-1000-8000-0026BB765291",
"filter change indication",
FilterChangeIndicationEnum.values(),
Optional.of(getter),
Optional.empty(),
Optional.of(subscriber),
Optional.of(unsubscriber));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.github.hapjava.characteristics.impl.filtermaintenance;

import io.github.hapjava.characteristics.CharacteristicEnum;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

public enum FilterChangeIndicationEnum implements CharacteristicEnum {
NO_CHANGE_NEEDED(0),
CHANGE_NEEDED(1);

private static final Map<Integer, FilterChangeIndicationEnum> reverse;

static {
reverse =
Arrays.stream(FilterChangeIndicationEnum.values())
.collect(Collectors.toMap(FilterChangeIndicationEnum::getCode, t -> t));
}

public static FilterChangeIndicationEnum fromCode(Integer code) {
return reverse.get(code);
}

private final int code;

FilterChangeIndicationEnum(int code) {
this.code = code;
}

@Override
public int getCode() {
return code;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.github.hapjava.characteristics.impl.filtermaintenance;

import io.github.hapjava.characteristics.EventableCharacteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.base.FloatCharacteristic;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class FilterLifeLevelCharacteristic extends FloatCharacteristic
implements EventableCharacteristic {

public FilterLifeLevelCharacteristic(
Supplier<CompletableFuture<Double>> getter,
Consumer<HomekitCharacteristicChangeCallback> subscriber,
Runnable unsubscriber) {
super(
"000000AB-0000-1000-8000-0026BB765291",
"Filter Life Level",
0,
100,
1,
"%",
Optional.of(getter),
Optional.empty(),
Optional.of(subscriber),
Optional.of(unsubscriber));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.github.hapjava.characteristics.impl.filtermaintenance;

import io.github.hapjava.characteristics.ExceptionalConsumer;
import io.github.hapjava.characteristics.impl.base.IntegerCharacteristic;
import java.util.Optional;

public class ResetFilterIndicationCharacteristic extends IntegerCharacteristic {

public ResetFilterIndicationCharacteristic(ExceptionalConsumer<Integer> setter) {
super(
"000000AD-0000-1000-8000-0026BB765291",
"Reset Filter Indication",
1,
1,
null,
Optional.empty(),
Optional.of(setter),
Optional.empty(),
Optional.empty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.github.hapjava.accessories.AirPurifierAccessory;
import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithName;
import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithPhysicalControlsLock;
import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithRotationSpeed;
import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithSwingMode;
import io.github.hapjava.characteristics.impl.airpurifier.CurrentAirPurifierCharacteristic;
import io.github.hapjava.characteristics.impl.airpurifier.TargetAirPurifierStateCharacteristic;
Expand Down Expand Up @@ -53,13 +54,13 @@ public AirPurifierService(AirPurifierAccessory accessory) {
((AccessoryWithSwingMode) accessory)::subscribeSwingMode,
((AccessoryWithSwingMode) accessory)::unsubscribeSwingMode));
}
if (accessory instanceof AccessoryWithSwingMode) {
if (accessory instanceof AccessoryWithRotationSpeed) {
addOptionalCharacteristic(
new SwingModeCharacteristic(
((AccessoryWithSwingMode) accessory)::getSwingMode,
((AccessoryWithSwingMode) accessory)::setSwingMode,
((AccessoryWithSwingMode) accessory)::subscribeSwingMode,
((AccessoryWithSwingMode) accessory)::unsubscribeSwingMode));
new RotationSpeedCharacteristic(
((AccessoryWithRotationSpeed) accessory)::getRotationSpeed,
((AccessoryWithRotationSpeed) accessory)::setRotationSpeed,
((AccessoryWithRotationSpeed) accessory)::subscribeRotationSpeed,
((AccessoryWithRotationSpeed) accessory)::unsubscribeRotationSpeed));
}
if (accessory instanceof AccessoryWithPhysicalControlsLock) {
addOptionalCharacteristic(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package io.github.hapjava.services.impl;

import io.github.hapjava.accessories.FilterMaintenanceAccessory;
import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithFilterLifeLevel;
import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithName;
import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithResetFilterIndication;
import io.github.hapjava.characteristics.impl.common.NameCharacteristic;
import io.github.hapjava.characteristics.impl.filtermaintenance.FilterChangeIndicationCharacteristic;
import io.github.hapjava.characteristics.impl.filtermaintenance.FilterLifeLevelCharacteristic;
import io.github.hapjava.characteristics.impl.filtermaintenance.ResetFilterIndicationCharacteristic;

/** This service describes a filter maintenance. */
public class FilterMaintenanceService extends AbstractServiceImpl {

public FilterMaintenanceService(FilterChangeIndicationCharacteristic filerChange) {
super("000000BA-0000-1000-8000-0026BB765291");
addCharacteristic(filerChange);
}

public FilterMaintenanceService(FilterMaintenanceAccessory accessory) {
this(
new FilterChangeIndicationCharacteristic(
accessory::getFilterChangeIndication,
accessory::subscribeFilterChangeIndication,
accessory::unsubscribeFilterChangeIndication));

if (accessory instanceof AccessoryWithName) {
addOptionalCharacteristic(new NameCharacteristic(((AccessoryWithName) accessory)::getName));
}

if (accessory instanceof AccessoryWithFilterLifeLevel) {
addOptionalCharacteristic(
new FilterLifeLevelCharacteristic(
((AccessoryWithFilterLifeLevel) accessory)::getFilterLifeLevel,
((AccessoryWithFilterLifeLevel) accessory)::subscribeFilterLifeLevel,
((AccessoryWithFilterLifeLevel) accessory)::unsubscribeFilterLifeLevel));
}

if (accessory instanceof AccessoryWithResetFilterIndication) {
addOptionalCharacteristic(
new ResetFilterIndicationCharacteristic(
((AccessoryWithResetFilterIndication) accessory)::resetFilterIndication));
}
}

public void addOptionalCharacteristic(NameCharacteristic name) {
addCharacteristic(name);
}

public void addOptionalCharacteristic(FilterLifeLevelCharacteristic filterLifeLevel) {
addCharacteristic(filterLifeLevel);
}

public void addOptionalCharacteristic(ResetFilterIndicationCharacteristic resetFilterIndication) {
addCharacteristic(resetFilterIndication);
}
}