From 7dd08680e9db17112b67b969db372518cfceec3c Mon Sep 17 00:00:00 2001 From: eugen Date: Mon, 30 Dec 2019 23:44:48 +0100 Subject: [PATCH 1/3] #93 Fix discoverability & pairing with ios13 (#95) Switch discoverable to false once client is authenticated --- .../io/github/hapjava/impl/connections/HttpSession.java | 4 +++- .../io/github/hapjava/impl/json/AccessoryController.java | 3 +-- .../io/github/hapjava/impl/pairing/FinalPairHandler.java | 6 +----- .../io/github/hapjava/impl/pairing/PairingManager.java | 8 ++------ 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/main/java/io/github/hapjava/impl/connections/HttpSession.java b/src/main/java/io/github/hapjava/impl/connections/HttpSession.java index 3ec22c42f..4a7efe7d9 100644 --- a/src/main/java/io/github/hapjava/impl/connections/HttpSession.java +++ b/src/main/java/io/github/hapjava/impl/connections/HttpSession.java @@ -66,6 +66,8 @@ public HttpResponse handleRequest(HttpRequest request) throws IOException { } public HttpResponse handleAuthenticatedRequest(HttpRequest request) throws IOException { + advertiser.setDiscoverable( + false); // brigde is already bound and should not be discoverable anymore try { switch (request.getUri()) { case "/accessories": @@ -101,7 +103,7 @@ private HttpResponse handlePairSetup(HttpRequest request) { if (pairingManager == null) { synchronized (HttpSession.class) { if (pairingManager == null) { - pairingManager = new PairingManager(authInfo, registry, advertiser); + pairingManager = new PairingManager(authInfo, registry); } } } diff --git a/src/main/java/io/github/hapjava/impl/json/AccessoryController.java b/src/main/java/io/github/hapjava/impl/json/AccessoryController.java index 9962fd58a..66c46bdcf 100644 --- a/src/main/java/io/github/hapjava/impl/json/AccessoryController.java +++ b/src/main/java/io/github/hapjava/impl/json/AccessoryController.java @@ -81,8 +81,7 @@ private CompletableFuture toJson(Service service, int interfaceId) t .thenApply( v -> { JsonArrayBuilder jsonCharacteristics = Json.createArrayBuilder(); - characteristicFutures - .stream() + characteristicFutures.stream() .map(future -> future.join()) .forEach(c -> jsonCharacteristics.add(c)); builder.add("characteristics", jsonCharacteristics); diff --git a/src/main/java/io/github/hapjava/impl/pairing/FinalPairHandler.java b/src/main/java/io/github/hapjava/impl/pairing/FinalPairHandler.java index 9ba8d1443..29b8b88a3 100644 --- a/src/main/java/io/github/hapjava/impl/pairing/FinalPairHandler.java +++ b/src/main/java/io/github/hapjava/impl/pairing/FinalPairHandler.java @@ -3,7 +3,6 @@ import io.github.hapjava.HomekitAuthInfo; import io.github.hapjava.impl.crypto.*; import io.github.hapjava.impl.http.HttpResponse; -import io.github.hapjava.impl.jmdns.JmdnsHomekitAdvertiser; import io.github.hapjava.impl.pairing.PairSetupRequest.Stage3Request; import io.github.hapjava.impl.pairing.TypeLengthValueUtils.DecodeResult; import io.github.hapjava.impl.pairing.TypeLengthValueUtils.Encoder; @@ -16,14 +15,12 @@ class FinalPairHandler { private final byte[] k; private final HomekitAuthInfo authInfo; - private final JmdnsHomekitAdvertiser advertiser; private byte[] hkdf_enc_key; - public FinalPairHandler(byte[] k, HomekitAuthInfo authInfo, JmdnsHomekitAdvertiser advertiser) { + public FinalPairHandler(byte[] k, HomekitAuthInfo authInfo) { this.k = k; this.authInfo = authInfo; - this.advertiser = advertiser; } public HttpResponse handle(PairSetupRequest req) throws Exception { @@ -66,7 +63,6 @@ private HttpResponse createUser(byte[] username, byte[] ltpk, byte[] proof) thro throw new Exception("Invalid signature"); } authInfo.createUser(authInfo.getMac() + new String(username, StandardCharsets.UTF_8), ltpk); - advertiser.setDiscoverable(false); return createResponse(); } diff --git a/src/main/java/io/github/hapjava/impl/pairing/PairingManager.java b/src/main/java/io/github/hapjava/impl/pairing/PairingManager.java index c415114b9..934181309 100644 --- a/src/main/java/io/github/hapjava/impl/pairing/PairingManager.java +++ b/src/main/java/io/github/hapjava/impl/pairing/PairingManager.java @@ -4,7 +4,6 @@ import io.github.hapjava.impl.HomekitRegistry; import io.github.hapjava.impl.http.HttpRequest; import io.github.hapjava.impl.http.HttpResponse; -import io.github.hapjava.impl.jmdns.JmdnsHomekitAdvertiser; import io.github.hapjava.impl.responses.NotFoundResponse; import io.github.hapjava.impl.responses.UnauthorizedResponse; import org.slf4j.Logger; @@ -16,15 +15,12 @@ public class PairingManager { private final HomekitAuthInfo authInfo; private final HomekitRegistry registry; - private final JmdnsHomekitAdvertiser advertiser; private SrpHandler srpHandler; - public PairingManager( - HomekitAuthInfo authInfo, HomekitRegistry registry, JmdnsHomekitAdvertiser advertiser) { + public PairingManager(HomekitAuthInfo authInfo, HomekitRegistry registry) { this.authInfo = authInfo; this.registry = registry; - this.advertiser = advertiser; } public HttpResponse handle(HttpRequest httpRequest) throws Exception { @@ -54,7 +50,7 @@ public HttpResponse handle(HttpRequest httpRequest) throws Exception { logger.warn("Received unexpected stage 3 request for " + registry.getLabel()); return new UnauthorizedResponse(); } else { - FinalPairHandler handler = new FinalPairHandler(srpHandler.getK(), authInfo, advertiser); + FinalPairHandler handler = new FinalPairHandler(srpHandler.getK(), authInfo); try { return handler.handle(req); } catch (Exception e) { From 5248eebc026a3126393b299b785a278ca3e03ed4 Mon Sep 17 00:00:00 2001 From: sobeos Date: Tue, 7 Jan 2020 23:33:23 +0100 Subject: [PATCH 2/3] Fixed package (#98) --- .../{com => io}/github/hapjava/HomekitRootTest.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) rename src/test/java/{com => io}/github/hapjava/HomekitRootTest.java (91%) diff --git a/src/test/java/com/github/hapjava/HomekitRootTest.java b/src/test/java/io/github/hapjava/HomekitRootTest.java similarity index 91% rename from src/test/java/com/github/hapjava/HomekitRootTest.java rename to src/test/java/io/github/hapjava/HomekitRootTest.java index 226e80d4a..33eb51b10 100644 --- a/src/test/java/com/github/hapjava/HomekitRootTest.java +++ b/src/test/java/io/github/hapjava/HomekitRootTest.java @@ -2,13 +2,18 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import io.github.hapjava.impl.HomekitWebHandler; import io.github.hapjava.impl.http.HomekitClientConnectionFactory; import io.github.hapjava.impl.jmdns.JmdnsHomekitAdvertiser; import java.util.concurrent.CompletableFuture; -import org.junit.*; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; public class HomekitRootTest { @@ -64,7 +69,7 @@ public void testWebHandlerStops() throws Exception { @Test public void testAdvertiserStarts() throws Exception { - String mac = "00:00:00:00:00:00"; + final String mac = "00:00:00:00:00:00"; when(authInfo.getMac()).thenReturn(mac); root.start(); verify(advertiser).advertise(eq(LABEL), eq(mac), eq(PORT), eq(1)); From 8b77a6ee9dd40f42a1d609b197be3da6611e629a Mon Sep 17 00:00:00 2001 From: eugen Date: Tue, 7 Jan 2020 23:33:59 +0100 Subject: [PATCH 3/3] add carbon dioxide sensor (#82) * increase java version * switch to openjdk8 --- .../accessories/CarbonDioxideSensor.java | 60 +++++++++++++++++++ .../CarbonDioxideDetectedState.java | 32 ++++++++++ .../CarbonDioxideDetectedCharacteristic.java | 41 +++++++++++++ .../CarbonDioxideLevelCharacteristic.java | 54 +++++++++++++++++ .../services/CarbonDioxideSensorService.java | 18 ++++++ 5 files changed, 205 insertions(+) create mode 100644 src/main/java/io/github/hapjava/accessories/CarbonDioxideSensor.java create mode 100644 src/main/java/io/github/hapjava/accessories/properties/CarbonDioxideDetectedState.java create mode 100644 src/main/java/io/github/hapjava/impl/characteristics/carbondioxide/CarbonDioxideDetectedCharacteristic.java create mode 100644 src/main/java/io/github/hapjava/impl/characteristics/carbondioxide/CarbonDioxideLevelCharacteristic.java create mode 100644 src/main/java/io/github/hapjava/impl/services/CarbonDioxideSensorService.java diff --git a/src/main/java/io/github/hapjava/accessories/CarbonDioxideSensor.java b/src/main/java/io/github/hapjava/accessories/CarbonDioxideSensor.java new file mode 100644 index 000000000..27c332471 --- /dev/null +++ b/src/main/java/io/github/hapjava/accessories/CarbonDioxideSensor.java @@ -0,0 +1,60 @@ +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.CarbonDioxideDetectedState; +import io.github.hapjava.impl.services.CarbonDioxideSensorService; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; + +/** + * A carbon dioxide sensor reports whether carbon dioxide has been detected or not. + * + *

Carbon dioxide sensors that run on batteries will need to implement this interface and also + * implement {@link BatteryStatusAccessory}. + * + * @author Eugen Freiter + */ +public interface CarbonDioxideSensor extends HomekitAccessory { + + /** + * Retrieves the state of the sensor that indicates if carbon dioxide has been detected. + * + * @return a future that will contain the carbon dioxide sensor's state + */ + CompletableFuture getCarbonDioxideDetectedState(); + + @Override + default Collection getServices() { + return Collections.singleton(new CarbonDioxideSensorService(this)); + } + + /** + * Subscribes to changes in the carbon dioxide's state. + * + * @param callback the function to call when the state changes. + */ + void subscribeCarbonDioxideDetectedState(HomekitCharacteristicChangeCallback callback); + + /** + * Retrieves the carbon dioxide level + * + * @return a future that will contain the carbon dioxide level as a value between 0 and 100000 + */ + CompletableFuture getCarbonDioxideLevel(); + + /** Unsubscribes from changes in the carbon dioxide's state. */ + void unsubscribeCarbonDioxideDetectedState(); + + /** + * Subscribes to changes in the carbon dioxide level. + * + * @param callback the function to call when the state changes. + */ + void subscribeCarbonDioxideLevel(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes in the carbon dioxide level. */ + void unsubscribeCarbonDioxideLevel(); +} diff --git a/src/main/java/io/github/hapjava/accessories/properties/CarbonDioxideDetectedState.java b/src/main/java/io/github/hapjava/accessories/properties/CarbonDioxideDetectedState.java new file mode 100644 index 000000000..66dabf5b6 --- /dev/null +++ b/src/main/java/io/github/hapjava/accessories/properties/CarbonDioxideDetectedState.java @@ -0,0 +1,32 @@ +package io.github.hapjava.accessories.properties; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +public enum CarbonDioxideDetectedState { + NORMAL(0), + ABNORMAL(1); + + private static final Map reverse; + + static { + reverse = + Arrays.stream(CarbonDioxideDetectedState.values()) + .collect(Collectors.toMap(CarbonDioxideDetectedState::getCode, t -> t)); + } + + public static CarbonDioxideDetectedState fromCode(Integer code) { + return reverse.get(code); + } + + private final int code; + + CarbonDioxideDetectedState(int code) { + this.code = code; + } + + public int getCode() { + return code; + } +} diff --git a/src/main/java/io/github/hapjava/impl/characteristics/carbondioxide/CarbonDioxideDetectedCharacteristic.java b/src/main/java/io/github/hapjava/impl/characteristics/carbondioxide/CarbonDioxideDetectedCharacteristic.java new file mode 100644 index 000000000..5ce03856a --- /dev/null +++ b/src/main/java/io/github/hapjava/impl/characteristics/carbondioxide/CarbonDioxideDetectedCharacteristic.java @@ -0,0 +1,41 @@ +package io.github.hapjava.impl.characteristics.carbondioxide; + +import io.github.hapjava.HomekitCharacteristicChangeCallback; +import io.github.hapjava.accessories.CarbonDioxideSensor; +import io.github.hapjava.accessories.properties.CarbonDioxideDetectedState; +import io.github.hapjava.characteristics.EnumCharacteristic; +import io.github.hapjava.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; + +public class CarbonDioxideDetectedCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { + + private final CarbonDioxideSensor carbonDioxideSensor; + + public CarbonDioxideDetectedCharacteristic(CarbonDioxideSensor carbonDioxideSensor) { + super("00000092-0000-1000-8000-0026BB765291", false, true, "Carbon Dioxide Detected", 1); + this.carbonDioxideSensor = carbonDioxideSensor; + } + + @Override + protected CompletableFuture getValue() { + return carbonDioxideSensor + .getCarbonDioxideDetectedState() + .thenApply(CarbonDioxideDetectedState::getCode); + } + + @Override + protected void setValue(Integer value) throws Exception { + // Read Only + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + carbonDioxideSensor.subscribeCarbonDioxideDetectedState(callback); + } + + @Override + public void unsubscribe() { + carbonDioxideSensor.unsubscribeCarbonDioxideDetectedState(); + } +} diff --git a/src/main/java/io/github/hapjava/impl/characteristics/carbondioxide/CarbonDioxideLevelCharacteristic.java b/src/main/java/io/github/hapjava/impl/characteristics/carbondioxide/CarbonDioxideLevelCharacteristic.java new file mode 100644 index 000000000..f6f6ecc9e --- /dev/null +++ b/src/main/java/io/github/hapjava/impl/characteristics/carbondioxide/CarbonDioxideLevelCharacteristic.java @@ -0,0 +1,54 @@ +package io.github.hapjava.impl.characteristics.carbondioxide; + +import io.github.hapjava.HomekitCharacteristicChangeCallback; +import io.github.hapjava.accessories.CarbonDioxideSensor; +import io.github.hapjava.characteristics.EventableCharacteristic; +import io.github.hapjava.characteristics.FloatCharacteristic; +import java.util.concurrent.CompletableFuture; + +public class CarbonDioxideLevelCharacteristic extends FloatCharacteristic + implements EventableCharacteristic { + + private final CarbonDioxideSensor sensor; + + public CarbonDioxideLevelCharacteristic(CarbonDioxideSensor sensor) { + super( + "00000093-0000-1000-8000-0026BB765291", + false, + true, + "Carbon Dioxide level", + 0, + 100000, + 0.1, + "%"); + this.sensor = sensor; + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + sensor.subscribeCarbonDioxideLevel(callback); + } + + @Override + public void unsubscribe() { + sensor.unsubscribeCarbonDioxideLevel(); + } + + @Override + protected void setValue(Double value) throws Exception { + // Read Only + } + + @Override + protected CompletableFuture getDoubleValue() { + return sensor.getCarbonDioxideLevel(); + } + + @Override + public String toString() { + return "CarbonDioxideLevelCharacteristic{" + + "sensor level =" + + sensor.getCarbonDioxideLevel() + + '}'; + } +} diff --git a/src/main/java/io/github/hapjava/impl/services/CarbonDioxideSensorService.java b/src/main/java/io/github/hapjava/impl/services/CarbonDioxideSensorService.java new file mode 100644 index 000000000..f00f04996 --- /dev/null +++ b/src/main/java/io/github/hapjava/impl/services/CarbonDioxideSensorService.java @@ -0,0 +1,18 @@ +package io.github.hapjava.impl.services; + +import io.github.hapjava.accessories.CarbonDioxideSensor; +import io.github.hapjava.impl.characteristics.carbondioxide.CarbonDioxideDetectedCharacteristic; +import io.github.hapjava.impl.characteristics.carbondioxide.CarbonDioxideLevelCharacteristic; + +public class CarbonDioxideSensorService extends AbstractServiceImpl { + + public CarbonDioxideSensorService(CarbonDioxideSensor carbonDioxideSensor) { + this(carbonDioxideSensor, carbonDioxideSensor.getLabel()); + } + + public CarbonDioxideSensorService(CarbonDioxideSensor carbonDioxideSensor, String serviceName) { + super("00000097-0000-1000-8000-0026BB765291", carbonDioxideSensor, serviceName); + addCharacteristic(new CarbonDioxideDetectedCharacteristic(carbonDioxideSensor)); + addCharacteristic(new CarbonDioxideLevelCharacteristic(carbonDioxideSensor)); + } +}