diff --git a/CHANGES.md b/CHANGES.md index 143958172..0579786cd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,3 +17,4 @@ * Occupancy sensor support [#59](https://github.com/hap-java/HAP-Java/pull/59) * Leak sensors and valve support added [#52](https://github.com/hap-java/HAP-Java/pull/52) * Notifications are batched now, when possible [#66](https://github.com/hap-java/HAP-Java/pull/66) +* Support for Doors and Windows added diff --git a/src/main/java/io/github/hapjava/accessories/BasicWindowCovering.java b/src/main/java/io/github/hapjava/accessories/BasicWindowCovering.java index 7d58b2b2d..e8a89e7b2 100644 --- a/src/main/java/io/github/hapjava/accessories/BasicWindowCovering.java +++ b/src/main/java/io/github/hapjava/accessories/BasicWindowCovering.java @@ -1,78 +1,5 @@ package io.github.hapjava.accessories; -import io.github.hapjava.HomekitAccessory; -import io.github.hapjava.HomekitCharacteristicChangeCallback; -import io.github.hapjava.Service; -import io.github.hapjava.accessories.properties.WindowCoveringPositionState; -import io.github.hapjava.impl.services.WindowCoveringService; -import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.CompletableFuture; +public interface BasicWindowCovering extends Positionable { -public interface BasicWindowCovering extends HomekitAccessory { - - /** - * Retrieves the current position - * - * @return a future that will contain the position as a value between 0 and 100 - */ - CompletableFuture getCurrentPosition(); - - /** - * Retrieves the target position - * - * @return a future that will contain the target position as a value between 0 and 100 - */ - CompletableFuture getTargetPosition(); - - /** - * Retrieves the state of the position: increasing, decreasing, or stopped - * - * @return a future that will contain the current state - */ - CompletableFuture getPositionState(); - - /** - * Sets the target position - * - * @param position the target position to set, as a value between 1 and 100 - * @return a future that completes when the change is made - * @throws Exception when the change cannot be made - */ - CompletableFuture setTargetPosition(int position) throws Exception; - - /** - * Subscribes to changes in the current position. - * - * @param callback the function to call when the state changes. - */ - void subscribeCurrentPosition(HomekitCharacteristicChangeCallback callback); - - /** - * Subscribes to changes in the target position. - * - * @param callback the function to call when the state changes. - */ - void subscribeTargetPosition(HomekitCharacteristicChangeCallback callback); - - /** - * Subscribes to changes in the position state: increasing, decreasing, or stopped - * - * @param callback the function to call when the state changes. - */ - void subscribePositionState(HomekitCharacteristicChangeCallback callback); - - /** Unsubscribes from changes in the current position. */ - void unsubscribeCurrentPosition(); - - /** Unsubscribes from changes in the target position. */ - void unsubscribeTargetPosition(); - - /** Unsubscribes from changes in the position state */ - void unsubscribePositionState(); - - @Override - default Collection getServices() { - return Collections.singleton(new WindowCoveringService(this)); - } } diff --git a/src/main/java/io/github/hapjava/accessories/Door.java b/src/main/java/io/github/hapjava/accessories/Door.java new file mode 100644 index 000000000..57bd0d2fe --- /dev/null +++ b/src/main/java/io/github/hapjava/accessories/Door.java @@ -0,0 +1,10 @@ +package io.github.hapjava.accessories; + +/** + * + * @author Benjamin Lafois + * + */ +public interface Door extends Positionable { + +} diff --git a/src/main/java/io/github/hapjava/accessories/Positionable.java b/src/main/java/io/github/hapjava/accessories/Positionable.java new file mode 100644 index 000000000..4147cca30 --- /dev/null +++ b/src/main/java/io/github/hapjava/accessories/Positionable.java @@ -0,0 +1,79 @@ +package io.github.hapjava.accessories; + +import java.util.concurrent.CompletableFuture; + +import io.github.hapjava.HomekitAccessory; +import io.github.hapjava.HomekitCharacteristicChangeCallback; +import io.github.hapjava.accessories.properties.PositionablePositionState; + +/** + * + * @author Benjamin Lafois + * + * Abstraction interface to allow implementation of other positionable items such as Window, Doors, and not only + * Coverings + * + */ +public interface Positionable extends HomekitAccessory { + + /** + * Retrieves the current position + * + * @return a future that will contain the position as a value between 0 and 100 + */ + CompletableFuture getCurrentPosition(); + + /** + * Retrieves the target position + * + * @return a future that will contain the target position as a value between 0 and 100 + */ + CompletableFuture getTargetPosition(); + + /** + * Retrieves the state of the position: increasing, decreasing, or stopped + * + * @return a future that will contain the current state + */ + CompletableFuture getPositionState(); + + /** + * Sets the target position + * + * @param position the target position to set, as a value between 1 and 100 + * @return a future that completes when the change is made + * @throws Exception when the change cannot be made + */ + CompletableFuture setTargetPosition(int position) throws Exception; + + /** + * Subscribes to changes in the current position. + * + * @param callback the function to call when the state changes. + */ + void subscribeCurrentPosition(HomekitCharacteristicChangeCallback callback); + + /** + * Subscribes to changes in the target position. + * + * @param callback the function to call when the state changes. + */ + void subscribeTargetPosition(HomekitCharacteristicChangeCallback callback); + + /** + * Subscribes to changes in the position state: increasing, decreasing, or stopped + * + * @param callback the function to call when the state changes. + */ + void subscribePositionState(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes in the current position. */ + void unsubscribeCurrentPosition(); + + /** Unsubscribes from changes in the target position. */ + void unsubscribeTargetPosition(); + + /** Unsubscribes from changes in the position state */ + void unsubscribePositionState(); + +} diff --git a/src/main/java/io/github/hapjava/accessories/Window.java b/src/main/java/io/github/hapjava/accessories/Window.java new file mode 100644 index 000000000..8a9f1b6c8 --- /dev/null +++ b/src/main/java/io/github/hapjava/accessories/Window.java @@ -0,0 +1,11 @@ +package io.github.hapjava.accessories; + +/** + * + * @author Benjamin Lafois + * HomeKit Window + * + */ +public interface Window extends Positionable { + +} diff --git a/src/main/java/io/github/hapjava/accessories/properties/PositionablePositionState.java b/src/main/java/io/github/hapjava/accessories/properties/PositionablePositionState.java new file mode 100644 index 000000000..43582becd --- /dev/null +++ b/src/main/java/io/github/hapjava/accessories/properties/PositionablePositionState.java @@ -0,0 +1,39 @@ +package io.github.hapjava.accessories.properties; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +import io.github.hapjava.accessories.Door; +import io.github.hapjava.accessories.WindowCovering; + +/** + * The position state used by a {@link WindowCovering}, {@link Door} or {@link Window} + * + * @author Andy Lintner + */ +public enum PositionablePositionState { + DECREASING(0), + INCREASING(1), + STOPPED(2); + + private static final Map reverse; + + static { + reverse = Arrays.stream(PositionablePositionState.values()).collect(Collectors.toMap(t -> t.getCode(), t -> t)); + } + + public static PositionablePositionState fromCode(Integer code) { + return reverse.get(code); + } + + private final int code; + + private PositionablePositionState(int code) { + this.code = code; + } + + public int getCode() { + return code; + } +} diff --git a/src/main/java/io/github/hapjava/accessories/properties/WindowCoveringPositionState.java b/src/main/java/io/github/hapjava/accessories/properties/WindowCoveringPositionState.java deleted file mode 100644 index 1686fd2fb..000000000 --- a/src/main/java/io/github/hapjava/accessories/properties/WindowCoveringPositionState.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.github.hapjava.accessories.properties; - -import io.github.hapjava.accessories.WindowCovering; -import java.util.Arrays; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * The position state used by a {@link WindowCovering} - * - * @author Andy Lintner - */ -public enum WindowCoveringPositionState { - DECREASING(0), - INCREASING(1), - STOPPED(2); - - private static final Map reverse; - - static { - reverse = - Arrays.stream(WindowCoveringPositionState.values()) - .collect(Collectors.toMap(t -> t.getCode(), t -> t)); - } - - public static WindowCoveringPositionState fromCode(Integer code) { - return reverse.get(code); - } - - private final int code; - - private WindowCoveringPositionState(int code) { - this.code = code; - } - - public int getCode() { - return code; - } -} diff --git a/src/main/java/io/github/hapjava/impl/characteristics/windowcovering/CurrentPositionCharacteristic.java b/src/main/java/io/github/hapjava/impl/characteristics/windowcovering/CurrentPositionCharacteristic.java index 22fbfd171..b1d52b616 100644 --- a/src/main/java/io/github/hapjava/impl/characteristics/windowcovering/CurrentPositionCharacteristic.java +++ b/src/main/java/io/github/hapjava/impl/characteristics/windowcovering/CurrentPositionCharacteristic.java @@ -1,38 +1,38 @@ package io.github.hapjava.impl.characteristics.windowcovering; +import java.util.concurrent.CompletableFuture; + import io.github.hapjava.HomekitCharacteristicChangeCallback; -import io.github.hapjava.accessories.BasicWindowCovering; +import io.github.hapjava.accessories.Positionable; import io.github.hapjava.characteristics.EventableCharacteristic; import io.github.hapjava.characteristics.IntegerCharacteristic; -import java.util.concurrent.CompletableFuture; -public class CurrentPositionCharacteristic extends IntegerCharacteristic - implements EventableCharacteristic { +public class CurrentPositionCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { - private final BasicWindowCovering windowCovering; + private final Positionable positionable; - public CurrentPositionCharacteristic(BasicWindowCovering windowCovering) { - super("0000006D-0000-1000-8000-0026BB765291", false, true, "The current position", 0, 100, "%"); - this.windowCovering = windowCovering; - } + public CurrentPositionCharacteristic(Positionable positionable) { + super("0000006D-0000-1000-8000-0026BB765291", false, true, "The current position", 0, 100, "%"); + this.positionable = positionable; + } - @Override - protected void setValue(Integer value) throws Exception { - // Read Only - } + @Override + protected void setValue(Integer value) throws Exception { + // Read Only + } - @Override - protected CompletableFuture getValue() { - return windowCovering.getCurrentPosition(); - } + @Override + protected CompletableFuture getValue() { + return positionable.getCurrentPosition(); + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - windowCovering.subscribeCurrentPosition(callback); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + positionable.subscribeCurrentPosition(callback); + } - @Override - public void unsubscribe() { - windowCovering.unsubscribeCurrentPosition(); - } + @Override + public void unsubscribe() { + positionable.unsubscribeCurrentPosition(); + } } diff --git a/src/main/java/io/github/hapjava/impl/characteristics/windowcovering/PositionStateCharacteristic.java b/src/main/java/io/github/hapjava/impl/characteristics/windowcovering/PositionStateCharacteristic.java index 80e87ad01..bb051d31f 100644 --- a/src/main/java/io/github/hapjava/impl/characteristics/windowcovering/PositionStateCharacteristic.java +++ b/src/main/java/io/github/hapjava/impl/characteristics/windowcovering/PositionStateCharacteristic.java @@ -1,38 +1,38 @@ package io.github.hapjava.impl.characteristics.windowcovering; +import java.util.concurrent.CompletableFuture; + import io.github.hapjava.HomekitCharacteristicChangeCallback; -import io.github.hapjava.accessories.BasicWindowCovering; +import io.github.hapjava.accessories.Positionable; import io.github.hapjava.characteristics.EnumCharacteristic; import io.github.hapjava.characteristics.EventableCharacteristic; -import java.util.concurrent.CompletableFuture; -public class PositionStateCharacteristic extends EnumCharacteristic - implements EventableCharacteristic { +public class PositionStateCharacteristic extends EnumCharacteristic implements EventableCharacteristic { - private final BasicWindowCovering windowCovering; + private final Positionable positionable; - public PositionStateCharacteristic(BasicWindowCovering windowCovering) { - super("00000072-0000-1000-8000-0026BB765291", false, true, "The position state", 2); - this.windowCovering = windowCovering; - } + public PositionStateCharacteristic(Positionable positionable) { + super("00000072-0000-1000-8000-0026BB765291", false, true, "The position state", 2); + this.positionable = positionable; + } - @Override - protected void setValue(Integer value) throws Exception { - // Read only - } + @Override + protected void setValue(Integer value) throws Exception { + // Read only + } - @Override - protected CompletableFuture getValue() { - return windowCovering.getPositionState().thenApply(v -> v.getCode()); - } + @Override + protected CompletableFuture getValue() { + return positionable.getPositionState().thenApply(v -> v.getCode()); + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - windowCovering.subscribePositionState(callback); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + positionable.subscribePositionState(callback); + } - @Override - public void unsubscribe() { - windowCovering.unsubscribePositionState(); - } + @Override + public void unsubscribe() { + positionable.unsubscribePositionState(); + } } diff --git a/src/main/java/io/github/hapjava/impl/characteristics/windowcovering/TargetPositionCharacteristic.java b/src/main/java/io/github/hapjava/impl/characteristics/windowcovering/TargetPositionCharacteristic.java index 0db8fe6df..3da4456bf 100644 --- a/src/main/java/io/github/hapjava/impl/characteristics/windowcovering/TargetPositionCharacteristic.java +++ b/src/main/java/io/github/hapjava/impl/characteristics/windowcovering/TargetPositionCharacteristic.java @@ -1,38 +1,38 @@ package io.github.hapjava.impl.characteristics.windowcovering; +import java.util.concurrent.CompletableFuture; + import io.github.hapjava.HomekitCharacteristicChangeCallback; -import io.github.hapjava.accessories.BasicWindowCovering; +import io.github.hapjava.accessories.Positionable; import io.github.hapjava.characteristics.EventableCharacteristic; import io.github.hapjava.characteristics.IntegerCharacteristic; -import java.util.concurrent.CompletableFuture; -public class TargetPositionCharacteristic extends IntegerCharacteristic - implements EventableCharacteristic { +public class TargetPositionCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { - private final BasicWindowCovering windowCovering; + private final Positionable positionable; - public TargetPositionCharacteristic(BasicWindowCovering windowCovering) { - super("0000007C-0000-1000-8000-0026BB765291", true, true, "The target position", 0, 100, "%"); - this.windowCovering = windowCovering; - } + public TargetPositionCharacteristic(Positionable positionable) { + super("0000007C-0000-1000-8000-0026BB765291", true, true, "The target position", 0, 100, "%"); + this.positionable = positionable; + } - @Override - protected void setValue(Integer value) throws Exception { - windowCovering.setTargetPosition(value); - } + @Override + protected void setValue(Integer value) throws Exception { + positionable.setTargetPosition(value); + } - @Override - protected CompletableFuture getValue() { - return windowCovering.getTargetPosition(); - } + @Override + protected CompletableFuture getValue() { + return positionable.getTargetPosition(); + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - windowCovering.subscribeTargetPosition(callback); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + positionable.subscribeTargetPosition(callback); + } - @Override - public void unsubscribe() { - windowCovering.unsubscribeTargetPosition(); - } + @Override + public void unsubscribe() { + positionable.unsubscribeTargetPosition(); + } } diff --git a/src/main/java/io/github/hapjava/impl/services/DoorService.java b/src/main/java/io/github/hapjava/impl/services/DoorService.java new file mode 100644 index 000000000..21d40166f --- /dev/null +++ b/src/main/java/io/github/hapjava/impl/services/DoorService.java @@ -0,0 +1,42 @@ +package io.github.hapjava.impl.services; + +import io.github.hapjava.accessories.Door; +import io.github.hapjava.impl.characteristics.windowcovering.CurrentPositionCharacteristic; +import io.github.hapjava.impl.characteristics.windowcovering.PositionStateCharacteristic; +import io.github.hapjava.impl.characteristics.windowcovering.TargetPositionCharacteristic; + +public class DoorService extends AbstractServiceImpl { + + public DoorService(Door door) { + this(door, door.getLabel()); + } + + public DoorService(Door door, String serviceName) { + super("00000081-0000-1000-8000-0026BB765291", door, serviceName); + + addCharacteristic(new CurrentPositionCharacteristic(door)); + addCharacteristic(new PositionStateCharacteristic(door)); + addCharacteristic(new TargetPositionCharacteristic(door)); + + /* + * if (door instanceof HorizontalTiltingWindowCovering) { + * addCharacteristic(new CurrentHorizontalTiltAngleCharacteristic((HorizontalTiltingWindowCovering) door)); + * addCharacteristic(new TargetHorizontalTiltAngleCharacteristic((HorizontalTiltingWindowCovering) door)); + * } + * if (door instanceof VerticalTiltingWindowCovering) { + * addCharacteristic(new CurrentVerticalTiltAngleCharacteristic((VerticalTiltingWindowCovering) door)); + * addCharacteristic(new TargetVerticalTiltAngleCharacteristic((VerticalTiltingWindowCovering) door)); + * } + * if (door instanceof HoldPositionWindowCovering) { + * HoldPositionWindowCovering hpwc = (HoldPositionWindowCovering) door; + * addCharacteristic(new HoldPositionCharacteristic(hpwc)); + * } + * if (door instanceof ObstructionDetectedWindowCovering) { + * ObstructionDetectedWindowCovering wc = (ObstructionDetectedWindowCovering) door; + * addCharacteristic(new ObstructionDetectedCharacteristic(() -> wc.getObstructionDetected(), + * c -> wc.subscribeObstructionDetected(c), () -> wc.unsubscribeObstructionDetected())); + * } + */ + } + +} diff --git a/src/main/java/io/github/hapjava/impl/services/WindowService.java b/src/main/java/io/github/hapjava/impl/services/WindowService.java new file mode 100644 index 000000000..d92ce72c6 --- /dev/null +++ b/src/main/java/io/github/hapjava/impl/services/WindowService.java @@ -0,0 +1,41 @@ +package io.github.hapjava.impl.services; + +import io.github.hapjava.accessories.Window; +import io.github.hapjava.impl.characteristics.windowcovering.CurrentPositionCharacteristic; +import io.github.hapjava.impl.characteristics.windowcovering.PositionStateCharacteristic; +import io.github.hapjava.impl.characteristics.windowcovering.TargetPositionCharacteristic; + +public class WindowService extends AbstractServiceImpl { + + public WindowService(Window window) { + this(window, window.getLabel()); + } + + public WindowService(Window window, String serviceName) { + super("0000008B-0000-1000-8000-0026BB765291", window, serviceName); + + addCharacteristic(new CurrentPositionCharacteristic(window)); + addCharacteristic(new PositionStateCharacteristic(window)); + addCharacteristic(new TargetPositionCharacteristic(window)); + + /* + * if (window instanceof HorizontalTiltingWindowCovering) { + * addCharacteristic(new CurrentHorizontalTiltAngleCharacteristic((HorizontalTiltingWindowCovering) window)); + * addCharacteristic(new TargetHorizontalTiltAngleCharacteristic((HorizontalTiltingWindowCovering) window)); + * } + * if (window instanceof VerticalTiltingWindowCovering) { + * addCharacteristic(new CurrentVerticalTiltAngleCharacteristic((VerticalTiltingWindowCovering) window)); + * addCharacteristic(new TargetVerticalTiltAngleCharacteristic((VerticalTiltingWindowCovering) window)); + * } + * if (window instanceof HoldPositionWindowCovering) { + * HoldPositionWindowCovering hpwc = (HoldPositionWindowCovering) window; + * addCharacteristic(new HoldPositionCharacteristic(hpwc)); + * } + * if (window instanceof ObstructionDetectedWindowCovering) { + * ObstructionDetectedWindowCovering wc = (ObstructionDetectedWindowCovering) window; + * addCharacteristic(new ObstructionDetectedCharacteristic(() -> wc.getObstructionDetected(), + * c -> wc.subscribeObstructionDetected(c), () -> wc.unsubscribeObstructionDetected())); + * } + */ + } +}