Skip to content

Commit e4068ce

Browse files
committed
Allow WindowCovering to be used without optional characteristics
The pattern for most accessories is to require only the required characteristics, and then allow the specification of optional characteristics via the inclusion of interfaces. This pattern was not followed with WindowCovering. Worse, for reasons currently not understood, the inclusion of the HoldPositionCharacteristic causes the homekit pairing with the bridge to be completely unresponsive. (See issue #56) Change is made in a backwards compatible way, so that existing implementations that depend on WindowCovering as implemented will continue to function Addresses #56
1 parent 939c344 commit e4068ce

File tree

9 files changed

+162
-121
lines changed

9 files changed

+162
-121
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.beowulfe.hap.accessories;
2+
3+
import com.beowulfe.hap.HomekitAccessory;
4+
import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
5+
import com.beowulfe.hap.Service;
6+
import com.beowulfe.hap.accessories.properties.WindowCoveringPositionState;
7+
import com.beowulfe.hap.impl.services.WindowCoveringService;
8+
import java.util.Collection;
9+
import java.util.Collections;
10+
import java.util.concurrent.CompletableFuture;
11+
12+
public interface BasicWindowCovering extends HomekitAccessory {
13+
14+
/**
15+
* Retrieves the current position
16+
*
17+
* @return a future that will contain the position as a value between 0 and 100
18+
*/
19+
CompletableFuture<Integer> getCurrentPosition();
20+
21+
/**
22+
* Retrieves the target position
23+
*
24+
* @return a future that will contain the target position as a value between 0 and 100
25+
*/
26+
CompletableFuture<Integer> getTargetPosition();
27+
28+
/**
29+
* Retrieves the state of the position: increasing, decreasing, or stopped
30+
*
31+
* @return a future that will contain the current state
32+
*/
33+
CompletableFuture<WindowCoveringPositionState> getPositionState();
34+
35+
/**
36+
* Sets the target position
37+
*
38+
* @param position the target position to set, as a value between 1 and 100
39+
* @return a future that completes when the change is made
40+
* @throws Exception when the change cannot be made
41+
*/
42+
CompletableFuture<Void> setTargetPosition(int position) throws Exception;
43+
44+
/**
45+
* Subscribes to changes in the current position.
46+
*
47+
* @param callback the function to call when the state changes.
48+
*/
49+
void subscribeCurrentPosition(HomekitCharacteristicChangeCallback callback);
50+
51+
/**
52+
* Subscribes to changes in the target position.
53+
*
54+
* @param callback the function to call when the state changes.
55+
*/
56+
void subscribeTargetPosition(HomekitCharacteristicChangeCallback callback);
57+
58+
/**
59+
* Subscribes to changes in the position state: increasing, decreasing, or stopped
60+
*
61+
* @param callback the function to call when the state changes.
62+
*/
63+
void subscribePositionState(HomekitCharacteristicChangeCallback callback);
64+
65+
/** Unsubscribes from changes in the current position. */
66+
void unsubscribeCurrentPosition();
67+
68+
/** Unsubscribes from changes in the target position. */
69+
void unsubscribeTargetPosition();
70+
71+
/** Unsubscribes from changes in the position state */
72+
void unsubscribePositionState();
73+
74+
@Override
75+
default Collection<Service> getServices() {
76+
return Collections.singleton(new WindowCoveringService(this));
77+
}
78+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.beowulfe.hap.accessories;
2+
3+
import java.util.concurrent.CompletableFuture;
4+
5+
public interface HoldPositionWindowCovering {
6+
7+
/**
8+
* Sets the hold position state
9+
*
10+
* @param hold whether or not to hold the current position state
11+
* @return a future that completes when the change is made
12+
* @throws Exception when the change cannot be made
13+
*/
14+
CompletableFuture<Void> setHoldPosition(boolean hold) throws Exception;
15+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.beowulfe.hap.accessories;
2+
3+
import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
4+
import java.util.concurrent.CompletableFuture;
5+
6+
public interface ObstructionDetectedWindowCovering {
7+
8+
/**
9+
* Retrieves an indication that the window covering is obstructed from moving
10+
*
11+
* @return a future that will contain a boolean indicating whether an obstruction is present
12+
*/
13+
CompletableFuture<Boolean> getObstructionDetected();
14+
15+
/**
16+
* Subscribes to changes in the obstruction detected state
17+
*
18+
* @param callback the function to call when the state changes.
19+
*/
20+
void subscribeObstructionDetected(HomekitCharacteristicChangeCallback callback);
21+
22+
/** Unsubscribes from changes in the obstruction detected state */
23+
void unsubscribeObstructionDetected();
24+
}
Lines changed: 8 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,16 @@
11
package com.beowulfe.hap.accessories;
22

3-
import com.beowulfe.hap.*;
4-
import com.beowulfe.hap.accessories.properties.WindowCoveringPositionState;
5-
import com.beowulfe.hap.impl.services.WindowCoveringService;
6-
import java.util.Collection;
7-
import java.util.Collections;
8-
import java.util.concurrent.CompletableFuture;
9-
103
/**
114
* A window covering, like blinds, which can be remotely controlled.
125
*
136
* @author Andy Lintner
7+
* @deprecated In 1.2.x, this interface will become replaced with BasicWindowCovering. Update your
8+
* code to use that interface for now, and include the HoldPositionWindowCovering and
9+
* ObstructionDetectedWindowCovering interfaces respectively
1410
*/
15-
public interface WindowCovering extends HomekitAccessory {
16-
17-
/**
18-
* Retrieves the current position
19-
*
20-
* @return a future that will contain the position as a value between 0 and 100
21-
*/
22-
CompletableFuture<Integer> getCurrentPosition();
23-
24-
/**
25-
* Retrieves the target position
26-
*
27-
* @return a future that will contain the target position as a value between 0 and 100
28-
*/
29-
CompletableFuture<Integer> getTargetPosition();
30-
31-
/**
32-
* Retrieves the state of the position: increasing, decreasing, or stopped
33-
*
34-
* @return a future that will contain the current state
35-
*/
36-
CompletableFuture<WindowCoveringPositionState> getPositionState();
37-
38-
/**
39-
* Retrieves an indication that the window covering is obstructed from moving
40-
*
41-
* @return a future that will contain a boolean indicating whether an obstruction is present
42-
*/
43-
CompletableFuture<Boolean> getObstructionDetected();
44-
45-
@Override
46-
default Collection<Service> getServices() {
47-
return Collections.singleton(new WindowCoveringService(this));
48-
}
49-
50-
/**
51-
* Sets the target position
52-
*
53-
* @param position the target position to set, as a value between 1 and 100
54-
* @return a future that completes when the change is made
55-
* @throws Exception when the change cannot be made
56-
*/
57-
CompletableFuture<Void> setTargetPosition(int position) throws Exception;
58-
59-
/**
60-
* Sets the hold position state
61-
*
62-
* @param hold whether or not to hold the current position state
63-
* @return a future that completes when the change is made
64-
* @throws Exception when the change cannot be made
65-
*/
66-
CompletableFuture<Void> setHoldPosition(boolean hold) throws Exception;
67-
68-
/**
69-
* Subscribes to changes in the current position.
70-
*
71-
* @param callback the function to call when the state changes.
72-
*/
73-
void subscribeCurrentPosition(HomekitCharacteristicChangeCallback callback);
74-
75-
/**
76-
* Subscribes to changes in the target position.
77-
*
78-
* @param callback the function to call when the state changes.
79-
*/
80-
void subscribeTargetPosition(HomekitCharacteristicChangeCallback callback);
81-
82-
/**
83-
* Subscribes to changes in the position state: increasing, decreasing, or stopped
84-
*
85-
* @param callback the function to call when the state changes.
86-
*/
87-
void subscribePositionState(HomekitCharacteristicChangeCallback callback);
88-
89-
/**
90-
* Subscribes to changes in the obstruction detected state
91-
*
92-
* @param callback the function to call when the state changes.
93-
*/
94-
void subscribeObstructionDetected(HomekitCharacteristicChangeCallback callback);
95-
96-
/** Unsubscribes from changes in the current position. */
97-
void unsubscribeCurrentPosition();
98-
99-
/** Unsubscribes from changes in the target position. */
100-
void unsubscribeTargetPosition();
101-
102-
/** Unsubscribes from changes in the position state */
103-
void unsubscribePositionState();
104-
105-
/** Unsubscribes from changes in the obstruction detected state */
106-
void unsubscribeObstructionDetected();
11+
@Deprecated
12+
public interface WindowCovering
13+
extends BasicWindowCovering, HoldPositionWindowCovering, ObstructionDetectedWindowCovering {
14+
/*
15+
* TODO - 1.2.x: Replace this interface with BasicWindowCovering */
10716
}

src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/CurrentPositionCharacteristic.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
package com.beowulfe.hap.impl.characteristics.windowcovering;
22

33
import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
4-
import com.beowulfe.hap.accessories.WindowCovering;
4+
import com.beowulfe.hap.accessories.BasicWindowCovering;
55
import com.beowulfe.hap.characteristics.EventableCharacteristic;
66
import com.beowulfe.hap.characteristics.IntegerCharacteristic;
77
import java.util.concurrent.CompletableFuture;
88

99
public class CurrentPositionCharacteristic extends IntegerCharacteristic
1010
implements EventableCharacteristic {
1111

12-
private final WindowCovering windowCovering;
12+
private final BasicWindowCovering windowCovering;
1313

14-
public CurrentPositionCharacteristic(WindowCovering windowCovering) {
14+
public CurrentPositionCharacteristic(BasicWindowCovering windowCovering) {
1515
super("0000006D-0000-1000-8000-0026BB765291", false, true, "The current position", 0, 100, "%");
1616
this.windowCovering = windowCovering;
1717
}

src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/HoldPositionCharacteristic.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package com.beowulfe.hap.impl.characteristics.windowcovering;
22

3-
import com.beowulfe.hap.accessories.WindowCovering;
3+
import com.beowulfe.hap.accessories.HoldPositionWindowCovering;
44
import com.beowulfe.hap.characteristics.BooleanCharacteristic;
55
import java.util.concurrent.CompletableFuture;
66

77
public class HoldPositionCharacteristic extends BooleanCharacteristic {
88

9-
private final WindowCovering windowCovering;
9+
private final HoldPositionWindowCovering windowCovering;
1010

11-
public HoldPositionCharacteristic(WindowCovering windowCovering) {
11+
public HoldPositionCharacteristic(HoldPositionWindowCovering windowCovering) {
1212
super("0000006F-0000-1000-8000-0026BB765291", true, false, "Whether or not to hold position");
1313
this.windowCovering = windowCovering;
1414
}

src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/PositionStateCharacteristic.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
package com.beowulfe.hap.impl.characteristics.windowcovering;
22

33
import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
4-
import com.beowulfe.hap.accessories.WindowCovering;
4+
import com.beowulfe.hap.accessories.BasicWindowCovering;
55
import com.beowulfe.hap.characteristics.EnumCharacteristic;
66
import com.beowulfe.hap.characteristics.EventableCharacteristic;
77
import java.util.concurrent.CompletableFuture;
88

99
public class PositionStateCharacteristic extends EnumCharacteristic
1010
implements EventableCharacteristic {
1111

12-
private final WindowCovering windowCovering;
12+
private final BasicWindowCovering windowCovering;
1313

14-
public PositionStateCharacteristic(WindowCovering windowCovering) {
14+
public PositionStateCharacteristic(BasicWindowCovering windowCovering) {
1515
super("00000072-0000-1000-8000-0026BB765291", false, true, "The position state", 2);
1616
this.windowCovering = windowCovering;
1717
}

src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/TargetPositionCharacteristic.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
package com.beowulfe.hap.impl.characteristics.windowcovering;
22

33
import com.beowulfe.hap.HomekitCharacteristicChangeCallback;
4-
import com.beowulfe.hap.accessories.WindowCovering;
4+
import com.beowulfe.hap.accessories.BasicWindowCovering;
55
import com.beowulfe.hap.characteristics.EventableCharacteristic;
66
import com.beowulfe.hap.characteristics.IntegerCharacteristic;
77
import java.util.concurrent.CompletableFuture;
88

99
public class TargetPositionCharacteristic extends IntegerCharacteristic
1010
implements EventableCharacteristic {
1111

12-
private final WindowCovering windowCovering;
12+
private final BasicWindowCovering windowCovering;
1313

14-
public TargetPositionCharacteristic(WindowCovering windowCovering) {
14+
public TargetPositionCharacteristic(BasicWindowCovering windowCovering) {
1515
super("0000007C-0000-1000-8000-0026BB765291", true, true, "The target position", 0, 100, "%");
1616
this.windowCovering = windowCovering;
1717
}
Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,31 @@
11
package com.beowulfe.hap.impl.services;
22

3+
import com.beowulfe.hap.accessories.BasicWindowCovering;
4+
import com.beowulfe.hap.accessories.HoldPositionWindowCovering;
35
import com.beowulfe.hap.accessories.HorizontalTiltingWindowCovering;
6+
import com.beowulfe.hap.accessories.ObstructionDetectedWindowCovering;
47
import com.beowulfe.hap.accessories.VerticalTiltingWindowCovering;
5-
import com.beowulfe.hap.accessories.WindowCovering;
68
import com.beowulfe.hap.impl.characteristics.common.ObstructionDetectedCharacteristic;
7-
import com.beowulfe.hap.impl.characteristics.windowcovering.*;
9+
import com.beowulfe.hap.impl.characteristics.windowcovering.CurrentHorizontalTiltAngleCharacteristic;
10+
import com.beowulfe.hap.impl.characteristics.windowcovering.CurrentPositionCharacteristic;
11+
import com.beowulfe.hap.impl.characteristics.windowcovering.CurrentVerticalTiltAngleCharacteristic;
12+
import com.beowulfe.hap.impl.characteristics.windowcovering.HoldPositionCharacteristic;
13+
import com.beowulfe.hap.impl.characteristics.windowcovering.PositionStateCharacteristic;
14+
import com.beowulfe.hap.impl.characteristics.windowcovering.TargetHorizontalTiltAngleCharacteristic;
15+
import com.beowulfe.hap.impl.characteristics.windowcovering.TargetPositionCharacteristic;
16+
import com.beowulfe.hap.impl.characteristics.windowcovering.TargetVerticalTiltAngleCharacteristic;
817

918
public class WindowCoveringService extends AbstractServiceImpl {
1019

11-
public WindowCoveringService(WindowCovering windowCovering) {
20+
public WindowCoveringService(BasicWindowCovering windowCovering) {
1221
this(windowCovering, windowCovering.getLabel());
1322
}
1423

15-
public WindowCoveringService(WindowCovering windowCovering, String serviceName) {
24+
public WindowCoveringService(BasicWindowCovering windowCovering, String serviceName) {
1625
super("0000008C-0000-1000-8000-0026BB765291", windowCovering, serviceName);
1726
addCharacteristic(new CurrentPositionCharacteristic(windowCovering));
18-
addCharacteristic(new HoldPositionCharacteristic(windowCovering));
1927
addCharacteristic(new PositionStateCharacteristic(windowCovering));
2028
addCharacteristic(new TargetPositionCharacteristic(windowCovering));
21-
addCharacteristic(
22-
new ObstructionDetectedCharacteristic(
23-
() -> windowCovering.getObstructionDetected(),
24-
c -> windowCovering.subscribeObstructionDetected(c),
25-
() -> windowCovering.unsubscribeObstructionDetected()));
2629

2730
if (windowCovering instanceof HorizontalTiltingWindowCovering) {
2831
addCharacteristic(
@@ -40,5 +43,17 @@ public WindowCoveringService(WindowCovering windowCovering, String serviceName)
4043
new TargetVerticalTiltAngleCharacteristic(
4144
(VerticalTiltingWindowCovering) windowCovering));
4245
}
46+
if (windowCovering instanceof HoldPositionWindowCovering) {
47+
HoldPositionWindowCovering hpwc = (HoldPositionWindowCovering) windowCovering;
48+
addCharacteristic(new HoldPositionCharacteristic(hpwc));
49+
}
50+
if (windowCovering instanceof ObstructionDetectedWindowCovering) {
51+
ObstructionDetectedWindowCovering wc = (ObstructionDetectedWindowCovering) windowCovering;
52+
addCharacteristic(
53+
new ObstructionDetectedCharacteristic(
54+
() -> wc.getObstructionDetected(),
55+
c -> wc.subscribeObstructionDetected(c),
56+
() -> wc.unsubscribeObstructionDetected()));
57+
}
4358
}
4459
}

0 commit comments

Comments
 (0)