Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Expand Up @@ -79,8 +79,23 @@ public interface AirPurifierAccessory extends HomekitAccessory {
/** Unsubscribes from changes in the target state of the air purifier. */
void unsubscribeTargetState();

/**
* If a filter maintenance service is needed as a linked service to this AirPurifier, this is the
* place.
*
* @return an instance of FilterMaintenanceAccessory, null if not needed.
*/
default FilterMaintenanceAccessory getFilterMaintenanceAccessory() {
return null;
};

@Override
default Collection<Service> getServices() {
return Collections.singleton(new AirPurifierService(this));
AirPurifierService service = new AirPurifierService(this);
FilterMaintenanceAccessory fmAccessory = this.getFilterMaintenanceAccessory();
if (fmAccessory != null) {
service.addLinkedService(fmAccessory.getPrimaryService());
}
return Collections.singleton(service);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
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 seperate FilterMaintenance, but as a linked service to
* AirPurifier.
*
* @see AirPurifierAccessory#getFilterMaintenanceAccessory()
*/
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);
}
}