From 2008ca849222857e567f8d1cd7967e97f8036e8a Mon Sep 17 00:00:00 2001 From: Tim Harper Date: Mon, 21 Jan 2019 13:36:59 -0700 Subject: [PATCH 1/2] Format code automatically during compile using google-java-format There's lot of inconsistent uses of tabs vs spaces throughout the project, and this is leading to some weird diffs. I submit the project should just enforce formatting during compile time and just remove any doubt. This way contributors won't need to update their Eclipse configuration to match, as long as they run mvn compile, it'll format correctly. --- pom.xml | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index 8c3cafd82..bd96a4976 100644 --- a/pom.xml +++ b/pom.xml @@ -116,6 +116,18 @@ + + com.coveo + fmt-maven-plugin + 2.6.0 + + + + format + + + + org.apache.maven.plugins maven-compiler-plugin @@ -272,19 +284,19 @@ ossrh - gpg - ${env.GPG_KEYNAME} - ${env.GPG_PASSPHRASE} - false - deploy/pubring.gpg - deploy/secring.gpg - + gpg + ${env.GPG_KEYNAME} + ${env.GPG_PASSPHRASE} + false + deploy/pubring.gpg + deploy/secring.gpg + - - performRelease - true - - + + performRelease + true + + From adf7af0b5e80528d3435209b169777ef92981276 Mon Sep 17 00:00:00 2001 From: Tim Harper Date: Mon, 21 Jan 2019 13:36:59 -0700 Subject: [PATCH 2/2] Check in the result of formatting --- .../com/beowulfe/hap/HomekitAccessory.java | 109 ++-- .../com/beowulfe/hap/HomekitAuthInfo.java | 141 ++-- .../HomekitCharacteristicChangeCallback.java | 18 +- .../java/com/beowulfe/hap/HomekitRoot.java | 302 ++++----- .../java/com/beowulfe/hap/HomekitServer.java | 267 ++++---- .../hap/HomekitStandaloneAccessoryServer.java | 40 +- src/main/java/com/beowulfe/hap/Service.java | 40 +- .../hap/accessories/BatteryAccessory.java | 33 +- .../accessories/BatteryStatusAccessory.java | 39 +- .../hap/accessories/CarbonMonoxideSensor.java | 45 +- .../hap/accessories/ColorfulLightbulb.java | 110 ++-- .../hap/accessories/ContactSensor.java | 50 +- .../hap/accessories/DimmableLightbulb.java | 53 +- .../com/beowulfe/hap/accessories/Fan.java | 169 ++--- .../beowulfe/hap/accessories/GarageDoor.java | 127 ++-- .../HorizontalTiltingWindowCovering.java | 86 +-- .../hap/accessories/HumiditySensor.java | 46 +- .../beowulfe/hap/accessories/LeakSensor.java | 53 +- .../beowulfe/hap/accessories/LightSensor.java | 39 +- .../beowulfe/hap/accessories/Lightbulb.java | 64 +- .../hap/accessories/LockMechanism.java | 45 +- .../accessories/LockableLockMechanism.java | 45 +- .../hap/accessories/MotionSensor.java | 45 +- .../com/beowulfe/hap/accessories/Outlet.java | 99 ++- .../hap/accessories/SecuritySystem.java | 126 ++-- .../beowulfe/hap/accessories/SmokeSensor.java | 45 +- .../com/beowulfe/hap/accessories/Switch.java | 64 +- .../hap/accessories/TemperatureSensor.java | 94 +-- .../beowulfe/hap/accessories/Thermostat.java | 9 +- .../com/beowulfe/hap/accessories/Valve.java | 139 ++-- .../hap/accessories/ValveWithTimer.java | 101 ++- .../VerticalTiltingWindowCovering.java | 86 +-- .../hap/accessories/WindowCovering.java | 185 +++--- .../hap/accessories/package-info.java | 6 +- .../CarbonMonoxideDetectedState.java | 34 +- .../accessories/properties/ContactState.java | 34 +- .../CurrentSecuritySystemState.java | 77 +-- .../hap/accessories/properties/DoorState.java | 49 +- .../properties/LockMechanismState.java | 54 +- .../properties/RotationDirection.java | 46 +- .../properties/SecuritySystemAlarmType.java | 55 +- .../properties/SmokeDetectedState.java | 34 +- .../properties/TargetSecuritySystemState.java | 67 +- .../properties/TemperatureUnit.java | 47 +- .../properties/ThermostatMode.java | 51 +- .../hap/accessories/properties/ValveType.java | 39 +- .../WindowCoveringPositionState.java | 51 +- .../accessories/properties/package-info.java | 6 +- .../thermostat/BasicThermostat.java | 133 ++-- .../thermostat/CoolingThermostat.java | 46 +- .../thermostat/HeatingThermostat.java | 46 +- .../characteristics/BaseCharacteristic.java | 331 +++++----- .../BooleanCharacteristic.java | 65 +- .../hap/characteristics/Characteristic.java | 54 +- .../characteristics/EnumCharacteristic.java | 106 ++- .../EventableCharacteristic.java | 18 +- .../characteristics/FloatCharacteristic.java | 191 +++--- .../IntegerCharacteristic.java | 108 +-- .../StaticStringCharacteristic.java | 102 ++- .../WriteOnlyBooleanCharacteristic.java | 43 +- .../hap/characteristics/package-info.java | 2 +- .../hap/impl/ExceptionalConsumer.java | 2 +- .../com/beowulfe/hap/impl/HomekitBridge.java | 87 ++- .../beowulfe/hap/impl/HomekitRegistry.java | 149 +++-- .../com/beowulfe/hap/impl/HomekitUtils.java | 69 +- .../beowulfe/hap/impl/HomekitWebHandler.java | 13 +- .../beowulfe/hap/impl/accessories/Bridge.java | 5 +- .../CarbonMonoxideDetectedCharacteristic.java | 61 +- .../common/ActiveCharacteristic.java | 76 +-- .../common/BatteryLevelCharacteristic.java | 81 +-- .../common/InUseCharacteristic.java | 71 +- .../LowBatteryStatusCharacteristic.java | 76 +-- .../hap/impl/characteristics/common/Name.java | 10 +- .../ObstructionDetectedCharacteristic.java | 79 ++- .../common/PowerStateCharacteristic.java | 85 ++- .../RemainingDurationCharacteristic.java | 83 +-- .../ContactSensorStateCharacteristic.java | 46 +- .../fan/RotationDirectionCharacteristic.java | 49 +- .../fan/RotationSpeedCharacteristic.java | 50 +- .../CurrentDoorStateCharacteristic.java | 49 +- .../garage/TargetDoorStateCharacteristic.java | 49 +- ...CurrentRelativeHumidityCharacteristic.java | 69 +- .../characteristics/information/Identify.java | 26 +- .../information/Manufacturer.java | 12 +- .../characteristics/information/Model.java | 9 +- .../information/SerialNumber.java | 12 +- .../LeakDetectedStateCharacteristic.java | 48 +- .../AmbientLightLevelCharacteristic.java | 67 +- .../lightbulb/BrightnessCharacteristic.java | 69 +- .../lightbulb/HueCharacteristic.java | 66 +- .../lightbulb/SaturationCharacteristic.java | 70 +- ...rrentLockMechanismStateCharacteristic.java | 49 +- ...argetLockMechanismStateCharacteristic.java | 49 +- .../MotionDetectedStateCharacteristic.java | 46 +- .../outlet/OutletInUseCharacteristic.java | 51 +- ...rentSecuritySystemStateCharacteristic.java | 60 +- ...SecuritySystemAlarmTypeCharacteristic.java | 46 +- ...rgetSecuritySystemStateCharacteristic.java | 60 +- .../SmokeDetectedCharacteristic.java | 46 +- ...tractHeatingCoolingModeCharacteristic.java | 37 +- .../AbstractTemperatureCharacteristic.java | 20 +- ...ingThresholdTemperatureCharacteristic.java | 65 +- ...rrentHeatingCoolingModeCharacteristic.java | 50 +- .../CurrentTemperatureCharacteristic.java | 49 +- ...ingThresholdTemperatureCharacteristic.java | 65 +- ...argetHeatingCoolingModeCharacteristic.java | 50 +- .../TargetTemperatureCharacteristic.java | 49 +- .../TemperatureUnitsCharacteristic.java | 30 +- .../valve/SetDurationCharacteristic.java | 59 +- .../valve/ValveTypeCharacteristic.java | 45 +- ...rentHorizontalTiltAngleCharacteristic.java | 68 +- .../CurrentPositionCharacteristic.java | 49 +- ...urrentVerticalTiltAngleCharacteristic.java | 68 +- .../HoldPositionCharacteristic.java | 32 +- .../PositionStateCharacteristic.java | 49 +- ...rgetHorizontalTiltAngleCharacteristic.java | 68 +- .../TargetPositionCharacteristic.java | 49 +- ...TargetVerticalTiltAngleCharacteristic.java | 68 +- .../hap/impl/connections/ConnectionImpl.java | 246 +++---- .../HomekitClientConnectionFactoryImpl.java | 44 +- .../hap/impl/connections/HttpSession.java | 305 ++++----- .../LengthPrefixedByteArrayProcessor.java | 143 ++-- .../impl/connections/SubscriptionManager.java | 167 ++--- .../hap/impl/crypto/ChachaDecoder.java | 73 +-- .../hap/impl/crypto/ChachaEncoder.java | 79 ++- .../beowulfe/hap/impl/crypto/EdsaSigner.java | 44 +- .../hap/impl/crypto/EdsaVerifier.java | 30 +- .../hap/impl/crypto/PolyKeyCreator.java | 66 +- .../impl/http/HomekitClientConnection.java | 15 +- .../http/HomekitClientConnectionFactory.java | 3 +- .../beowulfe/hap/impl/http/HttpMethod.java | 7 +- .../beowulfe/hap/impl/http/HttpRequest.java | 9 +- .../beowulfe/hap/impl/http/HttpResponse.java | 42 +- .../hap/impl/http/impl/AccessoryHandler.java | 166 ++--- .../hap/impl/http/impl/BinaryHandler.java | 113 ++-- .../http/impl/DefaultHttpRequestImpl.java | 55 +- .../http/impl/FullRequestHttpRequestImpl.java | 24 +- .../hap/impl/http/impl/HomekitHttpServer.java | 64 +- .../impl/HttpResponseEncoderAggregate.java | 27 +- .../hap/impl/http/impl/LoggingHandler.java | 70 +- .../http/impl/NettyHomekitHttpService.java | 120 ++-- .../hap/impl/http/impl/NettyResponseUtil.java | 36 +- .../hap/impl/http/impl/ServerInitializer.java | 51 +- .../impl/jmdns/JmdnsHomekitAdvertiser.java | 155 ++--- .../hap/impl/json/AccessoryController.java | 136 ++-- .../impl/json/CharacteristicsController.java | 145 +++-- .../hap/impl/json/EventController.java | 43 +- .../beowulfe/hap/impl/json/EventResponse.java | 17 +- .../impl/json/HapJsonNoContentResponse.java | 16 +- .../hap/impl/json/HapJsonResponse.java | 36 +- .../beowulfe/hap/impl/pairing/ByteUtils.java | 64 +- .../pairing/ClientEvidenceRoutineImpl.java | 102 ++- .../hap/impl/pairing/FinalPairHandler.java | 179 ++--- .../hap/impl/pairing/HomekitSRP6Routines.java | 99 ++- .../pairing/HomekitSRP6ServerSession.java | 613 ++++++++---------- .../hap/impl/pairing/MessageType.java | 46 +- .../hap/impl/pairing/PairSetupRequest.java | 166 +++-- .../impl/pairing/PairVerificationManager.java | 257 ++++---- .../impl/pairing/PairVerificationRequest.java | 130 ++-- .../hap/impl/pairing/PairingManager.java | 110 ++-- .../hap/impl/pairing/PairingResponse.java | 37 +- .../impl/pairing/PairingUpdateController.java | 56 +- .../pairing/ServerEvidenceRoutineImpl.java | 45 +- .../beowulfe/hap/impl/pairing/SrpHandler.java | 165 +++-- .../com/beowulfe/hap/impl/pairing/Stage.java | 8 +- .../impl/pairing/TypeLengthValueUtils.java | 172 +++-- .../hap/impl/pairing/UpgradeResponse.java | 39 +- .../hap/impl/responses/ConflictResponse.java | 9 +- .../InternalServerErrorResponse.java | 40 +- .../hap/impl/responses/NotFoundResponse.java | 9 +- .../hap/impl/responses/OkResponse.java | 32 +- .../impl/responses/UnauthorizedResponse.java | 9 +- .../impl/services/AbstractServiceImpl.java | 138 ++-- .../services/AccessoryInformationService.java | 22 +- .../services/CarbonMonoxideSensorService.java | 15 +- .../impl/services/ContactSensorService.java | 14 +- .../hap/impl/services/FanService.java | 31 +- .../hap/impl/services/GarageDoorService.java | 27 +- .../impl/services/HumiditySensorService.java | 17 +- .../hap/impl/services/LeakSensorService.java | 14 +- .../hap/impl/services/LightSensorService.java | 14 +- .../hap/impl/services/LightbulbService.java | 41 +- .../impl/services/LockMechanismService.java | 22 +- .../impl/services/MotionSensorService.java | 14 +- .../hap/impl/services/OutletService.java | 27 +- .../impl/services/SecuritySystemService.java | 18 +- .../hap/impl/services/SmokeSensorService.java | 14 +- .../hap/impl/services/SwitchService.java | 27 +- .../services/TemperatureSensorService.java | 15 +- .../hap/impl/services/ThermostatService.java | 37 +- .../hap/impl/services/ValveService.java | 40 +- .../impl/services/WindowCoveringService.java | 56 +- .../java/com/beowulfe/hap/package-info.java | 5 +- .../com/beowulfe/hap/HomekitRootTest.java | 176 ++--- 194 files changed, 6729 insertions(+), 6813 deletions(-) diff --git a/src/main/java/com/beowulfe/hap/HomekitAccessory.java b/src/main/java/com/beowulfe/hap/HomekitAccessory.java index af0a43e8d..0c4d57821 100644 --- a/src/main/java/com/beowulfe/hap/HomekitAccessory.java +++ b/src/main/java/com/beowulfe/hap/HomekitAccessory.java @@ -3,64 +3,67 @@ import java.util.Collection; /** - * Base interface for all Homekit Accessories. You can implement this interface directly, but most users will - * prefer to use the more full featured interfaces in {@link com.beowulfe.hap.accessories} which include a - * default implementation of {@link #getServices()}. - * + * Base interface for all Homekit Accessories. You can implement this interface directly, but most + * users will prefer to use the more full featured interfaces in {@link + * com.beowulfe.hap.accessories} which include a default implementation of {@link #getServices()}. + * * @author Andy Lintner */ public interface HomekitAccessory { - - /** - * A unique identifier that must remain static across invocations to prevent errors with paired iOS devices. When used - * as a child of a Bridge, this value must be greater than 1, as that ID is reserved for the Bridge itself. - * - * @return the unique identifier. - */ - int getId(); - /** - * Returns a label to display in iOS. - * - * @return the label. - */ - String getLabel(); - - /** - * Performs an operation that can be used to identify the accessory. This action can be performed without - * pairing. - */ - void identify(); + /** + * A unique identifier that must remain static across invocations to prevent errors with paired + * iOS devices. When used as a child of a Bridge, this value must be greater than 1, as that ID is + * reserved for the Bridge itself. + * + * @return the unique identifier. + */ + int getId(); - /** - * Returns a serial number to display in iOS. - * - * @return the serial number, or null. - */ - String getSerialNumber(); + /** + * Returns a label to display in iOS. + * + * @return the label. + */ + String getLabel(); - /** - * Returns a model name to display in iOS. - * - * @return the model name, or null. - */ - String getModel(); + /** + * Performs an operation that can be used to identify the accessory. This action can be performed + * without pairing. + */ + void identify(); - /** - * Returns a manufacturer to display in iOS. - * - * @return the manufacturer, or null. - */ - String getManufacturer(); - - /** - * The collection of Services this accessory supports. Services are the primary way to interact with the accessory via - * Homekit. Besides the Services offered here, the accessory will automatically include the required information service. - * - * This method will only be useful if you're implementing your own accessory type. For the standard accessories, use - * the default implementation provided by the interfaces in {@link com.beowulfe.hap.accessories}. - * - * @return the collection of services. - */ - Collection getServices(); + /** + * Returns a serial number to display in iOS. + * + * @return the serial number, or null. + */ + String getSerialNumber(); + + /** + * Returns a model name to display in iOS. + * + * @return the model name, or null. + */ + String getModel(); + + /** + * Returns a manufacturer to display in iOS. + * + * @return the manufacturer, or null. + */ + String getManufacturer(); + + /** + * The collection of Services this accessory supports. Services are the primary way to interact + * with the accessory via Homekit. Besides the Services offered here, the accessory will + * automatically include the required information service. + * + *

This method will only be useful if you're implementing your own accessory type. For the + * standard accessories, use the default implementation provided by the interfaces in {@link + * com.beowulfe.hap.accessories}. + * + * @return the collection of services. + */ + Collection getServices(); } diff --git a/src/main/java/com/beowulfe/hap/HomekitAuthInfo.java b/src/main/java/com/beowulfe/hap/HomekitAuthInfo.java index 0b91897e9..d43a57fc4 100644 --- a/src/main/java/com/beowulfe/hap/HomekitAuthInfo.java +++ b/src/main/java/com/beowulfe/hap/HomekitAuthInfo.java @@ -3,79 +3,86 @@ import java.math.BigInteger; /** - * Authentication info that must be provided when constructing a new {@link HomekitServer}. You will need to implement - * this interface yourself to provide the necessary callbacks to a persistent storage mechanism. All values provided - * must be constant across invocations or the accessories will require re-pairing within iOS. + * Authentication info that must be provided when constructing a new {@link HomekitServer}. You will + * need to implement this interface yourself to provide the necessary callbacks to a persistent + * storage mechanism. All values provided must be constant across invocations or the accessories + * will require re-pairing within iOS. * * @author Andy Lintner */ public interface HomekitAuthInfo { - /** - * A pin code used for pairing the device. This pin will be required within iOS in order to complete pairing. The numbers - * cannot be sequential and should not have a repeating pattern. - * - * @return the pin code, in the form ###-##-### - */ - String getPin(); - - /** - * A unique MAC address to be advertised with the Homekit information. This does not have to be the MAC address of the - * network interface. You can generate this using {@link HomekitServer#generateMac()}. - * - * @return the unique MAC address. - */ - String getMac(); + /** + * A pin code used for pairing the device. This pin will be required within iOS in order to + * complete pairing. The numbers cannot be sequential and should not have a repeating pattern. + * + * @return the pin code, in the form ###-##-### + */ + String getPin(); - /** - * The Salt that will be used when hashing the pin code to send to the client. You should generate this using - * {@link HomekitServer#generateSalt()}. - * - * @return the Salt. - */ - BigInteger getSalt(); + /** + * A unique MAC address to be advertised with the Homekit information. This does not have to be + * the MAC address of the network interface. You can generate this using {@link + * HomekitServer#generateMac()}. + * + * @return the unique MAC address. + */ + String getMac(); - /** - * The private key used by the server during pairing and message encryption. You should generate this using - * {@link HomekitServer#generateKey()} - * - * @return the private key. - */ - byte[] getPrivateKey(); - - /** - * Called during the pairing process, you should store the user and public key in a manner that the public key can later - * be retrieved using {@link #getUserPublicKey(String)}. This must be stored in a persistent store as pairing will - * need to be reset if the information is lost. - * - * @param username the iOS device's username. The value will not be meaningful to anything but iOS. - * @param publicKey the iOS device's public key. - */ - void createUser(String username, byte[] publicKey); - - /** - * Called when an iOS device needs to remove an existing pairing. Subsequent calls to {@link #getUserPublicKey(String)} for this - * username return null. - * - * @param username the username to delete from the persistent store. - */ - void removeUser(String username); + /** + * The Salt that will be used when hashing the pin code to send to the client. You should generate + * this using {@link HomekitServer#generateSalt()}. + * + * @return the Salt. + */ + BigInteger getSalt(); - /** - * Called when an already paired iOS device is re-connecting. The public key returned by this method will be compared - * with the signature of the pair verification request to validate the device. - * - * @param username the username of the iOS device to retrieve the public key for. - * @return the previously stored public key for this user. - */ - byte[] getUserPublicKey(String username); - - /** - * Called to check if a user has been created. The homekit accessory advertises whether the accessory has already been paired. - * At this time, it's unclear whether multiple users can be created, however it is known that advertising as unpaired - * will break in iOS 9. The default value has been provided to maintain API compatibility for implementations targeting iOS 8. - * - * @return whether a user has been created and stored - */ - default boolean hasUser() { return false; }; + /** + * The private key used by the server during pairing and message encryption. You should generate + * this using {@link HomekitServer#generateKey()} + * + * @return the private key. + */ + byte[] getPrivateKey(); + + /** + * Called during the pairing process, you should store the user and public key in a manner that + * the public key can later be retrieved using {@link #getUserPublicKey(String)}. This must be + * stored in a persistent store as pairing will need to be reset if the information is lost. + * + * @param username the iOS device's username. The value will not be meaningful to anything but + * iOS. + * @param publicKey the iOS device's public key. + */ + void createUser(String username, byte[] publicKey); + + /** + * Called when an iOS device needs to remove an existing pairing. Subsequent calls to {@link + * #getUserPublicKey(String)} for this username return null. + * + * @param username the username to delete from the persistent store. + */ + void removeUser(String username); + + /** + * Called when an already paired iOS device is re-connecting. The public key returned by this + * method will be compared with the signature of the pair verification request to validate the + * device. + * + * @param username the username of the iOS device to retrieve the public key for. + * @return the previously stored public key for this user. + */ + byte[] getUserPublicKey(String username); + + /** + * Called to check if a user has been created. The homekit accessory advertises whether the + * accessory has already been paired. At this time, it's unclear whether multiple users can be + * created, however it is known that advertising as unpaired will break in iOS 9. The default + * value has been provided to maintain API compatibility for implementations targeting iOS 8. + * + * @return whether a user has been created and stored + */ + default boolean hasUser() { + return false; + }; } diff --git a/src/main/java/com/beowulfe/hap/HomekitCharacteristicChangeCallback.java b/src/main/java/com/beowulfe/hap/HomekitCharacteristicChangeCallback.java index a02e88100..fbc160251 100644 --- a/src/main/java/com/beowulfe/hap/HomekitCharacteristicChangeCallback.java +++ b/src/main/java/com/beowulfe/hap/HomekitCharacteristicChangeCallback.java @@ -3,18 +3,20 @@ import com.beowulfe.hap.characteristics.EventableCharacteristic; /** - * A callback interface for notifying subscribers that a characteristic value has changed. - * - * {@link EventableCharacteristic}s can be subscribed to, and in doing so, are supplied an instance of this class. Implementors - * should call the {@link #changed()} method on the passed object when a subscribed characteristic changes. + * A callback interface for notifying subscribers that a characteristic value has changed. + * + *

{@link EventableCharacteristic}s can be subscribed to, and in doing so, are supplied an + * instance of this class. Implementors should call the {@link #changed()} method on the passed + * object when a subscribed characteristic changes. * * @author Andy Lintner */ @FunctionalInterface public interface HomekitCharacteristicChangeCallback { - /** - * Call when the value of the characteristic that was subscribed to when this object was passed changes. - */ - void changed(); + /** + * Call when the value of the characteristic that was subscribed to when this object was passed + * changes. + */ + void changed(); } diff --git a/src/main/java/com/beowulfe/hap/HomekitRoot.java b/src/main/java/com/beowulfe/hap/HomekitRoot.java index b9d954d0d..0d0ba6462 100644 --- a/src/main/java/com/beowulfe/hap/HomekitRoot.java +++ b/src/main/java/com/beowulfe/hap/HomekitRoot.java @@ -6,160 +6,170 @@ import com.beowulfe.hap.impl.connections.HomekitClientConnectionFactoryImpl; import com.beowulfe.hap.impl.connections.SubscriptionManager; import com.beowulfe.hap.impl.jmdns.JmdnsHomekitAdvertiser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.IOException; import java.net.InetAddress; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * Provides advertising and handling for Homekit accessories. This class handles the advertising of Homekit accessories and - * contains one or more accessories. When implementing a bridge accessory, you will interact with this class directly. Instantiate - * it via {@link HomekitServer#createBridge(HomekitAuthInfo, String, String, String, String)}. For single accessories, this is composed - * by {@link HomekitStandaloneAccessoryServer}. + * Provides advertising and handling for Homekit accessories. This class handles the advertising of + * Homekit accessories and contains one or more accessories. When implementing a bridge accessory, + * you will interact with this class directly. Instantiate it via {@link + * HomekitServer#createBridge(HomekitAuthInfo, String, String, String, String)}. For single + * accessories, this is composed by {@link HomekitStandaloneAccessoryServer}. * * @author Andy Lintner */ public class HomekitRoot { - - private final static Logger logger = LoggerFactory.getLogger(HomekitRoot.class); - - private final JmdnsHomekitAdvertiser advertiser; - private final HomekitWebHandler webHandler; - private final HomekitAuthInfo authInfo; - private final String label; - private final HomekitRegistry registry; - private final SubscriptionManager subscriptions = new SubscriptionManager(); - private boolean started = false; - private int configurationIndex = 1; - HomekitRoot(String label, HomekitWebHandler webHandler, InetAddress localhost, - HomekitAuthInfo authInfo) throws IOException { - this(label, webHandler, authInfo, new JmdnsHomekitAdvertiser(localhost)); - } - - HomekitRoot(String label, HomekitWebHandler webHandler, HomekitAuthInfo authInfo, - JmdnsHomekitAdvertiser advertiser) throws IOException { - this.advertiser = advertiser; - this.webHandler = webHandler; - this.authInfo = authInfo; - this.label = label; - this.registry = new HomekitRegistry(label); - } - - /** - * Add an accessory to be handled and advertised by this root. Any existing Homekit connections will be terminated to allow - * the clients to reconnect and see the updated accessory list. When using this for a bridge, the ID of the accessory must be - * greater than 1, as that ID is reserved for the Bridge itself. - * - * @param accessory to advertise and handle. - */ - public void addAccessory(HomekitAccessory accessory) { - if (accessory.getId() <= 1 && !(accessory instanceof Bridge)) { - throw new IndexOutOfBoundsException("The ID of an accessory used in a bridge must be greater than 1"); - } - addAccessorySkipRangeCheck(accessory); - } - - /** - * Skips the range check. Used by {@link HomekitStandaloneAccessoryServer} as well as {@link #addAccessory(HomekitAccessory)}; - * - * @param accessory to advertise and handle. - */ - void addAccessorySkipRangeCheck(HomekitAccessory accessory) { - this.registry.add(accessory); - logger.info("Added accessory " + accessory.getLabel()); - if (started) { - registry.reset(); - webHandler.resetConnections(); - } - } - - /** - * Removes an accessory from being handled or advertised by this root. Any existing Homekit connections will be terminated to allow - * the clients to reconnect and see the updated accessory list. - * - * @param accessory accessory to cease advertising and handling - */ - public void removeAccessory(HomekitAccessory accessory) { - this.registry.remove(accessory); - logger.info("Removed accessory " + accessory.getLabel()); - if (started) { - registry.reset(); - webHandler.resetConnections(); - } - } - - /** - * Starts advertising and handling the previously added Homekit accessories. You should try to call this after you have used the - * {@link #addAccessory(HomekitAccessory)} method to add all the initial accessories you plan on advertising, as any later additions - * will cause the Homekit clients to reconnect. - */ - public void start() { - started = true; - registry.reset(); - webHandler.start(new HomekitClientConnectionFactoryImpl(authInfo, - registry, subscriptions, advertiser)).thenAccept(port -> { - try { - refreshAuthInfo(); - advertiser.advertise(label, authInfo.getMac(), port, configurationIndex); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - } - - /** - * Stops advertising and handling the Homekit accessories. - */ - public void stop() { - advertiser.stop(); - webHandler.stop(); - started = false; - } - - /** - * Refreshes auth info after it has been changed outside this library - * - * @throws IOException if there is an error in the underlying protocol, such as a TCP error - */ - public void refreshAuthInfo() throws IOException { - advertiser.setDiscoverable(!authInfo.hasUser()); - } - - /** - * By default, most homekit requests require that the client be paired. Allowing unauthenticated requests - * can be useful for debugging, but should not be used in production. - * - * @param allow whether to allow unauthenticated requests - */ - public void allowUnauthenticatedRequests(boolean allow) { - registry.setAllowUnauthenticatedRequests(allow); - } - - - /** - * By default, the bridge advertises itself at revision 1. If you make changes to the accessories you're - * including in the bridge after your first call to {@link start()}, you should increment this number. The - * behavior of the client if the configuration index were to decrement is undefined, so this implementation will - * not manage the configuration index by automatically incrementing - preserving this state across invocations should - * be handled externally. - * - * @param revision an integer, greater than or equal to one, indicating the revision of the accessory information - * @throws IOException if there is an error in the underlying protocol, such as a TCP error - */ - public void setConfigurationIndex(int revision) throws IOException { - if (revision < 1) { - throw new IllegalArgumentException("revision must be greater than or equal to 1"); - } - this.configurationIndex = revision; - if (this.started) { - advertiser.setConfigurationIndex(revision); - } - } - - HomekitRegistry getRegistry() { - return registry; - } + private static final Logger logger = LoggerFactory.getLogger(HomekitRoot.class); + + private final JmdnsHomekitAdvertiser advertiser; + private final HomekitWebHandler webHandler; + private final HomekitAuthInfo authInfo; + private final String label; + private final HomekitRegistry registry; + private final SubscriptionManager subscriptions = new SubscriptionManager(); + private boolean started = false; + private int configurationIndex = 1; + + HomekitRoot( + String label, HomekitWebHandler webHandler, InetAddress localhost, HomekitAuthInfo authInfo) + throws IOException { + this(label, webHandler, authInfo, new JmdnsHomekitAdvertiser(localhost)); + } + + HomekitRoot( + String label, + HomekitWebHandler webHandler, + HomekitAuthInfo authInfo, + JmdnsHomekitAdvertiser advertiser) + throws IOException { + this.advertiser = advertiser; + this.webHandler = webHandler; + this.authInfo = authInfo; + this.label = label; + this.registry = new HomekitRegistry(label); + } + + /** + * Add an accessory to be handled and advertised by this root. Any existing Homekit connections + * will be terminated to allow the clients to reconnect and see the updated accessory list. When + * using this for a bridge, the ID of the accessory must be greater than 1, as that ID is reserved + * for the Bridge itself. + * + * @param accessory to advertise and handle. + */ + public void addAccessory(HomekitAccessory accessory) { + if (accessory.getId() <= 1 && !(accessory instanceof Bridge)) { + throw new IndexOutOfBoundsException( + "The ID of an accessory used in a bridge must be greater than 1"); + } + addAccessorySkipRangeCheck(accessory); + } + + /** + * Skips the range check. Used by {@link HomekitStandaloneAccessoryServer} as well as {@link + * #addAccessory(HomekitAccessory)}; + * + * @param accessory to advertise and handle. + */ + void addAccessorySkipRangeCheck(HomekitAccessory accessory) { + this.registry.add(accessory); + logger.info("Added accessory " + accessory.getLabel()); + if (started) { + registry.reset(); + webHandler.resetConnections(); + } + } + + /** + * Removes an accessory from being handled or advertised by this root. Any existing Homekit + * connections will be terminated to allow the clients to reconnect and see the updated accessory + * list. + * + * @param accessory accessory to cease advertising and handling + */ + public void removeAccessory(HomekitAccessory accessory) { + this.registry.remove(accessory); + logger.info("Removed accessory " + accessory.getLabel()); + if (started) { + registry.reset(); + webHandler.resetConnections(); + } + } + + /** + * Starts advertising and handling the previously added Homekit accessories. You should try to + * call this after you have used the {@link #addAccessory(HomekitAccessory)} method to add all the + * initial accessories you plan on advertising, as any later additions will cause the Homekit + * clients to reconnect. + */ + public void start() { + started = true; + registry.reset(); + webHandler + .start( + new HomekitClientConnectionFactoryImpl(authInfo, registry, subscriptions, advertiser)) + .thenAccept( + port -> { + try { + refreshAuthInfo(); + advertiser.advertise(label, authInfo.getMac(), port, configurationIndex); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } + + /** Stops advertising and handling the Homekit accessories. */ + public void stop() { + advertiser.stop(); + webHandler.stop(); + started = false; + } + + /** + * Refreshes auth info after it has been changed outside this library + * + * @throws IOException if there is an error in the underlying protocol, such as a TCP error + */ + public void refreshAuthInfo() throws IOException { + advertiser.setDiscoverable(!authInfo.hasUser()); + } + + /** + * By default, most homekit requests require that the client be paired. Allowing unauthenticated + * requests can be useful for debugging, but should not be used in production. + * + * @param allow whether to allow unauthenticated requests + */ + public void allowUnauthenticatedRequests(boolean allow) { + registry.setAllowUnauthenticatedRequests(allow); + } + + /** + * By default, the bridge advertises itself at revision 1. If you make changes to the accessories + * you're including in the bridge after your first call to {@link start()}, you should increment + * this number. The behavior of the client if the configuration index were to decrement is + * undefined, so this implementation will not manage the configuration index by automatically + * incrementing - preserving this state across invocations should be handled externally. + * + * @param revision an integer, greater than or equal to one, indicating the revision of the + * accessory information + * @throws IOException if there is an error in the underlying protocol, such as a TCP error + */ + public void setConfigurationIndex(int revision) throws IOException { + if (revision < 1) { + throw new IllegalArgumentException("revision must be greater than or equal to 1"); + } + this.configurationIndex = revision; + if (this.started) { + advertiser.setConfigurationIndex(revision); + } + } + HomekitRegistry getRegistry() { + return registry; + } } diff --git a/src/main/java/com/beowulfe/hap/HomekitServer.java b/src/main/java/com/beowulfe/hap/HomekitServer.java index 8653ab043..47e7afb2a 100644 --- a/src/main/java/com/beowulfe/hap/HomekitServer.java +++ b/src/main/java/com/beowulfe/hap/HomekitServer.java @@ -1,143 +1,152 @@ package com.beowulfe.hap; +import com.beowulfe.hap.impl.HomekitBridge; +import com.beowulfe.hap.impl.HomekitUtils; +import com.beowulfe.hap.impl.http.impl.HomekitHttpServer; import java.io.IOException; import java.math.BigInteger; import java.net.InetAddress; import java.security.InvalidAlgorithmParameterException; -import com.beowulfe.hap.impl.HomekitBridge; -import com.beowulfe.hap.impl.HomekitUtils; -import com.beowulfe.hap.impl.http.impl.HomekitHttpServer; - /** - * The main entry point for hap-java. Creating an instance of this class will listen for Homekit connections - * on the supplied port. Only a single root accessory can be added for each unique instance and port, however, - * that accessory may be a {@link #createBridge(HomekitAuthInfo, String, String, String, String) bridge accessory} - * containing child accessories. - * - * The {@link HomekitAuthInfo HomekitAuthInfo} argument when creating accessories should be an implementation supplied - * by your application. Several of the values needed for your implementation are provided by this class, specifically - * {@link #generateKey() generateKey}, {@link #generateMac() generateMac}, and {@link #generateSalt()}. It is important - * that you provide these same values on each start of your application or Homekit will fail to recognize your device as - * being the same. - * + * The main entry point for hap-java. Creating an instance of this class will listen for Homekit + * connections on the supplied port. Only a single root accessory can be added for each unique + * instance and port, however, that accessory may be a {@link #createBridge(HomekitAuthInfo, String, + * String, String, String) bridge accessory} containing child accessories. + * + *

The {@link HomekitAuthInfo HomekitAuthInfo} argument when creating accessories should be an + * implementation supplied by your application. Several of the values needed for your implementation + * are provided by this class, specifically {@link #generateKey() generateKey}, {@link + * #generateMac() generateMac}, and {@link #generateSalt()}. It is important that you provide these + * same values on each start of your application or Homekit will fail to recognize your device as + * being the same. + * * @author Andy Lintner */ public class HomekitServer { - private final HomekitHttpServer http; - private final InetAddress localAddress; - - /** - * Constructor. Contains an argument indicating the number of threads to use in the http server. The other constructors - * default this to the number of available processors, however you may increase this in an environment with many users - * and/or blocking accessory implementations. - * - * @param localAddress local address to bind to. - * @param port local port to bind to. - * @param nThreads number of threads to use in the http server - * @throws IOException when the server cannot bind to the supplied port - */ - public HomekitServer(InetAddress localAddress, int port, int nThreads) throws IOException { - this.localAddress = localAddress; - http = new HomekitHttpServer(port, nThreads); - } - - /** - * Constructor - * - * @param localAddress local address to bind to - * @param port local port to bind to - * @throws IOException when the server cannot bind to the supplied port - */ - public HomekitServer(InetAddress localAddress, int port) throws IOException { - this(localAddress, port, Runtime.getRuntime().availableProcessors()); - } - - /** - * Constructor - * - * @param port local port to bind to. - * @throws IOException when the server cannot bind to the supplied port - */ - public HomekitServer(int port) throws IOException { - this(InetAddress.getLocalHost(), port); - } - - /** - * Stops the service, closing down existing connections and preventing new ones. - */ - public void stop() { - http.stop(); - } - - /** - * Creates a single (non-bridge) accessory - * - * @param authInfo authentication information for this accessory. These values should be persisted and re-supplied on re-start - * of your application. - * @param accessory accessory implementation. This will usually be an implementation of an interface in - * {#link com.beowulfe.hap.accessories com.beowulfe.hap.accessories}. - * @return the newly created server. Call {@link HomekitStandaloneAccessoryServer#start start} on this to begin. - * @throws IOException when mDNS cannot connect to the network - */ - public HomekitStandaloneAccessoryServer createStandaloneAccessory(HomekitAuthInfo authInfo, - HomekitAccessory accessory) throws IOException { - return new HomekitStandaloneAccessoryServer(accessory, http, - localAddress, authInfo); - } - - /** - * Creates a bridge accessory, capable of holding multiple child accessories. This has the advantage over multiple standalone - * accessories of only requiring a single pairing from iOS for the bridge. - * - * @param authInfo authentication information for this accessory. These values should be persisted and re-supplied on re-start - * of your application. - * @param label label for the bridge. This will show in iOS during pairing. - * @param manufacturer manufacturer of the bridge. This information is exposed to iOS for unknown purposes. - * @param model model of the bridge. This is also exposed to iOS for unknown purposes. - * @param serialNumber serial number of the bridge. Also exposed. Purposes also unknown. - * @return the bridge, from which you can {@link HomekitRoot#addAccessory add accessories} and then {@link HomekitRoot#start start} handling requests. - * @throws IOException when mDNS cannot connect to the network - */ - public HomekitRoot createBridge(HomekitAuthInfo authInfo, String label, String manufacturer, - String model, String serialNumber) throws IOException { - HomekitRoot root = new HomekitRoot(label, http, localAddress, authInfo); - root.addAccessory(new HomekitBridge(label, serialNumber, model, manufacturer)); - return root; - } - - /** - * Generates a value to supply in {@link HomekitAuthInfo#getSalt() HomekitAuthInfo.getSalt()}. This is used to salt - * the pin-code. You don't need to worry about that though - the salting is done on the plaintext pin. (Yes, plaintext - * passwords are bad. Please don't secure your nuclear storage facility with this implementation) - * - * @return the generated salt - */ - static public BigInteger generateSalt() { - return HomekitUtils.generateSalt(); - } - - /** - * Generates a value to supply in {@link HomekitAuthInfo#getPrivateKey() HomekitAuthInfo.getPrivKey()}. This is used as the - * private key during pairing and connection setup. - * - * @return the generated key - * @throws InvalidAlgorithmParameterException if the JVM does not contain the necessary encryption algorithms. - */ - static public byte[] generateKey() throws InvalidAlgorithmParameterException { - return HomekitUtils.generateKey(); - } - - /** - * Generates a value to supply in {@link HomekitAuthInfo#getMac() HomekitAuthInfo.getMac()}. This is used as the unique - * identifier of the accessory during mDNS advertising. It is a valid MAC address generated in the locally administered - * range so as not to conflict with any commercial devices. - * - * @return the generated MAC - */ - static public String generateMac() { - return HomekitUtils.generateMac(); - } + private final HomekitHttpServer http; + private final InetAddress localAddress; + + /** + * Constructor. Contains an argument indicating the number of threads to use in the http server. + * The other constructors default this to the number of available processors, however you may + * increase this in an environment with many users and/or blocking accessory implementations. + * + * @param localAddress local address to bind to. + * @param port local port to bind to. + * @param nThreads number of threads to use in the http server + * @throws IOException when the server cannot bind to the supplied port + */ + public HomekitServer(InetAddress localAddress, int port, int nThreads) throws IOException { + this.localAddress = localAddress; + http = new HomekitHttpServer(port, nThreads); + } + + /** + * Constructor + * + * @param localAddress local address to bind to + * @param port local port to bind to + * @throws IOException when the server cannot bind to the supplied port + */ + public HomekitServer(InetAddress localAddress, int port) throws IOException { + this(localAddress, port, Runtime.getRuntime().availableProcessors()); + } + + /** + * Constructor + * + * @param port local port to bind to. + * @throws IOException when the server cannot bind to the supplied port + */ + public HomekitServer(int port) throws IOException { + this(InetAddress.getLocalHost(), port); + } + + /** Stops the service, closing down existing connections and preventing new ones. */ + public void stop() { + http.stop(); + } + + /** + * Creates a single (non-bridge) accessory + * + * @param authInfo authentication information for this accessory. These values should be persisted + * and re-supplied on re-start of your application. + * @param accessory accessory implementation. This will usually be an implementation of an + * interface in {#link com.beowulfe.hap.accessories com.beowulfe.hap.accessories}. + * @return the newly created server. Call {@link HomekitStandaloneAccessoryServer#start start} on + * this to begin. + * @throws IOException when mDNS cannot connect to the network + */ + public HomekitStandaloneAccessoryServer createStandaloneAccessory( + HomekitAuthInfo authInfo, HomekitAccessory accessory) throws IOException { + return new HomekitStandaloneAccessoryServer(accessory, http, localAddress, authInfo); + } + + /** + * Creates a bridge accessory, capable of holding multiple child accessories. This has the + * advantage over multiple standalone accessories of only requiring a single pairing from iOS for + * the bridge. + * + * @param authInfo authentication information for this accessory. These values should be persisted + * and re-supplied on re-start of your application. + * @param label label for the bridge. This will show in iOS during pairing. + * @param manufacturer manufacturer of the bridge. This information is exposed to iOS for unknown + * purposes. + * @param model model of the bridge. This is also exposed to iOS for unknown purposes. + * @param serialNumber serial number of the bridge. Also exposed. Purposes also unknown. + * @return the bridge, from which you can {@link HomekitRoot#addAccessory add accessories} and + * then {@link HomekitRoot#start start} handling requests. + * @throws IOException when mDNS cannot connect to the network + */ + public HomekitRoot createBridge( + HomekitAuthInfo authInfo, + String label, + String manufacturer, + String model, + String serialNumber) + throws IOException { + HomekitRoot root = new HomekitRoot(label, http, localAddress, authInfo); + root.addAccessory(new HomekitBridge(label, serialNumber, model, manufacturer)); + return root; + } + + /** + * Generates a value to supply in {@link HomekitAuthInfo#getSalt() HomekitAuthInfo.getSalt()}. + * This is used to salt the pin-code. You don't need to worry about that though - the salting is + * done on the plaintext pin. (Yes, plaintext passwords are bad. Please don't secure your nuclear + * storage facility with this implementation) + * + * @return the generated salt + */ + public static BigInteger generateSalt() { + return HomekitUtils.generateSalt(); + } + + /** + * Generates a value to supply in {@link HomekitAuthInfo#getPrivateKey() + * HomekitAuthInfo.getPrivKey()}. This is used as the private key during pairing and connection + * setup. + * + * @return the generated key + * @throws InvalidAlgorithmParameterException if the JVM does not contain the necessary encryption + * algorithms. + */ + public static byte[] generateKey() throws InvalidAlgorithmParameterException { + return HomekitUtils.generateKey(); + } + /** + * Generates a value to supply in {@link HomekitAuthInfo#getMac() HomekitAuthInfo.getMac()}. This + * is used as the unique identifier of the accessory during mDNS advertising. It is a valid MAC + * address generated in the locally administered range so as not to conflict with any commercial + * devices. + * + * @return the generated MAC + */ + public static String generateMac() { + return HomekitUtils.generateMac(); + } } diff --git a/src/main/java/com/beowulfe/hap/HomekitStandaloneAccessoryServer.java b/src/main/java/com/beowulfe/hap/HomekitStandaloneAccessoryServer.java index 9fee827f0..3b631f276 100644 --- a/src/main/java/com/beowulfe/hap/HomekitStandaloneAccessoryServer.java +++ b/src/main/java/com/beowulfe/hap/HomekitStandaloneAccessoryServer.java @@ -1,36 +1,34 @@ package com.beowulfe.hap; +import com.beowulfe.hap.impl.HomekitWebHandler; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; -import com.beowulfe.hap.impl.HomekitWebHandler; - /** - * A server for exposing standalone Homekit accessory (as opposed to a Bridge accessory which contains multiple accessories). - * Each standalone accessory will have its own pairing information, port, and pin. Instantiate this class via - * {@link HomekitServer#createStandaloneAccessory(HomekitAuthInfo, HomekitAccessory)}. + * A server for exposing standalone Homekit accessory (as opposed to a Bridge accessory which + * contains multiple accessories). Each standalone accessory will have its own pairing information, + * port, and pin. Instantiate this class via {@link + * HomekitServer#createStandaloneAccessory(HomekitAuthInfo, HomekitAccessory)}. * * @author Andy Lintner */ public class HomekitStandaloneAccessoryServer { - - private final HomekitRoot root; - HomekitStandaloneAccessoryServer(HomekitAccessory accessory, - HomekitWebHandler webHandler, InetAddress localhost, - HomekitAuthInfo authInfo) throws UnknownHostException, IOException { - root = new HomekitRoot(accessory.getLabel(), webHandler, localhost, authInfo); - root.addAccessory(accessory); - } - - /** - * Begins advertising and handling requests for this accessory. - */ - public void start() { - root.start(); - } + private final HomekitRoot root; - + HomekitStandaloneAccessoryServer( + HomekitAccessory accessory, + HomekitWebHandler webHandler, + InetAddress localhost, + HomekitAuthInfo authInfo) + throws UnknownHostException, IOException { + root = new HomekitRoot(accessory.getLabel(), webHandler, localhost, authInfo); + root.addAccessory(accessory); + } + /** Begins advertising and handling requests for this accessory. */ + public void start() { + root.start(); + } } diff --git a/src/main/java/com/beowulfe/hap/Service.java b/src/main/java/com/beowulfe/hap/Service.java index d9c74dae2..5bebea7be 100644 --- a/src/main/java/com/beowulfe/hap/Service.java +++ b/src/main/java/com/beowulfe/hap/Service.java @@ -1,8 +1,7 @@ package com.beowulfe.hap; -import java.util.List; - import com.beowulfe.hap.characteristics.Characteristic; +import java.util.List; /** * Interface for a Service offered by an accessory. @@ -11,22 +10,23 @@ */ public interface Service { - /** - * Characteristics are the variables offered for reading, updating, and eventing by the Service over the Homekit protocol. - * - * It is important to maintain the order of this list and not change its contents between invocations, or a pairing error - * will result. - * - * @return the list of Characteristics. - */ - List getCharacteristics(); - - /** - * The type is a UUID that uniquely identifies the type of Service offered. Apple defines several types for standard - * Services, however UUIDs outside this range are allowed for custom Services. - * - * @return A string representation of the UUID, with hexadecimal digits in the format ########-####-####-####-############. - */ - String getType(); + /** + * Characteristics are the variables offered for reading, updating, and eventing by the Service + * over the Homekit protocol. + * + *

It is important to maintain the order of this list and not change its contents between + * invocations, or a pairing error will result. + * + * @return the list of Characteristics. + */ + List getCharacteristics(); -} \ No newline at end of file + /** + * The type is a UUID that uniquely identifies the type of Service offered. Apple defines several + * types for standard Services, however UUIDs outside this range are allowed for custom Services. + * + * @return A string representation of the UUID, with hexadecimal digits in the format + * ########-####-####-####-############. + */ + String getType(); +} diff --git a/src/main/java/com/beowulfe/hap/accessories/BatteryAccessory.java b/src/main/java/com/beowulfe/hap/accessories/BatteryAccessory.java index b69bdf7e3..849454a97 100644 --- a/src/main/java/com/beowulfe/hap/accessories/BatteryAccessory.java +++ b/src/main/java/com/beowulfe/hap/accessories/BatteryAccessory.java @@ -1,8 +1,7 @@ package com.beowulfe.hap.accessories; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; +import java.util.concurrent.CompletableFuture; /** * Do not use. Devices that have battery levels should implement LowBatteryStatusAccessory. @@ -12,22 +11,20 @@ @Deprecated public interface BatteryAccessory { - /** - * Retrieves the battery level of the accessory. - * - * @return a future that will contain the accessory's battery state - */ - CompletableFuture getBatteryLevelState(); + /** + * Retrieves the battery level of the accessory. + * + * @return a future that will contain the accessory's battery state + */ + CompletableFuture getBatteryLevelState(); - /** - * Subscribes to changes in the battery level. - * - * @param callback the function to call when battery level changes. - */ - void subscribeBatteryLevelState(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the battery level. + * + * @param callback the function to call when battery level changes. + */ + void subscribeBatteryLevelState(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the battery level. - */ - void unsubscribeBatteryLevelState(); + /** Unsubscribes from changes in the battery level. */ + void unsubscribeBatteryLevelState(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/BatteryStatusAccessory.java b/src/main/java/com/beowulfe/hap/accessories/BatteryStatusAccessory.java index 2e817a603..21f8f0356 100644 --- a/src/main/java/com/beowulfe/hap/accessories/BatteryStatusAccessory.java +++ b/src/main/java/com/beowulfe/hap/accessories/BatteryStatusAccessory.java @@ -1,34 +1,31 @@ package com.beowulfe.hap.accessories; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; +import java.util.concurrent.CompletableFuture; /** - * An accessory that runs on batteries. Accessories that run on batteries are able to report - * battery level. + * An accessory that runs on batteries. Accessories that run on batteries are able to report battery + * level. * * @author Tim Harper */ public interface BatteryStatusAccessory { - /** - * Queries if the device battery level is low; returning a value of true - * will cause a low-battery status to appear in Home for the device. - * - * @return a future that will contain the accessory's low battery state - */ - CompletableFuture getLowBatteryState(); + /** + * Queries if the device battery level is low; returning a value of true will cause a low-battery + * status to appear in Home for the device. + * + * @return a future that will contain the accessory's low battery state + */ + CompletableFuture getLowBatteryState(); - /** - * Subscribes to changes in the battery level. - * - * @param callback the function to call when low battery state changes. - */ - void subscribeLowBatteryState(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the battery level. + * + * @param callback the function to call when low battery state changes. + */ + void subscribeLowBatteryState(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the low battery state. - */ - void unsubscribeLowBatteryState(); + /** Unsubscribes from changes in the low battery state. */ + void unsubscribeLowBatteryState(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/CarbonMonoxideSensor.java b/src/main/java/com/beowulfe/hap/accessories/CarbonMonoxideSensor.java index 545a6b22a..85bf73ac4 100644 --- a/src/main/java/com/beowulfe/hap/accessories/CarbonMonoxideSensor.java +++ b/src/main/java/com/beowulfe/hap/accessories/CarbonMonoxideSensor.java @@ -5,42 +5,39 @@ import com.beowulfe.hap.Service; import com.beowulfe.hap.accessories.properties.CarbonMonoxideDetectedState; import com.beowulfe.hap.impl.services.CarbonMonoxideSensorService; - import java.util.Collection; import java.util.Collections; import java.util.concurrent.CompletableFuture; /** - *

A carbon monoxide sensor reports whether carbon monoxide has been detected or not.

+ * A carbon monoxide sensor reports whether carbon monoxide has been detected or not. * - *

Carbon monoxide sensors that run on batteries will need to implement this interface - * and also implement {@link BatteryStatusAccessory}.

+ *

Carbon monoxide sensors that run on batteries will need to implement this interface and also + * implement {@link BatteryStatusAccessory}. * * @author Gaston Dombiak */ public interface CarbonMonoxideSensor extends HomekitAccessory { - /** - * Retrieves the state of the sensor that indicates if carbon monoxide has been detected. - * - * @return a future that will contain the carbon monoxide sensor's state - */ - CompletableFuture getCarbonMonoxideDetectedState(); + /** + * Retrieves the state of the sensor that indicates if carbon monoxide has been detected. + * + * @return a future that will contain the carbon monoxide sensor's state + */ + CompletableFuture getCarbonMonoxideDetectedState(); - @Override - default Collection getServices() { - return Collections.singleton(new CarbonMonoxideSensorService(this)); - } + @Override + default Collection getServices() { + return Collections.singleton(new CarbonMonoxideSensorService(this)); + } - /** - * Subscribes to changes in the carbon monoxide's state. - * - * @param callback the function to call when the state changes. - */ - void subscribeCarbonMonoxideDetectedState(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the carbon monoxide's state. + * + * @param callback the function to call when the state changes. + */ + void subscribeCarbonMonoxideDetectedState(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the carbon monoxide's state. - */ - void unsubscribeCarbonMonoxideDetectedState(); + /** Unsubscribes from changes in the carbon monoxide's state. */ + void unsubscribeCarbonMonoxideDetectedState(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/ColorfulLightbulb.java b/src/main/java/com/beowulfe/hap/accessories/ColorfulLightbulb.java index 6d971502a..d218bece4 100644 --- a/src/main/java/com/beowulfe/hap/accessories/ColorfulLightbulb.java +++ b/src/main/java/com/beowulfe/hap/accessories/ColorfulLightbulb.java @@ -1,67 +1,65 @@ package com.beowulfe.hap.accessories; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; +import java.util.concurrent.CompletableFuture; /** - * Extends {@link Lightbulb} with color settings. This will usually be implemented along with - * {@link DimmableLightbulb}, but not necessarily so. + * Extends {@link Lightbulb} with color settings. This will usually be implemented along with {@link + * DimmableLightbulb}, but not necessarily so. * * @author Andy Lintner */ public interface ColorfulLightbulb extends Lightbulb { - /** - * Retrieves the current hue of the light. - * - * @return a future that will contain the hue, expressed in arc degrees from 0 to 360. - */ - CompletableFuture getHue(); - - /** - * Sets the current hue of the light - * @param value the hue to set, expressed in arc degrees from 0 to 360. - * @return a future that completes when the hue is changed - * @throws Exception when the hue cannot be changed. - */ - CompletableFuture setHue(Double value) throws Exception; - - /** - * Subscribes to changes in the hue of the light. - * @param callback the function to call when the state changes. - */ - void subscribeHue(HomekitCharacteristicChangeCallback callback); - - /** - * Unsubscribes from changes in the hue of the light. - */ - void unsubscribeHue(); - - /** - * Retrieves the saturation of the light. - * - * @return a future that will contain the saturation, expressed as a value between 0 and 100. - */ - CompletableFuture getSaturation(); - - /** - * Sets the saturation of the light. - * @param value the saturation to set, expressed as a value between 0 and 100. - * @return a future that completes when the saturation is changed. - * @throws Exception when the saturation cannot be set. - */ - CompletableFuture setSaturation(Double value) throws Exception; - - /** - * Subscribes to changes in the saturation of the light. - * @param callback the function to call when the state changes. - */ - void subscribeSaturation(HomekitCharacteristicChangeCallback callback); - - /** - * Unsubscribes from changes in the saturation of the light. - */ - void unsubscribeSaturation(); - + /** + * Retrieves the current hue of the light. + * + * @return a future that will contain the hue, expressed in arc degrees from 0 to 360. + */ + CompletableFuture getHue(); + + /** + * Sets the current hue of the light + * + * @param value the hue to set, expressed in arc degrees from 0 to 360. + * @return a future that completes when the hue is changed + * @throws Exception when the hue cannot be changed. + */ + CompletableFuture setHue(Double value) throws Exception; + + /** + * Subscribes to changes in the hue of the light. + * + * @param callback the function to call when the state changes. + */ + void subscribeHue(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes in the hue of the light. */ + void unsubscribeHue(); + + /** + * Retrieves the saturation of the light. + * + * @return a future that will contain the saturation, expressed as a value between 0 and 100. + */ + CompletableFuture getSaturation(); + + /** + * Sets the saturation of the light. + * + * @param value the saturation to set, expressed as a value between 0 and 100. + * @return a future that completes when the saturation is changed. + * @throws Exception when the saturation cannot be set. + */ + CompletableFuture setSaturation(Double value) throws Exception; + + /** + * Subscribes to changes in the saturation of the light. + * + * @param callback the function to call when the state changes. + */ + void subscribeSaturation(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes in the saturation of the light. */ + void unsubscribeSaturation(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/ContactSensor.java b/src/main/java/com/beowulfe/hap/accessories/ContactSensor.java index 4f3b6bceb..4078278df 100644 --- a/src/main/java/com/beowulfe/hap/accessories/ContactSensor.java +++ b/src/main/java/com/beowulfe/hap/accessories/ContactSensor.java @@ -5,45 +5,41 @@ import com.beowulfe.hap.Service; import com.beowulfe.hap.accessories.properties.ContactState; import com.beowulfe.hap.impl.services.ContactSensorService; - import java.util.Collection; import java.util.Collections; import java.util.concurrent.CompletableFuture; /** - *

A contact sensor that reports whether contact is detected or not. Typical - * contact sensors are window/door sensors. When contact is detected it means - * that the door/window is closed.

+ * A contact sensor that reports whether contact is detected or not. Typical contact sensors are + * window/door sensors. When contact is detected it means that the door/window is closed. * - *

Contact sensors that run on batteries will need to implement this interface - * and also implement {@link BatteryStatusAccessory}.

+ *

Contact sensors that run on batteries will need to implement this interface and also implement + * {@link BatteryStatusAccessory}. * * @author Gaston Dombiak */ public interface ContactSensor extends HomekitAccessory { - /** - * Retrieves the state of the contact. This is whether the contact is detected or not. - * Detected contact means door/window is closed. - * - * @return a future that will contain the contact's state - */ - CompletableFuture getCurrentState(); + /** + * Retrieves the state of the contact. This is whether the contact is detected or not. Detected + * contact means door/window is closed. + * + * @return a future that will contain the contact's state + */ + CompletableFuture getCurrentState(); - @Override - default Collection getServices() { - return Collections.singleton(new ContactSensorService(this)); - } + @Override + default Collection getServices() { + return Collections.singleton(new ContactSensorService(this)); + } - /** - * Subscribes to changes in the contact state. - * - * @param callback the function to call when the state changes. - */ - void subscribeContactState(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the contact state. + * + * @param callback the function to call when the state changes. + */ + void subscribeContactState(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the contact state. - */ - void unsubscribeContactState(); + /** Unsubscribes from changes in the contact state. */ + void unsubscribeContactState(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/DimmableLightbulb.java b/src/main/java/com/beowulfe/hap/accessories/DimmableLightbulb.java index 77ae675bf..e83b592e5 100644 --- a/src/main/java/com/beowulfe/hap/accessories/DimmableLightbulb.java +++ b/src/main/java/com/beowulfe/hap/accessories/DimmableLightbulb.java @@ -1,8 +1,7 @@ package com.beowulfe.hap.accessories; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; +import java.util.concurrent.CompletableFuture; /** * Extends {@link Lightbulb} with brightness values. @@ -11,29 +10,29 @@ */ public interface DimmableLightbulb extends Lightbulb { - /** - * Retrieves the current brightness of the light - * @return a future that will contain the brightness, expressed as an integer between 0 and 100. - */ - CompletableFuture getBrightness(); - - /** - * Sets the current brightness of the light - * @param value the brightness, on a scale of 0 to 100, to set - * @return a future that completes when the brightness is changed - * @throws Exception when the brightness cannot be set - */ - CompletableFuture setBrightness(Integer value) throws Exception; - - /** - * Subscribes to changes in the brightness of the light. - * @param callback the function to call when the state changes. - */ - void subscribeBrightness(HomekitCharacteristicChangeCallback callback); - - /** - * Unsubscribes from changes in the brightness of the light. - */ - void unsubscribeBrightness(); - + /** + * Retrieves the current brightness of the light + * + * @return a future that will contain the brightness, expressed as an integer between 0 and 100. + */ + CompletableFuture getBrightness(); + + /** + * Sets the current brightness of the light + * + * @param value the brightness, on a scale of 0 to 100, to set + * @return a future that completes when the brightness is changed + * @throws Exception when the brightness cannot be set + */ + CompletableFuture setBrightness(Integer value) throws Exception; + + /** + * Subscribes to changes in the brightness of the light. + * + * @param callback the function to call when the state changes. + */ + void subscribeBrightness(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes in the brightness of the light. */ + void unsubscribeBrightness(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/Fan.java b/src/main/java/com/beowulfe/hap/accessories/Fan.java index 37a2871d7..fe1acbaae 100644 --- a/src/main/java/com/beowulfe/hap/accessories/Fan.java +++ b/src/main/java/com/beowulfe/hap/accessories/Fan.java @@ -1,12 +1,11 @@ package com.beowulfe.hap.accessories; -import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.*; import com.beowulfe.hap.accessories.properties.RotationDirection; import com.beowulfe.hap.impl.services.FanService; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; /** * A fan, with power and rotational characteristics. @@ -15,84 +14,86 @@ */ public interface Fan extends HomekitAccessory { - /** - * Retrieves the current binary state of the fan's power. - * @return a future that will contain the binary state - */ - CompletableFuture getFanPower(); - - /** - * Retrieves the current rotation direction of the fan. - * @return a future that will contain the direction - */ - CompletableFuture getRotationDirection(); - - /** - * Retrieves the current speed of the fan's rotation - * @return a future that will contain the speed, expressed as an integer between 0 and 100. - */ - CompletableFuture getRotationSpeed(); - - /** - * Sets the binary state of the fan's power - * @param state the binary state to set - * @return a future that completes when the change is made - * @throws Exception when the change cannot be made - */ - CompletableFuture setFanPower(boolean state) throws Exception; - - /** - * Sets the rotation direction of the fan - * @param direction the direction to set - * @return a future that completes when the change is made - * @throws Exception when the change cannot be made - */ - CompletableFuture setRotationDirection(RotationDirection direction) throws Exception; - - - /** - * Sets the speed of the fan's rotation - * @param speed the speed to set, expressed as an integer between 0 and 100. - * @return a future that completes when the change is made - * @throws Exception when the change cannot be made - */ - CompletableFuture setRotationSpeed(Integer speed) throws Exception; - - @Override - default Collection getServices() { - return Collections.singleton(new FanService(this)); - } - - /** - * Subscribes to changes in the binary state of the fan's power. - * @param callback the function to call when the state changes. - */ - void subscribeFanPower(HomekitCharacteristicChangeCallback callback); - - /** - * Subscribes to changes in the rotation direction of the fan. - * @param callback the function to call when the direction changes. - */ - void subscribeRotationDirection(HomekitCharacteristicChangeCallback callback); - - /** - * Subscribes to changes in the rotation speed of the fan. - * @param callback the function to call when the speed changes. - */ - void subscribeRotationSpeed(HomekitCharacteristicChangeCallback callback); - - /** - * Unsubscribes from changes in the binary state of the fan's power. - */ - void unsubscribeFanPower(); - - /** - * Unsubscribes from changes in the rotation direction of the fan. - */ - void unsubscribeRotationDirection(); - - /** - * Unsubscribes from changes in the fan's rotation speed. - */ - void unsubscribeRotationSpeed(); + /** + * Retrieves the current binary state of the fan's power. + * + * @return a future that will contain the binary state + */ + CompletableFuture getFanPower(); + + /** + * Retrieves the current rotation direction of the fan. + * + * @return a future that will contain the direction + */ + CompletableFuture getRotationDirection(); + + /** + * Retrieves the current speed of the fan's rotation + * + * @return a future that will contain the speed, expressed as an integer between 0 and 100. + */ + CompletableFuture getRotationSpeed(); + + /** + * Sets the binary state of the fan's power + * + * @param state the binary state to set + * @return a future that completes when the change is made + * @throws Exception when the change cannot be made + */ + CompletableFuture setFanPower(boolean state) throws Exception; + + /** + * Sets the rotation direction of the fan + * + * @param direction the direction to set + * @return a future that completes when the change is made + * @throws Exception when the change cannot be made + */ + CompletableFuture setRotationDirection(RotationDirection direction) throws Exception; + + /** + * Sets the speed of the fan's rotation + * + * @param speed the speed to set, expressed as an integer between 0 and 100. + * @return a future that completes when the change is made + * @throws Exception when the change cannot be made + */ + CompletableFuture setRotationSpeed(Integer speed) throws Exception; + + @Override + default Collection getServices() { + return Collections.singleton(new FanService(this)); + } + + /** + * Subscribes to changes in the binary state of the fan's power. + * + * @param callback the function to call when the state changes. + */ + void subscribeFanPower(HomekitCharacteristicChangeCallback callback); + + /** + * Subscribes to changes in the rotation direction of the fan. + * + * @param callback the function to call when the direction changes. + */ + void subscribeRotationDirection(HomekitCharacteristicChangeCallback callback); + + /** + * Subscribes to changes in the rotation speed of the fan. + * + * @param callback the function to call when the speed changes. + */ + void subscribeRotationSpeed(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes in the binary state of the fan's power. */ + void unsubscribeFanPower(); + + /** Unsubscribes from changes in the rotation direction of the fan. */ + void unsubscribeRotationDirection(); + + /** Unsubscribes from changes in the fan's rotation speed. */ + void unsubscribeRotationSpeed(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/GarageDoor.java b/src/main/java/com/beowulfe/hap/accessories/GarageDoor.java index 43dbb8b46..9197516cd 100644 --- a/src/main/java/com/beowulfe/hap/accessories/GarageDoor.java +++ b/src/main/java/com/beowulfe/hap/accessories/GarageDoor.java @@ -1,12 +1,11 @@ package com.beowulfe.hap.accessories; -import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.*; import com.beowulfe.hap.accessories.properties.DoorState; import com.beowulfe.hap.impl.services.GarageDoorService; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; /** * A garage door opener, with control and status of a garage door @@ -15,68 +14,68 @@ */ public interface GarageDoor extends HomekitAccessory { - /** - * Retrieves the current state of the door - * @return a future which will contain the door's state - */ - CompletableFuture getCurrentDoorState(); - - /** - * Retrieves the targeted state of the door - * @return a future which will contain the door's targeted state - */ - CompletableFuture getTargetDoorState(); - - /** - * Retrieves an indicator of an obstruction detected by the door - * @return a future which will contain the indicator - */ - CompletableFuture getObstructionDetected(); - - /** - * Sets the targeted state of the door. - * @param state the targeted state - * @return a future that completes when the change is made - * @throws Exception when the change cannot be made - */ - CompletableFuture setTargetDoorState(DoorState state) throws Exception; + /** + * Retrieves the current state of the door + * + * @return a future which will contain the door's state + */ + CompletableFuture getCurrentDoorState(); + + /** + * Retrieves the targeted state of the door + * + * @return a future which will contain the door's targeted state + */ + CompletableFuture getTargetDoorState(); + + /** + * Retrieves an indicator of an obstruction detected by the door + * + * @return a future which will contain the indicator + */ + CompletableFuture getObstructionDetected(); + + /** + * Sets the targeted state of the door. + * + * @param state the targeted state + * @return a future that completes when the change is made + * @throws Exception when the change cannot be made + */ + CompletableFuture setTargetDoorState(DoorState state) throws Exception; + + /** + * Subscribes to changes in the door's state + * + * @param callback the function to call when the state changes + */ + void subscribeCurrentDoorState(HomekitCharacteristicChangeCallback callback); + + /** + * Subscribes to changes in the door's targeted state + * + * @param callback the function to call when the targeted state changes + */ + void subscribeTargetDoorState(HomekitCharacteristicChangeCallback callback); + + /** + * Subscribes to changes in the obstruction detected indicator + * + * @param callback the function to call when the indicator chnages + */ + void subscribeObstructionDetected(HomekitCharacteristicChangeCallback callback); - /** - * Subscribes to changes in the door's state - * @param callback the function to call when the state changes - */ - void subscribeCurrentDoorState(HomekitCharacteristicChangeCallback callback); - - /** - * Subscribes to changes in the door's targeted state - * @param callback the function to call when the targeted state changes - */ - void subscribeTargetDoorState(HomekitCharacteristicChangeCallback callback); - - /** - * Subscribes to changes in the obstruction detected indicator - * @param callback the function to call when the indicator chnages - */ - void subscribeObstructionDetected(HomekitCharacteristicChangeCallback callback); + /** Unsubscribes from changes in the door's state */ + void unsubscribeCurrentDoorState(); - /** - * Unsubscribes from changes in the door's state - */ - void unsubscribeCurrentDoorState(); - - /** - * Unsubscribes from changes in the door's targeted state - */ - void unsubscribeTargetDoorState(); - - /** - * Unsubscribes from changes in the door's obstruction detected indicator - */ - void unsubscribeObstructionDetected(); + /** Unsubscribes from changes in the door's targeted state */ + void unsubscribeTargetDoorState(); + /** Unsubscribes from changes in the door's obstruction detected indicator */ + void unsubscribeObstructionDetected(); - @Override - default Collection getServices() { - return Collections.singleton(new GarageDoorService(this)); - } + @Override + default Collection getServices() { + return Collections.singleton(new GarageDoorService(this)); + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/HorizontalTiltingWindowCovering.java b/src/main/java/com/beowulfe/hap/accessories/HorizontalTiltingWindowCovering.java index abfaf4547..5835a7bd8 100644 --- a/src/main/java/com/beowulfe/hap/accessories/HorizontalTiltingWindowCovering.java +++ b/src/main/java/com/beowulfe/hap/accessories/HorizontalTiltingWindowCovering.java @@ -1,8 +1,7 @@ package com.beowulfe.hap.accessories; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; +import java.util.concurrent.CompletableFuture; /** * Extends WindowCovering with the ability to control horizontal tilt angles @@ -11,45 +10,46 @@ */ public interface HorizontalTiltingWindowCovering extends WindowCovering { - /** - * Retrieves the current horizontal tilt angle - * @return a future that will contain the position as a value between -90 and 90 - */ - CompletableFuture getCurrentHorizontalTiltAngle(); - - /** - * Retrieves the target horizontal tilt angle - * @return a future that will contain the target position as a value between -90 and 90 - */ - CompletableFuture getTargetHorizontalTiltAngle(); - - /** - * Sets the target position - * @param angle the target angle to set, as a value between -90 and 90 - * @return a future that completes when the change is made - * @throws Exception when the change cannot be made - */ - CompletableFuture setTargetHorizontalTiltAngle(int angle) throws Exception; - - /** - * Subscribes to changes in the current horizontal tilt angle. - * @param callback the function to call when the state changes. - */ - void subscribeCurrentHorizontalTiltAngle(HomekitCharacteristicChangeCallback callback); - - /** - * Subscribes to changes in the target horizontal tilt angle. - * @param callback the function to call when the state changes. - */ - void subscribeTargetHorizontalTiltAngle(HomekitCharacteristicChangeCallback callback); - - /** - * Unsubscribes from changes in the current horizontal tilt angle - */ - void unsubscribeCurrentHorizontalTiltAngle(); - - /** - * Unsubscribes from changes in the target horizontal tilt angle - */ - void unsubscribeTargetHorizontalTiltAngle(); + /** + * Retrieves the current horizontal tilt angle + * + * @return a future that will contain the position as a value between -90 and 90 + */ + CompletableFuture getCurrentHorizontalTiltAngle(); + + /** + * Retrieves the target horizontal tilt angle + * + * @return a future that will contain the target position as a value between -90 and 90 + */ + CompletableFuture getTargetHorizontalTiltAngle(); + + /** + * Sets the target position + * + * @param angle the target angle to set, as a value between -90 and 90 + * @return a future that completes when the change is made + * @throws Exception when the change cannot be made + */ + CompletableFuture setTargetHorizontalTiltAngle(int angle) throws Exception; + + /** + * Subscribes to changes in the current horizontal tilt angle. + * + * @param callback the function to call when the state changes. + */ + void subscribeCurrentHorizontalTiltAngle(HomekitCharacteristicChangeCallback callback); + + /** + * Subscribes to changes in the target horizontal tilt angle. + * + * @param callback the function to call when the state changes. + */ + void subscribeTargetHorizontalTiltAngle(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes in the current horizontal tilt angle */ + void unsubscribeCurrentHorizontalTiltAngle(); + + /** Unsubscribes from changes in the target horizontal tilt angle */ + void unsubscribeTargetHorizontalTiltAngle(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/HumiditySensor.java b/src/main/java/com/beowulfe/hap/accessories/HumiditySensor.java index b05bf209a..0401ee582 100644 --- a/src/main/java/com/beowulfe/hap/accessories/HumiditySensor.java +++ b/src/main/java/com/beowulfe/hap/accessories/HumiditySensor.java @@ -1,12 +1,11 @@ package com.beowulfe.hap.accessories; +import com.beowulfe.hap.*; +import com.beowulfe.hap.impl.services.HumiditySensorService; import java.util.Collection; import java.util.Collections; import java.util.concurrent.CompletableFuture; -import com.beowulfe.hap.*; -import com.beowulfe.hap.impl.services.HumiditySensorService; - /** * A humidity sensor that reports the current relative humidity. * @@ -14,26 +13,25 @@ */ public interface HumiditySensor extends HomekitAccessory { - /** - * Retrieves the current relative humidity. - * @return a future that will contain the humidity as a value between 0 and 100 - */ - CompletableFuture getCurrentRelativeHumidity(); - - @Override - default Collection getServices() { - return Collections.singleton(new HumiditySensorService(this)); - } - - /** - * Subscribes to changes in the current relative humidity. - * @param callback the function to call when the state changes. - */ - void subscribeCurrentRelativeHumidity(HomekitCharacteristicChangeCallback callback); + /** + * Retrieves the current relative humidity. + * + * @return a future that will contain the humidity as a value between 0 and 100 + */ + CompletableFuture getCurrentRelativeHumidity(); + + @Override + default Collection getServices() { + return Collections.singleton(new HumiditySensorService(this)); + } + + /** + * Subscribes to changes in the current relative humidity. + * + * @param callback the function to call when the state changes. + */ + void subscribeCurrentRelativeHumidity(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the current relative humidity. - */ - void unsubscribeCurrentRelativeHumidity(); - + /** Unsubscribes from changes in the current relative humidity. */ + void unsubscribeCurrentRelativeHumidity(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/LeakSensor.java b/src/main/java/com/beowulfe/hap/accessories/LeakSensor.java index 11443f155..9de42a52c 100644 --- a/src/main/java/com/beowulfe/hap/accessories/LeakSensor.java +++ b/src/main/java/com/beowulfe/hap/accessories/LeakSensor.java @@ -1,49 +1,42 @@ package com.beowulfe.hap.accessories; -import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitAccessory; import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.Service; import com.beowulfe.hap.impl.services.LeakSensorService; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; /** - *

* A leak sensor that reports whether a leak has been detected. - *

* - *

- * Leak sensors that run on batteries will need to implement this interface - * and also implement {@link BatteryStatusAccessory}. - *

+ *

Leak sensors that run on batteries will need to implement this interface and also implement + * {@link BatteryStatusAccessory}. * * @author Tim Harper */ public interface LeakSensor extends HomekitAccessory { - /** - * Retrieves the state of the leak sensor. If true then leak has been detected. - * - * @return a future that will contain the leak sensor's state - */ - CompletableFuture getLeakDetected(); + /** + * Retrieves the state of the leak sensor. If true then leak has been detected. + * + * @return a future that will contain the leak sensor's state + */ + CompletableFuture getLeakDetected(); - @Override - default Collection getServices() { - return Collections.singleton(new LeakSensorService(this)); - } + @Override + default Collection getServices() { + return Collections.singleton(new LeakSensorService(this)); + } - /** - * Subscribes to changes in the leak sensor. - * - * @param callback the function to call when the state changes. - */ - void subscribeLeakDetected(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the leak sensor. + * + * @param callback the function to call when the state changes. + */ + void subscribeLeakDetected(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the leak sensor. - */ - void unsubscribeLeakDetected(); + /** Unsubscribes from changes in the leak sensor. */ + void unsubscribeLeakDetected(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/LightSensor.java b/src/main/java/com/beowulfe/hap/accessories/LightSensor.java index d9f7f5c65..7d16f406e 100644 --- a/src/main/java/com/beowulfe/hap/accessories/LightSensor.java +++ b/src/main/java/com/beowulfe/hap/accessories/LightSensor.java @@ -4,7 +4,6 @@ import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.Service; import com.beowulfe.hap.impl.services.LightSensorService; - import java.util.Collection; import java.util.Collections; import java.util.concurrent.CompletableFuture; @@ -16,27 +15,25 @@ */ public interface LightSensor extends HomekitAccessory { - /** - * Retrieves the current ambient light level. - * - * @return a future that will contain the luminance level expressed in LUX. - */ - CompletableFuture getCurrentAmbientLightLevel(); + /** + * Retrieves the current ambient light level. + * + * @return a future that will contain the luminance level expressed in LUX. + */ + CompletableFuture getCurrentAmbientLightLevel(); - @Override - default Collection getServices() { - return Collections.singleton(new LightSensorService(this)); - } + @Override + default Collection getServices() { + return Collections.singleton(new LightSensorService(this)); + } - /** - * Subscribes to changes in the current ambient light level. - * - * @param callback the function to call when the state changes. - */ - void subscribeCurrentAmbientLightLevel(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the current ambient light level. + * + * @param callback the function to call when the state changes. + */ + void subscribeCurrentAmbientLightLevel(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the current ambient light level. - */ - void unsubscribeCurrentAmbientLightLevel(); + /** Unsubscribes from changes in the current ambient light level. */ + void unsubscribeCurrentAmbientLightLevel(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/Lightbulb.java b/src/main/java/com/beowulfe/hap/accessories/Lightbulb.java index e60fe3a4e..58f350618 100644 --- a/src/main/java/com/beowulfe/hap/accessories/Lightbulb.java +++ b/src/main/java/com/beowulfe/hap/accessories/Lightbulb.java @@ -1,12 +1,11 @@ package com.beowulfe.hap.accessories; +import com.beowulfe.hap.*; +import com.beowulfe.hap.impl.services.LightbulbService; import java.util.Collection; import java.util.Collections; import java.util.concurrent.CompletableFuture; -import com.beowulfe.hap.*; -import com.beowulfe.hap.impl.services.LightbulbService; - /** * A simple light with a binary state. * @@ -14,33 +13,34 @@ */ public interface Lightbulb extends HomekitAccessory { - /** - * Retrieves the current binary state of the light. - * @return a future that will contain the binary state - */ - CompletableFuture getLightbulbPowerState(); - - /** - * Sets the binary state of the light - * @param powerState the binary state to set - * @return a future that completes when the change is made - * @throws Exception when the change cannot be made - */ - CompletableFuture setLightbulbPowerState(boolean powerState) throws Exception; - - @Override - default Collection getServices() { - return Collections.singleton(new LightbulbService(this)); - } - - /** - * Subscribes to changes in the binary state of the light. - * @param callback the function to call when the state changes. - */ - void subscribeLightbulbPowerState(HomekitCharacteristicChangeCallback callback); - - /** - * Unsubscribes from changes in the binary state of the light. - */ - void unsubscribeLightbulbPowerState(); + /** + * Retrieves the current binary state of the light. + * + * @return a future that will contain the binary state + */ + CompletableFuture getLightbulbPowerState(); + + /** + * Sets the binary state of the light + * + * @param powerState the binary state to set + * @return a future that completes when the change is made + * @throws Exception when the change cannot be made + */ + CompletableFuture setLightbulbPowerState(boolean powerState) throws Exception; + + @Override + default Collection getServices() { + return Collections.singleton(new LightbulbService(this)); + } + + /** + * Subscribes to changes in the binary state of the light. + * + * @param callback the function to call when the state changes. + */ + void subscribeLightbulbPowerState(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes in the binary state of the light. */ + void unsubscribeLightbulbPowerState(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/LockMechanism.java b/src/main/java/com/beowulfe/hap/accessories/LockMechanism.java index 320d5dc0b..5f0fca812 100644 --- a/src/main/java/com/beowulfe/hap/accessories/LockMechanism.java +++ b/src/main/java/com/beowulfe/hap/accessories/LockMechanism.java @@ -5,41 +5,40 @@ import com.beowulfe.hap.Service; import com.beowulfe.hap.accessories.properties.LockMechanismState; import com.beowulfe.hap.impl.services.LockMechanismService; - import java.util.Collection; import java.util.Collections; import java.util.concurrent.CompletableFuture; /** - *

A lock capable of exposing its binary locked state. For a lock that can be locked/unlocked, use - * {@link LockableLockMechanism}.

+ * A lock capable of exposing its binary locked state. For a lock that can be locked/unlocked, use + * {@link LockableLockMechanism}. * - *

Locks that run on batteries will need to implement this interface and also - * implement {@link BatteryStatusAccessory}.

+ *

Locks that run on batteries will need to implement this interface and also implement {@link + * BatteryStatusAccessory}. * * @author Andy Lintner */ public interface LockMechanism extends HomekitAccessory { - /** - * Retrieves the current binary state of the lock. - * @return a future that will contain the binary state. - */ - CompletableFuture getCurrentMechanismState(); + /** + * Retrieves the current binary state of the lock. + * + * @return a future that will contain the binary state. + */ + CompletableFuture getCurrentMechanismState(); - /** - * Subscribes to changes in the binary state of the lock. - * @param callback the function to call when the state changes. - */ - void subscribeCurrentMechanismState(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the binary state of the lock. + * + * @param callback the function to call when the state changes. + */ + void subscribeCurrentMechanismState(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the binary state of the lock. - */ - void unsubscribeCurrentMechanismState(); + /** Unsubscribes from changes in the binary state of the lock. */ + void unsubscribeCurrentMechanismState(); - @Override - default Collection getServices() { - return Collections.singleton(new LockMechanismService(this)); - } + @Override + default Collection getServices() { + return Collections.singleton(new LockMechanismService(this)); + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/LockableLockMechanism.java b/src/main/java/com/beowulfe/hap/accessories/LockableLockMechanism.java index 50affacad..ef55e4d00 100644 --- a/src/main/java/com/beowulfe/hap/accessories/LockableLockMechanism.java +++ b/src/main/java/com/beowulfe/hap/accessories/LockableLockMechanism.java @@ -1,9 +1,8 @@ package com.beowulfe.hap.accessories; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.properties.LockMechanismState; +import java.util.concurrent.CompletableFuture; /** * Extends {@link LockMechanism} with the ability to lock and unlock the mechanism. @@ -12,28 +11,28 @@ */ public interface LockableLockMechanism extends LockMechanism { - /** - * Sets the binary state of the lock mechanism. - * - * @param state true for a locked mechanism, false for unlocked. - * @throws Exception when the change cannot be made. - */ - void setTargetMechanismState(LockMechanismState state) throws Exception; + /** + * Sets the binary state of the lock mechanism. + * + * @param state true for a locked mechanism, false for unlocked. + * @throws Exception when the change cannot be made. + */ + void setTargetMechanismState(LockMechanismState state) throws Exception; - /** - * Retrieves the pending, but not yet completed, state of the lock mechanism. - * @return the binary state - */ - CompletableFuture getTargetMechanismState(); + /** + * Retrieves the pending, but not yet completed, state of the lock mechanism. + * + * @return the binary state + */ + CompletableFuture getTargetMechanismState(); - /** - * Subscribes to changes in the pending, but not yet completed, binary state. - * @param callback the function to call when the state changes. - */ - void subscribeTargetMechanismState(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the pending, but not yet completed, binary state. + * + * @param callback the function to call when the state changes. + */ + void subscribeTargetMechanismState(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the pending, but not yet completed, binary state. - */ - void unsubscribeTargetMechanismState(); + /** Unsubscribes from changes in the pending, but not yet completed, binary state. */ + void unsubscribeTargetMechanismState(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/MotionSensor.java b/src/main/java/com/beowulfe/hap/accessories/MotionSensor.java index ee13e839c..41bd4ccbe 100644 --- a/src/main/java/com/beowulfe/hap/accessories/MotionSensor.java +++ b/src/main/java/com/beowulfe/hap/accessories/MotionSensor.java @@ -4,42 +4,39 @@ import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.Service; import com.beowulfe.hap.impl.services.MotionSensorService; - import java.util.Collection; import java.util.Collections; import java.util.concurrent.CompletableFuture; /** - *

A motion sensor that reports whether motion has been detected.

+ * A motion sensor that reports whether motion has been detected. * - *

Motion sensors that run on batteries will need to implement this interface - * and also implement {@link BatteryStatusAccessory}.

+ *

Motion sensors that run on batteries will need to implement this interface and also implement + * {@link BatteryStatusAccessory}. * * @author Gaston Dombiak */ public interface MotionSensor extends HomekitAccessory { - /** - * Retrieves the state of the motion sensor. If true then motion has been detected. - * - * @return a future that will contain the motion sensor's state - */ - CompletableFuture getMotionDetected(); + /** + * Retrieves the state of the motion sensor. If true then motion has been detected. + * + * @return a future that will contain the motion sensor's state + */ + CompletableFuture getMotionDetected(); - @Override - default Collection getServices() { - return Collections.singleton(new MotionSensorService(this)); - } + @Override + default Collection getServices() { + return Collections.singleton(new MotionSensorService(this)); + } - /** - * Subscribes to changes in the motion sensor. - * - * @param callback the function to call when the state changes. - */ - void subscribeMotionDetected(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the motion sensor. + * + * @param callback the function to call when the state changes. + */ + void subscribeMotionDetected(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the motion sensor. - */ - void unsubscribeMotionDetected(); + /** Unsubscribes from changes in the motion sensor. */ + void unsubscribeMotionDetected(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/Outlet.java b/src/main/java/com/beowulfe/hap/accessories/Outlet.java index 443acabe2..296c21a49 100644 --- a/src/main/java/com/beowulfe/hap/accessories/Outlet.java +++ b/src/main/java/com/beowulfe/hap/accessories/Outlet.java @@ -1,12 +1,11 @@ package com.beowulfe.hap.accessories; +import com.beowulfe.hap.*; +import com.beowulfe.hap.impl.services.OutletService; import java.util.Collection; import java.util.Collections; import java.util.concurrent.CompletableFuture; -import com.beowulfe.hap.*; -import com.beowulfe.hap.impl.services.OutletService; - /** * A power outlet with boolean power and usage states. * @@ -14,51 +13,51 @@ */ public interface Outlet extends HomekitAccessory { - @Override - default Collection getServices() { - return Collections.singleton(new OutletService(this)); - } - - /** - * Retrieves the current binary state of the outlet's power. - * @return a future that will contain the binary state - */ - CompletableFuture getPowerState(); - - /** - * Retrieves the current binary state indicating whether the outlet is in use. - * @return a future that will contain the binary state - */ - CompletableFuture getOutletInUse(); - - /** - * Sets the binary state of the outlet's power. - * @param state the binary state to set - * @return a future that completes when the change is made - * @throws Exception when the change cannot be made - */ - CompletableFuture setPowerState(boolean state) throws Exception; - - /** - * Subscribes to changes in the binary state of the outlet's power. - * @param callback the function to call when the state changes. - */ - void subscribePowerState(HomekitCharacteristicChangeCallback callback); - - /** - * Subscribes to changes in the binary state indicating whether the outlet is in use. - * @param callback the function to call when the state changes. - */ - void subscribeOutletInUse(HomekitCharacteristicChangeCallback callback); - - /** - * Unsubscribes from changes in the binary state of the outlet's power. - */ - void unsubscribePowerState(); - - /** - * Unsubscribes from changes in the binary state indicating whether hte outlet is in use. - */ - void unsubscribeOutletInUse(); - + @Override + default Collection getServices() { + return Collections.singleton(new OutletService(this)); + } + + /** + * Retrieves the current binary state of the outlet's power. + * + * @return a future that will contain the binary state + */ + CompletableFuture getPowerState(); + + /** + * Retrieves the current binary state indicating whether the outlet is in use. + * + * @return a future that will contain the binary state + */ + CompletableFuture getOutletInUse(); + + /** + * Sets the binary state of the outlet's power. + * + * @param state the binary state to set + * @return a future that completes when the change is made + * @throws Exception when the change cannot be made + */ + CompletableFuture setPowerState(boolean state) throws Exception; + + /** + * Subscribes to changes in the binary state of the outlet's power. + * + * @param callback the function to call when the state changes. + */ + void subscribePowerState(HomekitCharacteristicChangeCallback callback); + + /** + * Subscribes to changes in the binary state indicating whether the outlet is in use. + * + * @param callback the function to call when the state changes. + */ + void subscribeOutletInUse(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes in the binary state of the outlet's power. */ + void unsubscribePowerState(); + + /** Unsubscribes from changes in the binary state indicating whether hte outlet is in use. */ + void unsubscribeOutletInUse(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/SecuritySystem.java b/src/main/java/com/beowulfe/hap/accessories/SecuritySystem.java index 096937b25..86c274599 100644 --- a/src/main/java/com/beowulfe/hap/accessories/SecuritySystem.java +++ b/src/main/java/com/beowulfe/hap/accessories/SecuritySystem.java @@ -7,90 +7,84 @@ import com.beowulfe.hap.accessories.properties.SecuritySystemAlarmType; import com.beowulfe.hap.accessories.properties.TargetSecuritySystemState; import com.beowulfe.hap.impl.services.SecuritySystemService; - import java.util.Collection; import java.util.Collections; import java.util.concurrent.CompletableFuture; /** - *

A security system that can be armed so that when a contact sensor is opened or a motion - * sensor detects movement, then a siren could be fired off. There are different modes for arming - * the system. See {@link TargetSecuritySystemState} for more information.

+ * A security system that can be armed so that when a contact sensor is opened or a motion sensor + * detects movement, then a siren could be fired off. There are different modes for arming the + * system. See {@link TargetSecuritySystemState} for more information. * * @author Gaston Dombiak */ public interface SecuritySystem extends HomekitAccessory { - /** - * Retrieves the current state of the security system. The state describes if the system - * is armed in any of its variations; or if the alarm has been triggered; or if the system - * is disarmed. - * - * @return current state of the security system. - */ - CompletableFuture getCurrentSecuritySystemState(); + /** + * Retrieves the current state of the security system. The state describes if the system is armed + * in any of its variations; or if the alarm has been triggered; or if the system is disarmed. + * + * @return current state of the security system. + */ + CompletableFuture getCurrentSecuritySystemState(); - /** - * Subscribes to changes to the state of the security system. - * - * @param callback the function to call when the state changes. - */ - void subscribeCurrentSecuritySystemState(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes to the state of the security system. + * + * @param callback the function to call when the state changes. + */ + void subscribeCurrentSecuritySystemState(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the state of the security system. - */ - void unsubscribeCurrentSecuritySystemState(); + /** Unsubscribes from changes in the state of the security system. */ + void unsubscribeCurrentSecuritySystemState(); - /** - * Sets the state of the security system. The security system could be armed in any - * of its variations or disarmed. - * - * @param state target state of the security system. - * @throws Exception when the change cannot be made. - */ - void setTargetSecuritySystemState(TargetSecuritySystemState state) throws Exception; + /** + * Sets the state of the security system. The security system could be armed in any of its + * variations or disarmed. + * + * @param state target state of the security system. + * @throws Exception when the change cannot be made. + */ + void setTargetSecuritySystemState(TargetSecuritySystemState state) throws Exception; - /** - * Retrieves the pending, but not yet completed, state of the security system. - * - * @return target state of the security system. - */ - CompletableFuture getTargetSecuritySystemState(); + /** + * Retrieves the pending, but not yet completed, state of the security system. + * + * @return target state of the security system. + */ + CompletableFuture getTargetSecuritySystemState(); - /** - * Subscribes to changes in the pending, but not yet completed, state of the security system. - * - * @param callback the function to call when the state changes. - */ - void subscribeTargetSecuritySystemState(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the pending, but not yet completed, state of the security system. + * + * @param callback the function to call when the state changes. + */ + void subscribeTargetSecuritySystemState(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the pending, but not yet completed, state of the security system. - */ - void unsubscribeTargetSecuritySystemState(); + /** + * Unsubscribes from changes in the pending, but not yet completed, state of the security system. + */ + void unsubscribeTargetSecuritySystemState(); - /** - * Retrieves the alarm type of the security system. - * - * @return alarm type of the security system. - */ - CompletableFuture getAlarmTypeState(); + /** + * Retrieves the alarm type of the security system. + * + * @return alarm type of the security system. + */ + CompletableFuture getAlarmTypeState(); - /** - * Subscribes to changes to the alarm type of the security system. - * - * @param callback the function to call when the alarm type changes. - */ - void subscribeAlarmTypeState(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes to the alarm type of the security system. + * + * @param callback the function to call when the alarm type changes. + */ + void subscribeAlarmTypeState(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the alarm type of the security system. - */ - void unsubscribeAlarmTypeState(); + /** Unsubscribes from changes in the alarm type of the security system. */ + void unsubscribeAlarmTypeState(); - @Override - default Collection getServices() { - return Collections.singleton(new SecuritySystemService(this)); - } + @Override + default Collection getServices() { + return Collections.singleton(new SecuritySystemService(this)); + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/SmokeSensor.java b/src/main/java/com/beowulfe/hap/accessories/SmokeSensor.java index 431e8ec7a..1fa4c6412 100644 --- a/src/main/java/com/beowulfe/hap/accessories/SmokeSensor.java +++ b/src/main/java/com/beowulfe/hap/accessories/SmokeSensor.java @@ -5,42 +5,39 @@ import com.beowulfe.hap.Service; import com.beowulfe.hap.accessories.properties.SmokeDetectedState; import com.beowulfe.hap.impl.services.SmokeSensorService; - import java.util.Collection; import java.util.Collections; import java.util.concurrent.CompletableFuture; /** - *

A smoke sensor reports whether smoke has been detected or not.

+ * A smoke sensor reports whether smoke has been detected or not. * - *

Smoke sensors that run on batteries will need to implement this interface - * and also implement {@link BatteryStatusAccessory}.

+ *

Smoke sensors that run on batteries will need to implement this interface and also implement + * {@link BatteryStatusAccessory}. * * @author Gaston Dombiak */ public interface SmokeSensor extends HomekitAccessory { - /** - * Retrieves the state of the smoke sensor. This is whether smoke has been detected or not. - * - * @return a future that will contain the smoke sensor's state - */ - CompletableFuture getSmokeDetectedState(); + /** + * Retrieves the state of the smoke sensor. This is whether smoke has been detected or not. + * + * @return a future that will contain the smoke sensor's state + */ + CompletableFuture getSmokeDetectedState(); - @Override - default Collection getServices() { - return Collections.singleton(new SmokeSensorService(this)); - } + @Override + default Collection getServices() { + return Collections.singleton(new SmokeSensorService(this)); + } - /** - * Subscribes to changes in the smoke sensor's state. - * - * @param callback the function to call when the state changes. - */ - void subscribeSmokeDetectedState(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the smoke sensor's state. + * + * @param callback the function to call when the state changes. + */ + void subscribeSmokeDetectedState(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the smoke sensor's state. - */ - void unsubscribeSmokeDetectedState(); + /** Unsubscribes from changes in the smoke sensor's state. */ + void unsubscribeSmokeDetectedState(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/Switch.java b/src/main/java/com/beowulfe/hap/accessories/Switch.java index 8885a5caf..e34f4be16 100644 --- a/src/main/java/com/beowulfe/hap/accessories/Switch.java +++ b/src/main/java/com/beowulfe/hap/accessories/Switch.java @@ -1,12 +1,11 @@ package com.beowulfe.hap.accessories; +import com.beowulfe.hap.*; +import com.beowulfe.hap.impl.services.SwitchService; import java.util.Collection; import java.util.Collections; import java.util.concurrent.CompletableFuture; -import com.beowulfe.hap.*; -import com.beowulfe.hap.impl.services.SwitchService; - /** * A simple switch with a binary state. * @@ -14,33 +13,34 @@ */ public interface Switch extends HomekitAccessory { - /** - * Retrieves the current binary state of the switch. - * @return a future that will contain the binary state - */ - CompletableFuture getSwitchState(); - - /** - * Sets the binary state of the switch - * @param state the binary state to set - * @return a future that completes when the change is made - * @throws Exception when the change cannot be made - */ - CompletableFuture setSwitchState(boolean state) throws Exception; - - @Override - default Collection getServices() { - return Collections.singleton(new SwitchService(this)); - } - - /** - * Subscribes to changes in the binary state of the switch. - * @param callback the function to call when the state changes. - */ - void subscribeSwitchState(HomekitCharacteristicChangeCallback callback); - - /** - * Unsubscribes from changes in the binary state of the switch. - */ - void unsubscribeSwitchState(); + /** + * Retrieves the current binary state of the switch. + * + * @return a future that will contain the binary state + */ + CompletableFuture getSwitchState(); + + /** + * Sets the binary state of the switch + * + * @param state the binary state to set + * @return a future that completes when the change is made + * @throws Exception when the change cannot be made + */ + CompletableFuture setSwitchState(boolean state) throws Exception; + + @Override + default Collection getServices() { + return Collections.singleton(new SwitchService(this)); + } + + /** + * Subscribes to changes in the binary state of the switch. + * + * @param callback the function to call when the state changes. + */ + void subscribeSwitchState(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes in the binary state of the switch. */ + void unsubscribeSwitchState(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/TemperatureSensor.java b/src/main/java/com/beowulfe/hap/accessories/TemperatureSensor.java index ac3dd639d..1ec14d6f2 100644 --- a/src/main/java/com/beowulfe/hap/accessories/TemperatureSensor.java +++ b/src/main/java/com/beowulfe/hap/accessories/TemperatureSensor.java @@ -1,12 +1,11 @@ package com.beowulfe.hap.accessories; -import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.*; import com.beowulfe.hap.accessories.properties.TemperatureUnit; import com.beowulfe.hap.impl.services.TemperatureSensorService; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; /** * A temperature sensor that reports the current temperature @@ -15,45 +14,50 @@ */ public interface TemperatureSensor extends HomekitAccessory { - /** - * Retrieves the current temperature, in celsius degrees. - * @return a future that will contain the temperature. - */ - CompletableFuture getCurrentTemperature(); - - @Override - default Collection getServices() { - return Collections.singleton(new TemperatureSensorService(this)); - } - - /** - * Subscribes to changes in the current temperature. - * @param callback the function to call when the state changes. - */ - void subscribeCurrentTemperature(HomekitCharacteristicChangeCallback callback); - - /** - * Unsubscribes from changes in the current temperature. - */ - void unsubscribeCurrentTemperature(); - - /** - * Retrieves the minimum temperature, in celsius degrees, the thermostat can be set to. - * @return the minimum temperature. - */ - double getMinimumTemperature(); - - /** - * Retrieves the maximum temperature, in celsius degrees, the thermostat can be set to. - * @return the maximum temperature. - */ - double getMaximumTemperature(); - - /** - * Retrieves the temperature unit of the thermostat. The impact of this is unclear, as the actual temperature - * is always communicated in celsius degrees, and the iOS device uses the user's locale to determine - * the unit to convert to. - * @return the temperature unit of the thermostat. - */ - default TemperatureUnit getTemperatureUnit() { return TemperatureUnit.CELSIUS; } + /** + * Retrieves the current temperature, in celsius degrees. + * + * @return a future that will contain the temperature. + */ + CompletableFuture getCurrentTemperature(); + + @Override + default Collection getServices() { + return Collections.singleton(new TemperatureSensorService(this)); + } + + /** + * Subscribes to changes in the current temperature. + * + * @param callback the function to call when the state changes. + */ + void subscribeCurrentTemperature(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes in the current temperature. */ + void unsubscribeCurrentTemperature(); + + /** + * Retrieves the minimum temperature, in celsius degrees, the thermostat can be set to. + * + * @return the minimum temperature. + */ + double getMinimumTemperature(); + + /** + * Retrieves the maximum temperature, in celsius degrees, the thermostat can be set to. + * + * @return the maximum temperature. + */ + double getMaximumTemperature(); + + /** + * Retrieves the temperature unit of the thermostat. The impact of this is unclear, as the actual + * temperature is always communicated in celsius degrees, and the iOS device uses the user's + * locale to determine the unit to convert to. + * + * @return the temperature unit of the thermostat. + */ + default TemperatureUnit getTemperatureUnit() { + return TemperatureUnit.CELSIUS; + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/Thermostat.java b/src/main/java/com/beowulfe/hap/accessories/Thermostat.java index 40f916e44..380f365ca 100644 --- a/src/main/java/com/beowulfe/hap/accessories/Thermostat.java +++ b/src/main/java/com/beowulfe/hap/accessories/Thermostat.java @@ -6,11 +6,8 @@ * A thermostat with heating and cooling controls. * * @author Andy Lintner - * @deprecated Use {@link BasicThermostat}, {@link HeatingThermostat}, and {@link CoolingThermostat} instead + * @deprecated Use {@link BasicThermostat}, {@link HeatingThermostat}, and {@link CoolingThermostat} + * instead */ @Deprecated -public interface Thermostat extends BasicThermostat, HeatingThermostat, CoolingThermostat { - - - -} +public interface Thermostat extends BasicThermostat, HeatingThermostat, CoolingThermostat {} diff --git a/src/main/java/com/beowulfe/hap/accessories/Valve.java b/src/main/java/com/beowulfe/hap/accessories/Valve.java index 13606e09d..aef689123 100644 --- a/src/main/java/com/beowulfe/hap/accessories/Valve.java +++ b/src/main/java/com/beowulfe/hap/accessories/Valve.java @@ -1,14 +1,13 @@ package com.beowulfe.hap.accessories; -import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitAccessory; import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.Service; import com.beowulfe.hap.accessories.properties.ValveType; import com.beowulfe.hap.impl.services.ValveService; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; /** * A Valve (sprinkler head, faucet, etc.) @@ -17,83 +16,77 @@ */ public interface Valve extends HomekitAccessory { - @Override - default Collection getServices() { - return Collections.singleton(new ValveService(this)); - } + @Override + default Collection getServices() { + return Collections.singleton(new ValveService(this)); + } - /** - * Retrieves the current active state of the valve; Active could mean the valve is open (but not necessarily - * running), - * or that the valve is associated with an active watering program (like a watering program) but is not currently - * running. - * - * To communicate water is flowing through a valve, inUse should be used. - * - * @return a future that will contain the binary state - */ - CompletableFuture getValveActive(); + /** + * Retrieves the current active state of the valve; Active could mean the valve is open (but not + * necessarily running), or that the valve is associated with an active watering program (like a + * watering program) but is not currently running. + * + *

To communicate water is flowing through a valve, inUse should be used. + * + * @return a future that will contain the binary state + */ + CompletableFuture getValveActive(); - /** - * Sets the valve active state - * - * @param active the binary state to set - * @return a future that completes when the change is made - * @throws Exception when the change cannot be made - */ - CompletableFuture setValveActive(boolean active) throws Exception; + /** + * Sets the valve active state + * + * @param active the binary state to set + * @return a future that completes when the change is made + * @throws Exception when the change cannot be made + */ + CompletableFuture setValveActive(boolean active) throws Exception; - /** - * Subscribes to changes in the active state of the valve. - * - * @param callback the function to call when the state changes. - */ - void subscribeValveActive(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the active state of the valve. + * + * @param callback the function to call when the state changes. + */ + void subscribeValveActive(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the valve active state. - */ - void unsubscribeValveActive(); + /** Unsubscribes from changes in the valve active state. */ + void unsubscribeValveActive(); - /** - * Retrieves the current inUse state of the valve; InUse usually means water is flowing through the valve. - * - * To communicate water is flowing through a valve, inUse should be used. - * - * @return a future that will contain the binary state - */ - CompletableFuture getValveInUse(); + /** + * Retrieves the current inUse state of the valve; InUse usually means water is flowing through + * the valve. + * + *

To communicate water is flowing through a valve, inUse should be used. + * + * @return a future that will contain the binary state + */ + CompletableFuture getValveInUse(); - /** - * Subscribes to changes in the inUse state of the valve. - * - * @param callback the function to call when the state changes. - */ - void subscribeValveInUse(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the inUse state of the valve. + * + * @param callback the function to call when the state changes. + */ + void subscribeValveInUse(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the valve inUse state. - */ - void unsubscribeValveInUse(); + /** Unsubscribes from changes in the valve inUse state. */ + void unsubscribeValveInUse(); - /** - * Retrieves the valve type. - * - * To communicate water is flowing through a valve, inUse should be used. - * - * @return a future that will contain the binary state - */ - CompletableFuture getValveType(); + /** + * Retrieves the valve type. + * + *

To communicate water is flowing through a valve, inUse should be used. + * + * @return a future that will contain the binary state + */ + CompletableFuture getValveType(); - /** - * Subscribes to changes in the valveType state of the valve. - * - * @param callback the function to call when the state changes. - */ - void subscribeValveType(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the valveType state of the valve. + * + * @param callback the function to call when the state changes. + */ + void subscribeValveType(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the valveType state light. - */ - void unsubscribeValveType(); + /** Unsubscribes from changes in the valveType state light. */ + void unsubscribeValveType(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/ValveWithTimer.java b/src/main/java/com/beowulfe/hap/accessories/ValveWithTimer.java index 4d3a7d25b..fdd296120 100644 --- a/src/main/java/com/beowulfe/hap/accessories/ValveWithTimer.java +++ b/src/main/java/com/beowulfe/hap/accessories/ValveWithTimer.java @@ -1,8 +1,7 @@ package com.beowulfe.hap.accessories; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; +import java.util.concurrent.CompletableFuture; /** * Extends {@link Valve} with timer values. @@ -11,56 +10,50 @@ */ public interface ValveWithTimer extends Valve { - /** - * Retrieves the current duration for which the valve will run - * - * @return a future with the value - */ - CompletableFuture getRemainingDuration(); - - /** - * Subscribes to changes in the duration; note it is not necessary to emit a - * change every second, homekit infers the countdown progress clientside. - * - * @param callback the function when the existing duration has been replaced with a new one. - */ - void subscribeRemainingDuration(HomekitCharacteristicChangeCallback callback); - - /** - * Unsubscribes from changes - */ - void unsubscribeRemainingDuration(); - - /** - * Retrieves the current set duration for which the valve will be scheduled - * to run; this is usually used as the duration to use when the valve is set - * to active. - * - * @return a future with the value - */ - CompletableFuture getSetDuration(); - - /** - * Sets the duration for which the valve will be scheduled to run; this is - * usually used as the duration to use when the valve is set to active. - * - * If the valve is currently running, then Homekit assumes that changing - * this value affects the current remaining duration. - * - * @return a future with the value - */ - CompletableFuture setSetDuration(int value); - - /** - * Subscribes to changes in the set duration - * - * @param callback the function when the value has changed - */ - void subscribeSetDuration(HomekitCharacteristicChangeCallback callback); - - /** - * Unsubscribes from changes - */ - void unsubscribeSetDuration(); - + /** + * Retrieves the current duration for which the valve will run + * + * @return a future with the value + */ + CompletableFuture getRemainingDuration(); + + /** + * Subscribes to changes in the duration; note it is not necessary to emit a change every second, + * homekit infers the countdown progress clientside. + * + * @param callback the function when the existing duration has been replaced with a new one. + */ + void subscribeRemainingDuration(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes */ + void unsubscribeRemainingDuration(); + + /** + * Retrieves the current set duration for which the valve will be scheduled to run; this is + * usually used as the duration to use when the valve is set to active. + * + * @return a future with the value + */ + CompletableFuture getSetDuration(); + + /** + * Sets the duration for which the valve will be scheduled to run; this is usually used as the + * duration to use when the valve is set to active. + * + *

If the valve is currently running, then Homekit assumes that changing this value affects the + * current remaining duration. + * + * @return a future with the value + */ + CompletableFuture setSetDuration(int value); + + /** + * Subscribes to changes in the set duration + * + * @param callback the function when the value has changed + */ + void subscribeSetDuration(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes */ + void unsubscribeSetDuration(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/VerticalTiltingWindowCovering.java b/src/main/java/com/beowulfe/hap/accessories/VerticalTiltingWindowCovering.java index 263a09369..fae1c4c1b 100644 --- a/src/main/java/com/beowulfe/hap/accessories/VerticalTiltingWindowCovering.java +++ b/src/main/java/com/beowulfe/hap/accessories/VerticalTiltingWindowCovering.java @@ -1,8 +1,7 @@ package com.beowulfe.hap.accessories; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; +import java.util.concurrent.CompletableFuture; /** * Extends WindowCovering with the ability to control vertical tilt angles @@ -11,45 +10,46 @@ */ public interface VerticalTiltingWindowCovering extends WindowCovering { - /** - * Retrieves the current vertical tilt angle - * @return a future that will contain the position as a value between -90 and 90 - */ - CompletableFuture getCurrentVerticalTiltAngle(); - - /** - * Retrieves the target vertical tilt angle - * @return a future that will contain the target position as a value between -90 and 90 - */ - CompletableFuture getTargetVerticalTiltAngle(); - - /** - * Sets the target position - * @param angle the target angle to set, as a value between -90 and 90 - * @return a future that completes when the change is made - * @throws Exception when the change cannot be made - */ - CompletableFuture setTargetVerticalTiltAngle(int angle) throws Exception; - - /** - * Subscribes to changes in the current vertical tilt angle. - * @param callback the function to call when the state changes. - */ - void subscribeCurrentVerticalTiltAngle(HomekitCharacteristicChangeCallback callback); - - /** - * Subscribes to changes in the target vertical tilt angle. - * @param callback the function to call when the state changes. - */ - void subscribeTargetVerticalTiltAngle(HomekitCharacteristicChangeCallback callback); - - /** - * Unsubscribes from changes in the current vertical tilt angle - */ - void unsubscribeCurrentVerticalTiltAngle(); - - /** - * Unsubscribes from changes in the target vertical tilt angle - */ - void unsubscribeTargetVerticalTiltAngle(); + /** + * Retrieves the current vertical tilt angle + * + * @return a future that will contain the position as a value between -90 and 90 + */ + CompletableFuture getCurrentVerticalTiltAngle(); + + /** + * Retrieves the target vertical tilt angle + * + * @return a future that will contain the target position as a value between -90 and 90 + */ + CompletableFuture getTargetVerticalTiltAngle(); + + /** + * Sets the target position + * + * @param angle the target angle to set, as a value between -90 and 90 + * @return a future that completes when the change is made + * @throws Exception when the change cannot be made + */ + CompletableFuture setTargetVerticalTiltAngle(int angle) throws Exception; + + /** + * Subscribes to changes in the current vertical tilt angle. + * + * @param callback the function to call when the state changes. + */ + void subscribeCurrentVerticalTiltAngle(HomekitCharacteristicChangeCallback callback); + + /** + * Subscribes to changes in the target vertical tilt angle. + * + * @param callback the function to call when the state changes. + */ + void subscribeTargetVerticalTiltAngle(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes in the current vertical tilt angle */ + void unsubscribeCurrentVerticalTiltAngle(); + + /** Unsubscribes from changes in the target vertical tilt angle */ + void unsubscribeTargetVerticalTiltAngle(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/WindowCovering.java b/src/main/java/com/beowulfe/hap/accessories/WindowCovering.java index 230678f8c..340013ca7 100644 --- a/src/main/java/com/beowulfe/hap/accessories/WindowCovering.java +++ b/src/main/java/com/beowulfe/hap/accessories/WindowCovering.java @@ -1,12 +1,11 @@ package com.beowulfe.hap.accessories; -import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.*; import com.beowulfe.hap.accessories.properties.WindowCoveringPositionState; import com.beowulfe.hap.impl.services.WindowCoveringService; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; /** * A window covering, like blinds, which can be remotely controlled. @@ -15,92 +14,94 @@ */ public interface WindowCovering 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(); - - /** - * Retrieves an indication that the window covering is obstructed from moving - * @return a future that will contain a boolean indicating whether an obstruction is present - */ - CompletableFuture getObstructionDetected(); - - @Override - default Collection getServices() { - return Collections.singleton(new WindowCoveringService(this)); - } - - /** - * 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; - - /** - * Sets the hold position state - * @param hold whether or not to hold the current position state - * @return a future that completes when the change is made - * @throws Exception when the change cannot be made - */ - CompletableFuture setHoldPosition(boolean hold) 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); - - /** - * Subscribes to changes in the obstruction detected state - * @param callback the function to call when the state changes. - */ - void subscribeObstructionDetected(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(); - - /** - * Unsubscribes from changes in the obstruction detected state - */ - void unsubscribeObstructionDetected(); + /** + * 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(); + + /** + * Retrieves an indication that the window covering is obstructed from moving + * + * @return a future that will contain a boolean indicating whether an obstruction is present + */ + CompletableFuture getObstructionDetected(); + + @Override + default Collection getServices() { + return Collections.singleton(new WindowCoveringService(this)); + } + + /** + * 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; + + /** + * Sets the hold position state + * + * @param hold whether or not to hold the current position state + * @return a future that completes when the change is made + * @throws Exception when the change cannot be made + */ + CompletableFuture setHoldPosition(boolean hold) 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); + + /** + * Subscribes to changes in the obstruction detected state + * + * @param callback the function to call when the state changes. + */ + void subscribeObstructionDetected(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(); + + /** Unsubscribes from changes in the obstruction detected state */ + void unsubscribeObstructionDetected(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/package-info.java b/src/main/java/com/beowulfe/hap/accessories/package-info.java index 7c54d98bc..22f91c5ac 100644 --- a/src/main/java/com/beowulfe/hap/accessories/package-info.java +++ b/src/main/java/com/beowulfe/hap/accessories/package-info.java @@ -1,4 +1,2 @@ -/** - * Contains interfaces that can be implemented to represent an exposed accessory. - */ -package com.beowulfe.hap.accessories; \ No newline at end of file +/** Contains interfaces that can be implemented to represent an exposed accessory. */ +package com.beowulfe.hap.accessories; diff --git a/src/main/java/com/beowulfe/hap/accessories/properties/CarbonMonoxideDetectedState.java b/src/main/java/com/beowulfe/hap/accessories/properties/CarbonMonoxideDetectedState.java index 95bcf53b1..556eb2892 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/CarbonMonoxideDetectedState.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/CarbonMonoxideDetectedState.java @@ -5,26 +5,28 @@ import java.util.stream.Collectors; public enum CarbonMonoxideDetectedState { + NORMAL(0), + ABNORMAL(1); - NORMAL(0), - ABNORMAL(1); + private static final Map reverse; - private final static Map reverse; - static { - reverse = Arrays.stream(CarbonMonoxideDetectedState.values()).collect(Collectors.toMap(CarbonMonoxideDetectedState::getCode, t -> t)); - } + static { + reverse = + Arrays.stream(CarbonMonoxideDetectedState.values()) + .collect(Collectors.toMap(CarbonMonoxideDetectedState::getCode, t -> t)); + } - public static CarbonMonoxideDetectedState fromCode(Integer code) { - return reverse.get(code); - } + public static CarbonMonoxideDetectedState fromCode(Integer code) { + return reverse.get(code); + } - private final int code; + private final int code; - CarbonMonoxideDetectedState(int code) { - this.code = code; - } + CarbonMonoxideDetectedState(int code) { + this.code = code; + } - public int getCode() { - return code; - } + public int getCode() { + return code; + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/properties/ContactState.java b/src/main/java/com/beowulfe/hap/accessories/properties/ContactState.java index ca4a352ae..b8a466ceb 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/ContactState.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/ContactState.java @@ -5,26 +5,28 @@ import java.util.stream.Collectors; public enum ContactState { + DETECTED(0), + NOT_DETECTED(1); - DETECTED(0), - NOT_DETECTED(1); + private static final Map reverse; - private final static Map reverse; - static { - reverse = Arrays.stream(ContactState.values()).collect(Collectors.toMap(ContactState::getCode, t -> t)); - } + static { + reverse = + Arrays.stream(ContactState.values()) + .collect(Collectors.toMap(ContactState::getCode, t -> t)); + } - public static ContactState fromCode(Integer code) { - return reverse.get(code); - } + public static ContactState fromCode(Integer code) { + return reverse.get(code); + } - private final int code; + private final int code; - ContactState(int code) { - this.code = code; - } + ContactState(int code) { + this.code = code; + } - public int getCode() { - return code; - } + public int getCode() { + return code; + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/properties/CurrentSecuritySystemState.java b/src/main/java/com/beowulfe/hap/accessories/properties/CurrentSecuritySystemState.java index a9666c946..3c8291415 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/CurrentSecuritySystemState.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/CurrentSecuritySystemState.java @@ -1,57 +1,48 @@ package com.beowulfe.hap.accessories.properties; import com.beowulfe.hap.accessories.SecuritySystem; - import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; /** - * The current state of a {@link SecuritySystem}. Unlike {@link TargetSecuritySystemState}, this enum - * includes a triggered state. + * The current state of a {@link SecuritySystem}. Unlike {@link TargetSecuritySystemState}, this + * enum includes a triggered state. * * @author Gaston Dombiak */ public enum CurrentSecuritySystemState { - /** - * The home is occupied and residents are active. - */ - STAY_ARM(0), - /** - * The home is unoccupied. - */ - AWAY_ARM(1), - /** - * The home is occupied and residents are sleeping. - */ - NIGHT_ARM(2), - /** - * The security system is disarmed. - */ - DISARMED(3), - /** - * The security system is triggered. - */ - TRIGGERED(4); - - private final static Map reverse; - static { - reverse = Arrays.stream(CurrentSecuritySystemState.values()).collect(Collectors - .toMap(CurrentSecuritySystemState::getCode, t -> t)); - } - - public static CurrentSecuritySystemState fromCode(Integer code) { - return reverse.get(code); - } - - private final int code; - - CurrentSecuritySystemState(int code) { - this.code = code; - } - - public int getCode() { - return code; - } + /** The home is occupied and residents are active. */ + STAY_ARM(0), + /** The home is unoccupied. */ + AWAY_ARM(1), + /** The home is occupied and residents are sleeping. */ + NIGHT_ARM(2), + /** The security system is disarmed. */ + DISARMED(3), + /** The security system is triggered. */ + TRIGGERED(4); + + private static final Map reverse; + + static { + reverse = + Arrays.stream(CurrentSecuritySystemState.values()) + .collect(Collectors.toMap(CurrentSecuritySystemState::getCode, t -> t)); + } + + public static CurrentSecuritySystemState fromCode(Integer code) { + return reverse.get(code); + } + + private final int code; + + CurrentSecuritySystemState(int code) { + this.code = code; + } + + public int getCode() { + return code; + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/properties/DoorState.java b/src/main/java/com/beowulfe/hap/accessories/properties/DoorState.java index d85745986..bcb329768 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/DoorState.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/DoorState.java @@ -5,30 +5,29 @@ import java.util.stream.Collectors; public enum DoorState { + OPEN(0), + CLOSED(1), + OPENING(2), + CLOSING(3), + STOPPED(4); - OPEN(0), - CLOSED(1), - OPENING(2), - CLOSING(3), - STOPPED(4); - - - private final static Map reverse; - static { - reverse = Arrays.stream(DoorState.values()).collect(Collectors.toMap(t -> t.getCode(), t -> t)); - } - - public static DoorState fromCode(Integer code) { - return reverse.get(code); - } - - private final int code; - - private DoorState(int code) { - this.code = code; - } - - public int getCode() { - return code; - } + private static final Map reverse; + + static { + reverse = Arrays.stream(DoorState.values()).collect(Collectors.toMap(t -> t.getCode(), t -> t)); + } + + public static DoorState fromCode(Integer code) { + return reverse.get(code); + } + + private final int code; + + private DoorState(int code) { + this.code = code; + } + + public int getCode() { + return code; + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/properties/LockMechanismState.java b/src/main/java/com/beowulfe/hap/accessories/properties/LockMechanismState.java index 8250c8e28..0b2afb5cc 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/LockMechanismState.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/LockMechanismState.java @@ -1,40 +1,40 @@ package com.beowulfe.hap.accessories.properties; +import com.beowulfe.hap.accessories.LockMechanism; import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; -import com.beowulfe.hap.accessories.LockMechanism; - /** * The state of a {@link LockMechanism}. * * @author Andy Lintner */ public enum LockMechanismState { - - UNSECURED(0), - SECURED(1), - JAMMED(2), - UNKNOWN(3) - ; - - private final static Map reverse; - static { - reverse = Arrays.stream(LockMechanismState.values()).collect(Collectors.toMap(t -> t.getCode(), t -> t)); - } - - public static LockMechanismState fromCode(Integer code) { - return reverse.get(code); - } - - private final int code; - - private LockMechanismState(int code) { - this.code = code; - } - - public int getCode() { - return code; - } + UNSECURED(0), + SECURED(1), + JAMMED(2), + UNKNOWN(3); + + private static final Map reverse; + + static { + reverse = + Arrays.stream(LockMechanismState.values()) + .collect(Collectors.toMap(t -> t.getCode(), t -> t)); + } + + public static LockMechanismState fromCode(Integer code) { + return reverse.get(code); + } + + private final int code; + + private LockMechanismState(int code) { + this.code = code; + } + + public int getCode() { + return code; + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/properties/RotationDirection.java b/src/main/java/com/beowulfe/hap/accessories/properties/RotationDirection.java index 9a7d4693f..4c504d28a 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/RotationDirection.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/RotationDirection.java @@ -5,26 +5,28 @@ import java.util.stream.Collectors; public enum RotationDirection { - CLOCKWISE(0), - COUNTER_CLOCKWISE(1) - ; - - private final static Map reverse; - static { - reverse = Arrays.stream(RotationDirection.values()).collect(Collectors.toMap(t -> t.getCode(), t -> t)); - } - - public static RotationDirection fromCode(Integer code) { - return reverse.get(code); - } - - private final int code; - - private RotationDirection(int code) { - this.code = code; - } - - public int getCode() { - return code; - } + CLOCKWISE(0), + COUNTER_CLOCKWISE(1); + + private static final Map reverse; + + static { + reverse = + Arrays.stream(RotationDirection.values()) + .collect(Collectors.toMap(t -> t.getCode(), t -> t)); + } + + public static RotationDirection fromCode(Integer code) { + return reverse.get(code); + } + + private final int code; + + private RotationDirection(int code) { + this.code = code; + } + + public int getCode() { + return code; + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/properties/SecuritySystemAlarmType.java b/src/main/java/com/beowulfe/hap/accessories/properties/SecuritySystemAlarmType.java index 161cd91f9..aa8b0806c 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/SecuritySystemAlarmType.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/SecuritySystemAlarmType.java @@ -1,7 +1,6 @@ package com.beowulfe.hap.accessories.properties; import com.beowulfe.hap.accessories.SecuritySystem; - import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; @@ -13,32 +12,30 @@ */ public enum SecuritySystemAlarmType { - /** - * Alarm conditions are cleared - */ - NO_ALARM(0), - /** - * Alarm type is not known - */ - UNKNOWN(1); - - private final static Map reverse; - static { - reverse = Arrays.stream(SecuritySystemAlarmType.values()).collect(Collectors - .toMap(SecuritySystemAlarmType::getCode, t -> t)); - } - - public static SecuritySystemAlarmType fromCode(Integer code) { - return reverse.get(code); - } - - private final int code; - - SecuritySystemAlarmType(int code) { - this.code = code; - } - - public int getCode() { - return code; - } + /** Alarm conditions are cleared */ + NO_ALARM(0), + /** Alarm type is not known */ + UNKNOWN(1); + + private static final Map reverse; + + static { + reverse = + Arrays.stream(SecuritySystemAlarmType.values()) + .collect(Collectors.toMap(SecuritySystemAlarmType::getCode, t -> t)); + } + + public static SecuritySystemAlarmType fromCode(Integer code) { + return reverse.get(code); + } + + private final int code; + + SecuritySystemAlarmType(int code) { + this.code = code; + } + + public int getCode() { + return code; + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/properties/SmokeDetectedState.java b/src/main/java/com/beowulfe/hap/accessories/properties/SmokeDetectedState.java index 159a767ee..7c929c6b2 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/SmokeDetectedState.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/SmokeDetectedState.java @@ -5,26 +5,28 @@ import java.util.stream.Collectors; public enum SmokeDetectedState { + NOT_DETECTED(0), + DETECTED(1); - NOT_DETECTED(0), - DETECTED(1); + private static final Map reverse; - private final static Map reverse; - static { - reverse = Arrays.stream(SmokeDetectedState.values()).collect(Collectors.toMap(SmokeDetectedState::getCode, t -> t)); - } + static { + reverse = + Arrays.stream(SmokeDetectedState.values()) + .collect(Collectors.toMap(SmokeDetectedState::getCode, t -> t)); + } - public static SmokeDetectedState fromCode(Integer code) { - return reverse.get(code); - } + public static SmokeDetectedState fromCode(Integer code) { + return reverse.get(code); + } - private final int code; + private final int code; - SmokeDetectedState(int code) { - this.code = code; - } + SmokeDetectedState(int code) { + this.code = code; + } - public int getCode() { - return code; - } + public int getCode() { + return code; + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/properties/TargetSecuritySystemState.java b/src/main/java/com/beowulfe/hap/accessories/properties/TargetSecuritySystemState.java index 35bd087a2..bb924fcc8 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/TargetSecuritySystemState.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/TargetSecuritySystemState.java @@ -1,7 +1,6 @@ package com.beowulfe.hap.accessories.properties; import com.beowulfe.hap.accessories.SecuritySystem; - import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; @@ -13,40 +12,34 @@ */ public enum TargetSecuritySystemState { - /** - * Arm the system when the home is occupied and residents are active. - */ - STAY_ARM(0), - /** - * Arm the system when the home is unoccupied. - */ - AWAY_ARM(1), - /** - * Arm the system when the home is occupied and residents are sleeping. - */ - NIGHT_ARM(2), - /** - * Disarm the system. - */ - DISARM(3); - - private final static Map reverse; - static { - reverse = Arrays.stream(TargetSecuritySystemState.values()).collect(Collectors - .toMap(TargetSecuritySystemState::getCode, t -> t)); - } - - public static TargetSecuritySystemState fromCode(Integer code) { - return reverse.get(code); - } - - private final int code; - - TargetSecuritySystemState(int code) { - this.code = code; - } - - public int getCode() { - return code; - } + /** Arm the system when the home is occupied and residents are active. */ + STAY_ARM(0), + /** Arm the system when the home is unoccupied. */ + AWAY_ARM(1), + /** Arm the system when the home is occupied and residents are sleeping. */ + NIGHT_ARM(2), + /** Disarm the system. */ + DISARM(3); + + private static final Map reverse; + + static { + reverse = + Arrays.stream(TargetSecuritySystemState.values()) + .collect(Collectors.toMap(TargetSecuritySystemState::getCode, t -> t)); + } + + public static TargetSecuritySystemState fromCode(Integer code) { + return reverse.get(code); + } + + private final int code; + + TargetSecuritySystemState(int code) { + this.code = code; + } + + public int getCode() { + return code; + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/properties/TemperatureUnit.java b/src/main/java/com/beowulfe/hap/accessories/properties/TemperatureUnit.java index 7cf1a476e..27bf004b4 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/TemperatureUnit.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/TemperatureUnit.java @@ -1,38 +1,37 @@ package com.beowulfe.hap.accessories.properties; +import com.beowulfe.hap.accessories.TemperatureSensor; import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; -import com.beowulfe.hap.accessories.TemperatureSensor; - /** * The temperature unit used by a {@link TemperatureSensor}. * * @author Andy Lintner */ public enum TemperatureUnit { + CELSIUS(0), + FAHRENHEIT(1); + + private static final Map reverse; + + static { + reverse = + Arrays.stream(TemperatureUnit.values()).collect(Collectors.toMap(t -> t.getCode(), t -> t)); + } + + static TemperatureUnit fromCode(Integer code) { + return reverse.get(code); + } + + private final int code; + + private TemperatureUnit(int code) { + this.code = code; + } - CELSIUS(0), - FAHRENHEIT(1) - ; - - private final static Map reverse; - static { - reverse = Arrays.stream(TemperatureUnit.values()).collect(Collectors.toMap(t -> t.getCode(), t -> t)); - } - - static TemperatureUnit fromCode(Integer code) { - return reverse.get(code); - } - - private final int code; - - private TemperatureUnit(int code) { - this.code = code; - } - - public int getCode() { - return code; - } + public int getCode() { + return code; + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/properties/ThermostatMode.java b/src/main/java/com/beowulfe/hap/accessories/properties/ThermostatMode.java index 081e11793..4d6f2f893 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/ThermostatMode.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/ThermostatMode.java @@ -1,40 +1,39 @@ package com.beowulfe.hap.accessories.properties; +import com.beowulfe.hap.accessories.thermostat.BasicThermostat; import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; -import com.beowulfe.hap.accessories.thermostat.BasicThermostat; - /** * The mode used by a {@link BasicThermostat} * * @author Andy Lintner */ public enum ThermostatMode { + OFF(0), + HEAT(1), + COOL(2), + AUTO(3); + + private static final Map reverse; + + static { + reverse = + Arrays.stream(ThermostatMode.values()).collect(Collectors.toMap(t -> t.getCode(), t -> t)); + } + + public static ThermostatMode fromCode(Integer code) { + return reverse.get(code); + } + + private final int code; + + private ThermostatMode(int code) { + this.code = code; + } - OFF(0), - HEAT(1), - COOL(2), - AUTO(3) - ; - - private final static Map reverse; - static { - reverse = Arrays.stream(ThermostatMode.values()).collect(Collectors.toMap(t -> t.getCode(), t -> t)); - } - - public static ThermostatMode fromCode(Integer code) { - return reverse.get(code); - } - - private final int code; - - private ThermostatMode(int code) { - this.code = code; - } - - public int getCode() { - return code; - } + public int getCode() { + return code; + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/properties/ValveType.java b/src/main/java/com/beowulfe/hap/accessories/properties/ValveType.java index 0991e8fd4..a16105155 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/ValveType.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/ValveType.java @@ -1,39 +1,38 @@ package com.beowulfe.hap.accessories.properties; +import com.beowulfe.hap.accessories.Valve; import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; -import com.beowulfe.hap.accessories.Valve; - /** * The mode used by a {@link Valve} * * @author Tim Harper */ public enum ValveType { + GENERIC(0), + IRRIGATION(1), + SHOWER(2), + WATER_FAUCET(3); - GENERIC(0), - IRRIGATION(1), - SHOWER(2), - WATER_FAUCET(3); + private static final Map reverse; - private final static Map reverse; - static { - reverse = Arrays.stream(ValveType.values()).collect(Collectors.toMap(t -> t.getCode(), t -> t)); - } + static { + reverse = Arrays.stream(ValveType.values()).collect(Collectors.toMap(t -> t.getCode(), t -> t)); + } - public static ValveType fromCode(Integer code) { - return reverse.get(code); - } + public static ValveType fromCode(Integer code) { + return reverse.get(code); + } - private final int code; + private final int code; - private ValveType(int code) { - this.code = code; - } + private ValveType(int code) { + this.code = code; + } - public int getCode() { - return code; - } + public int getCode() { + return code; + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/properties/WindowCoveringPositionState.java b/src/main/java/com/beowulfe/hap/accessories/properties/WindowCoveringPositionState.java index 29624ad81..b57bc4b6f 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/WindowCoveringPositionState.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/WindowCoveringPositionState.java @@ -1,38 +1,39 @@ package com.beowulfe.hap.accessories.properties; +import com.beowulfe.hap.accessories.WindowCovering; import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; -import com.beowulfe.hap.accessories.WindowCovering; - /** * The position state used by a {@link WindowCovering} * * @author Andy Lintner */ public enum WindowCoveringPositionState { - DECREASING(0), - INCREASING(1), - STOPPED(2) - ; - - private final static 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; - } + 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/com/beowulfe/hap/accessories/properties/package-info.java b/src/main/java/com/beowulfe/hap/accessories/properties/package-info.java index ee3991bbf..e234adb4c 100644 --- a/src/main/java/com/beowulfe/hap/accessories/properties/package-info.java +++ b/src/main/java/com/beowulfe/hap/accessories/properties/package-info.java @@ -1,4 +1,2 @@ -/** - * Contains properties used by {@link com.beowulfe.hap.accessories}. - */ -package com.beowulfe.hap.accessories.properties; \ No newline at end of file +/** Contains properties used by {@link com.beowulfe.hap.accessories}. */ +package com.beowulfe.hap.accessories.properties; diff --git a/src/main/java/com/beowulfe/hap/accessories/thermostat/BasicThermostat.java b/src/main/java/com/beowulfe/hap/accessories/thermostat/BasicThermostat.java index 803738ca8..f6fc9ec36 100644 --- a/src/main/java/com/beowulfe/hap/accessories/thermostat/BasicThermostat.java +++ b/src/main/java/com/beowulfe/hap/accessories/thermostat/BasicThermostat.java @@ -1,83 +1,88 @@ package com.beowulfe.hap.accessories.thermostat; -import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.*; import com.beowulfe.hap.accessories.TemperatureSensor; import com.beowulfe.hap.accessories.properties.ThermostatMode; import com.beowulfe.hap.impl.services.ThermostatService; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; public interface BasicThermostat extends HomekitAccessory, TemperatureSensor { - /** - * Retrieves the current {@link ThermostatMode} of the thermostat. - * @return a future that will contain the mode. - */ - CompletableFuture getCurrentMode(); + /** + * Retrieves the current {@link ThermostatMode} of the thermostat. + * + * @return a future that will contain the mode. + */ + CompletableFuture getCurrentMode(); + + /** + * Subscribes to changes in the {@link ThermostatMode} of the thermostat. + * + * @param callback the function to call when the state changes. + */ + void subscribeCurrentMode(HomekitCharacteristicChangeCallback callback); + + /** Unsubscribes from changes in the mode of the thermostat. */ + void unsubscribeCurrentMode(); - /** - * Subscribes to changes in the {@link ThermostatMode} of the thermostat. - * @param callback the function to call when the state changes. - */ - void subscribeCurrentMode(HomekitCharacteristicChangeCallback callback); + /** + * Sets the {@link ThermostatMode} of the thermostat. + * + * @param mode The {@link ThermostatMode} to set. + * @throws Exception when the change cannot be made. + */ + void setTargetMode(ThermostatMode mode) throws Exception; - /** - * Unsubscribes from changes in the mode of the thermostat. - */ - void unsubscribeCurrentMode(); + /** + * Retrieves the pending, but not yet complete, {@link ThermostatMode} of the thermostat. + * + * @return a future that will contain the target mode. + */ + CompletableFuture getTargetMode(); - /** - * Sets the {@link ThermostatMode} of the thermostat. - * @param mode The {@link ThermostatMode} to set. - * @throws Exception when the change cannot be made. - */ - void setTargetMode(ThermostatMode mode) throws Exception; + /** + * Subscribes to changes in the pending, but not yet complete, {@link ThermostatMode} of the + * thermostat. + * + * @param callback the function to call when the state changes. + */ + void subscribeTargetMode(HomekitCharacteristicChangeCallback callback); - /** - * Retrieves the pending, but not yet complete, {@link ThermostatMode} of the thermostat. - * @return a future that will contain the target mode. - */ - CompletableFuture getTargetMode(); + /** + * Unsubscribes from changes in the pending, but not yet complete, {@link ThermostatMode} of the + * thermostat. + */ + void unsubscribeTargetMode(); - /** - * Subscribes to changes in the pending, but not yet complete, {@link ThermostatMode} of the thermostat. - * @param callback the function to call when the state changes. - */ - void subscribeTargetMode(HomekitCharacteristicChangeCallback callback); + /** + * Retrieves the target temperature, in celsius degrees. + * + * @return a future that will contain the target temperature. + */ + CompletableFuture getTargetTemperature(); - /** - * Unsubscribes from changes in the pending, but not yet complete, {@link ThermostatMode} of the thermostat. - */ - void unsubscribeTargetMode(); + /** + * Sets the target temperature. + * + * @param value the target temperature, in celsius degrees. + * @throws Exception when the temperature cannot be changed. + */ + void setTargetTemperature(Double value) throws Exception; - /** - * Retrieves the target temperature, in celsius degrees. - * @return a future that will contain the target temperature. - */ - CompletableFuture getTargetTemperature(); + /** + * Subscribes to changes in the target temperature. + * + * @param callback the function to call when the state changes. + */ + void subscribeTargetTemperature(HomekitCharacteristicChangeCallback callback); - /** - * Sets the target temperature. - * @param value the target temperature, in celsius degrees. - * @throws Exception when the temperature cannot be changed. - */ - void setTargetTemperature(Double value) throws Exception; - - /** - * Subscribes to changes in the target temperature. - * @param callback the function to call when the state changes. - */ - void subscribeTargetTemperature(HomekitCharacteristicChangeCallback callback); + /** Unsubscribes from changes in the target temperature. */ + void unsubscribeTargetTemperature(); - /** - * Unsubscribes from changes in the target temperature. - */ - void unsubscribeTargetTemperature(); - - @Override - default Collection getServices() { - return Collections.singleton(new ThermostatService(this)); - } + @Override + default Collection getServices() { + return Collections.singleton(new ThermostatService(this)); + } } diff --git a/src/main/java/com/beowulfe/hap/accessories/thermostat/CoolingThermostat.java b/src/main/java/com/beowulfe/hap/accessories/thermostat/CoolingThermostat.java index 60b0fe175..cb60ed88b 100644 --- a/src/main/java/com/beowulfe/hap/accessories/thermostat/CoolingThermostat.java +++ b/src/main/java/com/beowulfe/hap/accessories/thermostat/CoolingThermostat.java @@ -1,32 +1,32 @@ package com.beowulfe.hap.accessories.thermostat; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; +import java.util.concurrent.CompletableFuture; public interface CoolingThermostat extends BasicThermostat { - /** - * Retrieves the temperature above which the thermostat should begin cooling. - * @return a future that will contain the threshold temperature, in celsius degrees. - */ - CompletableFuture getCoolingThresholdTemperature(); + /** + * Retrieves the temperature above which the thermostat should begin cooling. + * + * @return a future that will contain the threshold temperature, in celsius degrees. + */ + CompletableFuture getCoolingThresholdTemperature(); + + /** + * Sets the temperature above which the thermostat should begin cooling. + * + * @param value the threshold temperature, in celsius degrees. + * @throws Exception when the threshold temperature cannot be changed. + */ + void setCoolingThresholdTemperature(Double value) throws Exception; - /** - * Sets the temperature above which the thermostat should begin cooling. - * @param value the threshold temperature, in celsius degrees. - * @throws Exception when the threshold temperature cannot be changed. - */ - void setCoolingThresholdTemperature(Double value) throws Exception; - - /** - * Subscribes to changes in the cooling threshold. - * @param callback the function to call when the state changes. - */ - void subscribeCoolingThresholdTemperature(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the cooling threshold. + * + * @param callback the function to call when the state changes. + */ + void subscribeCoolingThresholdTemperature(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the cooling threshold. - */ - void unsubscribeCoolingThresholdTemperature(); + /** Unsubscribes from changes in the cooling threshold. */ + void unsubscribeCoolingThresholdTemperature(); } diff --git a/src/main/java/com/beowulfe/hap/accessories/thermostat/HeatingThermostat.java b/src/main/java/com/beowulfe/hap/accessories/thermostat/HeatingThermostat.java index 9a0013677..36e946316 100644 --- a/src/main/java/com/beowulfe/hap/accessories/thermostat/HeatingThermostat.java +++ b/src/main/java/com/beowulfe/hap/accessories/thermostat/HeatingThermostat.java @@ -1,32 +1,32 @@ package com.beowulfe.hap.accessories.thermostat; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; +import java.util.concurrent.CompletableFuture; public interface HeatingThermostat extends BasicThermostat { - /** - * Retrieves the temperature below which the thermostat should begin heating. - * @return a future that will contain the threshold temperature, in celsius degrees. - */ - CompletableFuture getHeatingThresholdTemperature(); + /** + * Retrieves the temperature below which the thermostat should begin heating. + * + * @return a future that will contain the threshold temperature, in celsius degrees. + */ + CompletableFuture getHeatingThresholdTemperature(); + + /** + * Sets the temperature below which the thermostat should begin heating. + * + * @param value the threshold temperature, in celsius degrees. + * @throws Exception when the threshold temperature cannot be changed. + */ + void setHeatingThresholdTemperature(Double value) throws Exception; - /** - * Sets the temperature below which the thermostat should begin heating. - * @param value the threshold temperature, in celsius degrees. - * @throws Exception when the threshold temperature cannot be changed. - */ - void setHeatingThresholdTemperature(Double value) throws Exception; - - /** - * Subscribes to changes in the heating threshold. - * @param callback the function to call when the state changes. - */ - void subscribeHeatingThresholdTemperature(HomekitCharacteristicChangeCallback callback); + /** + * Subscribes to changes in the heating threshold. + * + * @param callback the function to call when the state changes. + */ + void subscribeHeatingThresholdTemperature(HomekitCharacteristicChangeCallback callback); - /** - * Unsubscribes from changes in the heating threshold. - */ - void unsubscribeHeatingThresholdTemperature(); + /** Unsubscribes from changes in the heating threshold. */ + void unsubscribeHeatingThresholdTemperature(); } diff --git a/src/main/java/com/beowulfe/hap/characteristics/BaseCharacteristic.java b/src/main/java/com/beowulfe/hap/characteristics/BaseCharacteristic.java index 661e53910..a4ba443b1 100644 --- a/src/main/java/com/beowulfe/hap/characteristics/BaseCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/characteristics/BaseCharacteristic.java @@ -4,13 +4,11 @@ import java.math.BigInteger; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; - import javax.json.Json; import javax.json.JsonArrayBuilder; import javax.json.JsonObject; import javax.json.JsonObjectBuilder; import javax.json.JsonValue; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,168 +18,169 @@ * @author Andy Lintner */ public abstract class BaseCharacteristic implements Characteristic { - - private final Logger logger = LoggerFactory.getLogger(BaseCharacteristic.class); - - private final String type; - private final String format; - private final boolean isWritable; - private final boolean isReadable; - private final boolean isEventable; - private final String description; - - /** - * Default constructor - * - * @param type a string containing a UUID that indicates the type of characteristic. Apple defines a set of these, - * however implementors can create their own as well. - * @param format a string indicating the value type, which must be a recognized type by the consuming device. - * @param isWritable indicates whether the value can be changed. - * @param isReadable indicates whether the value can be retrieved. - * @param description a description of the characteristic to be passed to the consuming device. - */ - public BaseCharacteristic(String type, String format, boolean isWritable, boolean isReadable, String description) { - if (type == null || format == null || description == null) { - throw new NullPointerException(); - } - - this.type = type; - this.format = format; - this.isWritable = isWritable; - this.isReadable = isReadable; - this.isEventable = this instanceof EventableCharacteristic; - this.description = description; - } - - @Override - /** - * {@inheritDoc} - */ - public final CompletableFuture toJson(int iid) { - return makeBuilder(iid).thenApply(builder -> builder.build()); - } - - /** - * Creates the JSON serialized form of the accessory for use over the Homekit Accessory Protocol. - * - * @param instanceId the static id of the accessory. - * @return a future that will complete with the JSON builder for the object. - */ - protected CompletableFuture makeBuilder(int instanceId) { - CompletableFuture futureValue = getValue(); - - if (futureValue == null) { - logger.error("Could not retrieve value "+this.getClass().getName()); - return null; - } - - return futureValue.exceptionally(t -> { - logger.error("Could not retrieve value "+this.getClass().getName(), t); - return null; - }).thenApply(value -> { - JsonArrayBuilder perms = Json.createArrayBuilder(); - if (isWritable) { - perms.add("pw"); - } - if (isReadable) { - perms.add("pr"); - } - if (isEventable) { - perms.add("ev"); - } - JsonObjectBuilder builder = Json.createObjectBuilder() - .add("iid", instanceId) - .add("type", type) - .add("perms", perms.build()) - .add("format", format) - .add("events", false) - .add("bonjour", false) - .add("description", description); - setJsonValue(builder, value); - return builder; - }); - } - - /** - * {@inheritDoc} - */ - @Override - public final void setValue(JsonValue jsonValue) { - try { - this.setValue(convert(jsonValue)); - } catch (Exception e) { - logger.error("Error while setting JSON value", e); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void supplyValue(JsonObjectBuilder builder) { - try { - setJsonValue(builder, getValue().get()); - } catch (InterruptedException | ExecutionException e) { - logger.error("Error retrieving value", e); - setJsonValue(builder, getDefault()); - } - } - - /** - * Converts from the JSON value to a Java object of the type T - * - * @param jsonValue the JSON value to convert from. - * @return the converted Java object. - */ - protected abstract T convert(JsonValue jsonValue); - - /** - * Update the characteristic value using a new value supplied by the connected client. - * - * @param value the new value to set. - * @throws Exception if the value cannot be set. - */ - protected abstract void setValue(T value) throws Exception; - - /** - * Retrieves the current value of the characteristic. - * - * @return a future that will complete with the current value. - */ - protected abstract CompletableFuture getValue(); - - /** - * Supplies a default value for the characteristic to send to connected clients when the real value. - * cannot be retrieved. - * - * @return a sensible default value. - */ - protected abstract T getDefault(); - - /** - * Writes the value key to the serialized characteristic - * - * @param builder The JSON builder to add the value to - * @param value The value to add - */ - protected void setJsonValue(JsonObjectBuilder builder, T value) { - //I don't like this - there should really be a way to construct a disconnected JSONValue... - if (value instanceof Boolean) { - builder.add("value", (Boolean) value); - } else if (value instanceof Double) { - builder.add("value", (Double) value); - } else if (value instanceof Integer) { - builder.add("value", (Integer) value); - } else if (value instanceof Long) { - builder.add("value", (Long) value); - } else if (value instanceof BigInteger) { - builder.add("value", (BigInteger) value); - } else if (value instanceof BigDecimal){ - builder.add("value", (BigDecimal) value); - } else if (value == null) { - builder.addNull("value"); - } else { - builder.add("value", value.toString()); - } - } + + private final Logger logger = LoggerFactory.getLogger(BaseCharacteristic.class); + + private final String type; + private final String format; + private final boolean isWritable; + private final boolean isReadable; + private final boolean isEventable; + private final String description; + + /** + * Default constructor + * + * @param type a string containing a UUID that indicates the type of characteristic. Apple defines + * a set of these, however implementors can create their own as well. + * @param format a string indicating the value type, which must be a recognized type by the + * consuming device. + * @param isWritable indicates whether the value can be changed. + * @param isReadable indicates whether the value can be retrieved. + * @param description a description of the characteristic to be passed to the consuming device. + */ + public BaseCharacteristic( + String type, String format, boolean isWritable, boolean isReadable, String description) { + if (type == null || format == null || description == null) { + throw new NullPointerException(); + } + + this.type = type; + this.format = format; + this.isWritable = isWritable; + this.isReadable = isReadable; + this.isEventable = this instanceof EventableCharacteristic; + this.description = description; + } + + @Override + /** {@inheritDoc} */ + public final CompletableFuture toJson(int iid) { + return makeBuilder(iid).thenApply(builder -> builder.build()); + } + + /** + * Creates the JSON serialized form of the accessory for use over the Homekit Accessory Protocol. + * + * @param instanceId the static id of the accessory. + * @return a future that will complete with the JSON builder for the object. + */ + protected CompletableFuture makeBuilder(int instanceId) { + CompletableFuture futureValue = getValue(); + + if (futureValue == null) { + logger.error("Could not retrieve value " + this.getClass().getName()); + return null; + } + + return futureValue + .exceptionally( + t -> { + logger.error("Could not retrieve value " + this.getClass().getName(), t); + return null; + }) + .thenApply( + value -> { + JsonArrayBuilder perms = Json.createArrayBuilder(); + if (isWritable) { + perms.add("pw"); + } + if (isReadable) { + perms.add("pr"); + } + if (isEventable) { + perms.add("ev"); + } + JsonObjectBuilder builder = + Json.createObjectBuilder() + .add("iid", instanceId) + .add("type", type) + .add("perms", perms.build()) + .add("format", format) + .add("events", false) + .add("bonjour", false) + .add("description", description); + setJsonValue(builder, value); + return builder; + }); + } + + /** {@inheritDoc} */ + @Override + public final void setValue(JsonValue jsonValue) { + try { + this.setValue(convert(jsonValue)); + } catch (Exception e) { + logger.error("Error while setting JSON value", e); + } + } + + /** {@inheritDoc} */ + @Override + public void supplyValue(JsonObjectBuilder builder) { + try { + setJsonValue(builder, getValue().get()); + } catch (InterruptedException | ExecutionException e) { + logger.error("Error retrieving value", e); + setJsonValue(builder, getDefault()); + } + } + + /** + * Converts from the JSON value to a Java object of the type T + * + * @param jsonValue the JSON value to convert from. + * @return the converted Java object. + */ + protected abstract T convert(JsonValue jsonValue); + + /** + * Update the characteristic value using a new value supplied by the connected client. + * + * @param value the new value to set. + * @throws Exception if the value cannot be set. + */ + protected abstract void setValue(T value) throws Exception; + + /** + * Retrieves the current value of the characteristic. + * + * @return a future that will complete with the current value. + */ + protected abstract CompletableFuture getValue(); + + /** + * Supplies a default value for the characteristic to send to connected clients when the real + * value. cannot be retrieved. + * + * @return a sensible default value. + */ + protected abstract T getDefault(); + + /** + * Writes the value key to the serialized characteristic + * + * @param builder The JSON builder to add the value to + * @param value The value to add + */ + protected void setJsonValue(JsonObjectBuilder builder, T value) { + // I don't like this - there should really be a way to construct a disconnected JSONValue... + if (value instanceof Boolean) { + builder.add("value", (Boolean) value); + } else if (value instanceof Double) { + builder.add("value", (Double) value); + } else if (value instanceof Integer) { + builder.add("value", (Integer) value); + } else if (value instanceof Long) { + builder.add("value", (Long) value); + } else if (value instanceof BigInteger) { + builder.add("value", (BigInteger) value); + } else if (value instanceof BigDecimal) { + builder.add("value", (BigDecimal) value); + } else if (value == null) { + builder.addNull("value"); + } else { + builder.add("value", value.toString()); + } + } } diff --git a/src/main/java/com/beowulfe/hap/characteristics/BooleanCharacteristic.java b/src/main/java/com/beowulfe/hap/characteristics/BooleanCharacteristic.java index 4782e9a72..1564c6f43 100644 --- a/src/main/java/com/beowulfe/hap/characteristics/BooleanCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/characteristics/BooleanCharacteristic.java @@ -10,42 +10,33 @@ * @author Andy Lintner */ public abstract class BooleanCharacteristic extends BaseCharacteristic { - - /** - * Default constructor - * - * @param type a string containing a UUID that indicates the type of characteristic. Apple defines a set of these, - * however implementors can create their own as well. - * @param isWritable indicates whether the value can be changed. - * @param isReadable indicates whether the value can be retrieved. - * @param description a description of the characteristic to be passed to the consuming device. - */ - public BooleanCharacteristic(String type, boolean isWritable, boolean isReadable, String description) { - super( type, - "bool", - isWritable, - isReadable, - description); - - } - - /** - * {@inheritDoc} - */ - @Override - protected Boolean convert(JsonValue jsonValue) { - if (jsonValue.getValueType().equals(ValueType.NUMBER)) { - return ((JsonNumber) jsonValue).intValue() > 0; - } - return jsonValue.equals(JsonValue.TRUE); - } - - /** - * {@inheritDoc} - */ - @Override - protected Boolean getDefault() { - return false; - } + /** + * Default constructor + * + * @param type a string containing a UUID that indicates the type of characteristic. Apple defines + * a set of these, however implementors can create their own as well. + * @param isWritable indicates whether the value can be changed. + * @param isReadable indicates whether the value can be retrieved. + * @param description a description of the characteristic to be passed to the consuming device. + */ + public BooleanCharacteristic( + String type, boolean isWritable, boolean isReadable, String description) { + super(type, "bool", isWritable, isReadable, description); + } + + /** {@inheritDoc} */ + @Override + protected Boolean convert(JsonValue jsonValue) { + if (jsonValue.getValueType().equals(ValueType.NUMBER)) { + return ((JsonNumber) jsonValue).intValue() > 0; + } + return jsonValue.equals(JsonValue.TRUE); + } + + /** {@inheritDoc} */ + @Override + protected Boolean getDefault() { + return false; + } } diff --git a/src/main/java/com/beowulfe/hap/characteristics/Characteristic.java b/src/main/java/com/beowulfe/hap/characteristics/Characteristic.java index 1ee1a3833..1530aeee0 100644 --- a/src/main/java/com/beowulfe/hap/characteristics/Characteristic.java +++ b/src/main/java/com/beowulfe/hap/characteristics/Characteristic.java @@ -1,43 +1,45 @@ package com.beowulfe.hap.characteristics; import java.util.concurrent.CompletableFuture; - import javax.json.JsonObject; import javax.json.JsonObjectBuilder; import javax.json.JsonValue; /** * Interface for the characteristics provided by a Service. - * - * Characteristics are the lowest level building block of the Homekit Accessory Protocol. They define variables - * that can be retrieved or set by the remote client. Most consumers of this library will be better served by using - * one of the characteristic classes in {@link com.beowulfe.hap.characteristics} when creating custom accessory types - * (the standard accessories from {@link com.beowulfe.hap.accessories} already include the necessary characteristics), - * instead of trying to implement the JSON formats directly. + * + *

Characteristics are the lowest level building block of the Homekit Accessory Protocol. They + * define variables that can be retrieved or set by the remote client. Most consumers of this + * library will be better served by using one of the characteristic classes in {@link + * com.beowulfe.hap.characteristics} when creating custom accessory types (the standard accessories + * from {@link com.beowulfe.hap.accessories} already include the necessary characteristics), instead + * of trying to implement the JSON formats directly. * * @author Andy Lintner */ public interface Characteristic { - /** - * Adds an attribute to the passed JsonObjectBuilder named "value" with the current value of the characteristic. - * - * @param characteristicBuilder the JsonObjectBuilder to add the value attribute to. - */ - void supplyValue(JsonObjectBuilder characteristicBuilder); + /** + * Adds an attribute to the passed JsonObjectBuilder named "value" with the current value of the + * characteristic. + * + * @param characteristicBuilder the JsonObjectBuilder to add the value attribute to. + */ + void supplyValue(JsonObjectBuilder characteristicBuilder); - /** - * Creates the JSON representation of the characteristic, in accordance with the Homekit Accessory Protocol. - * - * @param iid The instance ID of the characteristic to be included in the serialization. - * @return the future completing with the resulting JSON. - */ - CompletableFuture toJson(int iid); + /** + * Creates the JSON representation of the characteristic, in accordance with the Homekit Accessory + * Protocol. + * + * @param iid The instance ID of the characteristic to be included in the serialization. + * @return the future completing with the resulting JSON. + */ + CompletableFuture toJson(int iid); - /** - * Invoked by the remote client, this updates the current value of the characteristic. - * - * @param jsonValue the JSON serialized value to set. - */ - void setValue(JsonValue jsonValue); + /** + * Invoked by the remote client, this updates the current value of the characteristic. + * + * @param jsonValue the JSON serialized value to set. + */ + void setValue(JsonValue jsonValue); } diff --git a/src/main/java/com/beowulfe/hap/characteristics/EnumCharacteristic.java b/src/main/java/com/beowulfe/hap/characteristics/EnumCharacteristic.java index 2c1d84188..4007afcf5 100644 --- a/src/main/java/com/beowulfe/hap/characteristics/EnumCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/characteristics/EnumCharacteristic.java @@ -1,73 +1,65 @@ package com.beowulfe.hap.characteristics; import java.util.concurrent.CompletableFuture; - import javax.json.JsonNumber; import javax.json.JsonObject; import javax.json.JsonObjectBuilder; import javax.json.JsonValue; /** - * Characteristic that exposes an Enum value. Enums are represented as an Integer value - * in the Homekit protocol, and classes extending this one must handle the static mapping - * to an Integer value. + * Characteristic that exposes an Enum value. Enums are represented as an Integer value in the + * Homekit protocol, and classes extending this one must handle the static mapping to an Integer + * value. * * @author Andy Lintner */ public abstract class EnumCharacteristic extends BaseCharacteristic { - private final int maxValue; - - /** - * Default constructor - * - * @param type a string containing a UUID that indicates the type of characteristic. Apple defines a set of these, - * however implementors can create their own as well. - * @param isWritable indicates whether the value can be changed. - * @param isReadable indicates whether the value can be retrieved. - * @param description a description of the characteristic to be passed to the consuming device. - * @param maxValue the number of enum items. - */ - public EnumCharacteristic(String type, boolean isWritable, boolean isReadable, String description, int maxValue) { - super(type, "int", isWritable, isReadable, description); - this.maxValue = maxValue; - } - - /** - * {@inheritDoc} - */ - @Override - protected CompletableFuture makeBuilder(int iid) { - return super.makeBuilder(iid).thenApply(builder -> { - return builder - .add("minValue", 0) - .add("maxValue", maxValue) - .add("minStep", 1); - }); - } - - /** - * {@inheritDoc} - */ - @Override - protected Integer convert(JsonValue jsonValue) { - if (jsonValue instanceof JsonNumber) { - return ((JsonNumber) jsonValue).intValue(); - } else if (jsonValue == JsonObject.TRUE) { - return 1; //For at least one enum type (locks), homekit will send a true instead of 1 - } else if (jsonValue == JsonObject.FALSE) { - return 0; - } else { - throw new IndexOutOfBoundsException("Cannot convert "+jsonValue.getClass()+" to int"); - } - } - - /** - * {@inheritDoc} - */ - @Override - protected Integer getDefault() { - return 0; - } + private final int maxValue; + + /** + * Default constructor + * + * @param type a string containing a UUID that indicates the type of characteristic. Apple defines + * a set of these, however implementors can create their own as well. + * @param isWritable indicates whether the value can be changed. + * @param isReadable indicates whether the value can be retrieved. + * @param description a description of the characteristic to be passed to the consuming device. + * @param maxValue the number of enum items. + */ + public EnumCharacteristic( + String type, boolean isWritable, boolean isReadable, String description, int maxValue) { + super(type, "int", isWritable, isReadable, description); + this.maxValue = maxValue; + } + + /** {@inheritDoc} */ + @Override + protected CompletableFuture makeBuilder(int iid) { + return super.makeBuilder(iid) + .thenApply( + builder -> { + return builder.add("minValue", 0).add("maxValue", maxValue).add("minStep", 1); + }); + } + + /** {@inheritDoc} */ + @Override + protected Integer convert(JsonValue jsonValue) { + if (jsonValue instanceof JsonNumber) { + return ((JsonNumber) jsonValue).intValue(); + } else if (jsonValue == JsonObject.TRUE) { + return 1; // For at least one enum type (locks), homekit will send a true instead of 1 + } else if (jsonValue == JsonObject.FALSE) { + return 0; + } else { + throw new IndexOutOfBoundsException("Cannot convert " + jsonValue.getClass() + " to int"); + } + } + /** {@inheritDoc} */ + @Override + protected Integer getDefault() { + return 0; + } } diff --git a/src/main/java/com/beowulfe/hap/characteristics/EventableCharacteristic.java b/src/main/java/com/beowulfe/hap/characteristics/EventableCharacteristic.java index d36ec649c..c9527838f 100644 --- a/src/main/java/com/beowulfe/hap/characteristics/EventableCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/characteristics/EventableCharacteristic.java @@ -9,14 +9,14 @@ */ public interface EventableCharacteristic extends Characteristic { - /** - * Begin listening to changes to this characteristic. When a change is made, call the provided function. - * @param callback a function to call when a change is made to the characteristic value. - */ - void subscribe(HomekitCharacteristicChangeCallback callback); + /** + * Begin listening to changes to this characteristic. When a change is made, call the provided + * function. + * + * @param callback a function to call when a change is made to the characteristic value. + */ + void subscribe(HomekitCharacteristicChangeCallback callback); - /** - * Stop listening to changes to this characteristic. - */ - void unsubscribe(); + /** Stop listening to changes to this characteristic. */ + void unsubscribe(); } diff --git a/src/main/java/com/beowulfe/hap/characteristics/FloatCharacteristic.java b/src/main/java/com/beowulfe/hap/characteristics/FloatCharacteristic.java index 4ff06f36b..fda9aec56 100644 --- a/src/main/java/com/beowulfe/hap/characteristics/FloatCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/characteristics/FloatCharacteristic.java @@ -1,12 +1,11 @@ package com.beowulfe.hap.characteristics; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - +import java.util.concurrent.CompletableFuture; import javax.json.JsonNumber; import javax.json.JsonObjectBuilder; import javax.json.JsonValue; -import java.util.concurrent.CompletableFuture; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A characteristic that provides a Float value type. @@ -15,91 +14,105 @@ */ public abstract class FloatCharacteristic extends BaseCharacteristic { - private final static Logger LOGGER = LoggerFactory.getLogger(FloatCharacteristic.class); + private static final Logger LOGGER = LoggerFactory.getLogger(FloatCharacteristic.class); + + private final double minValue; + private final double maxValue; + private final double minStep; + private final String unit; + + /** + * Default constructor + * + * @param type a string containing a UUID that indicates the type of characteristic. Apple defines + * a set of these, however implementors can create their own as well. + * @param isWritable indicates whether the value can be changed. + * @param isReadable indicates whether the value can be retrieved. + * @param description a description of the characteristic to be passed to the consuming device. + * @param minValue the minimum supported value. + * @param maxValue the maximum supported value + * @param minStep the smallest supported step. Values will be rounded to a multiple of this. + * @param unit a description of the unit this characteristic supports. + */ + public FloatCharacteristic( + String type, + boolean isWritable, + boolean isReadable, + String description, + double minValue, + double maxValue, + double minStep, + String unit) { + super(type, "float", isWritable, isReadable, description); + this.minValue = minValue; + this.maxValue = maxValue; + this.minStep = minStep; + this.unit = unit; + } + + /** {@inheritDoc} */ + @Override + protected CompletableFuture makeBuilder(int iid) { + return super.makeBuilder(iid) + .thenApply( + builder -> + builder + .add("minValue", minValue) + .add("maxValue", maxValue) + .add("minStep", minStep) + .add("unit", unit)); + } + + /** {@inheritDoc} */ + @Override + protected Double convert(JsonValue jsonValue) { + return ((JsonNumber) jsonValue).doubleValue(); + } + + /** + * {@inheritDoc}. Calls the getDoubleValue method and applies rounding to the minStep supplied in + * the constructor. + */ + @Override + protected final CompletableFuture getValue() { + double rounder = 1 / this.minStep; + return getDoubleValue() + .thenApply(d -> d == null ? null : Math.round(d * rounder) / rounder) + .thenApply( + d -> { + if (d != null) { + if (d < minValue) { + LOGGER.warn( + "Detected value out of range " + + d + + ". Returning min value instead. Characteristic " + + this); + return minValue; + } + if (d > maxValue) { + LOGGER.warn( + "Detected value out of range " + + d + + ". Returning max value instead. Characteristic " + + this); + return maxValue; + } + return d; + } + return null; + }); + } - private final double minValue; - private final double maxValue; - private final double minStep; - private final String unit; - - /** - * Default constructor - * - * @param type a string containing a UUID that indicates the type of characteristic. Apple defines a set of these, - * however implementors can create their own as well. - * @param isWritable indicates whether the value can be changed. - * @param isReadable indicates whether the value can be retrieved. - * @param description a description of the characteristic to be passed to the consuming device. - * @param minValue the minimum supported value. - * @param maxValue the maximum supported value - * @param minStep the smallest supported step. Values will be rounded to a multiple of this. - * @param unit a description of the unit this characteristic supports. - */ - public FloatCharacteristic(String type, boolean isWritable, boolean isReadable, String description, - double minValue, double maxValue, double minStep, String unit) { - super(type, "float", isWritable, isReadable, description); - this.minValue = minValue; - this.maxValue = maxValue; - this.minStep = minStep; - this.unit = unit; - } - - /** - * {@inheritDoc} - */ - @Override - protected CompletableFuture makeBuilder(int iid) { - return super.makeBuilder(iid).thenApply(builder -> builder - .add("minValue", minValue) - .add("maxValue", maxValue) - .add("minStep", minStep) - .add("unit", unit)); - } + /** {@inheritDoc} */ + @Override + protected Double getDefault() { + return minValue; + } - /** - * {@inheritDoc} - */ - @Override - protected Double convert(JsonValue jsonValue) { - return ((JsonNumber) jsonValue).doubleValue(); - } - - /** - * {@inheritDoc}. Calls the getDoubleValue method and applies rounding to the minStep supplied in the constructor. - */ - @Override - protected final CompletableFuture getValue() { - double rounder = 1 / this.minStep; - return getDoubleValue().thenApply(d -> d == null ? null : Math.round(d * rounder) / rounder) - .thenApply(d -> { - if (d != null) { - if (d < minValue) { - LOGGER.warn("Detected value out of range " + d - + ". Returning min value instead. Characteristic " + this); - return minValue; - } - if (d > maxValue) { - LOGGER.warn("Detected value out of range " + d - + ". Returning max value instead. Characteristic " + this); - return maxValue; - } - return d; - } - return null; - }); - } - - /** - * {@inheritDoc} - */ - @Override - protected Double getDefault() { - return minValue; - } - - /** - * Supplies the value of this characteristic as a double. - * @return a future that will contain the value. - */ - protected abstract CompletableFuture getDoubleValue(); + /** + * Supplies the value of this characteristic as a double. + * + * @return a future that will contain the value. + */ + protected abstract CompletableFuture getDoubleValue(); } diff --git a/src/main/java/com/beowulfe/hap/characteristics/IntegerCharacteristic.java b/src/main/java/com/beowulfe/hap/characteristics/IntegerCharacteristic.java index a3c0fcfb6..30adeaa6b 100644 --- a/src/main/java/com/beowulfe/hap/characteristics/IntegerCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/characteristics/IntegerCharacteristic.java @@ -1,7 +1,6 @@ package com.beowulfe.hap.characteristics; import java.util.concurrent.CompletableFuture; - import javax.json.JsonNumber; import javax.json.JsonObjectBuilder; import javax.json.JsonValue; @@ -13,58 +12,59 @@ */ public abstract class IntegerCharacteristic extends BaseCharacteristic { - private final int minValue; - private final int maxValue; - private final String unit; - - /** - * Default constructor - * - * @param type a string containing a UUID that indicates the type of characteristic. Apple defines a set of these, - * however implementors can create their own as well. - * @param isWritable indicates whether the value can be changed. - * @param isReadable indicates whether the value can be retrieved. - * @param description a description of the characteristic to be passed to the consuming device. - * @param minValue the minimum supported value. - * @param maxValue the maximum supported value - * @param unit a description of the unit this characteristic supports. - */ - public IntegerCharacteristic(String type, boolean isWritable, boolean isReadable, String description, - int minValue, int maxValue, String unit) { - super(type, "int", isWritable, isReadable, description); - this.minValue = minValue; - this.maxValue = maxValue; - this.unit = unit; - } - - /** - * {@inheritDoc} - */ - @Override - protected CompletableFuture makeBuilder(int iid) { - return super.makeBuilder(iid).thenApply(builder -> { - return builder - .add("minValue", minValue) - .add("maxValue", maxValue) - .add("minStep", 1) - .add("unit", unit); - }); - } - - /** - * {@inheritDoc} - */ - @Override - protected Integer getDefault() { - return minValue; - } - - /** - * {@inheritDoc} - */ - @Override - protected Integer convert(JsonValue jsonValue) { - return ((JsonNumber) jsonValue).intValue(); - } + private final int minValue; + private final int maxValue; + private final String unit; + + /** + * Default constructor + * + * @param type a string containing a UUID that indicates the type of characteristic. Apple defines + * a set of these, however implementors can create their own as well. + * @param isWritable indicates whether the value can be changed. + * @param isReadable indicates whether the value can be retrieved. + * @param description a description of the characteristic to be passed to the consuming device. + * @param minValue the minimum supported value. + * @param maxValue the maximum supported value + * @param unit a description of the unit this characteristic supports. + */ + public IntegerCharacteristic( + String type, + boolean isWritable, + boolean isReadable, + String description, + int minValue, + int maxValue, + String unit) { + super(type, "int", isWritable, isReadable, description); + this.minValue = minValue; + this.maxValue = maxValue; + this.unit = unit; + } + + /** {@inheritDoc} */ + @Override + protected CompletableFuture makeBuilder(int iid) { + return super.makeBuilder(iid) + .thenApply( + builder -> { + return builder + .add("minValue", minValue) + .add("maxValue", maxValue) + .add("minStep", 1) + .add("unit", unit); + }); + } + + /** {@inheritDoc} */ + @Override + protected Integer getDefault() { + return minValue; + } + /** {@inheritDoc} */ + @Override + protected Integer convert(JsonValue jsonValue) { + return ((JsonNumber) jsonValue).intValue(); + } } diff --git a/src/main/java/com/beowulfe/hap/characteristics/StaticStringCharacteristic.java b/src/main/java/com/beowulfe/hap/characteristics/StaticStringCharacteristic.java index b3737ac12..8deaeb386 100644 --- a/src/main/java/com/beowulfe/hap/characteristics/StaticStringCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/characteristics/StaticStringCharacteristic.java @@ -1,7 +1,6 @@ package com.beowulfe.hap.characteristics; import java.util.concurrent.CompletableFuture; - import javax.json.JsonObjectBuilder; import javax.json.JsonString; import javax.json.JsonValue; @@ -13,65 +12,50 @@ */ public class StaticStringCharacteristic extends BaseCharacteristic { - final private static int MAX_LEN = 255; - - final private String value; - - /** - * Default constructor - * - * @param type a string containing a UUID that indicates the type of characteristic. Apple defines a set of these, - * however implementors can create their own as well. - * @param description a description of the characteristic to be passed to the consuming device. - * @param value the value of the static string. - */ - public StaticStringCharacteristic(String type, String description, String value) { - super(type, - "string", - false, - true, - description); - this.value = value; - } - - /** - * {@inheritDoc} - */ - @Override - protected CompletableFuture makeBuilder(int iid) { - return super.makeBuilder(iid).thenApply(builder -> builder.add("maxLen", MAX_LEN)); - } + private static final int MAX_LEN = 255; + + private final String value; + + /** + * Default constructor + * + * @param type a string containing a UUID that indicates the type of characteristic. Apple defines + * a set of these, however implementors can create their own as well. + * @param description a description of the characteristic to be passed to the consuming device. + * @param value the value of the static string. + */ + public StaticStringCharacteristic(String type, String description, String value) { + super(type, "string", false, true, description); + this.value = value; + } + + /** {@inheritDoc} */ + @Override + protected CompletableFuture makeBuilder(int iid) { + return super.makeBuilder(iid).thenApply(builder -> builder.add("maxLen", MAX_LEN)); + } + + /** {@inheritDoc} */ + @Override + public String convert(JsonValue jsonValue) { + return ((JsonString) jsonValue).getString(); + } - /** - * {@inheritDoc} - */ - @Override - public String convert(JsonValue jsonValue) { - return ((JsonString) jsonValue).getString(); - } + /** {@inheritDoc} */ + @Override + public void setValue(String value) throws Exception { + throw new Exception("Cannot modify static strings"); + } - /** - * {@inheritDoc} - */ - @Override - public void setValue(String value) throws Exception { - throw new Exception("Cannot modify static strings"); - } + /** {@inheritDoc} */ + @Override + protected CompletableFuture getValue() { + return CompletableFuture.completedFuture(value).thenApply(s -> s != null ? s : "Unavailable"); + } - /** - * {@inheritDoc} - */ - @Override - protected CompletableFuture getValue() { - return CompletableFuture.completedFuture(value).thenApply(s -> s != null ? s : "Unavailable"); - } - - /** - * {@inheritDoc} - */ - @Override - protected String getDefault() { - return "Unknown"; - } - + /** {@inheritDoc} */ + @Override + protected String getDefault() { + return "Unknown"; + } } diff --git a/src/main/java/com/beowulfe/hap/characteristics/WriteOnlyBooleanCharacteristic.java b/src/main/java/com/beowulfe/hap/characteristics/WriteOnlyBooleanCharacteristic.java index bcf100b6e..8f60c8e61 100644 --- a/src/main/java/com/beowulfe/hap/characteristics/WriteOnlyBooleanCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/characteristics/WriteOnlyBooleanCharacteristic.java @@ -1,7 +1,6 @@ package com.beowulfe.hap.characteristics; import java.util.concurrent.CompletableFuture; - import javax.json.JsonObjectBuilder; /** @@ -10,27 +9,25 @@ * @author Andy Lintner */ public abstract class WriteOnlyBooleanCharacteristic extends BooleanCharacteristic { - - /** - * Default constructor - * - * @param type a string containing a UUID that indicates the type of characteristic. Apple defines a set of these, - * however implementors can create their own as well. - * @param description a description of the characteristic to be passed to the consuming device. - */ - public WriteOnlyBooleanCharacteristic(String type, String description) { - super( type, - true, - false, - description - ); - } - - @Override - protected final CompletableFuture getValue() { return CompletableFuture.completedFuture(false); } - @Override - protected final void setJsonValue(JsonObjectBuilder builder, Boolean value) { - //Do nothing - non-readable characteristics cannot have a value key set - } + /** + * Default constructor + * + * @param type a string containing a UUID that indicates the type of characteristic. Apple defines + * a set of these, however implementors can create their own as well. + * @param description a description of the characteristic to be passed to the consuming device. + */ + public WriteOnlyBooleanCharacteristic(String type, String description) { + super(type, true, false, description); + } + + @Override + protected final CompletableFuture getValue() { + return CompletableFuture.completedFuture(false); + } + + @Override + protected final void setJsonValue(JsonObjectBuilder builder, Boolean value) { + // Do nothing - non-readable characteristics cannot have a value key set + } } diff --git a/src/main/java/com/beowulfe/hap/characteristics/package-info.java b/src/main/java/com/beowulfe/hap/characteristics/package-info.java index 94b6dd9eb..78085ead2 100644 --- a/src/main/java/com/beowulfe/hap/characteristics/package-info.java +++ b/src/main/java/com/beowulfe/hap/characteristics/package-info.java @@ -1,4 +1,4 @@ /** * Contains the basic characteristic types that can be supplied over the Homekit Accessory Protocol. */ -package com.beowulfe.hap.characteristics; \ No newline at end of file +package com.beowulfe.hap.characteristics; diff --git a/src/main/java/com/beowulfe/hap/impl/ExceptionalConsumer.java b/src/main/java/com/beowulfe/hap/impl/ExceptionalConsumer.java index 4db49d49c..ecbd5faad 100644 --- a/src/main/java/com/beowulfe/hap/impl/ExceptionalConsumer.java +++ b/src/main/java/com/beowulfe/hap/impl/ExceptionalConsumer.java @@ -1,5 +1,5 @@ package com.beowulfe.hap.impl; public interface ExceptionalConsumer { - void accept(T t) throws Exception; + void accept(T t) throws Exception; } diff --git a/src/main/java/com/beowulfe/hap/impl/HomekitBridge.java b/src/main/java/com/beowulfe/hap/impl/HomekitBridge.java index 9b4fb2d7b..476c83681 100644 --- a/src/main/java/com/beowulfe/hap/impl/HomekitBridge.java +++ b/src/main/java/com/beowulfe/hap/impl/HomekitBridge.java @@ -1,54 +1,51 @@ package com.beowulfe.hap.impl; -import java.util.Collection; -import java.util.Collections; - import com.beowulfe.hap.Service; import com.beowulfe.hap.impl.accessories.Bridge; +import java.util.Collection; +import java.util.Collections; public class HomekitBridge implements Bridge { - private final String label; - private final String serialNumber; - private final String model; - private final String manufacturer; - - public HomekitBridge(String label, String serialNumber, String model, - String manufacturer) { - this.label = label; - this.serialNumber = serialNumber; - this.model = model; - this.manufacturer = manufacturer; - } - - @Override - public String getLabel() { - return label; - } - - @Override - public String getSerialNumber() { - return serialNumber; - } - - @Override - public String getModel() { - return model; - } - - @Override - public String getManufacturer() { - return manufacturer; - } - - @Override - public Collection getServices() { - return Collections.emptyList(); - } - - @Override - public int getId() { - return 1; - } + private final String label; + private final String serialNumber; + private final String model; + private final String manufacturer; + + public HomekitBridge(String label, String serialNumber, String model, String manufacturer) { + this.label = label; + this.serialNumber = serialNumber; + this.model = model; + this.manufacturer = manufacturer; + } + + @Override + public String getLabel() { + return label; + } + + @Override + public String getSerialNumber() { + return serialNumber; + } + + @Override + public String getModel() { + return model; + } + + @Override + public String getManufacturer() { + return manufacturer; + } + + @Override + public Collection getServices() { + return Collections.emptyList(); + } + @Override + public int getId() { + return 1; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/HomekitRegistry.java b/src/main/java/com/beowulfe/hap/impl/HomekitRegistry.java index b784cae63..f691d9320 100644 --- a/src/main/java/com/beowulfe/hap/impl/HomekitRegistry.java +++ b/src/main/java/com/beowulfe/hap/impl/HomekitRegistry.java @@ -4,89 +4,88 @@ import com.beowulfe.hap.Service; import com.beowulfe.hap.characteristics.Characteristic; import com.beowulfe.hap.impl.services.AccessoryInformationService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class HomekitRegistry { - - private final static Logger logger = LoggerFactory.getLogger(HomekitRegistry.class); - private final String label; - private final Map accessories; - private final Map> services = new HashMap<>(); - private final Map> characteristics = new HashMap<>(); - private boolean isAllowUnauthenticatedRequests = false; - - public HomekitRegistry(String label) { - this.label = label; - this.accessories = new ConcurrentHashMap<>(); - reset(); - } - - public synchronized void reset() { - characteristics.clear(); - services.clear(); - for (HomekitAccessory accessory: accessories.values()) { - int iid = 0; - List newServices; - try { - newServices = new ArrayList<>(2); - newServices.add(new AccessoryInformationService(accessory)); - newServices.addAll(accessory.getServices()); - } catch (Exception e) { - logger.error("Could not instantiate services for accessory "+accessory.getLabel(), e); - services.put(accessory, Collections.emptyList()); - continue; - } - Map newCharacteristics = new HashMap<>(); - services.put(accessory, newServices); - for (Service service: newServices) { - iid++; - for (Characteristic characteristic: service.getCharacteristics()) { - newCharacteristics.put(++iid, characteristic); - } - } - characteristics.put(accessory, newCharacteristics); - } - } - - public String getLabel() { - return label; - } + private static final Logger logger = LoggerFactory.getLogger(HomekitRegistry.class); + + private final String label; + private final Map accessories; + private final Map> services = new HashMap<>(); + private final Map> characteristics = + new HashMap<>(); + private boolean isAllowUnauthenticatedRequests = false; + + public HomekitRegistry(String label) { + this.label = label; + this.accessories = new ConcurrentHashMap<>(); + reset(); + } + + public synchronized void reset() { + characteristics.clear(); + services.clear(); + for (HomekitAccessory accessory : accessories.values()) { + int iid = 0; + List newServices; + try { + newServices = new ArrayList<>(2); + newServices.add(new AccessoryInformationService(accessory)); + newServices.addAll(accessory.getServices()); + } catch (Exception e) { + logger.error("Could not instantiate services for accessory " + accessory.getLabel(), e); + services.put(accessory, Collections.emptyList()); + continue; + } + Map newCharacteristics = new HashMap<>(); + services.put(accessory, newServices); + for (Service service : newServices) { + iid++; + for (Characteristic characteristic : service.getCharacteristics()) { + newCharacteristics.put(++iid, characteristic); + } + } + characteristics.put(accessory, newCharacteristics); + } + } + + public String getLabel() { + return label; + } + + public Collection getAccessories() { + return accessories.values(); + } + + public List getServices(Integer aid) { + return Collections.unmodifiableList(services.get(accessories.get(aid))); + } - public Collection getAccessories() { - return accessories.values(); - } - - public List getServices(Integer aid) { - return Collections.unmodifiableList(services.get(accessories.get(aid))); - } - - public Map getCharacteristics(Integer aid) { - Map characteristics = this.characteristics.get(accessories.get(aid)); - if (characteristics == null) { - return Collections.emptyMap(); - } - return Collections.unmodifiableMap(characteristics); - } + public Map getCharacteristics(Integer aid) { + Map characteristics = this.characteristics.get(accessories.get(aid)); + if (characteristics == null) { + return Collections.emptyMap(); + } + return Collections.unmodifiableMap(characteristics); + } - public void add(HomekitAccessory accessory) { - accessories.put(accessory.getId(), accessory); - } + public void add(HomekitAccessory accessory) { + accessories.put(accessory.getId(), accessory); + } - public void remove(HomekitAccessory accessory) { - accessories.remove(accessory.getId()); - } - - public boolean isAllowUnauthenticatedRequests() { - return isAllowUnauthenticatedRequests; - } + public void remove(HomekitAccessory accessory) { + accessories.remove(accessory.getId()); + } - public void setAllowUnauthenticatedRequests(boolean allow) { - this.isAllowUnauthenticatedRequests = allow; - } + public boolean isAllowUnauthenticatedRequests() { + return isAllowUnauthenticatedRequests; + } + public void setAllowUnauthenticatedRequests(boolean allow) { + this.isAllowUnauthenticatedRequests = allow; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/HomekitUtils.java b/src/main/java/com/beowulfe/hap/impl/HomekitUtils.java index 8e5f09d70..f82eb77e1 100644 --- a/src/main/java/com/beowulfe/hap/impl/HomekitUtils.java +++ b/src/main/java/com/beowulfe/hap/impl/HomekitUtils.java @@ -1,47 +1,48 @@ package com.beowulfe.hap.impl; +import com.nimbusds.srp6.SRP6Routines; import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; import java.security.SecureRandom; import java.util.stream.Collectors; import java.util.stream.Stream; - import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec; -import com.nimbusds.srp6.SRP6Routines; - public class HomekitUtils { - - private static volatile SecureRandom secureRandom; - public static BigInteger generateSalt() { - return new BigInteger(SRP6Routines.generateRandomSalt(16)); - } - - public static byte[] generateKey() throws InvalidAlgorithmParameterException { - EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512"); - byte[] seed = new byte[spec.getCurve().getField().getb()/8]; - getSecureRandom().nextBytes(seed); - return seed; - } - - public static String generateMac() { - int byte1 = ((getSecureRandom().nextInt(255) + 1) | 2) & 0xFE; //Unicast locally administered MAC; - return Integer.toHexString(byte1) + ":" + Stream.generate(() -> getSecureRandom().nextInt(255) + 1) - .limit(5) - .map(i -> Integer.toHexString(i)) - .collect(Collectors.joining(":")); - } - - private static SecureRandom getSecureRandom() { - if (secureRandom == null) { - synchronized(HomekitUtils.class) { - if (secureRandom == null) { - secureRandom = new SecureRandom(); - } - } - } - return secureRandom; - } + private static volatile SecureRandom secureRandom; + + public static BigInteger generateSalt() { + return new BigInteger(SRP6Routines.generateRandomSalt(16)); + } + + public static byte[] generateKey() throws InvalidAlgorithmParameterException { + EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512"); + byte[] seed = new byte[spec.getCurve().getField().getb() / 8]; + getSecureRandom().nextBytes(seed); + return seed; + } + + public static String generateMac() { + int byte1 = + ((getSecureRandom().nextInt(255) + 1) | 2) & 0xFE; // Unicast locally administered MAC; + return Integer.toHexString(byte1) + + ":" + + Stream.generate(() -> getSecureRandom().nextInt(255) + 1) + .limit(5) + .map(i -> Integer.toHexString(i)) + .collect(Collectors.joining(":")); + } + + private static SecureRandom getSecureRandom() { + if (secureRandom == null) { + synchronized (HomekitUtils.class) { + if (secureRandom == null) { + secureRandom = new SecureRandom(); + } + } + } + return secureRandom; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/HomekitWebHandler.java b/src/main/java/com/beowulfe/hap/impl/HomekitWebHandler.java index 3652789db..32755e94e 100644 --- a/src/main/java/com/beowulfe/hap/impl/HomekitWebHandler.java +++ b/src/main/java/com/beowulfe/hap/impl/HomekitWebHandler.java @@ -1,16 +1,13 @@ package com.beowulfe.hap.impl; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.impl.http.HomekitClientConnectionFactory; - +import java.util.concurrent.CompletableFuture; public interface HomekitWebHandler { - CompletableFuture start(HomekitClientConnectionFactory clientConnectionFactory); - - void stop(); + CompletableFuture start(HomekitClientConnectionFactory clientConnectionFactory); + + void stop(); - void resetConnections(); - + void resetConnections(); } diff --git a/src/main/java/com/beowulfe/hap/impl/accessories/Bridge.java b/src/main/java/com/beowulfe/hap/impl/accessories/Bridge.java index 3ecf1328e..a0a1201ed 100644 --- a/src/main/java/com/beowulfe/hap/impl/accessories/Bridge.java +++ b/src/main/java/com/beowulfe/hap/impl/accessories/Bridge.java @@ -4,7 +4,6 @@ public interface Bridge extends HomekitAccessory { - @Override - default void identify() {} - + @Override + default void identify() {} } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/carbonmonoxide/CarbonMonoxideDetectedCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/carbonmonoxide/CarbonMonoxideDetectedCharacteristic.java index 4e1dbf481..989f7024c 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/carbonmonoxide/CarbonMonoxideDetectedCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/carbonmonoxide/CarbonMonoxideDetectedCharacteristic.java @@ -5,34 +5,37 @@ import com.beowulfe.hap.accessories.properties.CarbonMonoxideDetectedState; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; - import java.util.concurrent.CompletableFuture; -public class CarbonMonoxideDetectedCharacteristic extends EnumCharacteristic implements EventableCharacteristic { - - private final CarbonMonoxideSensor carbonMonoxideSensor; - - public CarbonMonoxideDetectedCharacteristic(CarbonMonoxideSensor carbonMonoxideSensor) { - super("00000069-0000-1000-8000-0026BB765291", false, true, "Carbon Monoxide Detected", 1); - this.carbonMonoxideSensor = carbonMonoxideSensor; - } - - @Override - protected CompletableFuture getValue() { - return carbonMonoxideSensor.getCarbonMonoxideDetectedState().thenApply(CarbonMonoxideDetectedState::getCode); - } - - @Override - protected void setValue(Integer value) throws Exception { - //Read Only - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - carbonMonoxideSensor.subscribeCarbonMonoxideDetectedState(callback); - } - - @Override - public void unsubscribe() { - carbonMonoxideSensor.unsubscribeCarbonMonoxideDetectedState(); - }} +public class CarbonMonoxideDetectedCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { + + private final CarbonMonoxideSensor carbonMonoxideSensor; + + public CarbonMonoxideDetectedCharacteristic(CarbonMonoxideSensor carbonMonoxideSensor) { + super("00000069-0000-1000-8000-0026BB765291", false, true, "Carbon Monoxide Detected", 1); + this.carbonMonoxideSensor = carbonMonoxideSensor; + } + + @Override + protected CompletableFuture getValue() { + return carbonMonoxideSensor + .getCarbonMonoxideDetectedState() + .thenApply(CarbonMonoxideDetectedState::getCode); + } + + @Override + protected void setValue(Integer value) throws Exception { + // Read Only + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + carbonMonoxideSensor.subscribeCarbonMonoxideDetectedState(callback); + } + + @Override + public void unsubscribe() { + carbonMonoxideSensor.unsubscribeCarbonMonoxideDetectedState(); + } +} diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/common/ActiveCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/common/ActiveCharacteristic.java index b3f94f7de..e0f8f409c 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/common/ActiveCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/common/ActiveCharacteristic.java @@ -1,47 +1,49 @@ package com.beowulfe.hap.impl.characteristics.common; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import java.util.function.Supplier; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.characteristics.BooleanCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.impl.ExceptionalConsumer; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Supplier; public class ActiveCharacteristic extends BooleanCharacteristic implements EventableCharacteristic { - private final Supplier> getter; - private final ExceptionalConsumer setter; - private final Consumer subscriber; - private final Runnable unsubscriber; - - public ActiveCharacteristic(Supplier> getter, ExceptionalConsumer setter, - Consumer subscriber, Runnable unsubscriber) { - super("000000B0-0000-1000-8000-0026BB765291", true, true, "Active"); - this.getter = getter; - this.setter = setter; - this.subscriber = subscriber; - this.unsubscriber = unsubscriber; - } - - @Override - protected CompletableFuture getValue() { - return getter.get(); - } - - @Override - protected void setValue(Boolean value) throws Exception { - setter.accept(value); - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - subscriber.accept(callback); - } - - @Override - public void unsubscribe() { - unsubscriber.run(); - } + private final Supplier> getter; + private final ExceptionalConsumer setter; + private final Consumer subscriber; + private final Runnable unsubscriber; + + public ActiveCharacteristic( + Supplier> getter, + ExceptionalConsumer setter, + Consumer subscriber, + Runnable unsubscriber) { + super("000000B0-0000-1000-8000-0026BB765291", true, true, "Active"); + this.getter = getter; + this.setter = setter; + this.subscriber = subscriber; + this.unsubscriber = unsubscriber; + } + + @Override + protected CompletableFuture getValue() { + return getter.get(); + } + + @Override + protected void setValue(Boolean value) throws Exception { + setter.accept(value); + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + subscriber.accept(callback); + } + + @Override + public void unsubscribe() { + unsubscriber.run(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/common/BatteryLevelCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/common/BatteryLevelCharacteristic.java index f0cd9aa4f..6a042ce11 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/common/BatteryLevelCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/common/BatteryLevelCharacteristic.java @@ -1,49 +1,50 @@ package com.beowulfe.hap.impl.characteristics.common; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import java.util.function.Supplier; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.IntegerCharacteristic; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Supplier; /** - * This characteristic is used by a stand-alone BatteryService, which describes - * a stand-alone battery device, not the battery status of a battery operated - * device such as a motion sensor. + * This characteristic is used by a stand-alone BatteryService, which describes a stand-alone + * battery device, not the battery status of a battery operated device such as a motion sensor. */ -public class BatteryLevelCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { - - private final Supplier> getter; - private final Consumer subscriber; - private final Runnable unsubscriber; - - public BatteryLevelCharacteristic(Supplier> getter, - Consumer subscriber, Runnable unsubscriber) { - super("00000068-0000-1000-8000-0026BB765291", false, true, "Battery Level", 0, 100, "%"); - this.getter = getter; - this.subscriber = subscriber; - this.unsubscriber = unsubscriber; - } - - @Override - protected CompletableFuture getValue() { - return getter.get(); - } - - @Override - protected void setValue(Integer value) throws Exception { - // Read Only - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - subscriber.accept(callback); - } - - @Override - public void unsubscribe() { - unsubscriber.run(); - } +public class BatteryLevelCharacteristic extends IntegerCharacteristic + implements EventableCharacteristic { + + private final Supplier> getter; + private final Consumer subscriber; + private final Runnable unsubscriber; + + public BatteryLevelCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + super("00000068-0000-1000-8000-0026BB765291", false, true, "Battery Level", 0, 100, "%"); + this.getter = getter; + this.subscriber = subscriber; + this.unsubscriber = unsubscriber; + } + + @Override + protected CompletableFuture getValue() { + return getter.get(); + } + + @Override + protected void setValue(Integer value) throws Exception { + // Read Only + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + subscriber.accept(callback); + } + + @Override + public void unsubscribe() { + unsubscriber.run(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/common/InUseCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/common/InUseCharacteristic.java index 25ecace9d..f050f6ef0 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/common/InUseCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/common/InUseCharacteristic.java @@ -1,44 +1,45 @@ package com.beowulfe.hap.impl.characteristics.common; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import java.util.function.Supplier; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.characteristics.BooleanCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Supplier; public class InUseCharacteristic extends BooleanCharacteristic implements EventableCharacteristic { - private final Supplier> getter; - private final Consumer subscriber; - private final Runnable unsubscriber; - - public InUseCharacteristic(Supplier> getter, - Consumer subscriber, Runnable unsubscriber) { - super("000000D2-0000-1000-8000-0026BB765291", false, true, "InUse"); - this.getter = getter; - this.subscriber = subscriber; - this.unsubscriber = unsubscriber; - } - - @Override - protected CompletableFuture getValue() { - return getter.get(); - } - - @Override - protected void setValue(Boolean value) throws Exception { - // Read Only - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - subscriber.accept(callback); - } - - @Override - public void unsubscribe() { - unsubscriber.run(); - } + private final Supplier> getter; + private final Consumer subscriber; + private final Runnable unsubscriber; + + public InUseCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + super("000000D2-0000-1000-8000-0026BB765291", false, true, "InUse"); + this.getter = getter; + this.subscriber = subscriber; + this.unsubscriber = unsubscriber; + } + + @Override + protected CompletableFuture getValue() { + return getter.get(); + } + + @Override + protected void setValue(Boolean value) throws Exception { + // Read Only + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + subscriber.accept(callback); + } + + @Override + public void unsubscribe() { + unsubscriber.run(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/common/LowBatteryStatusCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/common/LowBatteryStatusCharacteristic.java index ad44c51e2..74fd47b7c 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/common/LowBatteryStatusCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/common/LowBatteryStatusCharacteristic.java @@ -1,44 +1,46 @@ package com.beowulfe.hap.impl.characteristics.common; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import java.util.function.Supplier; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.characteristics.BooleanCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Supplier; -public class LowBatteryStatusCharacteristic extends BooleanCharacteristic implements EventableCharacteristic { - - private final Supplier> getter; - private final Consumer subscriber; - private final Runnable unsubscriber; - - public LowBatteryStatusCharacteristic(Supplier> getter, - Consumer subscriber, Runnable unsubscriber) { - super("00000079-0000-1000-8000-0026BB765291", false, true, "Status Low Battery"); - this.getter = getter; - this.subscriber = subscriber; - this.unsubscriber = unsubscriber; - } - - @Override - protected CompletableFuture getValue() { - return getter.get(); - } - - @Override - protected void setValue(Boolean value) throws Exception { - // Read Only - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - subscriber.accept(callback); - } - - @Override - public void unsubscribe() { - unsubscriber.run(); - } +public class LowBatteryStatusCharacteristic extends BooleanCharacteristic + implements EventableCharacteristic { + + private final Supplier> getter; + private final Consumer subscriber; + private final Runnable unsubscriber; + + public LowBatteryStatusCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + super("00000079-0000-1000-8000-0026BB765291", false, true, "Status Low Battery"); + this.getter = getter; + this.subscriber = subscriber; + this.unsubscriber = unsubscriber; + } + + @Override + protected CompletableFuture getValue() { + return getter.get(); + } + + @Override + protected void setValue(Boolean value) throws Exception { + // Read Only + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + subscriber.accept(callback); + } + + @Override + public void unsubscribe() { + unsubscriber.run(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/common/Name.java b/src/main/java/com/beowulfe/hap/impl/characteristics/common/Name.java index a80c1941b..3a5e41eb7 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/common/Name.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/common/Name.java @@ -3,10 +3,8 @@ import com.beowulfe.hap.characteristics.StaticStringCharacteristic; public class Name extends StaticStringCharacteristic { - - public Name(String label) { - super("00000023-0000-1000-8000-0026BB765291", - "Name of the accessory", - label); - } + + public Name(String label) { + super("00000023-0000-1000-8000-0026BB765291", "Name of the accessory", label); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/common/ObstructionDetectedCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/common/ObstructionDetectedCharacteristic.java index 4cc365beb..f3910082e 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/common/ObstructionDetectedCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/common/ObstructionDetectedCharacteristic.java @@ -1,47 +1,46 @@ package com.beowulfe.hap.impl.characteristics.common; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import java.util.function.Supplier; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.characteristics.BooleanCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Supplier; -public class ObstructionDetectedCharacteristic extends BooleanCharacteristic implements EventableCharacteristic { - - private final Supplier> getter; - private final Consumer subscriber; - private final Runnable unsubscriber; - - public ObstructionDetectedCharacteristic(Supplier> getter, - Consumer subscriber, Runnable unsubscriber) { - super("00000024-0000-1000-8000-0026BB765291", false, true, "An obstruction has been detected"); - this.getter = getter; - this.subscriber = subscriber; - this.unsubscriber = unsubscriber; - } - - @Override - protected void setValue(Boolean value) throws Exception { - //Read Only - } - - @Override - protected CompletableFuture getValue() { - return getter.get(); - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - subscriber.accept(callback); - } - - @Override - public void unsubscribe() { - unsubscriber.run(); - } - - - +public class ObstructionDetectedCharacteristic extends BooleanCharacteristic + implements EventableCharacteristic { + + private final Supplier> getter; + private final Consumer subscriber; + private final Runnable unsubscriber; + + public ObstructionDetectedCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + super("00000024-0000-1000-8000-0026BB765291", false, true, "An obstruction has been detected"); + this.getter = getter; + this.subscriber = subscriber; + this.unsubscriber = unsubscriber; + } + + @Override + protected void setValue(Boolean value) throws Exception { + // Read Only + } + + @Override + protected CompletableFuture getValue() { + return getter.get(); + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + subscriber.accept(callback); + } + + @Override + public void unsubscribe() { + unsubscriber.run(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/common/PowerStateCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/common/PowerStateCharacteristic.java index 0902902ee..1479f55fb 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/common/PowerStateCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/common/PowerStateCharacteristic.java @@ -1,51 +1,50 @@ package com.beowulfe.hap.impl.characteristics.common; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import java.util.function.Supplier; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.characteristics.BooleanCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.impl.ExceptionalConsumer; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class PowerStateCharacteristic extends BooleanCharacteristic + implements EventableCharacteristic { + + private final Supplier> getter; + private final ExceptionalConsumer setter; + private final Consumer subscriber; + private final Runnable unsubscriber; + + public PowerStateCharacteristic( + Supplier> getter, + ExceptionalConsumer setter, + Consumer subscriber, + Runnable unsubscriber) { + super("00000025-0000-1000-8000-0026BB765291", true, true, "Turn on and off"); + this.getter = getter; + this.setter = setter; + this.subscriber = subscriber; + this.unsubscriber = unsubscriber; + } + + @Override + public void setValue(Boolean value) throws Exception { + setter.accept(value); + } + + @Override + protected CompletableFuture getValue() { + return getter.get(); + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + subscriber.accept(callback); + } -public class PowerStateCharacteristic extends BooleanCharacteristic implements EventableCharacteristic { - - private final Supplier> getter; - private final ExceptionalConsumer setter; - private final Consumer subscriber; - private final Runnable unsubscriber; - - public PowerStateCharacteristic(Supplier> getter, ExceptionalConsumer setter, - Consumer subscriber, Runnable unsubscriber) { - super("00000025-0000-1000-8000-0026BB765291", - true, - true, - "Turn on and off"); - this.getter = getter; - this.setter = setter; - this.subscriber = subscriber; - this.unsubscriber = unsubscriber; - } - - @Override - public void setValue(Boolean value) throws Exception { - setter.accept(value); - } - - @Override - protected CompletableFuture getValue() { - return getter.get(); - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - subscriber.accept(callback); - } - - @Override - public void unsubscribe() { - unsubscriber.run(); - } - + @Override + public void unsubscribe() { + unsubscriber.run(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/common/RemainingDurationCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/common/RemainingDurationCharacteristic.java index 37d47c2ff..f57253de9 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/common/RemainingDurationCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/common/RemainingDurationCharacteristic.java @@ -1,44 +1,53 @@ package com.beowulfe.hap.impl.characteristics.common; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import java.util.function.Supplier; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.IntegerCharacteristic; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Supplier; -public class RemainingDurationCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { - - private final Supplier> getter; - private final Consumer subscriber; - private final Runnable unsubscriber; - - public RemainingDurationCharacteristic(Supplier> getter, - Consumer subscriber, Runnable unsubscriber) { - super("000000D4-0000-1000-8000-0026BB765291", false, true, "Remaining Duration", 0, 3600, "seconds"); - this.getter = getter; - this.subscriber = subscriber; - this.unsubscriber = unsubscriber; - } - - @Override - protected CompletableFuture getValue() { - return getter.get(); - } - - @Override - protected void setValue(Integer value) throws Exception { - // Read Only - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - subscriber.accept(callback); - } - - @Override - public void unsubscribe() { - unsubscriber.run(); - } +public class RemainingDurationCharacteristic extends IntegerCharacteristic + implements EventableCharacteristic { + + private final Supplier> getter; + private final Consumer subscriber; + private final Runnable unsubscriber; + + public RemainingDurationCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + super( + "000000D4-0000-1000-8000-0026BB765291", + false, + true, + "Remaining Duration", + 0, + 3600, + "seconds"); + this.getter = getter; + this.subscriber = subscriber; + this.unsubscriber = unsubscriber; + } + + @Override + protected CompletableFuture getValue() { + return getter.get(); + } + + @Override + protected void setValue(Integer value) throws Exception { + // Read Only + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + subscriber.accept(callback); + } + + @Override + public void unsubscribe() { + unsubscriber.run(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/contactsensor/ContactSensorStateCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/contactsensor/ContactSensorStateCharacteristic.java index 57a710a02..0792d8531 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/contactsensor/ContactSensorStateCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/contactsensor/ContactSensorStateCharacteristic.java @@ -5,35 +5,35 @@ import com.beowulfe.hap.accessories.properties.ContactState; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; - import java.util.concurrent.CompletableFuture; -public class ContactSensorStateCharacteristic extends EnumCharacteristic implements EventableCharacteristic { +public class ContactSensorStateCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { - private final ContactSensor contactSensor; + private final ContactSensor contactSensor; - public ContactSensorStateCharacteristic(ContactSensor contactSensor) { - super("0000006A-0000-1000-8000-0026BB765291", false, true, "Contact State", 1); - this.contactSensor = contactSensor; - } + public ContactSensorStateCharacteristic(ContactSensor contactSensor) { + super("0000006A-0000-1000-8000-0026BB765291", false, true, "Contact State", 1); + this.contactSensor = contactSensor; + } - @Override - protected CompletableFuture getValue() { - return contactSensor.getCurrentState().thenApply(ContactState::getCode); - } + @Override + protected CompletableFuture getValue() { + return contactSensor.getCurrentState().thenApply(ContactState::getCode); + } - @Override - protected void setValue(Integer value) throws Exception { - //Read Only - } + @Override + protected void setValue(Integer value) throws Exception { + // Read Only + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - contactSensor.subscribeContactState(callback); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + contactSensor.subscribeContactState(callback); + } - @Override - public void unsubscribe() { - contactSensor.unsubscribeContactState(); - } + @Override + public void unsubscribe() { + contactSensor.unsubscribeContactState(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/fan/RotationDirectionCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/fan/RotationDirectionCharacteristic.java index 16d4009be..a051ed4e2 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/fan/RotationDirectionCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/fan/RotationDirectionCharacteristic.java @@ -1,40 +1,39 @@ package com.beowulfe.hap.impl.characteristics.fan; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.Fan; import com.beowulfe.hap.accessories.properties.RotationDirection; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; -public class RotationDirectionCharacteristic extends EnumCharacteristic implements EventableCharacteristic { +public class RotationDirectionCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { - private final Fan fan; - - public RotationDirectionCharacteristic(Fan fan) { - super("00000028-0000-1000-8000-0026BB765291", true, true, "Rotation Direction", 1); - this.fan = fan; - } + private final Fan fan; - @Override - protected void setValue(Integer value) throws Exception { - fan.setRotationDirection(RotationDirection.fromCode(value)); - } + public RotationDirectionCharacteristic(Fan fan) { + super("00000028-0000-1000-8000-0026BB765291", true, true, "Rotation Direction", 1); + this.fan = fan; + } - @Override - protected CompletableFuture getValue() { - return fan.getRotationDirection().thenApply(s -> s.getCode()); - } + @Override + protected void setValue(Integer value) throws Exception { + fan.setRotationDirection(RotationDirection.fromCode(value)); + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - fan.subscribeRotationDirection(callback); - } + @Override + protected CompletableFuture getValue() { + return fan.getRotationDirection().thenApply(s -> s.getCode()); + } - @Override - public void unsubscribe() { - fan.unsubscribeRotationDirection(); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + fan.subscribeRotationDirection(callback); + } + @Override + public void unsubscribe() { + fan.unsubscribeRotationDirection(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/fan/RotationSpeedCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/fan/RotationSpeedCharacteristic.java index 8db60b6ed..e3c899e2a 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/fan/RotationSpeedCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/fan/RotationSpeedCharacteristic.java @@ -1,40 +1,38 @@ package com.beowulfe.hap.impl.characteristics.fan; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.Fan; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.IntegerCharacteristic; +import java.util.concurrent.CompletableFuture; -public class RotationSpeedCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { +public class RotationSpeedCharacteristic extends IntegerCharacteristic + implements EventableCharacteristic { - private final Fan fan; - - public RotationSpeedCharacteristic(Fan fan) { - super("00000029-0000-1000-8000-0026BB765291", true, true, "Rotation speed", 0, - 100, "%"); - this.fan = fan; - } + private final Fan fan; - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - fan.subscribeRotationSpeed(callback); - } + public RotationSpeedCharacteristic(Fan fan) { + super("00000029-0000-1000-8000-0026BB765291", true, true, "Rotation speed", 0, 100, "%"); + this.fan = fan; + } - @Override - public void unsubscribe() { - fan.unsubscribeRotationSpeed(); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + fan.subscribeRotationSpeed(callback); + } - @Override - protected void setValue(Integer value) throws Exception { - fan.setRotationSpeed(value); - } + @Override + public void unsubscribe() { + fan.unsubscribeRotationSpeed(); + } - @Override - protected CompletableFuture getValue() { - return fan.getRotationSpeed(); - } + @Override + protected void setValue(Integer value) throws Exception { + fan.setRotationSpeed(value); + } + @Override + protected CompletableFuture getValue() { + return fan.getRotationSpeed(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/garage/CurrentDoorStateCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/garage/CurrentDoorStateCharacteristic.java index 82bf04a0b..694ce3666 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/garage/CurrentDoorStateCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/garage/CurrentDoorStateCharacteristic.java @@ -1,40 +1,39 @@ package com.beowulfe.hap.impl.characteristics.garage; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.GarageDoor; import com.beowulfe.hap.accessories.properties.DoorState; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; -public class CurrentDoorStateCharacteristic extends EnumCharacteristic implements EventableCharacteristic { +public class CurrentDoorStateCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { - private final GarageDoor door; - - public CurrentDoorStateCharacteristic(GarageDoor door) { - super("00000032-0000-1000-8000-0026BB765291", true, true, "Target Door State", 1); - this.door = door; - } + private final GarageDoor door; - @Override - protected void setValue(Integer value) throws Exception { - door.setTargetDoorState(DoorState.fromCode(value)); - } + public CurrentDoorStateCharacteristic(GarageDoor door) { + super("00000032-0000-1000-8000-0026BB765291", true, true, "Target Door State", 1); + this.door = door; + } - @Override - protected CompletableFuture getValue() { - return door.getTargetDoorState().thenApply(s -> s.getCode()); - } + @Override + protected void setValue(Integer value) throws Exception { + door.setTargetDoorState(DoorState.fromCode(value)); + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - door.subscribeTargetDoorState(callback); - } + @Override + protected CompletableFuture getValue() { + return door.getTargetDoorState().thenApply(s -> s.getCode()); + } - @Override - public void unsubscribe() { - door.unsubscribeTargetDoorState(); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + door.subscribeTargetDoorState(callback); + } + @Override + public void unsubscribe() { + door.unsubscribeTargetDoorState(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/garage/TargetDoorStateCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/garage/TargetDoorStateCharacteristic.java index f7cb9ec30..843260621 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/garage/TargetDoorStateCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/garage/TargetDoorStateCharacteristic.java @@ -1,39 +1,38 @@ package com.beowulfe.hap.impl.characteristics.garage; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.GarageDoor; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; -public class TargetDoorStateCharacteristic extends EnumCharacteristic implements EventableCharacteristic { +public class TargetDoorStateCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { - private final GarageDoor door; - - public TargetDoorStateCharacteristic(GarageDoor door) { - super("0000000E-0000-1000-8000-0026BB765291", false, true, "Current Door State", 4); - this.door = door; - } + private final GarageDoor door; - @Override - protected void setValue(Integer value) throws Exception { - //Read Only - } + public TargetDoorStateCharacteristic(GarageDoor door) { + super("0000000E-0000-1000-8000-0026BB765291", false, true, "Current Door State", 4); + this.door = door; + } - @Override - protected CompletableFuture getValue() { - return door.getCurrentDoorState().thenApply(s -> s.getCode()); - } + @Override + protected void setValue(Integer value) throws Exception { + // Read Only + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - door.subscribeCurrentDoorState(callback); - } + @Override + protected CompletableFuture getValue() { + return door.getCurrentDoorState().thenApply(s -> s.getCode()); + } - @Override - public void unsubscribe() { - door.unsubscribeCurrentDoorState(); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + door.subscribeCurrentDoorState(callback); + } + @Override + public void unsubscribe() { + door.unsubscribeCurrentDoorState(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/humiditysensor/CurrentRelativeHumidityCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/humiditysensor/CurrentRelativeHumidityCharacteristic.java index 3c181da96..6a5380d8f 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/humiditysensor/CurrentRelativeHumidityCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/humiditysensor/CurrentRelativeHumidityCharacteristic.java @@ -1,39 +1,46 @@ package com.beowulfe.hap.impl.characteristics.humiditysensor; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.HumiditySensor; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.FloatCharacteristic; +import java.util.concurrent.CompletableFuture; + +public class CurrentRelativeHumidityCharacteristic extends FloatCharacteristic + implements EventableCharacteristic { + + private final HumiditySensor sensor; + + public CurrentRelativeHumidityCharacteristic(HumiditySensor sensor) { + super( + "00000010-0000-1000-8000-0026BB765291", + false, + true, + "Current relative humidity", + 0, + 100, + 0.1, + "%"); + this.sensor = sensor; + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + sensor.subscribeCurrentRelativeHumidity(callback); + } + + @Override + public void unsubscribe() { + sensor.unsubscribeCurrentRelativeHumidity(); + } + + @Override + protected void setValue(Double value) throws Exception { + // Read Only + } -public class CurrentRelativeHumidityCharacteristic extends FloatCharacteristic implements EventableCharacteristic { - - private final HumiditySensor sensor; - - public CurrentRelativeHumidityCharacteristic(HumiditySensor sensor) { - super("00000010-0000-1000-8000-0026BB765291", false, true, "Current relative humidity", 0, 100, - 0.1, "%"); - this.sensor = sensor; - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - sensor.subscribeCurrentRelativeHumidity(callback); - } - - @Override - public void unsubscribe() { - sensor.unsubscribeCurrentRelativeHumidity(); - } - - @Override - protected void setValue(Double value) throws Exception { - //Read Only - } - - @Override - protected CompletableFuture getDoubleValue() { - return sensor.getCurrentRelativeHumidity(); - } + @Override + protected CompletableFuture getDoubleValue() { + return sensor.getCurrentRelativeHumidity(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/information/Identify.java b/src/main/java/com/beowulfe/hap/impl/characteristics/information/Identify.java index 670f78907..16127e86c 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/information/Identify.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/information/Identify.java @@ -5,19 +5,19 @@ public class Identify extends WriteOnlyBooleanCharacteristic { - private HomekitAccessory accessory; - - public Identify(HomekitAccessory accessory) throws Exception { - super("00000014-0000-1000-8000-0026BB765291", - "Identifies the accessory via a physical action on the accessory"); - this.accessory = accessory; - } + private HomekitAccessory accessory; - @Override - public void setValue(Boolean value) throws Exception { - if (value) { - accessory.identify(); - } - } + public Identify(HomekitAccessory accessory) throws Exception { + super( + "00000014-0000-1000-8000-0026BB765291", + "Identifies the accessory via a physical action on the accessory"); + this.accessory = accessory; + } + @Override + public void setValue(Boolean value) throws Exception { + if (value) { + accessory.identify(); + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/information/Manufacturer.java b/src/main/java/com/beowulfe/hap/impl/characteristics/information/Manufacturer.java index 15b050cd0..6e4a207f9 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/information/Manufacturer.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/information/Manufacturer.java @@ -5,10 +5,10 @@ public class Manufacturer extends StaticStringCharacteristic { - public Manufacturer(HomekitAccessory accessory) throws Exception { - super("00000020-0000-1000-8000-0026BB765291", - "The name of the manufacturer", - accessory.getManufacturer()); - } - + public Manufacturer(HomekitAccessory accessory) throws Exception { + super( + "00000020-0000-1000-8000-0026BB765291", + "The name of the manufacturer", + accessory.getManufacturer()); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/information/Model.java b/src/main/java/com/beowulfe/hap/impl/characteristics/information/Model.java index f720809f7..4c0325f69 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/information/Model.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/information/Model.java @@ -5,10 +5,7 @@ public class Model extends StaticStringCharacteristic { - public Model(HomekitAccessory accessory) throws Exception { - super("00000021-0000-1000-8000-0026BB765291", - "The name of the model", - accessory.getModel()); - } - + public Model(HomekitAccessory accessory) throws Exception { + super("00000021-0000-1000-8000-0026BB765291", "The name of the model", accessory.getModel()); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/information/SerialNumber.java b/src/main/java/com/beowulfe/hap/impl/characteristics/information/SerialNumber.java index f5dcf71b5..ae65afffe 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/information/SerialNumber.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/information/SerialNumber.java @@ -5,10 +5,10 @@ public class SerialNumber extends StaticStringCharacteristic { - public SerialNumber(HomekitAccessory accessory) throws Exception { - super("00000030-0000-1000-8000-0026BB765291", - "The serial number of the accessory", - accessory.getSerialNumber()); - } - + public SerialNumber(HomekitAccessory accessory) throws Exception { + super( + "00000030-0000-1000-8000-0026BB765291", + "The serial number of the accessory", + accessory.getSerialNumber()); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/leaksensor/LeakDetectedStateCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/leaksensor/LeakDetectedStateCharacteristic.java index 371d0b52a..47817821d 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/leaksensor/LeakDetectedStateCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/leaksensor/LeakDetectedStateCharacteristic.java @@ -1,38 +1,38 @@ package com.beowulfe.hap.impl.characteristics.leaksensor; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.LeakSensor; import com.beowulfe.hap.characteristics.BooleanCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; -public class LeakDetectedStateCharacteristic extends BooleanCharacteristic implements EventableCharacteristic { +public class LeakDetectedStateCharacteristic extends BooleanCharacteristic + implements EventableCharacteristic { - private final LeakSensor leakSensor; + private final LeakSensor leakSensor; - public LeakDetectedStateCharacteristic(LeakSensor leakSensor) { - super("00000070-0000-1000-8000-0026BB765291", false, true, "Leak Detected"); - this.leakSensor = leakSensor; - } + public LeakDetectedStateCharacteristic(LeakSensor leakSensor) { + super("00000070-0000-1000-8000-0026BB765291", false, true, "Leak Detected"); + this.leakSensor = leakSensor; + } - @Override - protected CompletableFuture getValue() { - return leakSensor.getLeakDetected(); - } + @Override + protected CompletableFuture getValue() { + return leakSensor.getLeakDetected(); + } - @Override - protected void setValue(Boolean value) throws Exception { - // Read Only - } + @Override + protected void setValue(Boolean value) throws Exception { + // Read Only + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - leakSensor.subscribeLeakDetected(callback); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + leakSensor.subscribeLeakDetected(callback); + } - @Override - public void unsubscribe() { - leakSensor.unsubscribeLeakDetected(); - } + @Override + public void unsubscribe() { + leakSensor.unsubscribeLeakDetected(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/light/AmbientLightLevelCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/light/AmbientLightLevelCharacteristic.java index 32797ca83..b9838b714 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/light/AmbientLightLevelCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/light/AmbientLightLevelCharacteristic.java @@ -4,36 +4,43 @@ import com.beowulfe.hap.accessories.LightSensor; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.FloatCharacteristic; - import java.util.concurrent.CompletableFuture; -public class AmbientLightLevelCharacteristic extends FloatCharacteristic implements EventableCharacteristic { - - private final LightSensor lightSensor; - - public AmbientLightLevelCharacteristic(LightSensor lightSensor) { - super("0000006B-0000-1000-8000-0026BB765291", false, true, "Current ambient light level", 0.0001, 100000, - 0.0001, "lux"); - this.lightSensor = lightSensor; - } - - @Override - protected void setValue(Double value) throws Exception { - //Read Only - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - lightSensor.subscribeCurrentAmbientLightLevel(callback); - } - - @Override - public void unsubscribe() { - lightSensor.unsubscribeCurrentAmbientLightLevel(); - } - - @Override - protected CompletableFuture getDoubleValue() { - return lightSensor.getCurrentAmbientLightLevel(); - } +public class AmbientLightLevelCharacteristic extends FloatCharacteristic + implements EventableCharacteristic { + + private final LightSensor lightSensor; + + public AmbientLightLevelCharacteristic(LightSensor lightSensor) { + super( + "0000006B-0000-1000-8000-0026BB765291", + false, + true, + "Current ambient light level", + 0.0001, + 100000, + 0.0001, + "lux"); + this.lightSensor = lightSensor; + } + + @Override + protected void setValue(Double value) throws Exception { + // Read Only + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + lightSensor.subscribeCurrentAmbientLightLevel(callback); + } + + @Override + public void unsubscribe() { + lightSensor.unsubscribeCurrentAmbientLightLevel(); + } + + @Override + protected CompletableFuture getDoubleValue() { + return lightSensor.getCurrentAmbientLightLevel(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/lightbulb/BrightnessCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/lightbulb/BrightnessCharacteristic.java index 27da3fa57..3cd303332 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/lightbulb/BrightnessCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/lightbulb/BrightnessCharacteristic.java @@ -1,40 +1,45 @@ package com.beowulfe.hap.impl.characteristics.lightbulb; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.DimmableLightbulb; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.IntegerCharacteristic; +import java.util.concurrent.CompletableFuture; -public class BrightnessCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { - - private final DimmableLightbulb lightbulb; - - public BrightnessCharacteristic(DimmableLightbulb lightbulb) { - super("00000008-0000-1000-8000-0026BB765291", true, true, "Adjust brightness of the light", 0, - 100, "%"); - this.lightbulb = lightbulb; - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - lightbulb.subscribeBrightness(callback); - } - - @Override - public void unsubscribe() { - lightbulb.unsubscribeBrightness(); - } - - @Override - protected void setValue(Integer value) throws Exception { - lightbulb.setBrightness(value); - } - - @Override - protected CompletableFuture getValue() { - return lightbulb.getBrightness(); - } - +public class BrightnessCharacteristic extends IntegerCharacteristic + implements EventableCharacteristic { + + private final DimmableLightbulb lightbulb; + + public BrightnessCharacteristic(DimmableLightbulb lightbulb) { + super( + "00000008-0000-1000-8000-0026BB765291", + true, + true, + "Adjust brightness of the light", + 0, + 100, + "%"); + this.lightbulb = lightbulb; + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + lightbulb.subscribeBrightness(callback); + } + + @Override + public void unsubscribe() { + lightbulb.unsubscribeBrightness(); + } + + @Override + protected void setValue(Integer value) throws Exception { + lightbulb.setBrightness(value); + } + + @Override + protected CompletableFuture getValue() { + return lightbulb.getBrightness(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/lightbulb/HueCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/lightbulb/HueCharacteristic.java index a17b41f14..561a74b39 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/lightbulb/HueCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/lightbulb/HueCharacteristic.java @@ -1,41 +1,45 @@ package com.beowulfe.hap.impl.characteristics.lightbulb; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.ColorfulLightbulb; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.FloatCharacteristic; +import java.util.concurrent.CompletableFuture; public class HueCharacteristic extends FloatCharacteristic implements EventableCharacteristic { - private final ColorfulLightbulb lightbulb; - - public HueCharacteristic(ColorfulLightbulb lightbulb) { - super("00000013-0000-1000-8000-0026BB765291", true, true, "Adjust hue of the light", 0, 360, 1, "arcdegrees"); - this.lightbulb = lightbulb; - } - - @Override - protected void setValue(Double value) throws Exception { - lightbulb.setHue(value); - } - - @Override - protected CompletableFuture getDoubleValue() { - return lightbulb.getHue(); - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - lightbulb.subscribeHue(callback); - } - - @Override - public void unsubscribe() { - lightbulb.unsubscribeHue(); - } - - - + private final ColorfulLightbulb lightbulb; + + public HueCharacteristic(ColorfulLightbulb lightbulb) { + super( + "00000013-0000-1000-8000-0026BB765291", + true, + true, + "Adjust hue of the light", + 0, + 360, + 1, + "arcdegrees"); + this.lightbulb = lightbulb; + } + + @Override + protected void setValue(Double value) throws Exception { + lightbulb.setHue(value); + } + + @Override + protected CompletableFuture getDoubleValue() { + return lightbulb.getHue(); + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + lightbulb.subscribeHue(callback); + } + + @Override + public void unsubscribe() { + lightbulb.unsubscribeHue(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/lightbulb/SaturationCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/lightbulb/SaturationCharacteristic.java index ae2e4d183..29d39da3b 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/lightbulb/SaturationCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/lightbulb/SaturationCharacteristic.java @@ -1,40 +1,46 @@ package com.beowulfe.hap.impl.characteristics.lightbulb; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.ColorfulLightbulb; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.FloatCharacteristic; +import java.util.concurrent.CompletableFuture; -public class SaturationCharacteristic extends FloatCharacteristic implements EventableCharacteristic { - - private final ColorfulLightbulb lightbulb; - - public SaturationCharacteristic(ColorfulLightbulb lightbulb) { - super("0000002F-0000-1000-8000-0026BB765291", true, true, "Adjust saturation of the light", 0, - 100, 1, "%"); - this.lightbulb = lightbulb; - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - lightbulb.subscribeSaturation(callback); - } - - @Override - public void unsubscribe() { - lightbulb.unsubscribeSaturation(); - } - - @Override - protected void setValue(Double value) throws Exception { - lightbulb.setSaturation(value); - } - - @Override - protected CompletableFuture getDoubleValue() { - return lightbulb.getSaturation(); - } - +public class SaturationCharacteristic extends FloatCharacteristic + implements EventableCharacteristic { + + private final ColorfulLightbulb lightbulb; + + public SaturationCharacteristic(ColorfulLightbulb lightbulb) { + super( + "0000002F-0000-1000-8000-0026BB765291", + true, + true, + "Adjust saturation of the light", + 0, + 100, + 1, + "%"); + this.lightbulb = lightbulb; + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + lightbulb.subscribeSaturation(callback); + } + + @Override + public void unsubscribe() { + lightbulb.unsubscribeSaturation(); + } + + @Override + protected void setValue(Double value) throws Exception { + lightbulb.setSaturation(value); + } + + @Override + protected CompletableFuture getDoubleValue() { + return lightbulb.getSaturation(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/lock/mechanism/CurrentLockMechanismStateCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/lock/mechanism/CurrentLockMechanismStateCharacteristic.java index 6cb0c247d..0fa3922f1 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/lock/mechanism/CurrentLockMechanismStateCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/lock/mechanism/CurrentLockMechanismStateCharacteristic.java @@ -1,39 +1,38 @@ package com.beowulfe.hap.impl.characteristics.lock.mechanism; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.LockMechanism; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; -public class CurrentLockMechanismStateCharacteristic extends EnumCharacteristic implements EventableCharacteristic { +public class CurrentLockMechanismStateCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { - private final LockMechanism lock; - - public CurrentLockMechanismStateCharacteristic(LockMechanism lock) { - super("0000001D-0000-1000-8000-0026BB765291", false, true, "Current lock state", 3); - this.lock = lock; - } + private final LockMechanism lock; - @Override - protected void setValue(Integer value) throws Exception { - //Not writable - } + public CurrentLockMechanismStateCharacteristic(LockMechanism lock) { + super("0000001D-0000-1000-8000-0026BB765291", false, true, "Current lock state", 3); + this.lock = lock; + } - @Override - protected CompletableFuture getValue() { - return lock.getCurrentMechanismState().thenApply(s -> s.getCode()); - } + @Override + protected void setValue(Integer value) throws Exception { + // Not writable + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - lock.subscribeCurrentMechanismState(callback); - } + @Override + protected CompletableFuture getValue() { + return lock.getCurrentMechanismState().thenApply(s -> s.getCode()); + } - @Override - public void unsubscribe() { - lock.unsubscribeCurrentMechanismState(); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + lock.subscribeCurrentMechanismState(callback); + } + @Override + public void unsubscribe() { + lock.unsubscribeCurrentMechanismState(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/lock/mechanism/TargetLockMechanismStateCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/lock/mechanism/TargetLockMechanismStateCharacteristic.java index 65c5bc469..d9e6b147c 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/lock/mechanism/TargetLockMechanismStateCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/lock/mechanism/TargetLockMechanismStateCharacteristic.java @@ -1,40 +1,39 @@ package com.beowulfe.hap.impl.characteristics.lock.mechanism; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.LockableLockMechanism; import com.beowulfe.hap.accessories.properties.LockMechanismState; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; -public class TargetLockMechanismStateCharacteristic extends EnumCharacteristic implements EventableCharacteristic { +public class TargetLockMechanismStateCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { - private final LockableLockMechanism lock; - - public TargetLockMechanismStateCharacteristic(LockableLockMechanism lock) { - super("0000001E-0000-1000-8000-0026BB765291", true, true, "Current lock state", 3); - this.lock = lock; - } + private final LockableLockMechanism lock; - @Override - protected void setValue(Integer value) throws Exception { - lock.setTargetMechanismState(LockMechanismState.fromCode(value)); - } + public TargetLockMechanismStateCharacteristic(LockableLockMechanism lock) { + super("0000001E-0000-1000-8000-0026BB765291", true, true, "Current lock state", 3); + this.lock = lock; + } - @Override - protected CompletableFuture getValue() { - return lock.getTargetMechanismState().thenApply(s -> s.getCode()); - } + @Override + protected void setValue(Integer value) throws Exception { + lock.setTargetMechanismState(LockMechanismState.fromCode(value)); + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - lock.subscribeTargetMechanismState(callback); - } + @Override + protected CompletableFuture getValue() { + return lock.getTargetMechanismState().thenApply(s -> s.getCode()); + } - @Override - public void unsubscribe() { - lock.unsubscribeTargetMechanismState(); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + lock.subscribeTargetMechanismState(callback); + } + @Override + public void unsubscribe() { + lock.unsubscribeTargetMechanismState(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/motionsensor/MotionDetectedStateCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/motionsensor/MotionDetectedStateCharacteristic.java index 3d02299e2..064474ae3 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/motionsensor/MotionDetectedStateCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/motionsensor/MotionDetectedStateCharacteristic.java @@ -4,35 +4,35 @@ import com.beowulfe.hap.accessories.MotionSensor; import com.beowulfe.hap.characteristics.BooleanCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; - import java.util.concurrent.CompletableFuture; -public class MotionDetectedStateCharacteristic extends BooleanCharacteristic implements EventableCharacteristic { +public class MotionDetectedStateCharacteristic extends BooleanCharacteristic + implements EventableCharacteristic { - private final MotionSensor motionSensor; + private final MotionSensor motionSensor; - public MotionDetectedStateCharacteristic(MotionSensor motionSensor) { - super("00000022-0000-1000-8000-0026BB765291", false, true, "Motion Detected"); - this.motionSensor = motionSensor; - } + public MotionDetectedStateCharacteristic(MotionSensor motionSensor) { + super("00000022-0000-1000-8000-0026BB765291", false, true, "Motion Detected"); + this.motionSensor = motionSensor; + } - @Override - protected CompletableFuture getValue() { - return motionSensor.getMotionDetected(); - } + @Override + protected CompletableFuture getValue() { + return motionSensor.getMotionDetected(); + } - @Override - protected void setValue(Boolean value) throws Exception { - //Read Only - } + @Override + protected void setValue(Boolean value) throws Exception { + // Read Only + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - motionSensor.subscribeMotionDetected(callback); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + motionSensor.subscribeMotionDetected(callback); + } - @Override - public void unsubscribe() { - motionSensor.unsubscribeMotionDetected(); - } + @Override + public void unsubscribe() { + motionSensor.unsubscribeMotionDetected(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/outlet/OutletInUseCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/outlet/OutletInUseCharacteristic.java index 110575936..2edf41e0b 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/outlet/OutletInUseCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/outlet/OutletInUseCharacteristic.java @@ -1,41 +1,38 @@ package com.beowulfe.hap.impl.characteristics.outlet; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.Outlet; import com.beowulfe.hap.characteristics.BooleanCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; -public class OutletInUseCharacteristic extends BooleanCharacteristic implements EventableCharacteristic { - - private final Outlet outlet; - - public OutletInUseCharacteristic(Outlet outlet) { - super("00000026-0000-1000-8000-0026BB765291", false, true, "The outlet is in use"); - this.outlet = outlet; - } +public class OutletInUseCharacteristic extends BooleanCharacteristic + implements EventableCharacteristic { - @Override - protected void setValue(Boolean value) throws Exception { - //Read Only - } + private final Outlet outlet; - @Override - protected CompletableFuture getValue() { - return outlet.getOutletInUse(); - } + public OutletInUseCharacteristic(Outlet outlet) { + super("00000026-0000-1000-8000-0026BB765291", false, true, "The outlet is in use"); + this.outlet = outlet; + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - outlet.subscribeOutletInUse(callback); - } + @Override + protected void setValue(Boolean value) throws Exception { + // Read Only + } - @Override - public void unsubscribe() { - outlet.unsubscribeOutletInUse(); - } + @Override + protected CompletableFuture getValue() { + return outlet.getOutletInUse(); + } - + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + outlet.subscribeOutletInUse(callback); + } + @Override + public void unsubscribe() { + outlet.unsubscribeOutletInUse(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/securitysystem/CurrentSecuritySystemStateCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/securitysystem/CurrentSecuritySystemStateCharacteristic.java index 327a45a49..f97de285f 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/securitysystem/CurrentSecuritySystemStateCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/securitysystem/CurrentSecuritySystemStateCharacteristic.java @@ -5,35 +5,37 @@ import com.beowulfe.hap.accessories.properties.CurrentSecuritySystemState; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; - import java.util.concurrent.CompletableFuture; -public class CurrentSecuritySystemStateCharacteristic extends EnumCharacteristic implements EventableCharacteristic { - - private final SecuritySystem securitySystem; - - public CurrentSecuritySystemStateCharacteristic(SecuritySystem securitySystem) { - super("00000066-0000-1000-8000-0026BB765291", false, true, "Current security system state", 4); - this.securitySystem = securitySystem; - } - - @Override - protected CompletableFuture getValue() { - return securitySystem.getCurrentSecuritySystemState().thenApply(CurrentSecuritySystemState::getCode); - } - - @Override - protected void setValue(Integer value) throws Exception { - //Not writable - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - securitySystem.subscribeCurrentSecuritySystemState(callback); - } - - @Override - public void unsubscribe() { - securitySystem.unsubscribeCurrentSecuritySystemState(); - } +public class CurrentSecuritySystemStateCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { + + private final SecuritySystem securitySystem; + + public CurrentSecuritySystemStateCharacteristic(SecuritySystem securitySystem) { + super("00000066-0000-1000-8000-0026BB765291", false, true, "Current security system state", 4); + this.securitySystem = securitySystem; + } + + @Override + protected CompletableFuture getValue() { + return securitySystem + .getCurrentSecuritySystemState() + .thenApply(CurrentSecuritySystemState::getCode); + } + + @Override + protected void setValue(Integer value) throws Exception { + // Not writable + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + securitySystem.subscribeCurrentSecuritySystemState(callback); + } + + @Override + public void unsubscribe() { + securitySystem.unsubscribeCurrentSecuritySystemState(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/securitysystem/SecuritySystemAlarmTypeCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/securitysystem/SecuritySystemAlarmTypeCharacteristic.java index 680089b61..9bbaed53a 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/securitysystem/SecuritySystemAlarmTypeCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/securitysystem/SecuritySystemAlarmTypeCharacteristic.java @@ -5,35 +5,35 @@ import com.beowulfe.hap.accessories.properties.SecuritySystemAlarmType; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; - import java.util.concurrent.CompletableFuture; -public class SecuritySystemAlarmTypeCharacteristic extends EnumCharacteristic implements EventableCharacteristic { +public class SecuritySystemAlarmTypeCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { - private final SecuritySystem securitySystem; + private final SecuritySystem securitySystem; - public SecuritySystemAlarmTypeCharacteristic(SecuritySystem securitySystem) { - super("0000008E-0000-1000-8000-0026BB765291", false, true, "Security system alarm type", 1); - this.securitySystem = securitySystem; - } + public SecuritySystemAlarmTypeCharacteristic(SecuritySystem securitySystem) { + super("0000008E-0000-1000-8000-0026BB765291", false, true, "Security system alarm type", 1); + this.securitySystem = securitySystem; + } - @Override - protected CompletableFuture getValue() { - return securitySystem.getAlarmTypeState().thenApply(SecuritySystemAlarmType::getCode); - } + @Override + protected CompletableFuture getValue() { + return securitySystem.getAlarmTypeState().thenApply(SecuritySystemAlarmType::getCode); + } - @Override - protected void setValue(Integer value) throws Exception { - //Not writable - } + @Override + protected void setValue(Integer value) throws Exception { + // Not writable + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - securitySystem.subscribeAlarmTypeState(callback); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + securitySystem.subscribeAlarmTypeState(callback); + } - @Override - public void unsubscribe() { - securitySystem.unsubscribeAlarmTypeState(); - } + @Override + public void unsubscribe() { + securitySystem.unsubscribeAlarmTypeState(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/securitysystem/TargetSecuritySystemStateCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/securitysystem/TargetSecuritySystemStateCharacteristic.java index 7fc53fa72..c6d5910f2 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/securitysystem/TargetSecuritySystemStateCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/securitysystem/TargetSecuritySystemStateCharacteristic.java @@ -5,35 +5,37 @@ import com.beowulfe.hap.accessories.properties.TargetSecuritySystemState; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; - import java.util.concurrent.CompletableFuture; -public class TargetSecuritySystemStateCharacteristic extends EnumCharacteristic implements EventableCharacteristic { - - private final SecuritySystem securitySystem; - - public TargetSecuritySystemStateCharacteristic(SecuritySystem securitySystem) { - super("00000067-0000-1000-8000-0026BB765291", true, true, "Target security system state", 3); - this.securitySystem = securitySystem; - } - - @Override - protected CompletableFuture getValue() { - return securitySystem.getTargetSecuritySystemState().thenApply(TargetSecuritySystemState::getCode); - } - - @Override - protected void setValue(Integer value) throws Exception { - securitySystem.setTargetSecuritySystemState(TargetSecuritySystemState.fromCode(value)); - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - securitySystem.subscribeTargetSecuritySystemState(callback); - } - - @Override - public void unsubscribe() { - securitySystem.unsubscribeTargetSecuritySystemState(); - } +public class TargetSecuritySystemStateCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { + + private final SecuritySystem securitySystem; + + public TargetSecuritySystemStateCharacteristic(SecuritySystem securitySystem) { + super("00000067-0000-1000-8000-0026BB765291", true, true, "Target security system state", 3); + this.securitySystem = securitySystem; + } + + @Override + protected CompletableFuture getValue() { + return securitySystem + .getTargetSecuritySystemState() + .thenApply(TargetSecuritySystemState::getCode); + } + + @Override + protected void setValue(Integer value) throws Exception { + securitySystem.setTargetSecuritySystemState(TargetSecuritySystemState.fromCode(value)); + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + securitySystem.subscribeTargetSecuritySystemState(callback); + } + + @Override + public void unsubscribe() { + securitySystem.unsubscribeTargetSecuritySystemState(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/smokesensor/SmokeDetectedCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/smokesensor/SmokeDetectedCharacteristic.java index c351697d8..2de1a8c6b 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/smokesensor/SmokeDetectedCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/smokesensor/SmokeDetectedCharacteristic.java @@ -5,35 +5,35 @@ import com.beowulfe.hap.accessories.properties.SmokeDetectedState; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; - import java.util.concurrent.CompletableFuture; -public class SmokeDetectedCharacteristic extends EnumCharacteristic implements EventableCharacteristic { +public class SmokeDetectedCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { - private final SmokeSensor smokeSensor; + private final SmokeSensor smokeSensor; - public SmokeDetectedCharacteristic(SmokeSensor smokeSensor) { - super("00000076-0000-1000-8000-0026BB765291", false, true, "Smoke Detected", 1); - this.smokeSensor = smokeSensor; - } + public SmokeDetectedCharacteristic(SmokeSensor smokeSensor) { + super("00000076-0000-1000-8000-0026BB765291", false, true, "Smoke Detected", 1); + this.smokeSensor = smokeSensor; + } - @Override - protected CompletableFuture getValue() { - return smokeSensor.getSmokeDetectedState().thenApply(SmokeDetectedState::getCode); - } + @Override + protected CompletableFuture getValue() { + return smokeSensor.getSmokeDetectedState().thenApply(SmokeDetectedState::getCode); + } - @Override - protected void setValue(Integer value) throws Exception { - //Read Only - } + @Override + protected void setValue(Integer value) throws Exception { + // Read Only + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - smokeSensor.subscribeSmokeDetectedState(callback); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + smokeSensor.subscribeSmokeDetectedState(callback); + } - @Override - public void unsubscribe() { - smokeSensor.unsubscribeSmokeDetectedState(); - } + @Override + public void unsubscribe() { + smokeSensor.unsubscribeSmokeDetectedState(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/AbstractHeatingCoolingModeCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/AbstractHeatingCoolingModeCharacteristic.java index 1966ac9b4..e0ac363eb 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/AbstractHeatingCoolingModeCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/AbstractHeatingCoolingModeCharacteristic.java @@ -1,30 +1,29 @@ package com.beowulfe.hap.impl.characteristics.thermostat; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.accessories.properties.ThermostatMode; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; + +abstract class AbstractHeatingCoolingModeCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { -abstract class AbstractHeatingCoolingModeCharacteristic extends EnumCharacteristic implements EventableCharacteristic { + public AbstractHeatingCoolingModeCharacteristic( + String type, boolean isWritable, String description) { + super(type, isWritable, true, description, 3); + } - public AbstractHeatingCoolingModeCharacteristic(String type, boolean isWritable, String description) { - super(type, isWritable, true, description, 3); - } + @Override + protected final void setValue(Integer value) throws Exception { + setModeValue(ThermostatMode.fromCode(value)); + } - @Override - protected final void setValue(Integer value) throws Exception { - setModeValue(ThermostatMode.fromCode(value)); - } + @Override + protected final CompletableFuture getValue() { + return getModeValue().thenApply(t -> t.getCode()); + } - @Override - protected final CompletableFuture getValue() { - return getModeValue().thenApply(t -> t.getCode()); - } + protected abstract void setModeValue(ThermostatMode mode) throws Exception; - protected abstract void setModeValue(ThermostatMode mode) throws Exception; - - protected abstract CompletableFuture getModeValue(); - - + protected abstract CompletableFuture getModeValue(); } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/AbstractTemperatureCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/AbstractTemperatureCharacteristic.java index 090680068..28a2edf18 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/AbstractTemperatureCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/AbstractTemperatureCharacteristic.java @@ -4,11 +4,19 @@ import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.FloatCharacteristic; -public abstract class AbstractTemperatureCharacteristic extends FloatCharacteristic implements EventableCharacteristic { - - public AbstractTemperatureCharacteristic(String type, boolean isWritable, String description, TemperatureSensor sensor) { - super(type, isWritable, true, description, sensor.getMinimumTemperature(), sensor.getMaximumTemperature(), - 0.1, "celsius"); - } +public abstract class AbstractTemperatureCharacteristic extends FloatCharacteristic + implements EventableCharacteristic { + public AbstractTemperatureCharacteristic( + String type, boolean isWritable, String description, TemperatureSensor sensor) { + super( + type, + isWritable, + true, + description, + sensor.getMinimumTemperature(), + sensor.getMaximumTemperature(), + 0.1, + "celsius"); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/CoolingThresholdTemperatureCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/CoolingThresholdTemperatureCharacteristic.java index c509d97a4..2c17598d0 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/CoolingThresholdTemperatureCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/CoolingThresholdTemperatureCharacteristic.java @@ -1,38 +1,39 @@ package com.beowulfe.hap.impl.characteristics.thermostat; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.thermostat.CoolingThermostat; +import java.util.concurrent.CompletableFuture; -public class CoolingThresholdTemperatureCharacteristic extends - AbstractTemperatureCharacteristic { - - private final CoolingThermostat thermostat; - - public CoolingThresholdTemperatureCharacteristic(CoolingThermostat thermostat) { - super("0000000D-0000-1000-8000-0026BB765291", true, "Temperature above which cooling will be active", thermostat); - this.thermostat = thermostat; - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - thermostat.subscribeCoolingThresholdTemperature(callback); - } - - @Override - public void unsubscribe() { - thermostat.unsubscribeCoolingThresholdTemperature(); - } - - @Override - protected CompletableFuture getDoubleValue() { - return thermostat.getCoolingThresholdTemperature(); - } - - @Override - protected void setValue(Double value) throws Exception { - thermostat.setCoolingThresholdTemperature(value); - } - +public class CoolingThresholdTemperatureCharacteristic extends AbstractTemperatureCharacteristic { + + private final CoolingThermostat thermostat; + + public CoolingThresholdTemperatureCharacteristic(CoolingThermostat thermostat) { + super( + "0000000D-0000-1000-8000-0026BB765291", + true, + "Temperature above which cooling will be active", + thermostat); + this.thermostat = thermostat; + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + thermostat.subscribeCoolingThresholdTemperature(callback); + } + + @Override + public void unsubscribe() { + thermostat.unsubscribeCoolingThresholdTemperature(); + } + + @Override + protected CompletableFuture getDoubleValue() { + return thermostat.getCoolingThresholdTemperature(); + } + + @Override + protected void setValue(Double value) throws Exception { + thermostat.setCoolingThresholdTemperature(value); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/CurrentHeatingCoolingModeCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/CurrentHeatingCoolingModeCharacteristic.java index a6ba57899..0d5d7aaf3 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/CurrentHeatingCoolingModeCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/CurrentHeatingCoolingModeCharacteristic.java @@ -1,39 +1,37 @@ package com.beowulfe.hap.impl.characteristics.thermostat; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.properties.ThermostatMode; import com.beowulfe.hap.accessories.thermostat.BasicThermostat; +import java.util.concurrent.CompletableFuture; -public class CurrentHeatingCoolingModeCharacteristic extends - AbstractHeatingCoolingModeCharacteristic { - - private final BasicThermostat thermostat; +public class CurrentHeatingCoolingModeCharacteristic + extends AbstractHeatingCoolingModeCharacteristic { - public CurrentHeatingCoolingModeCharacteristic(BasicThermostat thermostat) { - super("0000000F-0000-1000-8000-0026BB765291", false, "Current Mode"); - this.thermostat = thermostat; - } + private final BasicThermostat thermostat; - @Override - protected void setModeValue(ThermostatMode mode) throws Exception { - //Not writable - } + public CurrentHeatingCoolingModeCharacteristic(BasicThermostat thermostat) { + super("0000000F-0000-1000-8000-0026BB765291", false, "Current Mode"); + this.thermostat = thermostat; + } - @Override - protected CompletableFuture getModeValue() { - return thermostat.getCurrentMode(); - } + @Override + protected void setModeValue(ThermostatMode mode) throws Exception { + // Not writable + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - thermostat.subscribeCurrentMode(callback); - } + @Override + protected CompletableFuture getModeValue() { + return thermostat.getCurrentMode(); + } - @Override - public void unsubscribe() { - thermostat.unsubscribeCurrentMode(); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + thermostat.subscribeCurrentMode(callback); + } + @Override + public void unsubscribe() { + thermostat.unsubscribeCurrentMode(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/CurrentTemperatureCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/CurrentTemperatureCharacteristic.java index cf065cf6c..af8b3ca62 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/CurrentTemperatureCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/CurrentTemperatureCharacteristic.java @@ -1,38 +1,35 @@ package com.beowulfe.hap.impl.characteristics.thermostat; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.TemperatureSensor; +import java.util.concurrent.CompletableFuture; -public class CurrentTemperatureCharacteristic extends - AbstractTemperatureCharacteristic { +public class CurrentTemperatureCharacteristic extends AbstractTemperatureCharacteristic { - private final TemperatureSensor sensor; - - public CurrentTemperatureCharacteristic(TemperatureSensor thermostat) { - super("00000011-0000-1000-8000-0026BB765291", false, "Current Temperature", thermostat); - this.sensor = thermostat; - } + private final TemperatureSensor sensor; - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - sensor.subscribeCurrentTemperature(callback); - } + public CurrentTemperatureCharacteristic(TemperatureSensor thermostat) { + super("00000011-0000-1000-8000-0026BB765291", false, "Current Temperature", thermostat); + this.sensor = thermostat; + } - @Override - public void unsubscribe() { - sensor.unsubscribeCurrentTemperature(); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + sensor.subscribeCurrentTemperature(callback); + } - @Override - protected CompletableFuture getDoubleValue() { - return sensor.getCurrentTemperature(); - } + @Override + public void unsubscribe() { + sensor.unsubscribeCurrentTemperature(); + } - @Override - protected void setValue(Double value) throws Exception { - //Not writable - } + @Override + protected CompletableFuture getDoubleValue() { + return sensor.getCurrentTemperature(); + } + @Override + protected void setValue(Double value) throws Exception { + // Not writable + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/HeatingThresholdTemperatureCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/HeatingThresholdTemperatureCharacteristic.java index 756a749fa..aa0427c52 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/HeatingThresholdTemperatureCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/HeatingThresholdTemperatureCharacteristic.java @@ -1,38 +1,39 @@ package com.beowulfe.hap.impl.characteristics.thermostat; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.thermostat.HeatingThermostat; +import java.util.concurrent.CompletableFuture; -public class HeatingThresholdTemperatureCharacteristic extends - AbstractTemperatureCharacteristic { - - private final HeatingThermostat thermostat; - - public HeatingThresholdTemperatureCharacteristic(HeatingThermostat thermostat) { - super("00000012-0000-1000-8000-0026BB765291", true, "Temperature below which heating will be active", thermostat); - this.thermostat = thermostat; - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - thermostat.subscribeHeatingThresholdTemperature(callback); - } - - @Override - public void unsubscribe() { - thermostat.unsubscribeHeatingThresholdTemperature(); - } - - @Override - protected CompletableFuture getDoubleValue() { - return thermostat.getHeatingThresholdTemperature(); - } - - @Override - protected void setValue(Double value) throws Exception { - thermostat.setHeatingThresholdTemperature(value); - } - +public class HeatingThresholdTemperatureCharacteristic extends AbstractTemperatureCharacteristic { + + private final HeatingThermostat thermostat; + + public HeatingThresholdTemperatureCharacteristic(HeatingThermostat thermostat) { + super( + "00000012-0000-1000-8000-0026BB765291", + true, + "Temperature below which heating will be active", + thermostat); + this.thermostat = thermostat; + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + thermostat.subscribeHeatingThresholdTemperature(callback); + } + + @Override + public void unsubscribe() { + thermostat.unsubscribeHeatingThresholdTemperature(); + } + + @Override + protected CompletableFuture getDoubleValue() { + return thermostat.getHeatingThresholdTemperature(); + } + + @Override + protected void setValue(Double value) throws Exception { + thermostat.setHeatingThresholdTemperature(value); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/TargetHeatingCoolingModeCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/TargetHeatingCoolingModeCharacteristic.java index f12725dea..de126ccb2 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/TargetHeatingCoolingModeCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/TargetHeatingCoolingModeCharacteristic.java @@ -1,39 +1,37 @@ package com.beowulfe.hap.impl.characteristics.thermostat; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.properties.ThermostatMode; import com.beowulfe.hap.accessories.thermostat.BasicThermostat; +import java.util.concurrent.CompletableFuture; -public class TargetHeatingCoolingModeCharacteristic extends - AbstractHeatingCoolingModeCharacteristic { +public class TargetHeatingCoolingModeCharacteristic + extends AbstractHeatingCoolingModeCharacteristic { - private final BasicThermostat thermostat; - - public TargetHeatingCoolingModeCharacteristic(BasicThermostat thermostat) { - super("00000033-0000-1000-8000-0026BB765291", true, "Target Mode"); - this.thermostat = thermostat; - } + private final BasicThermostat thermostat; - @Override - protected void setModeValue(ThermostatMode mode) throws Exception { - thermostat.setTargetMode(mode); - } + public TargetHeatingCoolingModeCharacteristic(BasicThermostat thermostat) { + super("00000033-0000-1000-8000-0026BB765291", true, "Target Mode"); + this.thermostat = thermostat; + } - @Override - protected CompletableFuture getModeValue() { - return thermostat.getTargetMode(); - } + @Override + protected void setModeValue(ThermostatMode mode) throws Exception { + thermostat.setTargetMode(mode); + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - thermostat.subscribeTargetMode(callback); - } + @Override + protected CompletableFuture getModeValue() { + return thermostat.getTargetMode(); + } - @Override - public void unsubscribe() { - thermostat.unsubscribeTargetMode(); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + thermostat.subscribeTargetMode(callback); + } + @Override + public void unsubscribe() { + thermostat.unsubscribeTargetMode(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/TargetTemperatureCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/TargetTemperatureCharacteristic.java index a1140a92f..278ea7ea0 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/TargetTemperatureCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/TargetTemperatureCharacteristic.java @@ -1,38 +1,35 @@ package com.beowulfe.hap.impl.characteristics.thermostat; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.thermostat.BasicThermostat; +import java.util.concurrent.CompletableFuture; -public class TargetTemperatureCharacteristic extends - AbstractTemperatureCharacteristic { - - private final BasicThermostat thermostat; +public class TargetTemperatureCharacteristic extends AbstractTemperatureCharacteristic { - public TargetTemperatureCharacteristic(BasicThermostat thermostat) { - super("00000035-0000-1000-8000-0026BB765291", true, "Target Temperature", thermostat); - this.thermostat = thermostat; - } + private final BasicThermostat thermostat; - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - thermostat.subscribeTargetTemperature(callback); - } + public TargetTemperatureCharacteristic(BasicThermostat thermostat) { + super("00000035-0000-1000-8000-0026BB765291", true, "Target Temperature", thermostat); + this.thermostat = thermostat; + } - @Override - public void unsubscribe() { - thermostat.unsubscribeTargetTemperature(); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + thermostat.subscribeTargetTemperature(callback); + } - @Override - protected CompletableFuture getDoubleValue() { - return thermostat.getTargetTemperature(); - } + @Override + public void unsubscribe() { + thermostat.unsubscribeTargetTemperature(); + } - @Override - protected void setValue(Double value) throws Exception { - thermostat.setTargetTemperature(value); - } + @Override + protected CompletableFuture getDoubleValue() { + return thermostat.getTargetTemperature(); + } + @Override + protected void setValue(Double value) throws Exception { + thermostat.setTargetTemperature(value); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/TemperatureUnitsCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/TemperatureUnitsCharacteristic.java index 87dd0a2bc..2a884a966 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/TemperatureUnitsCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/thermostat/TemperatureUnitsCharacteristic.java @@ -1,27 +1,25 @@ package com.beowulfe.hap.impl.characteristics.thermostat; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.accessories.thermostat.BasicThermostat; import com.beowulfe.hap.characteristics.EnumCharacteristic; +import java.util.concurrent.CompletableFuture; public class TemperatureUnitsCharacteristic extends EnumCharacteristic { - private final BasicThermostat thermostat; - - public TemperatureUnitsCharacteristic(BasicThermostat thermostat) { - super("00000036-0000-1000-8000-0026BB765291", false, true, "The temperature unit", 1); - this.thermostat = thermostat; - } + private final BasicThermostat thermostat; - @Override - protected void setValue(Integer value) throws Exception { - //Not writable - } + public TemperatureUnitsCharacteristic(BasicThermostat thermostat) { + super("00000036-0000-1000-8000-0026BB765291", false, true, "The temperature unit", 1); + this.thermostat = thermostat; + } - @Override - protected CompletableFuture getValue() { - return CompletableFuture.completedFuture(thermostat.getTemperatureUnit().getCode()); - } + @Override + protected void setValue(Integer value) throws Exception { + // Not writable + } + @Override + protected CompletableFuture getValue() { + return CompletableFuture.completedFuture(thermostat.getTemperatureUnit().getCode()); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/valve/SetDurationCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/valve/SetDurationCharacteristic.java index da77109de..320420ae7 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/valve/SetDurationCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/valve/SetDurationCharacteristic.java @@ -1,38 +1,37 @@ package com.beowulfe.hap.impl.characteristics.valve; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.ValveWithTimer; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.IntegerCharacteristic; +import java.util.concurrent.CompletableFuture; -public class SetDurationCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { - private final ValveWithTimer valve; - - public SetDurationCharacteristic(ValveWithTimer valve) { - super("000000D3-0000-1000-8000-0026BB765291", true, true, "Set Duration", 0, 3600, "seconds"); - this.valve = valve; - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - valve.subscribeSetDuration(callback); - } - - @Override - public void unsubscribe() { - valve.unsubscribeSetDuration(); - } - - @Override - protected void setValue(Integer value) throws Exception { - valve.setSetDuration(value); - } - - @Override - protected CompletableFuture getValue() { - return valve.getSetDuration(); - } - +public class SetDurationCharacteristic extends IntegerCharacteristic + implements EventableCharacteristic { + private final ValveWithTimer valve; + + public SetDurationCharacteristic(ValveWithTimer valve) { + super("000000D3-0000-1000-8000-0026BB765291", true, true, "Set Duration", 0, 3600, "seconds"); + this.valve = valve; + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + valve.subscribeSetDuration(callback); + } + + @Override + public void unsubscribe() { + valve.unsubscribeSetDuration(); + } + + @Override + protected void setValue(Integer value) throws Exception { + valve.setSetDuration(value); + } + + @Override + protected CompletableFuture getValue() { + return valve.getSetDuration(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/valve/ValveTypeCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/valve/ValveTypeCharacteristic.java index e0ef14e62..23fcc9b25 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/valve/ValveTypeCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/valve/ValveTypeCharacteristic.java @@ -1,38 +1,37 @@ package com.beowulfe.hap.impl.characteristics.valve; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.Valve; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; public class ValveTypeCharacteristic extends EnumCharacteristic implements EventableCharacteristic { - private final Valve valve; + private final Valve valve; - public ValveTypeCharacteristic(Valve valve) { - super("000000D5-0000-1000-8000-0026BB765291", false, true, "Valve Type", 3); - this.valve = valve; - } + public ValveTypeCharacteristic(Valve valve) { + super("000000D5-0000-1000-8000-0026BB765291", false, true, "Valve Type", 3); + this.valve = valve; + } - @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 valve.getValveType().thenApply(v -> v.getCode()); - } + @Override + protected CompletableFuture getValue() { + return valve.getValveType().thenApply(v -> v.getCode()); + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - valve.subscribeValveType(callback); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + valve.subscribeValveType(callback); + } - @Override - public void unsubscribe() { - valve.unsubscribeValveType(); - } + @Override + public void unsubscribe() { + valve.unsubscribeValveType(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/CurrentHorizontalTiltAngleCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/CurrentHorizontalTiltAngleCharacteristic.java index ba269096c..0e43f61f2 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/CurrentHorizontalTiltAngleCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/CurrentHorizontalTiltAngleCharacteristic.java @@ -1,39 +1,45 @@ package com.beowulfe.hap.impl.characteristics.windowcovering; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.HorizontalTiltingWindowCovering; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.IntegerCharacteristic; +import java.util.concurrent.CompletableFuture; -public class CurrentHorizontalTiltAngleCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { - - private final HorizontalTiltingWindowCovering windowCovering; - - public CurrentHorizontalTiltAngleCharacteristic(HorizontalTiltingWindowCovering windowCovering) { - super("0000006C-0000-1000-8000-0026BB765291", false, true, "The current horizontal tilt angle", -90, 90, "Arc Degree"); - this.windowCovering = windowCovering; - } - - @Override - protected void setValue(Integer value) throws Exception { - //Read Only - } - - @Override - protected CompletableFuture getValue() { - return windowCovering.getCurrentHorizontalTiltAngle(); - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - windowCovering.subscribeCurrentHorizontalTiltAngle(callback); - } - - @Override - public void unsubscribe() { - windowCovering.unsubscribeCurrentHorizontalTiltAngle(); - } - +public class CurrentHorizontalTiltAngleCharacteristic extends IntegerCharacteristic + implements EventableCharacteristic { + + private final HorizontalTiltingWindowCovering windowCovering; + + public CurrentHorizontalTiltAngleCharacteristic(HorizontalTiltingWindowCovering windowCovering) { + super( + "0000006C-0000-1000-8000-0026BB765291", + false, + true, + "The current horizontal tilt angle", + -90, + 90, + "Arc Degree"); + this.windowCovering = windowCovering; + } + + @Override + protected void setValue(Integer value) throws Exception { + // Read Only + } + + @Override + protected CompletableFuture getValue() { + return windowCovering.getCurrentHorizontalTiltAngle(); + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + windowCovering.subscribeCurrentHorizontalTiltAngle(callback); + } + + @Override + public void unsubscribe() { + windowCovering.unsubscribeCurrentHorizontalTiltAngle(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/CurrentPositionCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/CurrentPositionCharacteristic.java index c05d0ead1..0ce752232 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/CurrentPositionCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/CurrentPositionCharacteristic.java @@ -1,39 +1,38 @@ package com.beowulfe.hap.impl.characteristics.windowcovering; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.WindowCovering; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.IntegerCharacteristic; +import java.util.concurrent.CompletableFuture; -public class CurrentPositionCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { +public class CurrentPositionCharacteristic extends IntegerCharacteristic + implements EventableCharacteristic { - private final WindowCovering windowCovering; - - public CurrentPositionCharacteristic(WindowCovering windowCovering) { - super("0000006D-0000-1000-8000-0026BB765291", false, true, "The current position", 0, 100, "%"); - this.windowCovering = windowCovering; - } + private final WindowCovering windowCovering; - @Override - protected void setValue(Integer value) throws Exception { - //Read Only - } + public CurrentPositionCharacteristic(WindowCovering windowCovering) { + super("0000006D-0000-1000-8000-0026BB765291", false, true, "The current position", 0, 100, "%"); + this.windowCovering = windowCovering; + } - @Override - protected CompletableFuture getValue() { - return windowCovering.getCurrentPosition(); - } + @Override + protected void setValue(Integer value) throws Exception { + // Read Only + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - windowCovering.subscribeCurrentPosition(callback); - } + @Override + protected CompletableFuture getValue() { + return windowCovering.getCurrentPosition(); + } - @Override - public void unsubscribe() { - windowCovering.unsubscribeCurrentPosition(); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + windowCovering.subscribeCurrentPosition(callback); + } + @Override + public void unsubscribe() { + windowCovering.unsubscribeCurrentPosition(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/CurrentVerticalTiltAngleCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/CurrentVerticalTiltAngleCharacteristic.java index c86a5dca1..19b3d8bd8 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/CurrentVerticalTiltAngleCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/CurrentVerticalTiltAngleCharacteristic.java @@ -1,39 +1,45 @@ package com.beowulfe.hap.impl.characteristics.windowcovering; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.VerticalTiltingWindowCovering; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.IntegerCharacteristic; +import java.util.concurrent.CompletableFuture; -public class CurrentVerticalTiltAngleCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { - - private final VerticalTiltingWindowCovering windowCovering; - - public CurrentVerticalTiltAngleCharacteristic(VerticalTiltingWindowCovering windowCovering) { - super("0000006E-0000-1000-8000-0026BB765291", false, true, "The current vertical tilt angle", -90, 90, "Arc Degree"); - this.windowCovering = windowCovering; - } - - @Override - protected void setValue(Integer value) throws Exception { - //Read Only - } - - @Override - protected CompletableFuture getValue() { - return windowCovering.getCurrentVerticalTiltAngle(); - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - windowCovering.subscribeCurrentVerticalTiltAngle(callback); - } - - @Override - public void unsubscribe() { - windowCovering.unsubscribeCurrentVerticalTiltAngle(); - } - +public class CurrentVerticalTiltAngleCharacteristic extends IntegerCharacteristic + implements EventableCharacteristic { + + private final VerticalTiltingWindowCovering windowCovering; + + public CurrentVerticalTiltAngleCharacteristic(VerticalTiltingWindowCovering windowCovering) { + super( + "0000006E-0000-1000-8000-0026BB765291", + false, + true, + "The current vertical tilt angle", + -90, + 90, + "Arc Degree"); + this.windowCovering = windowCovering; + } + + @Override + protected void setValue(Integer value) throws Exception { + // Read Only + } + + @Override + protected CompletableFuture getValue() { + return windowCovering.getCurrentVerticalTiltAngle(); + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + windowCovering.subscribeCurrentVerticalTiltAngle(callback); + } + + @Override + public void unsubscribe() { + windowCovering.unsubscribeCurrentVerticalTiltAngle(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/HoldPositionCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/HoldPositionCharacteristic.java index 3895befc7..3dccf5252 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/HoldPositionCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/HoldPositionCharacteristic.java @@ -1,28 +1,26 @@ package com.beowulfe.hap.impl.characteristics.windowcovering; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.accessories.WindowCovering; import com.beowulfe.hap.characteristics.BooleanCharacteristic; +import java.util.concurrent.CompletableFuture; public class HoldPositionCharacteristic extends BooleanCharacteristic { - private final WindowCovering windowCovering; - - public HoldPositionCharacteristic(WindowCovering windowCovering) { - super("0000006F-0000-1000-8000-0026BB765291", true, false, "Whether or not to hold position"); - this.windowCovering = windowCovering; - } + private final WindowCovering windowCovering; - @Override - protected void setValue(Boolean value) throws Exception { - this.windowCovering.setHoldPosition(value); - } + public HoldPositionCharacteristic(WindowCovering windowCovering) { + super("0000006F-0000-1000-8000-0026BB765291", true, false, "Whether or not to hold position"); + this.windowCovering = windowCovering; + } - @Override - protected CompletableFuture getValue() { - //Write only - return CompletableFuture.completedFuture(null); - } + @Override + protected void setValue(Boolean value) throws Exception { + this.windowCovering.setHoldPosition(value); + } + @Override + protected CompletableFuture getValue() { + // Write only + return CompletableFuture.completedFuture(null); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/PositionStateCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/PositionStateCharacteristic.java index cbde47717..ccf159a1e 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/PositionStateCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/PositionStateCharacteristic.java @@ -1,39 +1,38 @@ package com.beowulfe.hap.impl.characteristics.windowcovering; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.WindowCovering; import com.beowulfe.hap.characteristics.EnumCharacteristic; import com.beowulfe.hap.characteristics.EventableCharacteristic; +import java.util.concurrent.CompletableFuture; -public class PositionStateCharacteristic extends EnumCharacteristic implements EventableCharacteristic { +public class PositionStateCharacteristic extends EnumCharacteristic + implements EventableCharacteristic { - private final WindowCovering windowCovering; - - public PositionStateCharacteristic(WindowCovering windowCovering) { - super("00000072-0000-1000-8000-0026BB765291", false, true, "The position state", 2); - this.windowCovering = windowCovering; - } + private final WindowCovering windowCovering; - @Override - protected void setValue(Integer value) throws Exception { - //Read only - } + public PositionStateCharacteristic(WindowCovering windowCovering) { + super("00000072-0000-1000-8000-0026BB765291", false, true, "The position state", 2); + this.windowCovering = windowCovering; + } - @Override - protected CompletableFuture getValue() { - return windowCovering.getPositionState().thenApply(v -> v.getCode()); - } + @Override + protected void setValue(Integer value) throws Exception { + // Read only + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - windowCovering.subscribePositionState(callback); - } + @Override + protected CompletableFuture getValue() { + return windowCovering.getPositionState().thenApply(v -> v.getCode()); + } - @Override - public void unsubscribe() { - windowCovering.unsubscribePositionState(); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + windowCovering.subscribePositionState(callback); + } + @Override + public void unsubscribe() { + windowCovering.unsubscribePositionState(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/TargetHorizontalTiltAngleCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/TargetHorizontalTiltAngleCharacteristic.java index a9bf57fbd..95411d6f2 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/TargetHorizontalTiltAngleCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/TargetHorizontalTiltAngleCharacteristic.java @@ -1,39 +1,45 @@ package com.beowulfe.hap.impl.characteristics.windowcovering; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.HorizontalTiltingWindowCovering; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.IntegerCharacteristic; +import java.util.concurrent.CompletableFuture; -public class TargetHorizontalTiltAngleCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { - - private final HorizontalTiltingWindowCovering windowCovering; - - public TargetHorizontalTiltAngleCharacteristic(HorizontalTiltingWindowCovering windowCovering) { - super("0000007B-0000-1000-8000-0026BB765291", true, true, "The target horizontal tilt angle", -90, 90, "Arc Degree"); - this.windowCovering = windowCovering; - } - - @Override - protected void setValue(Integer value) throws Exception { - windowCovering.setTargetHorizontalTiltAngle(value); - } - - @Override - protected CompletableFuture getValue() { - return windowCovering.getTargetHorizontalTiltAngle(); - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - windowCovering.subscribeTargetHorizontalTiltAngle(callback); - } - - @Override - public void unsubscribe() { - windowCovering.unsubscribeTargetHorizontalTiltAngle(); - } - +public class TargetHorizontalTiltAngleCharacteristic extends IntegerCharacteristic + implements EventableCharacteristic { + + private final HorizontalTiltingWindowCovering windowCovering; + + public TargetHorizontalTiltAngleCharacteristic(HorizontalTiltingWindowCovering windowCovering) { + super( + "0000007B-0000-1000-8000-0026BB765291", + true, + true, + "The target horizontal tilt angle", + -90, + 90, + "Arc Degree"); + this.windowCovering = windowCovering; + } + + @Override + protected void setValue(Integer value) throws Exception { + windowCovering.setTargetHorizontalTiltAngle(value); + } + + @Override + protected CompletableFuture getValue() { + return windowCovering.getTargetHorizontalTiltAngle(); + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + windowCovering.subscribeTargetHorizontalTiltAngle(callback); + } + + @Override + public void unsubscribe() { + windowCovering.unsubscribeTargetHorizontalTiltAngle(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/TargetPositionCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/TargetPositionCharacteristic.java index 19756be78..ceaf76e29 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/TargetPositionCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/TargetPositionCharacteristic.java @@ -1,39 +1,38 @@ package com.beowulfe.hap.impl.characteristics.windowcovering; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.WindowCovering; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.IntegerCharacteristic; +import java.util.concurrent.CompletableFuture; -public class TargetPositionCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { +public class TargetPositionCharacteristic extends IntegerCharacteristic + implements EventableCharacteristic { - private final WindowCovering windowCovering; - - public TargetPositionCharacteristic(WindowCovering windowCovering) { - super("0000007C-0000-1000-8000-0026BB765291", true, true, "The target position", 0, 100, "%"); - this.windowCovering = windowCovering; - } + private final WindowCovering windowCovering; - @Override - protected void setValue(Integer value) throws Exception { - windowCovering.setTargetPosition(value); - } + public TargetPositionCharacteristic(WindowCovering windowCovering) { + super("0000007C-0000-1000-8000-0026BB765291", true, true, "The target position", 0, 100, "%"); + this.windowCovering = windowCovering; + } - @Override - protected CompletableFuture getValue() { - return windowCovering.getTargetPosition(); - } + @Override + protected void setValue(Integer value) throws Exception { + windowCovering.setTargetPosition(value); + } - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - windowCovering.subscribeTargetPosition(callback); - } + @Override + protected CompletableFuture getValue() { + return windowCovering.getTargetPosition(); + } - @Override - public void unsubscribe() { - windowCovering.unsubscribeTargetPosition(); - } + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + windowCovering.subscribeTargetPosition(callback); + } + @Override + public void unsubscribe() { + windowCovering.unsubscribeTargetPosition(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/TargetVerticalTiltAngleCharacteristic.java b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/TargetVerticalTiltAngleCharacteristic.java index 8a3f30cae..fd0b5ccfe 100644 --- a/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/TargetVerticalTiltAngleCharacteristic.java +++ b/src/main/java/com/beowulfe/hap/impl/characteristics/windowcovering/TargetVerticalTiltAngleCharacteristic.java @@ -1,39 +1,45 @@ package com.beowulfe.hap.impl.characteristics.windowcovering; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.HomekitCharacteristicChangeCallback; import com.beowulfe.hap.accessories.VerticalTiltingWindowCovering; import com.beowulfe.hap.characteristics.EventableCharacteristic; import com.beowulfe.hap.characteristics.IntegerCharacteristic; +import java.util.concurrent.CompletableFuture; -public class TargetVerticalTiltAngleCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { - - private final VerticalTiltingWindowCovering windowCovering; - - public TargetVerticalTiltAngleCharacteristic(VerticalTiltingWindowCovering windowCovering) { - super("0000007D-0000-1000-8000-0026BB765291", true, true, "The target vertical tilt angle", -90, 90, "Arc Degree"); - this.windowCovering = windowCovering; - } - - @Override - protected void setValue(Integer value) throws Exception { - windowCovering.setTargetVerticalTiltAngle(value); - } - - @Override - protected CompletableFuture getValue() { - return windowCovering.getTargetVerticalTiltAngle(); - } - - @Override - public void subscribe(HomekitCharacteristicChangeCallback callback) { - windowCovering.subscribeTargetVerticalTiltAngle(callback); - } - - @Override - public void unsubscribe() { - windowCovering.unsubscribeTargetVerticalTiltAngle(); - } - +public class TargetVerticalTiltAngleCharacteristic extends IntegerCharacteristic + implements EventableCharacteristic { + + private final VerticalTiltingWindowCovering windowCovering; + + public TargetVerticalTiltAngleCharacteristic(VerticalTiltingWindowCovering windowCovering) { + super( + "0000007D-0000-1000-8000-0026BB765291", + true, + true, + "The target vertical tilt angle", + -90, + 90, + "Arc Degree"); + this.windowCovering = windowCovering; + } + + @Override + protected void setValue(Integer value) throws Exception { + windowCovering.setTargetVerticalTiltAngle(value); + } + + @Override + protected CompletableFuture getValue() { + return windowCovering.getTargetVerticalTiltAngle(); + } + + @Override + public void subscribe(HomekitCharacteristicChangeCallback callback) { + windowCovering.subscribeTargetVerticalTiltAngle(callback); + } + + @Override + public void unsubscribe() { + windowCovering.unsubscribeTargetVerticalTiltAngle(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/connections/ConnectionImpl.java b/src/main/java/com/beowulfe/hap/impl/connections/ConnectionImpl.java index b85215ba0..8b4f2cb8e 100644 --- a/src/main/java/com/beowulfe/hap/impl/connections/ConnectionImpl.java +++ b/src/main/java/com/beowulfe/hap/impl/connections/ConnectionImpl.java @@ -1,142 +1,146 @@ package com.beowulfe.hap.impl.connections; +import com.beowulfe.hap.HomekitAuthInfo; +import com.beowulfe.hap.impl.HomekitRegistry; +import com.beowulfe.hap.impl.crypto.ChachaDecoder; +import com.beowulfe.hap.impl.crypto.ChachaEncoder; +import com.beowulfe.hap.impl.http.*; +import com.beowulfe.hap.impl.jmdns.JmdnsHomekitAdvertiser; +import com.beowulfe.hap.impl.pairing.UpgradeResponse; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Collection; import java.util.function.Consumer; - import org.bouncycastle.util.Pack; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.beowulfe.hap.HomekitAuthInfo; -import com.beowulfe.hap.impl.HomekitRegistry; -import com.beowulfe.hap.impl.crypto.ChachaDecoder; -import com.beowulfe.hap.impl.crypto.ChachaEncoder; -import com.beowulfe.hap.impl.http.*; -import com.beowulfe.hap.impl.jmdns.JmdnsHomekitAdvertiser; -import com.beowulfe.hap.impl.pairing.UpgradeResponse; - class ConnectionImpl implements HomekitClientConnection { - private final HttpSession httpSession; - private LengthPrefixedByteArrayProcessor binaryProcessor; - private int inboundBinaryMessageCount = 0; - private int outboundBinaryMessageCount = 0; - private byte[] readKey; - private byte[] writeKey; - private boolean isUpgraded = false; - private final Consumer outOfBandMessageCallback; - private final SubscriptionManager subscriptions; - - private final static Logger LOGGER = LoggerFactory.getLogger(HomekitClientConnection.class); - - public ConnectionImpl(HomekitAuthInfo authInfo, HomekitRegistry registry, - Consumer outOfBandMessageCallback, SubscriptionManager subscriptions, - JmdnsHomekitAdvertiser advertiser) { - httpSession = new HttpSession(authInfo, registry, subscriptions, this, advertiser); - this.outOfBandMessageCallback = outOfBandMessageCallback; - this.subscriptions = subscriptions; - } + private final HttpSession httpSession; + private LengthPrefixedByteArrayProcessor binaryProcessor; + private int inboundBinaryMessageCount = 0; + private int outboundBinaryMessageCount = 0; + private byte[] readKey; + private byte[] writeKey; + private boolean isUpgraded = false; + private final Consumer outOfBandMessageCallback; + private final SubscriptionManager subscriptions; + + private static final Logger LOGGER = LoggerFactory.getLogger(HomekitClientConnection.class); + + public ConnectionImpl( + HomekitAuthInfo authInfo, + HomekitRegistry registry, + Consumer outOfBandMessageCallback, + SubscriptionManager subscriptions, + JmdnsHomekitAdvertiser advertiser) { + httpSession = new HttpSession(authInfo, registry, subscriptions, this, advertiser); + this.outOfBandMessageCallback = outOfBandMessageCallback; + this.subscriptions = subscriptions; + } + + @Override + public synchronized HttpResponse handleRequest(HttpRequest request) throws IOException { + return doHandleRequest(request); + } + + private HttpResponse doHandleRequest(HttpRequest request) throws IOException { + HttpResponse response = + isUpgraded + ? httpSession.handleAuthenticatedRequest(request) + : httpSession.handleRequest(request); + if (response instanceof UpgradeResponse) { + isUpgraded = true; + readKey = ((UpgradeResponse) response).getReadKey().array(); + writeKey = ((UpgradeResponse) response).getWriteKey().array(); + } + LOGGER.info(response.getStatusCode() + " " + request.getUri()); + return response; + } - @Override - public synchronized HttpResponse handleRequest(HttpRequest request) throws IOException { - return doHandleRequest(request); - } - - private HttpResponse doHandleRequest(HttpRequest request) throws IOException { - HttpResponse response = isUpgraded ? - httpSession.handleAuthenticatedRequest(request) : httpSession.handleRequest(request); - if (response instanceof UpgradeResponse) { - isUpgraded = true; - readKey = ((UpgradeResponse) response).getReadKey().array(); - writeKey = ((UpgradeResponse) response).getWriteKey().array(); - } - LOGGER.info(response.getStatusCode()+" "+request.getUri()); - return response; - } - - @Override - public byte[] decryptRequest(byte[] ciphertext) { - if (!isUpgraded) { - throw new RuntimeException("Cannot handle binary before connection is upgraded"); - } - if (binaryProcessor == null) { - binaryProcessor = new LengthPrefixedByteArrayProcessor(); - } - Collection res = binaryProcessor.handle(ciphertext); - if (res.isEmpty()) { - return new byte[0]; - } else { - try(ByteArrayOutputStream decrypted = new ByteArrayOutputStream()) { - res.stream().map(msg -> decrypt(msg)) - .forEach(bytes -> { - try { - decrypted.write(bytes); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - return decrypted.toByteArray(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } - + @Override + public byte[] decryptRequest(byte[] ciphertext) { + if (!isUpgraded) { + throw new RuntimeException("Cannot handle binary before connection is upgraded"); + } + if (binaryProcessor == null) { + binaryProcessor = new LengthPrefixedByteArrayProcessor(); + } + Collection res = binaryProcessor.handle(ciphertext); + if (res.isEmpty()) { + return new byte[0]; + } else { + try (ByteArrayOutputStream decrypted = new ByteArrayOutputStream()) { + res.stream() + .map(msg -> decrypt(msg)) + .forEach( + bytes -> { + try { + decrypted.write(bytes); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + return decrypted.toByteArray(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } - @Override - public byte[] encryptResponse(byte[] response) throws IOException { - int offset=0; - try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) { - while(offset < response.length) { - short length = (short) Math.min(response.length - offset, 0x400); - byte[] lengthBytes = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN) - .putShort(length).array(); - baos.write(lengthBytes); - - byte[] nonce = Pack.longToLittleEndian(outboundBinaryMessageCount++); - byte[] plaintext; - if (response.length == length) { - plaintext = response; - } else { - plaintext = new byte[length]; - System.arraycopy(response, offset, plaintext, 0, length); - } - offset += length; - baos.write(new ChachaEncoder(writeKey, nonce).encodeCiphertext(plaintext, lengthBytes)); - } - return baos.toByteArray(); - } - } - - private byte[] decrypt(byte[] msg) { - byte[] mac = new byte[16]; - byte[] ciphertext = new byte[msg.length - 16]; - System.arraycopy(msg, 0, ciphertext, 0, msg.length - 16); - System.arraycopy(msg, msg.length - 16, mac, 0, 16); - byte[] additionalData = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN) - .putShort((short) (msg.length - 16)).array(); - try { - byte[] nonce = Pack.longToLittleEndian(inboundBinaryMessageCount++); - return new ChachaDecoder(readKey, nonce) - .decodeCiphertext(mac, additionalData, ciphertext); - } catch (IOException e) { - throw new RuntimeException(e); - } - } + @Override + public byte[] encryptResponse(byte[] response) throws IOException { + int offset = 0; + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + while (offset < response.length) { + short length = (short) Math.min(response.length - offset, 0x400); + byte[] lengthBytes = + ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(length).array(); + baos.write(lengthBytes); - @Override - public void close() { - subscriptions.removeConnection(this); - } + byte[] nonce = Pack.longToLittleEndian(outboundBinaryMessageCount++); + byte[] plaintext; + if (response.length == length) { + plaintext = response; + } else { + plaintext = new byte[length]; + System.arraycopy(response, offset, plaintext, 0, length); + } + offset += length; + baos.write(new ChachaEncoder(writeKey, nonce).encodeCiphertext(plaintext, lengthBytes)); + } + return baos.toByteArray(); + } + } - @Override - public void outOfBand(HttpResponse message) { - outOfBandMessageCallback.accept(message); - } + private byte[] decrypt(byte[] msg) { + byte[] mac = new byte[16]; + byte[] ciphertext = new byte[msg.length - 16]; + System.arraycopy(msg, 0, ciphertext, 0, msg.length - 16); + System.arraycopy(msg, msg.length - 16, mac, 0, 16); + byte[] additionalData = + ByteBuffer.allocate(2) + .order(ByteOrder.LITTLE_ENDIAN) + .putShort((short) (msg.length - 16)) + .array(); + try { + byte[] nonce = Pack.longToLittleEndian(inboundBinaryMessageCount++); + return new ChachaDecoder(readKey, nonce).decodeCiphertext(mac, additionalData, ciphertext); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + @Override + public void close() { + subscriptions.removeConnection(this); + } + @Override + public void outOfBand(HttpResponse message) { + outOfBandMessageCallback.accept(message); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/connections/HomekitClientConnectionFactoryImpl.java b/src/main/java/com/beowulfe/hap/impl/connections/HomekitClientConnectionFactoryImpl.java index 0d0492633..3d5eb0169 100644 --- a/src/main/java/com/beowulfe/hap/impl/connections/HomekitClientConnectionFactoryImpl.java +++ b/src/main/java/com/beowulfe/hap/impl/connections/HomekitClientConnectionFactoryImpl.java @@ -1,34 +1,34 @@ package com.beowulfe.hap.impl.connections; -import java.util.function.Consumer; - import com.beowulfe.hap.HomekitAuthInfo; import com.beowulfe.hap.impl.HomekitRegistry; import com.beowulfe.hap.impl.http.HomekitClientConnection; import com.beowulfe.hap.impl.http.HomekitClientConnectionFactory; import com.beowulfe.hap.impl.http.HttpResponse; import com.beowulfe.hap.impl.jmdns.JmdnsHomekitAdvertiser; +import java.util.function.Consumer; + +public class HomekitClientConnectionFactoryImpl implements HomekitClientConnectionFactory { -public class HomekitClientConnectionFactoryImpl implements HomekitClientConnectionFactory{ + private final HomekitAuthInfo authInfo; + private final HomekitRegistry registry; + private final SubscriptionManager subscriptions; + private final JmdnsHomekitAdvertiser advertiser; - private final HomekitAuthInfo authInfo; - private final HomekitRegistry registry; - private final SubscriptionManager subscriptions; - private final JmdnsHomekitAdvertiser advertiser; - - public HomekitClientConnectionFactoryImpl(HomekitAuthInfo authInfo, - HomekitRegistry registry, SubscriptionManager subscriptions, JmdnsHomekitAdvertiser advertiser) { - this.registry = registry; - this.authInfo = authInfo; - this.subscriptions = subscriptions; - this.advertiser = advertiser; - } - - @Override - public HomekitClientConnection createConnection(Consumer outOfBandMessageCallback) { - return new ConnectionImpl(authInfo, registry, outOfBandMessageCallback, subscriptions, advertiser); - } + public HomekitClientConnectionFactoryImpl( + HomekitAuthInfo authInfo, + HomekitRegistry registry, + SubscriptionManager subscriptions, + JmdnsHomekitAdvertiser advertiser) { + this.registry = registry; + this.authInfo = authInfo; + this.subscriptions = subscriptions; + this.advertiser = advertiser; + } - - + @Override + public HomekitClientConnection createConnection(Consumer outOfBandMessageCallback) { + return new ConnectionImpl( + authInfo, registry, outOfBandMessageCallback, subscriptions, advertiser); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/connections/HttpSession.java b/src/main/java/com/beowulfe/hap/impl/connections/HttpSession.java index 15cee94e7..2f4e72386 100644 --- a/src/main/java/com/beowulfe/hap/impl/connections/HttpSession.java +++ b/src/main/java/com/beowulfe/hap/impl/connections/HttpSession.java @@ -1,11 +1,5 @@ package com.beowulfe.hap.impl.connections; -import java.io.IOException; -import java.net.InetAddress; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.beowulfe.hap.HomekitAccessory; import com.beowulfe.hap.HomekitAuthInfo; import com.beowulfe.hap.impl.HomekitRegistry; @@ -20,153 +14,160 @@ import com.beowulfe.hap.impl.pairing.PairingUpdateController; import com.beowulfe.hap.impl.responses.InternalServerErrorResponse; import com.beowulfe.hap.impl.responses.NotFoundResponse; +import java.io.IOException; +import java.net.InetAddress; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; class HttpSession { - - private volatile PairingManager pairingManager; - private volatile PairVerificationManager pairVerificationManager; - private volatile AccessoryController accessoryController; - private volatile CharacteristicsController characteristicsController; - - private final HomekitAuthInfo authInfo; - private final HomekitRegistry registry; - private final SubscriptionManager subscriptions; - private final HomekitClientConnection connection; - private final JmdnsHomekitAdvertiser advertiser; - - private final static Logger logger = LoggerFactory.getLogger(HttpSession.class); - - public HttpSession(HomekitAuthInfo authInfo, HomekitRegistry registry, SubscriptionManager subscriptions, - HomekitClientConnection connection, JmdnsHomekitAdvertiser advertiser) { - this.authInfo = authInfo; - this.registry = registry; - this.subscriptions = subscriptions; - this.connection = connection; - this.advertiser = advertiser; - } - - public HttpResponse handleRequest(HttpRequest request) throws IOException { - switch(request.getUri()) { - case "/pair-setup": - return handlePairSetup(request); - - case "/pair-verify": - return handlePairVerify(request); - - default: - if (registry.isAllowUnauthenticatedRequests()) { - return handleAuthenticatedRequest(request); - } else { - logger.info("Unrecognized request for "+request.getUri()); - return new NotFoundResponse(); - } - } - } - - public HttpResponse handleAuthenticatedRequest(HttpRequest request) throws IOException { - try { - switch(request.getUri()) { - case "/accessories": - return getAccessoryController().listing(); - - case "/characteristics": - switch(request.getMethod()) { - case PUT: - return getCharacteristicsController().put(request, connection); - - default: - logger.info("Unrecognized method for "+request.getUri()); - return new NotFoundResponse(); - } - - case "/pairings": - return new PairingUpdateController(authInfo, advertiser).handle(request); - - default: - if (request.getUri().startsWith("/characteristics?")) { - return getCharacteristicsController().get(request); - } - logger.info("Unrecognized request for "+request.getUri()); - return new NotFoundResponse(); - } - } catch (Exception e) { - logger.error("Could not handle request", e); - return new InternalServerErrorResponse(e); - } - } - - private HttpResponse handlePairSetup(HttpRequest request) { - if (pairingManager == null) { - synchronized(HttpSession.class) { - if (pairingManager == null) { - pairingManager = new PairingManager(authInfo, registry, advertiser); - } - } - } - try { - return pairingManager.handle(request); - } catch (Exception e) { - logger.error("Exception encountered during pairing", e); - return new InternalServerErrorResponse(e); - } - } - - private HttpResponse handlePairVerify(HttpRequest request) { - if (pairVerificationManager == null) { - synchronized(HttpSession.class) { - if (pairVerificationManager == null) { - pairVerificationManager = new PairVerificationManager(authInfo, registry); - } - } - } - try { - return pairVerificationManager.handle(request); - } catch (Exception e) { - logger.error("Excepton encountered while verifying pairing", e); - return new InternalServerErrorResponse(e); - } - } - - private synchronized AccessoryController getAccessoryController() { - if (accessoryController == null) { - accessoryController = new AccessoryController(registry); - } - return accessoryController; - } - - private synchronized CharacteristicsController getCharacteristicsController() { - if (characteristicsController == null) { - characteristicsController = new CharacteristicsController(registry, subscriptions); - } - return characteristicsController; - } - - public static class SessionKey { - private final InetAddress address; - private final HomekitAccessory accessory; - - public SessionKey(InetAddress address, HomekitAccessory accessory) { - this.address = address; - this.accessory = accessory; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof SessionKey) { - return address.equals(((SessionKey) obj).address) && - accessory.equals(((SessionKey) obj).accessory); - } else { - return false; - } - } - - @Override - public int hashCode() { - int hash = 1; - hash = hash * 31 + address.hashCode(); - hash = hash * 31 + accessory.hashCode(); - return hash; - } - } + private volatile PairingManager pairingManager; + private volatile PairVerificationManager pairVerificationManager; + private volatile AccessoryController accessoryController; + private volatile CharacteristicsController characteristicsController; + + private final HomekitAuthInfo authInfo; + private final HomekitRegistry registry; + private final SubscriptionManager subscriptions; + private final HomekitClientConnection connection; + private final JmdnsHomekitAdvertiser advertiser; + + private static final Logger logger = LoggerFactory.getLogger(HttpSession.class); + + public HttpSession( + HomekitAuthInfo authInfo, + HomekitRegistry registry, + SubscriptionManager subscriptions, + HomekitClientConnection connection, + JmdnsHomekitAdvertiser advertiser) { + this.authInfo = authInfo; + this.registry = registry; + this.subscriptions = subscriptions; + this.connection = connection; + this.advertiser = advertiser; + } + + public HttpResponse handleRequest(HttpRequest request) throws IOException { + switch (request.getUri()) { + case "/pair-setup": + return handlePairSetup(request); + + case "/pair-verify": + return handlePairVerify(request); + + default: + if (registry.isAllowUnauthenticatedRequests()) { + return handleAuthenticatedRequest(request); + } else { + logger.info("Unrecognized request for " + request.getUri()); + return new NotFoundResponse(); + } + } + } + + public HttpResponse handleAuthenticatedRequest(HttpRequest request) throws IOException { + try { + switch (request.getUri()) { + case "/accessories": + return getAccessoryController().listing(); + + case "/characteristics": + switch (request.getMethod()) { + case PUT: + return getCharacteristicsController().put(request, connection); + + default: + logger.info("Unrecognized method for " + request.getUri()); + return new NotFoundResponse(); + } + + case "/pairings": + return new PairingUpdateController(authInfo, advertiser).handle(request); + + default: + if (request.getUri().startsWith("/characteristics?")) { + return getCharacteristicsController().get(request); + } + logger.info("Unrecognized request for " + request.getUri()); + return new NotFoundResponse(); + } + } catch (Exception e) { + logger.error("Could not handle request", e); + return new InternalServerErrorResponse(e); + } + } + + private HttpResponse handlePairSetup(HttpRequest request) { + if (pairingManager == null) { + synchronized (HttpSession.class) { + if (pairingManager == null) { + pairingManager = new PairingManager(authInfo, registry, advertiser); + } + } + } + try { + return pairingManager.handle(request); + } catch (Exception e) { + logger.error("Exception encountered during pairing", e); + return new InternalServerErrorResponse(e); + } + } + + private HttpResponse handlePairVerify(HttpRequest request) { + if (pairVerificationManager == null) { + synchronized (HttpSession.class) { + if (pairVerificationManager == null) { + pairVerificationManager = new PairVerificationManager(authInfo, registry); + } + } + } + try { + return pairVerificationManager.handle(request); + } catch (Exception e) { + logger.error("Excepton encountered while verifying pairing", e); + return new InternalServerErrorResponse(e); + } + } + + private synchronized AccessoryController getAccessoryController() { + if (accessoryController == null) { + accessoryController = new AccessoryController(registry); + } + return accessoryController; + } + + private synchronized CharacteristicsController getCharacteristicsController() { + if (characteristicsController == null) { + characteristicsController = new CharacteristicsController(registry, subscriptions); + } + return characteristicsController; + } + + public static class SessionKey { + private final InetAddress address; + private final HomekitAccessory accessory; + + public SessionKey(InetAddress address, HomekitAccessory accessory) { + this.address = address; + this.accessory = accessory; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof SessionKey) { + return address.equals(((SessionKey) obj).address) + && accessory.equals(((SessionKey) obj).accessory); + } else { + return false; + } + } + + @Override + public int hashCode() { + int hash = 1; + hash = hash * 31 + address.hashCode(); + hash = hash * 31 + accessory.hashCode(); + return hash; + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/connections/LengthPrefixedByteArrayProcessor.java b/src/main/java/com/beowulfe/hap/impl/connections/LengthPrefixedByteArrayProcessor.java index 0ecb671a9..11cbe6d91 100644 --- a/src/main/java/com/beowulfe/hap/impl/connections/LengthPrefixedByteArrayProcessor.java +++ b/src/main/java/com/beowulfe/hap/impl/connections/LengthPrefixedByteArrayProcessor.java @@ -3,79 +3,86 @@ import java.io.ByteArrayOutputStream; import java.util.Collection; import java.util.LinkedList; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; class LengthPrefixedByteArrayProcessor { - private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - private Byte firstLengthByteBuffer; //Only used if we've received a single byte at the start of a message - private int targetLength = 0; - - private final static Logger LOGGER = LoggerFactory.getLogger(LengthPrefixedByteArrayProcessor.class); + private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + private Byte + firstLengthByteBuffer; // Only used if we've received a single byte at the start of a message + private int targetLength = 0; + + private static final Logger LOGGER = + LoggerFactory.getLogger(LengthPrefixedByteArrayProcessor.class); - public synchronized Collection handle(byte[] data) { - Collection results = new LinkedList<>(); - int pos = 0; - LOGGER.trace("Received message of length {}. Existing buffer is {}", data.length, buffer.size()); - if (buffer.size() == 0) { - while(data.length - pos > 18) { - int targetLength = (data[0] & 0xFF) + (data[1] & 0xFF) * 256 + 16 + 2; - LOGGER.trace("Attempting to read message of length {}", targetLength); - if (data.length >= pos + targetLength) { - byte[] b = new byte[targetLength - 2]; - System.arraycopy(data, pos+2, b, 0, targetLength-2); - results.add(b); - LOGGER.trace("Read complete message"); - pos = pos + targetLength; - } else { - LOGGER.trace("Not enough data available"); - break; - } - } - } - if (data.length > pos) { - LOGGER.trace("Remaining data available"); - step(data, pos, results); - } - LOGGER.trace("Returning {} results", results.size()); - return results; - } - - private void step(byte[] data, int pos, Collection results) { - LOGGER.trace("Performing step operation on buffer of length {} with pos {}", data.length, pos); - if (targetLength == 0 && data.length == 1 + pos) { - firstLengthByteBuffer = data[pos]; - LOGGER.trace("Received a single byte message, storing byte {} for later", firstLengthByteBuffer); - return; - } - if (targetLength == 0) { - if (firstLengthByteBuffer != null) { - targetLength = (firstLengthByteBuffer & 0xFF) + (data[pos] & 0xFF) * 256 + 16; - pos += 1; - LOGGER.trace("Received the second byte after storing the first byte. New length is {}", targetLength); - } else { - targetLength = (data[pos] & 0xFF) + (data[pos+1] & 0xFF) * 256 + 16; - pos += 2; - LOGGER.trace("targetLength is {}", targetLength); - } - } - int toWrite = targetLength - buffer.size(); - if (toWrite <= data.length - pos) { - //We have a complete message - LOGGER.trace("Received a complete message"); - buffer.write(data, pos, toWrite); - results.add(buffer.toByteArray()); - buffer.reset(); - targetLength=0; - if (pos + toWrite > data.length) { - step(data, pos + toWrite, results); - } - } else { - LOGGER.trace("Storing {} bytes in buffer until we receive the complete {}", data.length-pos, targetLength); - buffer.write(data, pos, data.length - pos); - } - } + public synchronized Collection handle(byte[] data) { + Collection results = new LinkedList<>(); + int pos = 0; + LOGGER.trace( + "Received message of length {}. Existing buffer is {}", data.length, buffer.size()); + if (buffer.size() == 0) { + while (data.length - pos > 18) { + int targetLength = (data[0] & 0xFF) + (data[1] & 0xFF) * 256 + 16 + 2; + LOGGER.trace("Attempting to read message of length {}", targetLength); + if (data.length >= pos + targetLength) { + byte[] b = new byte[targetLength - 2]; + System.arraycopy(data, pos + 2, b, 0, targetLength - 2); + results.add(b); + LOGGER.trace("Read complete message"); + pos = pos + targetLength; + } else { + LOGGER.trace("Not enough data available"); + break; + } + } + } + if (data.length > pos) { + LOGGER.trace("Remaining data available"); + step(data, pos, results); + } + LOGGER.trace("Returning {} results", results.size()); + return results; + } + private void step(byte[] data, int pos, Collection results) { + LOGGER.trace("Performing step operation on buffer of length {} with pos {}", data.length, pos); + if (targetLength == 0 && data.length == 1 + pos) { + firstLengthByteBuffer = data[pos]; + LOGGER.trace( + "Received a single byte message, storing byte {} for later", firstLengthByteBuffer); + return; + } + if (targetLength == 0) { + if (firstLengthByteBuffer != null) { + targetLength = (firstLengthByteBuffer & 0xFF) + (data[pos] & 0xFF) * 256 + 16; + pos += 1; + LOGGER.trace( + "Received the second byte after storing the first byte. New length is {}", + targetLength); + } else { + targetLength = (data[pos] & 0xFF) + (data[pos + 1] & 0xFF) * 256 + 16; + pos += 2; + LOGGER.trace("targetLength is {}", targetLength); + } + } + int toWrite = targetLength - buffer.size(); + if (toWrite <= data.length - pos) { + // We have a complete message + LOGGER.trace("Received a complete message"); + buffer.write(data, pos, toWrite); + results.add(buffer.toByteArray()); + buffer.reset(); + targetLength = 0; + if (pos + toWrite > data.length) { + step(data, pos + toWrite, results); + } + } else { + LOGGER.trace( + "Storing {} bytes in buffer until we receive the complete {}", + data.length - pos, + targetLength); + buffer.write(data, pos, data.length - pos); + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/connections/SubscriptionManager.java b/src/main/java/com/beowulfe/hap/impl/connections/SubscriptionManager.java index 621c9111f..5ccbf306a 100644 --- a/src/main/java/com/beowulfe/hap/impl/connections/SubscriptionManager.java +++ b/src/main/java/com/beowulfe/hap/impl/connections/SubscriptionManager.java @@ -1,92 +1,101 @@ package com.beowulfe.hap.impl.connections; +import com.beowulfe.hap.characteristics.EventableCharacteristic; +import com.beowulfe.hap.impl.http.HomekitClientConnection; +import com.beowulfe.hap.impl.http.HttpResponse; +import com.beowulfe.hap.impl.json.EventController; import java.util.Collections; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.beowulfe.hap.characteristics.EventableCharacteristic; -import com.beowulfe.hap.impl.http.HomekitClientConnection; -import com.beowulfe.hap.impl.http.HttpResponse; -import com.beowulfe.hap.impl.json.EventController; - public class SubscriptionManager { - private final static Logger LOGGER = LoggerFactory.getLogger(SubscriptionManager.class); - - private final ConcurrentMap> subscriptions = new ConcurrentHashMap<>(); - private final ConcurrentMap> reverse = new ConcurrentHashMap<>(); + private static final Logger LOGGER = LoggerFactory.getLogger(SubscriptionManager.class); + + private final ConcurrentMap> subscriptions = + new ConcurrentHashMap<>(); + private final ConcurrentMap> reverse = + new ConcurrentHashMap<>(); + + public synchronized void addSubscription( + int aid, + int iid, + EventableCharacteristic characteristic, + HomekitClientConnection connection) { + synchronized (this) { + if (!subscriptions.containsKey(characteristic)) { + subscriptions.putIfAbsent(characteristic, newSet()); + } + subscriptions.get(characteristic).add(connection); + if (subscriptions.get(characteristic).size() == 1) { + characteristic.subscribe( + () -> { + publish(aid, iid, characteristic); + }); + } + + if (!reverse.containsKey(connection)) { + reverse.putIfAbsent(connection, newSet()); + } + reverse.get(connection).add(characteristic); + LOGGER.info( + "Added subscription to " + characteristic.getClass() + " for " + connection.hashCode()); + } + try { + connection.outOfBand(new EventController().getMessage(aid, iid, characteristic)); + } catch (Exception e) { + LOGGER.error("Could not send initial state in response to subscribe event", e); + } + } + + public synchronized void removeSubscription( + EventableCharacteristic characteristic, HomekitClientConnection connection) { + Set subscriptions = this.subscriptions.get(characteristic); + if (subscriptions != null) { + subscriptions.remove(connection); + if (subscriptions.size() == 0) { + characteristic.unsubscribe(); + } + } + + Set reverse = this.reverse.get(connection); + if (reverse != null) { + reverse.remove(characteristic); + } + LOGGER.info( + "Removed subscription to " + characteristic.getClass() + " for " + connection.hashCode()); + } + + public synchronized void removeConnection(HomekitClientConnection connection) { + Set characteristics = reverse.remove(connection); + if (characteristics != null) { + for (EventableCharacteristic characteristic : characteristics) { + Set characteristicSubscriptions = + subscriptions.get(characteristic); + characteristicSubscriptions.remove(connection); + if (characteristicSubscriptions.isEmpty()) { + characteristic.unsubscribe(); + } + } + } + } + + private Set newSet() { + return Collections.newSetFromMap(new ConcurrentHashMap()); + } - public synchronized void addSubscription(int aid, int iid, EventableCharacteristic characteristic, HomekitClientConnection connection) { - synchronized(this) { - if (!subscriptions.containsKey(characteristic)) { - subscriptions.putIfAbsent(characteristic, newSet()); - } - subscriptions.get(characteristic).add(connection); - if (subscriptions.get(characteristic).size() == 1) { - characteristic.subscribe(() -> { - publish(aid, iid, characteristic); - }); - } - - if (!reverse.containsKey(connection)) { - reverse.putIfAbsent(connection, newSet()); - } - reverse.get(connection).add(characteristic); - LOGGER.info("Added subscription to "+characteristic.getClass()+" for "+connection.hashCode()); - } - try { - connection.outOfBand(new EventController().getMessage(aid, iid, characteristic)); - } catch (Exception e) { - LOGGER.error("Could not send initial state in response to subscribe event", e); - } - } - - public synchronized void removeSubscription(EventableCharacteristic characteristic, HomekitClientConnection connection) { - Set subscriptions = this.subscriptions.get(characteristic); - if (subscriptions != null) { - subscriptions.remove(connection); - if (subscriptions.size() == 0) { - characteristic.unsubscribe(); - } - } - - Set reverse = this.reverse.get(connection); - if (reverse != null) { - reverse.remove(characteristic); - } - LOGGER.info("Removed subscription to "+characteristic.getClass()+" for "+connection.hashCode()); - } - - public synchronized void removeConnection(HomekitClientConnection connection) { - Set characteristics = reverse.remove(connection); - if (characteristics != null) { - for (EventableCharacteristic characteristic: characteristics) { - Set characteristicSubscriptions = subscriptions.get(characteristic); - characteristicSubscriptions.remove(connection); - if (characteristicSubscriptions.isEmpty()) { - characteristic.unsubscribe(); - } - } - } - } - - private Set newSet() { - return Collections.newSetFromMap(new ConcurrentHashMap()); - } - - public void publish(int accessoryId, int iid, EventableCharacteristic changed) { - try { - HttpResponse message = new EventController().getMessage(accessoryId, iid, changed); - LOGGER.info("Publishing changes for "+accessoryId); - for (HomekitClientConnection connection: subscriptions.get(changed)) { - connection.outOfBand(message); - } - } catch (Exception e) { - LOGGER.error("Failed to create new event message", e); - } - } + public void publish(int accessoryId, int iid, EventableCharacteristic changed) { + try { + HttpResponse message = new EventController().getMessage(accessoryId, iid, changed); + LOGGER.info("Publishing changes for " + accessoryId); + for (HomekitClientConnection connection : subscriptions.get(changed)) { + connection.outOfBand(message); + } + } catch (Exception e) { + LOGGER.error("Failed to create new event message", e); + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/crypto/ChachaDecoder.java b/src/main/java/com/beowulfe/hap/impl/crypto/ChachaDecoder.java index 4e8615330..e91bdd14f 100644 --- a/src/main/java/com/beowulfe/hap/impl/crypto/ChachaDecoder.java +++ b/src/main/java/com/beowulfe/hap/impl/crypto/ChachaDecoder.java @@ -1,7 +1,6 @@ package com.beowulfe.hap.impl.crypto; import java.io.IOException; - import org.bouncycastle.crypto.engines.ChaChaEngine; import org.bouncycastle.crypto.generators.Poly1305KeyGenerator; import org.bouncycastle.crypto.params.KeyParameter; @@ -12,50 +11,44 @@ public class ChachaDecoder { - private final ChaChaEngine decryptCipher; - - public ChachaDecoder(byte[] key, byte[] nonce) throws IOException { - - this.decryptCipher = new ChaChaEngine(20); - - this.decryptCipher.init(false, new ParametersWithIV(new KeyParameter(key), nonce)); - - - } + private final ChaChaEngine decryptCipher; - public byte[] decodeCiphertext(byte[] receivedMAC, byte[] additionalData, byte[] ciphertext) - throws IOException { + public ChachaDecoder(byte[] key, byte[] nonce) throws IOException { - KeyParameter macKey = initRecordMAC(decryptCipher); + this.decryptCipher = new ChaChaEngine(20); - byte[] calculatedMAC = PolyKeyCreator.create(macKey, additionalData, ciphertext); + this.decryptCipher.init(false, new ParametersWithIV(new KeyParameter(key), nonce)); + } - if (!Arrays.constantTimeAreEqual(calculatedMAC, receivedMAC)) - { - throw new TlsFatalAlert(AlertDescription.bad_record_mac); - } + public byte[] decodeCiphertext(byte[] receivedMAC, byte[] additionalData, byte[] ciphertext) + throws IOException { - byte[] output = new byte[ciphertext.length]; - decryptCipher.processBytes(ciphertext, 0, ciphertext.length, output, 0); + KeyParameter macKey = initRecordMAC(decryptCipher); - return output; - } - - public byte[] decodeCiphertext(byte[] receivedMAC, byte[] ciphertext) throws IOException - { - return decodeCiphertext(receivedMAC, null, ciphertext); - } - - private KeyParameter initRecordMAC(ChaChaEngine cipher) - { - byte[] firstBlock = new byte[64]; - cipher.processBytes(firstBlock, 0, firstBlock.length, firstBlock, 0); - - // NOTE: The BC implementation puts 'r' after 'k' - System.arraycopy(firstBlock, 0, firstBlock, 32, 16); - KeyParameter macKey = new KeyParameter(firstBlock, 16, 32); - Poly1305KeyGenerator.clamp(macKey.getKey()); - return macKey; + byte[] calculatedMAC = PolyKeyCreator.create(macKey, additionalData, ciphertext); + + if (!Arrays.constantTimeAreEqual(calculatedMAC, receivedMAC)) { + throw new TlsFatalAlert(AlertDescription.bad_record_mac); } - + + byte[] output = new byte[ciphertext.length]; + decryptCipher.processBytes(ciphertext, 0, ciphertext.length, output, 0); + + return output; + } + + public byte[] decodeCiphertext(byte[] receivedMAC, byte[] ciphertext) throws IOException { + return decodeCiphertext(receivedMAC, null, ciphertext); + } + + private KeyParameter initRecordMAC(ChaChaEngine cipher) { + byte[] firstBlock = new byte[64]; + cipher.processBytes(firstBlock, 0, firstBlock.length, firstBlock, 0); + + // NOTE: The BC implementation puts 'r' after 'k' + System.arraycopy(firstBlock, 0, firstBlock, 32, 16); + KeyParameter macKey = new KeyParameter(firstBlock, 16, 32); + Poly1305KeyGenerator.clamp(macKey.getKey()); + return macKey; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/crypto/ChachaEncoder.java b/src/main/java/com/beowulfe/hap/impl/crypto/ChachaEncoder.java index deb3c69c6..809f6ad1f 100644 --- a/src/main/java/com/beowulfe/hap/impl/crypto/ChachaEncoder.java +++ b/src/main/java/com/beowulfe/hap/impl/crypto/ChachaEncoder.java @@ -1,7 +1,6 @@ package com.beowulfe.hap.impl.crypto; import java.io.IOException; - import org.bouncycastle.crypto.engines.ChaChaEngine; import org.bouncycastle.crypto.generators.Poly1305KeyGenerator; import org.bouncycastle.crypto.params.KeyParameter; @@ -9,45 +8,41 @@ public class ChachaEncoder { - private final ChaChaEngine encryptCipher; - - public ChachaEncoder(byte[] key, byte[] nonce) throws IOException { - - this.encryptCipher = new ChaChaEngine(20); - - this.encryptCipher.init(true, new ParametersWithIV(new KeyParameter(key), nonce)); - - - } - - public byte[] encodeCiphertext(byte[] plaintext) throws IOException { - return encodeCiphertext(plaintext, null); - } - - public byte[] encodeCiphertext(byte[] plaintext, byte[] additionalData) throws IOException { - KeyParameter macKey = initRecordMAC(encryptCipher); - - byte[] ciphertext = new byte[plaintext.length]; - encryptCipher.processBytes(plaintext, 0, plaintext.length, ciphertext, 0); - - byte[] calculatedMAC = PolyKeyCreator.create(macKey, additionalData, ciphertext); - - byte[] ret = new byte[ciphertext.length + 16]; - System.arraycopy(ciphertext, 0, ret, 0, ciphertext.length); - System.arraycopy(calculatedMAC, 0, ret, ciphertext.length, 16); - return ret; - } - - private KeyParameter initRecordMAC(ChaChaEngine cipher) - { - byte[] firstBlock = new byte[64]; - cipher.processBytes(firstBlock, 0, firstBlock.length, firstBlock, 0); - - // NOTE: The BC implementation puts 'r' after 'k' - System.arraycopy(firstBlock, 0, firstBlock, 32, 16); - KeyParameter macKey = new KeyParameter(firstBlock, 16, 32); - Poly1305KeyGenerator.clamp(macKey.getKey()); - return macKey; - } - + private final ChaChaEngine encryptCipher; + + public ChachaEncoder(byte[] key, byte[] nonce) throws IOException { + + this.encryptCipher = new ChaChaEngine(20); + + this.encryptCipher.init(true, new ParametersWithIV(new KeyParameter(key), nonce)); + } + + public byte[] encodeCiphertext(byte[] plaintext) throws IOException { + return encodeCiphertext(plaintext, null); + } + + public byte[] encodeCiphertext(byte[] plaintext, byte[] additionalData) throws IOException { + KeyParameter macKey = initRecordMAC(encryptCipher); + + byte[] ciphertext = new byte[plaintext.length]; + encryptCipher.processBytes(plaintext, 0, plaintext.length, ciphertext, 0); + + byte[] calculatedMAC = PolyKeyCreator.create(macKey, additionalData, ciphertext); + + byte[] ret = new byte[ciphertext.length + 16]; + System.arraycopy(ciphertext, 0, ret, 0, ciphertext.length); + System.arraycopy(calculatedMAC, 0, ret, ciphertext.length, 16); + return ret; + } + + private KeyParameter initRecordMAC(ChaChaEngine cipher) { + byte[] firstBlock = new byte[64]; + cipher.processBytes(firstBlock, 0, firstBlock.length, firstBlock, 0); + + // NOTE: The BC implementation puts 'r' after 'k' + System.arraycopy(firstBlock, 0, firstBlock, 32, 16); + KeyParameter macKey = new KeyParameter(firstBlock, 16, 32); + Poly1305KeyGenerator.clamp(macKey.getKey()); + return macKey; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/crypto/EdsaSigner.java b/src/main/java/com/beowulfe/hap/impl/crypto/EdsaSigner.java index bab1d3a63..1ea917067 100644 --- a/src/main/java/com/beowulfe/hap/impl/crypto/EdsaSigner.java +++ b/src/main/java/com/beowulfe/hap/impl/crypto/EdsaSigner.java @@ -5,7 +5,6 @@ import java.security.NoSuchAlgorithmException; import java.security.Signature; import java.security.SignatureException; - import net.i2p.crypto.eddsa.EdDSAEngine; import net.i2p.crypto.eddsa.EdDSAPrivateKey; import net.i2p.crypto.eddsa.EdDSAPublicKey; @@ -15,28 +14,27 @@ import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; public class EdsaSigner { - - private final EdDSAPublicKey publicKey; - private final EdDSAPrivateKey privateKey; - public EdsaSigner(byte[] privateKeyBytes) { - EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512"); - EdDSAPrivateKeySpec privateKeySpec = new EdDSAPrivateKeySpec(privateKeyBytes, spec); - EdDSAPublicKeySpec pubKeySpec = new EdDSAPublicKeySpec(privateKeySpec.getA(), spec); - publicKey = new EdDSAPublicKey(pubKeySpec); - privateKey = new EdDSAPrivateKey(privateKeySpec); - } - - public byte[] getPublicKey() { - return publicKey.getAbyte(); - } - - public byte[] sign(byte[] material) throws NoSuchAlgorithmException, InvalidKeyException, - SignatureException { - Signature sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512")); - sgr.initSign(privateKey); - sgr.update(material); - return sgr.sign(); - } + private final EdDSAPublicKey publicKey; + private final EdDSAPrivateKey privateKey; + + public EdsaSigner(byte[] privateKeyBytes) { + EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512"); + EdDSAPrivateKeySpec privateKeySpec = new EdDSAPrivateKeySpec(privateKeyBytes, spec); + EdDSAPublicKeySpec pubKeySpec = new EdDSAPublicKeySpec(privateKeySpec.getA(), spec); + publicKey = new EdDSAPublicKey(pubKeySpec); + privateKey = new EdDSAPrivateKey(privateKeySpec); + } + + public byte[] getPublicKey() { + return publicKey.getAbyte(); + } + public byte[] sign(byte[] material) + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { + Signature sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512")); + sgr.initSign(privateKey); + sgr.update(material); + return sgr.sign(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/crypto/EdsaVerifier.java b/src/main/java/com/beowulfe/hap/impl/crypto/EdsaVerifier.java index c1bbbd9be..3d3570b44 100644 --- a/src/main/java/com/beowulfe/hap/impl/crypto/EdsaVerifier.java +++ b/src/main/java/com/beowulfe/hap/impl/crypto/EdsaVerifier.java @@ -3,7 +3,6 @@ import java.security.MessageDigest; import java.security.PublicKey; import java.security.Signature; - import net.i2p.crypto.eddsa.EdDSAEngine; import net.i2p.crypto.eddsa.EdDSAPublicKey; import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; @@ -11,21 +10,20 @@ import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; public class EdsaVerifier { - - private final PublicKey publicKey; - public EdsaVerifier(byte[] publicKey) { - EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512"); - EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(publicKey, spec); - this.publicKey = new EdDSAPublicKey(pubKey); - } - - public boolean verify(byte[] data, byte[] signature) throws Exception { - Signature sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512")); - sgr.initVerify(publicKey); - sgr.update(data); - - return sgr.verify(signature); - } + private final PublicKey publicKey; + + public EdsaVerifier(byte[] publicKey) { + EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512"); + EdDSAPublicKeySpec pubKey = new EdDSAPublicKeySpec(publicKey, spec); + this.publicKey = new EdDSAPublicKey(pubKey); + } + + public boolean verify(byte[] data, byte[] signature) throws Exception { + Signature sgr = new EdDSAEngine(MessageDigest.getInstance("SHA-512")); + sgr.initVerify(publicKey); + sgr.update(data); + return sgr.verify(signature); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/crypto/PolyKeyCreator.java b/src/main/java/com/beowulfe/hap/impl/crypto/PolyKeyCreator.java index 9557a803a..d5e65a67f 100644 --- a/src/main/java/com/beowulfe/hap/impl/crypto/PolyKeyCreator.java +++ b/src/main/java/com/beowulfe/hap/impl/crypto/PolyKeyCreator.java @@ -6,37 +6,37 @@ class PolyKeyCreator { - public static byte[] create(KeyParameter macKey, byte[] additionalData, byte[] ciphertext) { - Poly1305 poly = new Poly1305(); - poly.init(macKey); - - if (additionalData != null) { - poly.update(additionalData, 0, additionalData.length); - if (additionalData.length % 16 != 0) { - int round = 16-(additionalData.length%16); - poly.update(new byte[round], 0, round); - } - } - - poly.update(ciphertext, 0, ciphertext.length); - if (ciphertext.length % 16 != 0) { - int round = 16-(ciphertext.length%16); - poly.update(new byte[round], 0, round); - } - - //additional data length - byte[] additionalDataLength; - if (additionalData != null) { - additionalDataLength = Pack.longToLittleEndian(additionalData.length); - } else { - additionalDataLength = new byte[8]; - } - poly.update(additionalDataLength, 0, 8); - byte[] ciphertextLength = Pack.longToLittleEndian(ciphertext.length); - poly.update(ciphertextLength, 0, 8); - - byte[] calculatedMAC = new byte[poly.getMacSize()]; - poly.doFinal(calculatedMAC, 0); - return calculatedMAC; - } + public static byte[] create(KeyParameter macKey, byte[] additionalData, byte[] ciphertext) { + Poly1305 poly = new Poly1305(); + poly.init(macKey); + + if (additionalData != null) { + poly.update(additionalData, 0, additionalData.length); + if (additionalData.length % 16 != 0) { + int round = 16 - (additionalData.length % 16); + poly.update(new byte[round], 0, round); + } + } + + poly.update(ciphertext, 0, ciphertext.length); + if (ciphertext.length % 16 != 0) { + int round = 16 - (ciphertext.length % 16); + poly.update(new byte[round], 0, round); + } + + // additional data length + byte[] additionalDataLength; + if (additionalData != null) { + additionalDataLength = Pack.longToLittleEndian(additionalData.length); + } else { + additionalDataLength = new byte[8]; + } + poly.update(additionalDataLength, 0, 8); + byte[] ciphertextLength = Pack.longToLittleEndian(ciphertext.length); + poly.update(ciphertextLength, 0, 8); + + byte[] calculatedMAC = new byte[poly.getMacSize()]; + poly.doFinal(calculatedMAC, 0); + return calculatedMAC; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/http/HomekitClientConnection.java b/src/main/java/com/beowulfe/hap/impl/http/HomekitClientConnection.java index 663834ee5..1ec53496c 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/HomekitClientConnection.java +++ b/src/main/java/com/beowulfe/hap/impl/http/HomekitClientConnection.java @@ -4,14 +4,13 @@ public interface HomekitClientConnection { - HttpResponse handleRequest(HttpRequest request) throws IOException; + HttpResponse handleRequest(HttpRequest request) throws IOException; - byte[] decryptRequest(byte[] ciphertext); - - byte[] encryptResponse(byte[] plaintext) throws IOException; - - void close(); + byte[] decryptRequest(byte[] ciphertext); - void outOfBand(HttpResponse message); - + byte[] encryptResponse(byte[] plaintext) throws IOException; + + void close(); + + void outOfBand(HttpResponse message); } diff --git a/src/main/java/com/beowulfe/hap/impl/http/HomekitClientConnectionFactory.java b/src/main/java/com/beowulfe/hap/impl/http/HomekitClientConnectionFactory.java index 1e2c434f1..e5236d0e8 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/HomekitClientConnectionFactory.java +++ b/src/main/java/com/beowulfe/hap/impl/http/HomekitClientConnectionFactory.java @@ -4,6 +4,5 @@ public interface HomekitClientConnectionFactory { - HomekitClientConnection createConnection(Consumer outOfBandMessageCallback); - + HomekitClientConnection createConnection(Consumer outOfBandMessageCallback); } diff --git a/src/main/java/com/beowulfe/hap/impl/http/HttpMethod.java b/src/main/java/com/beowulfe/hap/impl/http/HttpMethod.java index 7653b8336..4c91a80f7 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/HttpMethod.java +++ b/src/main/java/com/beowulfe/hap/impl/http/HttpMethod.java @@ -1,8 +1,7 @@ package com.beowulfe.hap.impl.http; public enum HttpMethod { - - GET, - POST, - PUT + GET, + POST, + PUT } diff --git a/src/main/java/com/beowulfe/hap/impl/http/HttpRequest.java b/src/main/java/com/beowulfe/hap/impl/http/HttpRequest.java index 22498a049..f6989d81b 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/HttpRequest.java +++ b/src/main/java/com/beowulfe/hap/impl/http/HttpRequest.java @@ -2,8 +2,9 @@ public interface HttpRequest { - String getUri(); - byte[] getBody(); - HttpMethod getMethod(); - + String getUri(); + + byte[] getBody(); + + HttpMethod getMethod(); } diff --git a/src/main/java/com/beowulfe/hap/impl/http/HttpResponse.java b/src/main/java/com/beowulfe/hap/impl/http/HttpResponse.java index 03f0a5448..328f8e795 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/HttpResponse.java +++ b/src/main/java/com/beowulfe/hap/impl/http/HttpResponse.java @@ -6,24 +6,26 @@ public interface HttpResponse { - int getStatusCode(); - - default ByteBuffer getBody() { - return ByteBuffer.allocate(0); - } - - default HttpVersion getVersion() { - return HttpVersion.HTTP_1_1; - } - - default Map getHeaders() { - return Collections.emptyMap(); - } - - default boolean doUpgrade() { return false; } - - public enum HttpVersion { - HTTP_1_1, - EVENT_1_0 - } + int getStatusCode(); + + default ByteBuffer getBody() { + return ByteBuffer.allocate(0); + } + + default HttpVersion getVersion() { + return HttpVersion.HTTP_1_1; + } + + default Map getHeaders() { + return Collections.emptyMap(); + } + + default boolean doUpgrade() { + return false; + } + + public enum HttpVersion { + HTTP_1_1, + EVENT_1_0 + } } diff --git a/src/main/java/com/beowulfe/hap/impl/http/impl/AccessoryHandler.java b/src/main/java/com/beowulfe/hap/impl/http/impl/AccessoryHandler.java index 2a3e3715c..f8673eef2 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/impl/AccessoryHandler.java +++ b/src/main/java/com/beowulfe/hap/impl/http/impl/AccessoryHandler.java @@ -9,90 +9,96 @@ import io.netty.channel.ChannelPipeline; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.IOException; import java.nio.charset.StandardCharsets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; class AccessoryHandler extends SimpleChannelInboundHandler { - private final static Logger LOGGER = LoggerFactory.getLogger(AccessoryHandler.class); - - private HomekitClientConnection connection; - private final HomekitClientConnectionFactory homekitClientConnectionFactory; - - public AccessoryHandler(HomekitClientConnectionFactory homekitClientConnectionFactory) { - this.homekitClientConnectionFactory = homekitClientConnectionFactory; - } - - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - final Channel channel = ctx.pipeline().channel(); - this.connection = homekitClientConnectionFactory.createConnection(response -> { - if (!channel.isActive()) { return; } - channel.writeAndFlush(NettyResponseUtil.createResponse(response)); - }); - LOGGER.info("New homekit connection from "+ctx.channel().remoteAddress().toString()); - super.channelActive(ctx); - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - LOGGER.info("Terminated homekit connection from "+ctx.channel().remoteAddress().toString()); - super.channelInactive(ctx); - } + private static final Logger LOGGER = LoggerFactory.getLogger(AccessoryHandler.class); + + private HomekitClientConnection connection; + private final HomekitClientConnectionFactory homekitClientConnectionFactory; + + public AccessoryHandler(HomekitClientConnectionFactory homekitClientConnectionFactory) { + this.homekitClientConnectionFactory = homekitClientConnectionFactory; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + final Channel channel = ctx.pipeline().channel(); + this.connection = + homekitClientConnectionFactory.createConnection( + response -> { + if (!channel.isActive()) { + return; + } + channel.writeAndFlush(NettyResponseUtil.createResponse(response)); + }); + LOGGER.info("New homekit connection from " + ctx.channel().remoteAddress().toString()); + super.channelActive(ctx); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + LOGGER.info("Terminated homekit connection from " + ctx.channel().remoteAddress().toString()); + super.channelInactive(ctx); + } + + @Override + public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception { + try { + HttpResponse response = connection.handleRequest(new FullRequestHttpRequestImpl(req)); + if (response.doUpgrade()) { + ChannelPipeline pipeline = ctx.channel().pipeline(); + pipeline.addBefore( + ServerInitializer.HTTP_HANDLER_NAME, "binary", new BinaryHandler(connection)); + } + sendResponse(response, ctx); + } catch (Exception e) { + LOGGER.error("Error handling homekit http request", e); + sendResponse(HttpResponseStatus.INTERNAL_SERVER_ERROR, "Error: " + e.getMessage(), ctx); + } + } + + private void sendResponse( + HttpResponseStatus status, String responseBody, ChannelHandlerContext ctx) { + if (responseBody == null) { + responseBody = ""; + } + FullHttpResponse response = + new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + status, + Unpooled.copiedBuffer(responseBody.getBytes(StandardCharsets.UTF_8))); + response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain"); + response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes()); + response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); + ctx.write(response); + ctx.flush(); + } + + private void sendResponse(HttpResponse homekitResponse, ChannelHandlerContext ctx) { + FullHttpResponse response = NettyResponseUtil.createResponse(homekitResponse); + ctx.write(response); + ctx.flush(); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + ctx.flush(); + super.channelReadComplete(ctx); + } - @Override - public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) - throws Exception { - try { - HttpResponse response = connection.handleRequest(new FullRequestHttpRequestImpl(req)); - if (response.doUpgrade()) { - ChannelPipeline pipeline = ctx.channel().pipeline(); - pipeline.addBefore(ServerInitializer.HTTP_HANDLER_NAME, "binary", new BinaryHandler(connection)); - } - sendResponse(response, ctx); - } catch (Exception e) { - LOGGER.error("Error handling homekit http request", e); - sendResponse(HttpResponseStatus.INTERNAL_SERVER_ERROR, "Error: "+e.getMessage(), ctx); - } - } - - private void sendResponse(HttpResponseStatus status, String responseBody, ChannelHandlerContext ctx) { - if (responseBody == null) { - responseBody = ""; - } - FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, - Unpooled.copiedBuffer(responseBody.getBytes(StandardCharsets.UTF_8))); - response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain"); - response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes()); - response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); - ctx.write(response); - ctx.flush(); - } - - private void sendResponse(HttpResponse homekitResponse, ChannelHandlerContext ctx) { - FullHttpResponse response = NettyResponseUtil.createResponse(homekitResponse); - ctx.write(response); - ctx.flush(); - } - - @Override - public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { - ctx.flush(); - super.channelReadComplete(ctx); - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) - throws Exception { - boolean errorLevel = !(cause instanceof IOException); - if (errorLevel) { - LOGGER.error("Exception caught in web handler", cause); - } else { - LOGGER.debug("Exception caught in web handler", cause); - } - ctx.close(); - } + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + boolean errorLevel = !(cause instanceof IOException); + if (errorLevel) { + LOGGER.error("Exception caught in web handler", cause); + } else { + LOGGER.debug("Exception caught in web handler", cause); + } + ctx.close(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/http/impl/BinaryHandler.java b/src/main/java/com/beowulfe/hap/impl/http/impl/BinaryHandler.java index 4e75f592d..7723d090e 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/impl/BinaryHandler.java +++ b/src/main/java/com/beowulfe/hap/impl/http/impl/BinaryHandler.java @@ -5,71 +5,70 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageCodec; -import org.apache.commons.io.HexDump; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; +import org.apache.commons.io.HexDump; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class BinaryHandler extends ByteToMessageCodec { - - private final static Logger logger = LoggerFactory.getLogger(BinaryHandler.class); - private final HomekitClientConnection connection; - private boolean started = false; - - public BinaryHandler(HomekitClientConnection connection) { - this.connection = connection; - } + private static final Logger logger = LoggerFactory.getLogger(BinaryHandler.class); + + private final HomekitClientConnection connection; + private boolean started = false; + + public BinaryHandler(HomekitClientConnection connection) { + this.connection = connection; + } + + @Override + protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception { + if (started) { + byte[] b = new byte[msg.readableBytes()]; + msg.readBytes(b); + traceData("Sending data", b, ctx); + out.writeBytes(connection.encryptResponse(b)); + } else { + out.writeBytes(msg); + } + } - @Override - protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) - throws Exception { - if (started) { - byte[] b = new byte[msg.readableBytes()]; - msg.readBytes(b); - traceData("Sending data", b, ctx); - out.writeBytes(connection.encryptResponse(b)); - } else { - out.writeBytes(msg); - } - } + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + byte[] b = new byte[in.readableBytes()]; + in.readBytes(b); + byte[] decrypted = connection.decryptRequest(b); + traceData("Received data", decrypted, ctx); + out.add(Unpooled.copiedBuffer(decrypted)); + started = true; + } - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, - List out) throws Exception { - byte[] b = new byte[in.readableBytes()]; - in.readBytes(b); - byte[] decrypted = connection.decryptRequest(b); - traceData("Received data", decrypted, ctx); - out.add(Unpooled.copiedBuffer(decrypted)); - started = true; - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) - throws Exception { - boolean errorLevel = !(cause instanceof IOException); - if (errorLevel) { - logger.error("Exception in binary handler", cause); - } else { - logger.debug("Exception in binary handler", cause); - } - super.exceptionCaught(ctx, cause); - } - - private void traceData(String msg, byte[] b, ChannelHandlerContext ctx) throws Exception { - if (logger.isTraceEnabled() && b.length > 0) { - try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) { - HexDump.dump(b, 0, stream, 0); - stream.flush(); - logger.trace(String.format("%s [%s]:%n%s%n", msg, ctx.channel().remoteAddress().toString(), - stream.toString(StandardCharsets.UTF_8.name()))); - } - } - } + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + boolean errorLevel = !(cause instanceof IOException); + if (errorLevel) { + logger.error("Exception in binary handler", cause); + } else { + logger.debug("Exception in binary handler", cause); + } + super.exceptionCaught(ctx, cause); + } + private void traceData(String msg, byte[] b, ChannelHandlerContext ctx) throws Exception { + if (logger.isTraceEnabled() && b.length > 0) { + try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) { + HexDump.dump(b, 0, stream, 0); + stream.flush(); + logger.trace( + String.format( + "%s [%s]:%n%s%n", + msg, + ctx.channel().remoteAddress().toString(), + stream.toString(StandardCharsets.UTF_8.name()))); + } + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/http/impl/DefaultHttpRequestImpl.java b/src/main/java/com/beowulfe/hap/impl/http/impl/DefaultHttpRequestImpl.java index f9fde2226..5725ec985 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/impl/DefaultHttpRequestImpl.java +++ b/src/main/java/com/beowulfe/hap/impl/http/impl/DefaultHttpRequestImpl.java @@ -5,34 +5,33 @@ class DefaultHttpRequestImpl implements HttpRequest { - private final io.netty.handler.codec.http.HttpRequest request; - - public DefaultHttpRequestImpl(io.netty.handler.codec.http.HttpRequest request) { - this.request = request; - } - - @Override - public String getUri() { - return request.getUri(); - } + private final io.netty.handler.codec.http.HttpRequest request; - @Override - public byte[] getBody() { - return new byte[0]; - } - - @Override - public HttpMethod getMethod() { - io.netty.handler.codec.http.HttpMethod method = request.getMethod(); - if (method.equals(io.netty.handler.codec.http.HttpMethod.GET)) { - return HttpMethod.GET; - } else if (method.equals(io.netty.handler.codec.http.HttpMethod.POST)) { - return HttpMethod.POST; - } else if (method.equals(io.netty.handler.codec.http.HttpMethod.PUT)) { - return HttpMethod.PUT; - } else { - throw new RuntimeException("Unrecognized method: "+method.toString()); - } - } + public DefaultHttpRequestImpl(io.netty.handler.codec.http.HttpRequest request) { + this.request = request; + } + @Override + public String getUri() { + return request.getUri(); + } + + @Override + public byte[] getBody() { + return new byte[0]; + } + + @Override + public HttpMethod getMethod() { + io.netty.handler.codec.http.HttpMethod method = request.getMethod(); + if (method.equals(io.netty.handler.codec.http.HttpMethod.GET)) { + return HttpMethod.GET; + } else if (method.equals(io.netty.handler.codec.http.HttpMethod.POST)) { + return HttpMethod.POST; + } else if (method.equals(io.netty.handler.codec.http.HttpMethod.PUT)) { + return HttpMethod.PUT; + } else { + throw new RuntimeException("Unrecognized method: " + method.toString()); + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/http/impl/FullRequestHttpRequestImpl.java b/src/main/java/com/beowulfe/hap/impl/http/impl/FullRequestHttpRequestImpl.java index 2a455fdfb..5acaad387 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/impl/FullRequestHttpRequestImpl.java +++ b/src/main/java/com/beowulfe/hap/impl/http/impl/FullRequestHttpRequestImpl.java @@ -3,20 +3,18 @@ import io.netty.handler.codec.http.FullHttpRequest; class FullRequestHttpRequestImpl extends DefaultHttpRequestImpl { - - private final FullHttpRequest nettyRequest; - - public FullRequestHttpRequestImpl(FullHttpRequest nettyRequest) { - super(nettyRequest); - this.nettyRequest = nettyRequest; - } + private final FullHttpRequest nettyRequest; - @Override - public byte[] getBody() { - byte[] ret = new byte[nettyRequest.content().readableBytes()]; - nettyRequest.content().readBytes(ret); - return ret; - } + public FullRequestHttpRequestImpl(FullHttpRequest nettyRequest) { + super(nettyRequest); + this.nettyRequest = nettyRequest; + } + @Override + public byte[] getBody() { + byte[] ret = new byte[nettyRequest.content().readableBytes()]; + nettyRequest.content().readBytes(ret); + return ret; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/http/impl/HomekitHttpServer.java b/src/main/java/com/beowulfe/hap/impl/http/impl/HomekitHttpServer.java index 547114c26..189b82e46 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/impl/HomekitHttpServer.java +++ b/src/main/java/com/beowulfe/hap/impl/http/impl/HomekitHttpServer.java @@ -1,41 +1,39 @@ package com.beowulfe.hap.impl.http.impl; -import java.util.concurrent.CompletableFuture; - import com.beowulfe.hap.impl.HomekitWebHandler; import com.beowulfe.hap.impl.http.HomekitClientConnectionFactory; +import java.util.concurrent.CompletableFuture; public class HomekitHttpServer implements HomekitWebHandler { - private NettyHomekitHttpService service = null; - private final int port; - private final int nThreads; - - @Override - public void stop() { - if (this.service != null) { - this.service.shutdown(); - } - } - - public HomekitHttpServer(int port, int nThreads) { - this.port = port; - this.nThreads = nThreads; - } - - @Override - public CompletableFuture start(HomekitClientConnectionFactory clientConnectionFactory) { - if (service == null) { - this.service = NettyHomekitHttpService.create(port, nThreads); - return this.service.create(clientConnectionFactory); - } else { - throw new RuntimeException("HomekitHttpServer can only be started once"); - } - } - - @Override - public void resetConnections() { - service.resetConnections(); - } - + private NettyHomekitHttpService service = null; + private final int port; + private final int nThreads; + + @Override + public void stop() { + if (this.service != null) { + this.service.shutdown(); + } + } + + public HomekitHttpServer(int port, int nThreads) { + this.port = port; + this.nThreads = nThreads; + } + + @Override + public CompletableFuture start(HomekitClientConnectionFactory clientConnectionFactory) { + if (service == null) { + this.service = NettyHomekitHttpService.create(port, nThreads); + return this.service.create(clientConnectionFactory); + } else { + throw new RuntimeException("HomekitHttpServer can only be started once"); + } + } + + @Override + public void resetConnections() { + service.resetConnections(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/http/impl/HttpResponseEncoderAggregate.java b/src/main/java/com/beowulfe/hap/impl/http/impl/HttpResponseEncoderAggregate.java index d1ae6d278..34460127d 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/impl/HttpResponseEncoderAggregate.java +++ b/src/main/java/com/beowulfe/hap/impl/http/impl/HttpResponseEncoderAggregate.java @@ -3,24 +3,21 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.HttpResponseEncoder; - import java.util.Iterator; import java.util.List; public class HttpResponseEncoderAggregate extends HttpResponseEncoder { - @Override - protected void encode(ChannelHandlerContext ctx, Object msg, - List out) throws Exception { - super.encode(ctx, msg, out); - if (out.size() > 0) { - Iterator i = out.iterator(); - ByteBuf b = (ByteBuf) i.next(); - while (i.hasNext()) { - b.writeBytes((ByteBuf) i.next()); - i.remove(); - } - } - } - + @Override + protected void encode(ChannelHandlerContext ctx, Object msg, List out) throws Exception { + super.encode(ctx, msg, out); + if (out.size() > 0) { + Iterator i = out.iterator(); + ByteBuf b = (ByteBuf) i.next(); + while (i.hasNext()) { + b.writeBytes((ByteBuf) i.next()); + i.remove(); + } + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/http/impl/LoggingHandler.java b/src/main/java/com/beowulfe/hap/impl/http/impl/LoggingHandler.java index c6fc56a15..eee9b2e9b 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/impl/LoggingHandler.java +++ b/src/main/java/com/beowulfe/hap/impl/http/impl/LoggingHandler.java @@ -2,47 +2,49 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.*; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; - import org.apache.commons.io.HexDump; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LoggingHandler extends ChannelDuplexHandler { - - private final static Logger logger = LoggerFactory.getLogger(NettyHomekitHttpService.class); - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) - throws Exception { - if (logger.isTraceEnabled() && msg instanceof ByteBuf) { - logBytes("READ", (ByteBuf) msg, ctx); - } - super.channelRead(ctx, msg); - } - - @Override - public void write(ChannelHandlerContext ctx, Object msg, - ChannelPromise promise) throws Exception { - if (logger.isTraceEnabled() && msg instanceof ByteBuf) { - logBytes("WRITE", (ByteBuf) msg, ctx); - } - super.write(ctx, msg, promise); - } - - private void logBytes(String type, ByteBuf buf, ChannelHandlerContext ctx) throws IOException { - if (buf.readableBytes() > 0) { - try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) { - byte[] bytes = new byte[buf.readableBytes()]; - buf.getBytes(0, bytes, 0, bytes.length); - HexDump.dump(bytes, 0, stream, 0); - stream.flush(); - logger.trace(String.format("%s %s [%s]:%n%s%n", type, buf, ctx.channel().remoteAddress().toString(), - stream.toString(StandardCharsets.UTF_8.name()))); - } - } - } + private static final Logger logger = LoggerFactory.getLogger(NettyHomekitHttpService.class); + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if (logger.isTraceEnabled() && msg instanceof ByteBuf) { + logBytes("READ", (ByteBuf) msg, ctx); + } + super.channelRead(ctx, msg); + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) + throws Exception { + if (logger.isTraceEnabled() && msg instanceof ByteBuf) { + logBytes("WRITE", (ByteBuf) msg, ctx); + } + super.write(ctx, msg, promise); + } + + private void logBytes(String type, ByteBuf buf, ChannelHandlerContext ctx) throws IOException { + if (buf.readableBytes() > 0) { + try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) { + byte[] bytes = new byte[buf.readableBytes()]; + buf.getBytes(0, bytes, 0, bytes.length); + HexDump.dump(bytes, 0, stream, 0); + stream.flush(); + logger.trace( + String.format( + "%s %s [%s]:%n%s%n", + type, + buf, + ctx.channel().remoteAddress().toString(), + stream.toString(StandardCharsets.UTF_8.name()))); + } + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/http/impl/NettyHomekitHttpService.java b/src/main/java/com/beowulfe/hap/impl/http/impl/NettyHomekitHttpService.java index 4dd8bd166..1247c3936 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/impl/NettyHomekitHttpService.java +++ b/src/main/java/com/beowulfe/hap/impl/http/impl/NettyHomekitHttpService.java @@ -1,5 +1,6 @@ package com.beowulfe.hap.impl.http.impl; +import com.beowulfe.hap.impl.http.HomekitClientConnectionFactory; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.group.ChannelGroup; @@ -9,76 +10,73 @@ import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import io.netty.util.concurrent.*; - import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.concurrent.CompletableFuture; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.beowulfe.hap.impl.http.HomekitClientConnectionFactory; - class NettyHomekitHttpService { - private final EventLoopGroup bossGroup; - private final EventLoopGroup workerGroup; - - private final static Logger logger = LoggerFactory.getLogger(NettyHomekitHttpService.class); - private final ChannelGroup allChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); - private final int port; - private final int nThreads; - - public static NettyHomekitHttpService create(int port, int nThreads) { - return new NettyHomekitHttpService(port, nThreads); - } - - private NettyHomekitHttpService(int port, int nThreads) { - bossGroup = new NioEventLoopGroup(); - workerGroup = new NioEventLoopGroup(); - this.port = port; - this.nThreads = nThreads; - } - - public CompletableFuture create(HomekitClientConnectionFactory connectionFactory) { - final CompletableFuture portFuture = new CompletableFuture(); - ServerBootstrap b = new ServerBootstrap(); - b.group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .handler(new LoggingHandler(LogLevel.INFO)) - .childHandler(new ServerInitializer(connectionFactory, allChannels, nThreads)) - .option(ChannelOption.SO_BACKLOG, 128) - .childOption(ChannelOption.SO_KEEPALIVE, true); - final ChannelFuture bindFuture = b.bind(port); - bindFuture.addListener(new GenericFutureListener>() { + private final EventLoopGroup bossGroup; + private final EventLoopGroup workerGroup; + + private static final Logger logger = LoggerFactory.getLogger(NettyHomekitHttpService.class); + private final ChannelGroup allChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); + private final int port; + private final int nThreads; + + public static NettyHomekitHttpService create(int port, int nThreads) { + return new NettyHomekitHttpService(port, nThreads); + } + + private NettyHomekitHttpService(int port, int nThreads) { + bossGroup = new NioEventLoopGroup(); + workerGroup = new NioEventLoopGroup(); + this.port = port; + this.nThreads = nThreads; + } + + public CompletableFuture create(HomekitClientConnectionFactory connectionFactory) { + final CompletableFuture portFuture = new CompletableFuture(); + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new ServerInitializer(connectionFactory, allChannels, nThreads)) + .option(ChannelOption.SO_BACKLOG, 128) + .childOption(ChannelOption.SO_KEEPALIVE, true); + final ChannelFuture bindFuture = b.bind(port); + bindFuture.addListener( + new GenericFutureListener>() { - @Override - public void operationComplete(Future future) - throws Exception { - try { - future.get(); - SocketAddress socketAddress = bindFuture.channel().localAddress(); - if (socketAddress instanceof InetSocketAddress) { - logger.info("Bound homekit listener to "+socketAddress.toString()); - portFuture.complete(((InetSocketAddress) socketAddress).getPort()); - } else { - throw new RuntimeException("Unknown socket address type: "+socketAddress.getClass().getName()); - } - } catch (Exception e) { - portFuture.completeExceptionally(e); - } - } - }); - return portFuture; - } + @Override + public void operationComplete(Future future) throws Exception { + try { + future.get(); + SocketAddress socketAddress = bindFuture.channel().localAddress(); + if (socketAddress instanceof InetSocketAddress) { + logger.info("Bound homekit listener to " + socketAddress.toString()); + portFuture.complete(((InetSocketAddress) socketAddress).getPort()); + } else { + throw new RuntimeException( + "Unknown socket address type: " + socketAddress.getClass().getName()); + } + } catch (Exception e) { + portFuture.completeExceptionally(e); + } + } + }); + return portFuture; + } - public void shutdown() { - workerGroup.shutdownGracefully(); - bossGroup.shutdownGracefully(); - } + public void shutdown() { + workerGroup.shutdownGracefully(); + bossGroup.shutdownGracefully(); + } - public void resetConnections() { - logger.info("Resetting connections"); - allChannels.close(); - } + public void resetConnections() { + logger.info("Resetting connections"); + allChannels.close(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/http/impl/NettyResponseUtil.java b/src/main/java/com/beowulfe/hap/impl/http/impl/NettyResponseUtil.java index 3eaafcc58..71e897427 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/impl/NettyResponseUtil.java +++ b/src/main/java/com/beowulfe/hap/impl/http/impl/NettyResponseUtil.java @@ -1,32 +1,32 @@ package com.beowulfe.hap.impl.http.impl; +import com.beowulfe.hap.impl.http.HttpResponse; import io.netty.buffer.Unpooled; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; - import java.util.Map.Entry; -import com.beowulfe.hap.impl.http.HttpResponse; - class NettyResponseUtil { - private static final HttpVersion EVENT_VERSION = new HttpVersion("EVENT", 1, 0, true); - - public static FullHttpResponse createResponse(HttpResponse homekitResponse) { - - FullHttpResponse response = new DefaultFullHttpResponse( - homekitResponse.getVersion() == HttpResponse.HttpVersion.EVENT_1_0 ? EVENT_VERSION : HttpVersion.HTTP_1_1, - HttpResponseStatus.valueOf(homekitResponse.getStatusCode()), - Unpooled.copiedBuffer(homekitResponse.getBody())); - for (Entry header: homekitResponse.getHeaders().entrySet()) { - response.headers().add(header.getKey(), header.getValue()); - } - response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes()); - response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); - return response; - } + private static final HttpVersion EVENT_VERSION = new HttpVersion("EVENT", 1, 0, true); + + public static FullHttpResponse createResponse(HttpResponse homekitResponse) { + FullHttpResponse response = + new DefaultFullHttpResponse( + homekitResponse.getVersion() == HttpResponse.HttpVersion.EVENT_1_0 + ? EVENT_VERSION + : HttpVersion.HTTP_1_1, + HttpResponseStatus.valueOf(homekitResponse.getStatusCode()), + Unpooled.copiedBuffer(homekitResponse.getBody())); + for (Entry header : homekitResponse.getHeaders().entrySet()) { + response.headers().add(header.getKey(), header.getValue()); + } + response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes()); + response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); + return response; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/http/impl/ServerInitializer.java b/src/main/java/com/beowulfe/hap/impl/http/impl/ServerInitializer.java index 031909917..5026bf2cf 100644 --- a/src/main/java/com/beowulfe/hap/impl/http/impl/ServerInitializer.java +++ b/src/main/java/com/beowulfe/hap/impl/http/impl/ServerInitializer.java @@ -1,5 +1,6 @@ package com.beowulfe.hap.impl.http.impl; +import com.beowulfe.hap.impl.http.HomekitClientConnectionFactory; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.group.ChannelGroup; @@ -9,33 +10,31 @@ import io.netty.util.concurrent.DefaultEventExecutorGroup; import io.netty.util.concurrent.EventExecutorGroup; -import com.beowulfe.hap.impl.http.HomekitClientConnectionFactory; - class ServerInitializer extends ChannelInitializer { - private static final int MAX_POST = 1000000; - - public static final String HTTP_HANDLER_NAME = "http"; - - private final HomekitClientConnectionFactory homekit; - private final ChannelGroup allChannels; - private final EventExecutorGroup blockingExecutorGroup; - - public ServerInitializer(HomekitClientConnectionFactory homekit, ChannelGroup allChannels, int nThreads) { - this.homekit = homekit; - this.allChannels = allChannels; - this.blockingExecutorGroup = new DefaultEventExecutorGroup(nThreads); - } - - @Override - protected void initChannel(SocketChannel ch) throws Exception { - ChannelPipeline pipeline = ch.pipeline(); - pipeline.addLast(new LoggingHandler()); - pipeline.addLast(HTTP_HANDLER_NAME, new HttpResponseEncoderAggregate()); - pipeline.addLast(new HttpRequestDecoder()); - pipeline.addLast(new HttpObjectAggregator(MAX_POST)); - pipeline.addLast(blockingExecutorGroup, new AccessoryHandler(homekit)); - allChannels.add(ch); - } + private static final int MAX_POST = 1000000; + + public static final String HTTP_HANDLER_NAME = "http"; + + private final HomekitClientConnectionFactory homekit; + private final ChannelGroup allChannels; + private final EventExecutorGroup blockingExecutorGroup; + + public ServerInitializer( + HomekitClientConnectionFactory homekit, ChannelGroup allChannels, int nThreads) { + this.homekit = homekit; + this.allChannels = allChannels; + this.blockingExecutorGroup = new DefaultEventExecutorGroup(nThreads); + } + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + pipeline.addLast(new LoggingHandler()); + pipeline.addLast(HTTP_HANDLER_NAME, new HttpResponseEncoderAggregate()); + pipeline.addLast(new HttpRequestDecoder()); + pipeline.addLast(new HttpObjectAggregator(MAX_POST)); + pipeline.addLast(blockingExecutorGroup, new AccessoryHandler(homekit)); + allChannels.add(ch); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/jmdns/JmdnsHomekitAdvertiser.java b/src/main/java/com/beowulfe/hap/impl/jmdns/JmdnsHomekitAdvertiser.java index 5520c9c3f..8eea15ce8 100644 --- a/src/main/java/com/beowulfe/hap/impl/jmdns/JmdnsHomekitAdvertiser.java +++ b/src/main/java/com/beowulfe/hap/impl/jmdns/JmdnsHomekitAdvertiser.java @@ -5,88 +5,89 @@ import java.net.UnknownHostException; import java.util.HashMap; import java.util.Map; - import javax.jmdns.JmDNS; import javax.jmdns.ServiceInfo; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class JmdnsHomekitAdvertiser { - - private static final String SERVICE_TYPE = "_hap._tcp.local."; - - private final JmDNS jmdns; - private boolean discoverable = true; - private final static Logger logger = LoggerFactory.getLogger(JmdnsHomekitAdvertiser.class); - private boolean isAdvertising = false; - - private String label; - private String mac; - private int port; - private int configurationIndex; - - public JmdnsHomekitAdvertiser(InetAddress localAddress) throws UnknownHostException, IOException { - jmdns = JmDNS.create(localAddress); - } - public synchronized void advertise(String label, String mac, int port, int configurationIndex) throws Exception { - if (isAdvertising) { - throw new IllegalStateException("Homekit advertiser is already running"); - } - this.label = label; - this.mac = mac; - this.port = port; - this.configurationIndex = configurationIndex; - - logger.info("Advertising accessory "+label); - - registerService(); - - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - logger.info("Stopping advertising in response to shutdown."); - jmdns.unregisterAllServices(); - })); - isAdvertising = true; - } - - public synchronized void stop() { - jmdns.unregisterAllServices(); - } - - public synchronized void setDiscoverable(boolean discoverable) throws IOException { - if (this.discoverable != discoverable) { - this.discoverable = discoverable; - if (isAdvertising) { - logger.info("Re-creating service due to change in discoverability to "+discoverable); - jmdns.unregisterAllServices(); - registerService(); - } - } - } - - public synchronized void setConfigurationIndex(int revision) throws IOException { - if (this.configurationIndex != revision) { - this.configurationIndex = revision; - if (isAdvertising) { - logger.info("Re-creating service due to change in configuration index to "+revision); - jmdns.unregisterAllServices(); - registerService(); - } - } - } - - private void registerService() throws IOException { - logger.info("Registering "+SERVICE_TYPE+" on port "+port); - Map props = new HashMap<>(); - props.put("sf", discoverable ? "1" : "0"); - props.put("id", mac); - props.put("md", label); - props.put("c#", Integer.toString(configurationIndex)); - props.put("s#", "1"); - props.put("ff", "0"); - props.put("ci", "1"); - jmdns.registerService(ServiceInfo.create(SERVICE_TYPE, label, port, 1, 1, props)); - } - + private static final String SERVICE_TYPE = "_hap._tcp.local."; + + private final JmDNS jmdns; + private boolean discoverable = true; + private static final Logger logger = LoggerFactory.getLogger(JmdnsHomekitAdvertiser.class); + private boolean isAdvertising = false; + + private String label; + private String mac; + private int port; + private int configurationIndex; + + public JmdnsHomekitAdvertiser(InetAddress localAddress) throws UnknownHostException, IOException { + jmdns = JmDNS.create(localAddress); + } + + public synchronized void advertise(String label, String mac, int port, int configurationIndex) + throws Exception { + if (isAdvertising) { + throw new IllegalStateException("Homekit advertiser is already running"); + } + this.label = label; + this.mac = mac; + this.port = port; + this.configurationIndex = configurationIndex; + + logger.info("Advertising accessory " + label); + + registerService(); + + Runtime.getRuntime() + .addShutdownHook( + new Thread( + () -> { + logger.info("Stopping advertising in response to shutdown."); + jmdns.unregisterAllServices(); + })); + isAdvertising = true; + } + + public synchronized void stop() { + jmdns.unregisterAllServices(); + } + + public synchronized void setDiscoverable(boolean discoverable) throws IOException { + if (this.discoverable != discoverable) { + this.discoverable = discoverable; + if (isAdvertising) { + logger.info("Re-creating service due to change in discoverability to " + discoverable); + jmdns.unregisterAllServices(); + registerService(); + } + } + } + + public synchronized void setConfigurationIndex(int revision) throws IOException { + if (this.configurationIndex != revision) { + this.configurationIndex = revision; + if (isAdvertising) { + logger.info("Re-creating service due to change in configuration index to " + revision); + jmdns.unregisterAllServices(); + registerService(); + } + } + } + + private void registerService() throws IOException { + logger.info("Registering " + SERVICE_TYPE + " on port " + port); + Map props = new HashMap<>(); + props.put("sf", discoverable ? "1" : "0"); + props.put("id", mac); + props.put("md", label); + props.put("c#", Integer.toString(configurationIndex)); + props.put("s#", "1"); + props.put("ff", "0"); + props.put("ci", "1"); + jmdns.registerService(ServiceInfo.create(SERVICE_TYPE, label, port, 1, 1, props)); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/json/AccessoryController.java b/src/main/java/com/beowulfe/hap/impl/json/AccessoryController.java index 0f92bc1ea..67304e615 100644 --- a/src/main/java/com/beowulfe/hap/impl/json/AccessoryController.java +++ b/src/main/java/com/beowulfe/hap/impl/json/AccessoryController.java @@ -1,5 +1,10 @@ package com.beowulfe.hap.impl.json; +import com.beowulfe.hap.HomekitAccessory; +import com.beowulfe.hap.Service; +import com.beowulfe.hap.characteristics.Characteristic; +import com.beowulfe.hap.impl.HomekitRegistry; +import com.beowulfe.hap.impl.http.HttpResponse; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Collection; @@ -8,77 +13,78 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.CompletableFuture; - import javax.json.Json; import javax.json.JsonArrayBuilder; import javax.json.JsonObject; import javax.json.JsonObjectBuilder; -import com.beowulfe.hap.HomekitAccessory; -import com.beowulfe.hap.Service; -import com.beowulfe.hap.characteristics.Characteristic; -import com.beowulfe.hap.impl.HomekitRegistry; -import com.beowulfe.hap.impl.http.HttpResponse; - public class AccessoryController { - private final HomekitRegistry registry; - - public AccessoryController(HomekitRegistry registry) { - this.registry = registry; - } + private final HomekitRegistry registry; + + public AccessoryController(HomekitRegistry registry) { + this.registry = registry; + } + + public HttpResponse listing() throws Exception { + JsonArrayBuilder accessories = Json.createArrayBuilder(); + + Map>> accessoryServiceFutures = new HashMap<>(); + for (HomekitAccessory accessory : registry.getAccessories()) { + int iid = 0; + List> serviceFutures = new ArrayList<>(); + for (Service service : registry.getServices(accessory.getId())) { + serviceFutures.add(toJson(service, iid)); + iid += service.getCharacteristics().size() + 1; + } + accessoryServiceFutures.put(accessory.getId(), serviceFutures); + } + + Map serviceArrayBuilders = new HashMap<>(); + for (Entry>> entry : + accessoryServiceFutures.entrySet()) { + JsonArrayBuilder arr = Json.createArrayBuilder(); + for (CompletableFuture future : entry.getValue()) { + arr.add(future.join()); + } + serviceArrayBuilders.put(entry.getKey(), arr); + } + + for (HomekitAccessory accessory : registry.getAccessories()) { + accessories.add( + Json.createObjectBuilder() + .add("aid", accessory.getId()) + .add("services", serviceArrayBuilders.get(accessory.getId()))); + } + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + Json.createWriter(baos) + .write(Json.createObjectBuilder().add("accessories", accessories).build()); + return new HapJsonResponse(baos.toByteArray()); + } + } + + private CompletableFuture toJson(Service service, int interfaceId) throws Exception { + JsonObjectBuilder builder = + Json.createObjectBuilder().add("iid", ++interfaceId).add("type", service.getType()); + List characteristics = service.getCharacteristics(); + Collection> characteristicFutures = + new ArrayList<>(characteristics.size()); + for (Characteristic characteristic : characteristics) { + characteristicFutures.add(characteristic.toJson(++interfaceId)); + } - public HttpResponse listing() throws Exception { - JsonArrayBuilder accessories = Json.createArrayBuilder(); - - Map>> accessoryServiceFutures = new HashMap<>(); - for (HomekitAccessory accessory: registry.getAccessories()) { - int iid = 0; - List> serviceFutures = new ArrayList<>(); - for (Service service: registry.getServices(accessory.getId())) { - serviceFutures.add(toJson(service, iid)); - iid += service.getCharacteristics().size() + 1; - } - accessoryServiceFutures.put(accessory.getId(), serviceFutures); - } - - Map serviceArrayBuilders = new HashMap<>(); - for (Entry>> entry: accessoryServiceFutures.entrySet()) { - JsonArrayBuilder arr = Json.createArrayBuilder(); - for (CompletableFuture future: entry.getValue()) { - arr.add(future.join()); - } - serviceArrayBuilders.put(entry.getKey(), arr); - } - - for (HomekitAccessory accessory: registry.getAccessories()) { - accessories.add(Json.createObjectBuilder().add("aid", accessory.getId()).add("services", serviceArrayBuilders.get(accessory.getId()))); - } - - try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) { - Json.createWriter(baos).write( - Json.createObjectBuilder().add("accessories", accessories).build() - ); - return new HapJsonResponse(baos.toByteArray()); - } - } - - private CompletableFuture toJson(Service service, int interfaceId) throws Exception { - JsonObjectBuilder builder = Json.createObjectBuilder() - .add("iid", ++interfaceId) - .add("type", service.getType()); - List characteristics = service.getCharacteristics(); - Collection> characteristicFutures = new ArrayList<>(characteristics.size()); - for (Characteristic characteristic: characteristics) { - characteristicFutures.add(characteristic.toJson(++interfaceId)); - } - - return CompletableFuture.allOf(characteristicFutures.toArray(new CompletableFuture[characteristicFutures.size()])) - .thenApply(v -> { - JsonArrayBuilder jsonCharacteristics = Json.createArrayBuilder(); - characteristicFutures.stream().map(future -> future.join()).forEach(c -> jsonCharacteristics.add(c)); - builder.add("characteristics", jsonCharacteristics); - return builder.build(); - }); - } + return CompletableFuture.allOf( + characteristicFutures.toArray(new CompletableFuture[characteristicFutures.size()])) + .thenApply( + v -> { + JsonArrayBuilder jsonCharacteristics = Json.createArrayBuilder(); + characteristicFutures + .stream() + .map(future -> future.join()) + .forEach(c -> jsonCharacteristics.add(c)); + builder.add("characteristics", jsonCharacteristics); + return builder.build(); + }); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/json/CharacteristicsController.java b/src/main/java/com/beowulfe/hap/impl/json/CharacteristicsController.java index 343ddd0fa..820cab5c8 100644 --- a/src/main/java/com/beowulfe/hap/impl/json/CharacteristicsController.java +++ b/src/main/java/com/beowulfe/hap/impl/json/CharacteristicsController.java @@ -8,84 +8,89 @@ import com.beowulfe.hap.impl.http.HttpRequest; import com.beowulfe.hap.impl.http.HttpResponse; import com.beowulfe.hap.impl.responses.NotFoundResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.json.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.Map; +import javax.json.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class CharacteristicsController { - - Logger logger = LoggerFactory.getLogger(CharacteristicsController.class); - private final HomekitRegistry registry; - private final SubscriptionManager subscriptions; - - public CharacteristicsController(HomekitRegistry registry, SubscriptionManager subscriptions) { - this.registry = registry; - this.subscriptions = subscriptions; - } + Logger logger = LoggerFactory.getLogger(CharacteristicsController.class); + + private final HomekitRegistry registry; + private final SubscriptionManager subscriptions; + + public CharacteristicsController(HomekitRegistry registry, SubscriptionManager subscriptions) { + this.registry = registry; + this.subscriptions = subscriptions; + } - public HttpResponse get(HttpRequest request) throws Exception { - String uri = request.getUri(); - // Characteristics are requested with /characteristics?id=1.1,2.1,3.1 - String query = uri.substring("/characteristics?id=".length()); - String[] ids = query.split(","); - JsonArrayBuilder characteristics = Json.createArrayBuilder(); - for (String id : ids) { - String[] parts = id.split("\\."); - if (parts.length != 2) { - logger.error("Unexpected characteristics request: " + uri); - return new NotFoundResponse(); - } - int aid = Integer.parseInt(parts[0]); - int iid = Integer.parseInt(parts[1]); - JsonObjectBuilder characteristic = Json.createObjectBuilder(); - Map characteristicMap = registry.getCharacteristics(aid); - if (!characteristicMap.isEmpty()) { - Characteristic targetCharacteristic = characteristicMap.get(iid); - if (targetCharacteristic != null) { - targetCharacteristic.supplyValue(characteristic); + public HttpResponse get(HttpRequest request) throws Exception { + String uri = request.getUri(); + // Characteristics are requested with /characteristics?id=1.1,2.1,3.1 + String query = uri.substring("/characteristics?id=".length()); + String[] ids = query.split(","); + JsonArrayBuilder characteristics = Json.createArrayBuilder(); + for (String id : ids) { + String[] parts = id.split("\\."); + if (parts.length != 2) { + logger.error("Unexpected characteristics request: " + uri); + return new NotFoundResponse(); + } + int aid = Integer.parseInt(parts[0]); + int iid = Integer.parseInt(parts[1]); + JsonObjectBuilder characteristic = Json.createObjectBuilder(); + Map characteristicMap = registry.getCharacteristics(aid); + if (!characteristicMap.isEmpty()) { + Characteristic targetCharacteristic = characteristicMap.get(iid); + if (targetCharacteristic != null) { + targetCharacteristic.supplyValue(characteristic); - characteristics.add(characteristic.add("aid", aid).add("iid", iid).build()); - } else { - logger.warn("Accessory " + aid + " does not have characteristic " + iid + "Request: " + uri); - } - } else { - logger.warn("Accessory " + aid + " has no characteristics or does not exist. Request: " + uri); - } - } - try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) { - Json.createWriter(baos).write(Json.createObjectBuilder().add("characteristics", characteristics.build()).build()); - return new HapJsonResponse(baos.toByteArray()); - } - } + characteristics.add(characteristic.add("aid", aid).add("iid", iid).build()); + } else { + logger.warn( + "Accessory " + aid + " does not have characteristic " + iid + "Request: " + uri); + } + } else { + logger.warn( + "Accessory " + aid + " has no characteristics or does not exist. Request: " + uri); + } + } + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + Json.createWriter(baos) + .write( + Json.createObjectBuilder().add("characteristics", characteristics.build()).build()); + return new HapJsonResponse(baos.toByteArray()); + } + } - public HttpResponse put(HttpRequest request, HomekitClientConnection connection) throws Exception { - try(ByteArrayInputStream bais = new ByteArrayInputStream(request.getBody())) { - JsonArray jsonCharacteristics = Json.createReader(bais) - .readObject().getJsonArray("characteristics"); - for (JsonValue value: jsonCharacteristics) { - JsonObject jsonCharacteristic = (JsonObject) value; - int aid = jsonCharacteristic.getInt("aid"); - int iid = jsonCharacteristic.getInt("iid"); - Characteristic characteristic = registry.getCharacteristics(aid).get(iid); - - if (jsonCharacteristic.containsKey("value")) { - characteristic.setValue(jsonCharacteristic.get("value")); - } - if (jsonCharacteristic.containsKey("ev") && characteristic instanceof EventableCharacteristic) { - if (jsonCharacteristic.getBoolean("ev")) { - subscriptions.addSubscription(aid, iid, (EventableCharacteristic) characteristic, connection); - } else { - subscriptions.removeSubscription((EventableCharacteristic) characteristic, connection); - } - } - } - } - return new HapJsonNoContentResponse(); - } + public HttpResponse put(HttpRequest request, HomekitClientConnection connection) + throws Exception { + try (ByteArrayInputStream bais = new ByteArrayInputStream(request.getBody())) { + JsonArray jsonCharacteristics = + Json.createReader(bais).readObject().getJsonArray("characteristics"); + for (JsonValue value : jsonCharacteristics) { + JsonObject jsonCharacteristic = (JsonObject) value; + int aid = jsonCharacteristic.getInt("aid"); + int iid = jsonCharacteristic.getInt("iid"); + Characteristic characteristic = registry.getCharacteristics(aid).get(iid); + if (jsonCharacteristic.containsKey("value")) { + characteristic.setValue(jsonCharacteristic.get("value")); + } + if (jsonCharacteristic.containsKey("ev") + && characteristic instanceof EventableCharacteristic) { + if (jsonCharacteristic.getBoolean("ev")) { + subscriptions.addSubscription( + aid, iid, (EventableCharacteristic) characteristic, connection); + } else { + subscriptions.removeSubscription((EventableCharacteristic) characteristic, connection); + } + } + } + } + return new HapJsonNoContentResponse(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/json/EventController.java b/src/main/java/com/beowulfe/hap/impl/json/EventController.java index b660a77ba..c1cd3d22c 100644 --- a/src/main/java/com/beowulfe/hap/impl/json/EventController.java +++ b/src/main/java/com/beowulfe/hap/impl/json/EventController.java @@ -1,35 +1,32 @@ package com.beowulfe.hap.impl.json; +import com.beowulfe.hap.characteristics.EventableCharacteristic; +import com.beowulfe.hap.impl.http.HttpResponse; import java.io.ByteArrayOutputStream; - import javax.json.Json; import javax.json.JsonArrayBuilder; import javax.json.JsonObject; import javax.json.JsonObjectBuilder; -import com.beowulfe.hap.characteristics.EventableCharacteristic; -import com.beowulfe.hap.impl.http.HttpResponse; - public class EventController { - public HttpResponse getMessage(int accessoryId, int iid, EventableCharacteristic changed) throws Exception { - JsonArrayBuilder characteristics = Json.createArrayBuilder(); - - JsonObjectBuilder characteristicBuilder = Json.createObjectBuilder(); - characteristicBuilder.add("aid", accessoryId); - characteristicBuilder.add("iid", iid); - changed.supplyValue(characteristicBuilder); - characteristics.add(characteristicBuilder.build()); - - JsonObject data = Json.createObjectBuilder().add("characteristics", characteristics).build(); - - try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) { - Json.createWriter(baos).write(data); - byte[] dataBytes = baos.toByteArray(); - - return new EventResponse(dataBytes); - } - - } + public HttpResponse getMessage(int accessoryId, int iid, EventableCharacteristic changed) + throws Exception { + JsonArrayBuilder characteristics = Json.createArrayBuilder(); + + JsonObjectBuilder characteristicBuilder = Json.createObjectBuilder(); + characteristicBuilder.add("aid", accessoryId); + characteristicBuilder.add("iid", iid); + changed.supplyValue(characteristicBuilder); + characteristics.add(characteristicBuilder.build()); + + JsonObject data = Json.createObjectBuilder().add("characteristics", characteristics).build(); + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + Json.createWriter(baos).write(data); + byte[] dataBytes = baos.toByteArray(); + return new EventResponse(dataBytes); + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/json/EventResponse.java b/src/main/java/com/beowulfe/hap/impl/json/EventResponse.java index 2cb06ec23..5ece1de25 100644 --- a/src/main/java/com/beowulfe/hap/impl/json/EventResponse.java +++ b/src/main/java/com/beowulfe/hap/impl/json/EventResponse.java @@ -1,14 +1,13 @@ package com.beowulfe.hap.impl.json; - public class EventResponse extends HapJsonResponse { - public EventResponse(byte[] body) { - super(body); - } - - @Override - public HttpVersion getVersion() { - return HttpVersion.EVENT_1_0; - } + public EventResponse(byte[] body) { + super(body); + } + + @Override + public HttpVersion getVersion() { + return HttpVersion.EVENT_1_0; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/json/HapJsonNoContentResponse.java b/src/main/java/com/beowulfe/hap/impl/json/HapJsonNoContentResponse.java index c21f8efe1..a339bb5bc 100644 --- a/src/main/java/com/beowulfe/hap/impl/json/HapJsonNoContentResponse.java +++ b/src/main/java/com/beowulfe/hap/impl/json/HapJsonNoContentResponse.java @@ -1,13 +1,13 @@ package com.beowulfe.hap.impl.json; -class HapJsonNoContentResponse extends HapJsonResponse{ +class HapJsonNoContentResponse extends HapJsonResponse { - public HapJsonNoContentResponse() { - super(new byte[0]); - } + public HapJsonNoContentResponse() { + super(new byte[0]); + } - @Override - public int getStatusCode() { - return 204; - } + @Override + public int getStatusCode() { + return 204; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/json/HapJsonResponse.java b/src/main/java/com/beowulfe/hap/impl/json/HapJsonResponse.java index b7282a94c..a4f8a6cc9 100644 --- a/src/main/java/com/beowulfe/hap/impl/json/HapJsonResponse.java +++ b/src/main/java/com/beowulfe/hap/impl/json/HapJsonResponse.java @@ -1,28 +1,28 @@ package com.beowulfe.hap.impl.json; +import com.beowulfe.hap.impl.responses.OkResponse; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import com.beowulfe.hap.impl.responses.OkResponse; - class HapJsonResponse extends OkResponse { - - private static final Map headers = Collections.unmodifiableMap( - new HashMap() { - private static final long serialVersionUID = 1L; - { - put("Content-type", "application/hap+json"); - } - }); - public HapJsonResponse(byte[] body) { - super(body); - } - - @Override - public Map getHeaders() { - return headers; - } + private static final Map headers = + Collections.unmodifiableMap( + new HashMap() { + private static final long serialVersionUID = 1L; + + { + put("Content-type", "application/hap+json"); + } + }); + + public HapJsonResponse(byte[] body) { + super(body); + } + @Override + public Map getHeaders() { + return headers; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/ByteUtils.java b/src/main/java/com/beowulfe/hap/impl/pairing/ByteUtils.java index 1d8eba7f8..0ce9e8d4d 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/ByteUtils.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/ByteUtils.java @@ -8,36 +8,36 @@ class ByteUtils { - public static byte[] joinBytes(byte[]... piece) { - int pos = 0; - int length = 0; - for(int i=0; i 0) - { - output.write(buffer, 0, bytesRead); - remaining -= bytesRead; - } - } + public static byte[] joinBytes(byte[]... piece) { + int pos = 0; + int length = 0; + for (int i = 0; i < piece.length; i++) { + length += piece[i].length; + } + byte[] ret = new byte[length]; + for (int i = 0; i < piece.length; i++) { + System.arraycopy(piece[i], 0, ret, pos, piece[i].length); + pos += piece[i].length; + } + return ret; + } + + public static byte[] toByteArray(BigInteger i) { + byte[] array = i.toByteArray(); + if (array[0] == 0) { + array = Arrays.copyOfRange(array, 1, array.length); + } + return array; + } + + public static void copyStream(InputStream input, OutputStream output, int length) + throws IOException { + byte[] buffer = new byte[length]; + int remaining = length; + int bytesRead; + while ((bytesRead = input.read(buffer, 0, remaining)) != -1 && remaining > 0) { + output.write(buffer, 0, bytesRead); + remaining -= bytesRead; + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/ClientEvidenceRoutineImpl.java b/src/main/java/com/beowulfe/hap/impl/pairing/ClientEvidenceRoutineImpl.java index c8c9ccce7..1afd877bb 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/ClientEvidenceRoutineImpl.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/ClientEvidenceRoutineImpl.java @@ -1,63 +1,61 @@ package com.beowulfe.hap.impl.pairing; +import com.nimbusds.srp6.*; import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import com.nimbusds.srp6.*; - class ClientEvidenceRoutineImpl implements ClientEvidenceRoutine { - public ClientEvidenceRoutineImpl() { - // TODO Auto-generated constructor stub - } - - /** - * Calculates M1 according to the following formula: - * - * M1 = H(H(N) xor H(g) || H(username) || s || A || B || H(S)) - */ - @Override - public BigInteger computeClientEvidence(SRP6CryptoParams cryptoParams, - SRP6ClientEvidenceContext ctx) { - - MessageDigest digest; - try { - digest = MessageDigest.getInstance(cryptoParams.H); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("Could not locate requested algorithm", e); - } - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(cryptoParams.N)); - byte[] hN = digest.digest(); - - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(cryptoParams.g)); - byte[] hg = digest.digest(); - - byte[] hNhg = xor(hN, hg); - - digest.update(ctx.userID.getBytes(StandardCharsets.UTF_8)); - byte[] hu = digest.digest(); - - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.S)); - byte[] hS = digest.digest(); - - digest.update(hNhg); - digest.update(hu); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.s)); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.A)); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.B)); - digest.update(hS); - BigInteger ret = new BigInteger(1, digest.digest()); - return ret; - } - - private static byte[] xor(byte[] b1, byte[] b2) { - byte[] result = new byte[b1.length]; - for (int i=0; iM1 = H(H(N) xor H(g) || H(username) || s || A || B || H(S)) + */ + @Override + public BigInteger computeClientEvidence( + SRP6CryptoParams cryptoParams, SRP6ClientEvidenceContext ctx) { + + MessageDigest digest; + try { + digest = MessageDigest.getInstance(cryptoParams.H); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("Could not locate requested algorithm", e); + } + digest.update(SrpHandler.bigIntegerToUnsignedByteArray(cryptoParams.N)); + byte[] hN = digest.digest(); + + digest.update(SrpHandler.bigIntegerToUnsignedByteArray(cryptoParams.g)); + byte[] hg = digest.digest(); + + byte[] hNhg = xor(hN, hg); + + digest.update(ctx.userID.getBytes(StandardCharsets.UTF_8)); + byte[] hu = digest.digest(); + + digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.S)); + byte[] hS = digest.digest(); + + digest.update(hNhg); + digest.update(hu); + digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.s)); + digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.A)); + digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.B)); + digest.update(hS); + BigInteger ret = new BigInteger(1, digest.digest()); + return ret; + } + private static byte[] xor(byte[] b1, byte[] b2) { + byte[] result = new byte[b1.length]; + for (int i = 0; i < b1.length; i++) { + result[i] = (byte) (b1[i] ^ b2[i]); + } + return result; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/FinalPairHandler.java b/src/main/java/com/beowulfe/hap/impl/pairing/FinalPairHandler.java index 3ba60e4be..1e37d1fa8 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/FinalPairHandler.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/FinalPairHandler.java @@ -1,11 +1,5 @@ package com.beowulfe.hap.impl.pairing; -import java.nio.charset.StandardCharsets; - -import org.bouncycastle.crypto.digests.SHA512Digest; -import org.bouncycastle.crypto.generators.HKDFBytesGenerator; -import org.bouncycastle.crypto.params.HKDFParameters; - import com.beowulfe.hap.HomekitAuthInfo; import com.beowulfe.hap.impl.crypto.*; import com.beowulfe.hap.impl.http.HttpResponse; @@ -13,86 +7,101 @@ import com.beowulfe.hap.impl.pairing.PairSetupRequest.Stage3Request; import com.beowulfe.hap.impl.pairing.TypeLengthValueUtils.DecodeResult; import com.beowulfe.hap.impl.pairing.TypeLengthValueUtils.Encoder; +import java.nio.charset.StandardCharsets; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.generators.HKDFBytesGenerator; +import org.bouncycastle.crypto.params.HKDFParameters; 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) { - this.k = k; - this.authInfo = authInfo; - this.advertiser = advertiser; - } - - public HttpResponse handle(PairSetupRequest req) throws Exception { - HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); - hkdf.init(new HKDFParameters(k, "Pair-Setup-Encrypt-Salt".getBytes(StandardCharsets.UTF_8), - "Pair-Setup-Encrypt-Info".getBytes(StandardCharsets.UTF_8))); - byte[] okm = hkdf_enc_key = new byte[32]; - hkdf.generateBytes(okm, 0, 32); - - return decrypt((Stage3Request) req, okm); - } - - private HttpResponse decrypt(Stage3Request req, byte[] key) throws Exception { - ChachaDecoder chacha = new ChachaDecoder(key, "PS-Msg05".getBytes(StandardCharsets.UTF_8)); - byte[] plaintext = chacha.decodeCiphertext(req.getAuthTagData(), req.getMessageData()); - - DecodeResult d = TypeLengthValueUtils.decode(plaintext); - byte[] username = d.getBytes(MessageType.USERNAME); - byte[] ltpk = d.getBytes(MessageType.PUBLIC_KEY); - byte[] proof = d.getBytes(MessageType.SIGNATURE); - return createUser(username, ltpk, proof); - } - - private HttpResponse createUser(byte[] username, byte[] ltpk, byte[] proof) throws Exception { - HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); - hkdf.init(new HKDFParameters(k, "Pair-Setup-Controller-Sign-Salt".getBytes(StandardCharsets.UTF_8), - "Pair-Setup-Controller-Sign-Info".getBytes(StandardCharsets.UTF_8))); - byte[] okm = new byte[32]; - hkdf.generateBytes(okm, 0, 32); - - byte[] completeData = ByteUtils.joinBytes(okm, username, ltpk); - - if (!new EdsaVerifier(ltpk).verify(completeData, proof)) { - throw new Exception("Invalid signature"); - } - authInfo.createUser(authInfo.getMac()+new String(username, StandardCharsets.UTF_8), ltpk); - advertiser.setDiscoverable(false); - return createResponse(); - } - - private HttpResponse createResponse() throws Exception { - HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); - hkdf.init(new HKDFParameters(k, "Pair-Setup-Accessory-Sign-Salt".getBytes(StandardCharsets.UTF_8), - "Pair-Setup-Accessory-Sign-Info".getBytes(StandardCharsets.UTF_8))); - byte[] okm = new byte[32]; - hkdf.generateBytes(okm, 0, 32); - - EdsaSigner signer = new EdsaSigner(authInfo.getPrivateKey()); - - byte[] material = ByteUtils.joinBytes(okm, authInfo.getMac().getBytes(StandardCharsets.UTF_8), signer.getPublicKey()); - - byte[] proof = signer.sign(material); - - Encoder encoder = TypeLengthValueUtils.getEncoder(); - encoder.add(MessageType.USERNAME, authInfo.getMac().getBytes(StandardCharsets.UTF_8)); - encoder.add(MessageType.PUBLIC_KEY, signer.getPublicKey()); - encoder.add(MessageType.SIGNATURE, proof); - byte[] plaintext = encoder.toByteArray(); - - ChachaEncoder chacha = new ChachaEncoder(hkdf_enc_key, "PS-Msg06".getBytes(StandardCharsets.UTF_8)); - byte[] ciphertext = chacha.encodeCiphertext(plaintext); - - encoder = TypeLengthValueUtils.getEncoder(); - encoder.add(MessageType.STATE, (short) 6); - encoder.add(MessageType.ENCRYPTED_DATA, ciphertext); - - return new PairingResponse(encoder.toByteArray()); - } + 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) { + this.k = k; + this.authInfo = authInfo; + this.advertiser = advertiser; + } + + public HttpResponse handle(PairSetupRequest req) throws Exception { + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); + hkdf.init( + new HKDFParameters( + k, + "Pair-Setup-Encrypt-Salt".getBytes(StandardCharsets.UTF_8), + "Pair-Setup-Encrypt-Info".getBytes(StandardCharsets.UTF_8))); + byte[] okm = hkdf_enc_key = new byte[32]; + hkdf.generateBytes(okm, 0, 32); + + return decrypt((Stage3Request) req, okm); + } + + private HttpResponse decrypt(Stage3Request req, byte[] key) throws Exception { + ChachaDecoder chacha = new ChachaDecoder(key, "PS-Msg05".getBytes(StandardCharsets.UTF_8)); + byte[] plaintext = chacha.decodeCiphertext(req.getAuthTagData(), req.getMessageData()); + + DecodeResult d = TypeLengthValueUtils.decode(plaintext); + byte[] username = d.getBytes(MessageType.USERNAME); + byte[] ltpk = d.getBytes(MessageType.PUBLIC_KEY); + byte[] proof = d.getBytes(MessageType.SIGNATURE); + return createUser(username, ltpk, proof); + } + + private HttpResponse createUser(byte[] username, byte[] ltpk, byte[] proof) throws Exception { + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); + hkdf.init( + new HKDFParameters( + k, + "Pair-Setup-Controller-Sign-Salt".getBytes(StandardCharsets.UTF_8), + "Pair-Setup-Controller-Sign-Info".getBytes(StandardCharsets.UTF_8))); + byte[] okm = new byte[32]; + hkdf.generateBytes(okm, 0, 32); + + byte[] completeData = ByteUtils.joinBytes(okm, username, ltpk); + + if (!new EdsaVerifier(ltpk).verify(completeData, proof)) { + throw new Exception("Invalid signature"); + } + authInfo.createUser(authInfo.getMac() + new String(username, StandardCharsets.UTF_8), ltpk); + advertiser.setDiscoverable(false); + return createResponse(); + } + + private HttpResponse createResponse() throws Exception { + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); + hkdf.init( + new HKDFParameters( + k, + "Pair-Setup-Accessory-Sign-Salt".getBytes(StandardCharsets.UTF_8), + "Pair-Setup-Accessory-Sign-Info".getBytes(StandardCharsets.UTF_8))); + byte[] okm = new byte[32]; + hkdf.generateBytes(okm, 0, 32); + + EdsaSigner signer = new EdsaSigner(authInfo.getPrivateKey()); + + byte[] material = + ByteUtils.joinBytes( + okm, authInfo.getMac().getBytes(StandardCharsets.UTF_8), signer.getPublicKey()); + + byte[] proof = signer.sign(material); + + Encoder encoder = TypeLengthValueUtils.getEncoder(); + encoder.add(MessageType.USERNAME, authInfo.getMac().getBytes(StandardCharsets.UTF_8)); + encoder.add(MessageType.PUBLIC_KEY, signer.getPublicKey()); + encoder.add(MessageType.SIGNATURE, proof); + byte[] plaintext = encoder.toByteArray(); + + ChachaEncoder chacha = + new ChachaEncoder(hkdf_enc_key, "PS-Msg06".getBytes(StandardCharsets.UTF_8)); + byte[] ciphertext = chacha.encodeCiphertext(plaintext); + + encoder = TypeLengthValueUtils.getEncoder(); + encoder.add(MessageType.STATE, (short) 6); + encoder.add(MessageType.ENCRYPTED_DATA, ciphertext); + + return new PairingResponse(encoder.toByteArray()); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/HomekitSRP6Routines.java b/src/main/java/com/beowulfe/hap/impl/pairing/HomekitSRP6Routines.java index d919f24cd..a63135f3f 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/HomekitSRP6Routines.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/HomekitSRP6Routines.java @@ -4,62 +4,55 @@ import java.security.SecureRandom; /** - * This class is modified from the nimbus SRP library to provide methods that are compatible - * with some pecularities of Homekit. Namely, the need for a 3072 bit private value - * + * This class is modified from the nimbus SRP library to provide methods that are compatible with + * some pecularities of Homekit. Namely, the need for a 3072 bit private value + * * @author Vladimir Dzhuvinov */ public class HomekitSRP6Routines { - public static BigInteger generatePrivateValue(BigInteger N, SecureRandom random) { - final int minBits = Math.min(3072, N.bitLength() / 2); - - BigInteger min = BigInteger.ONE.shiftLeft(minBits - 1); - BigInteger max = N.subtract(BigInteger.ONE); - - return createRandomBigIntegerInRange(min, max, random); - } - - /** - * Returns a random big integer in the specified range [min, max]. - * - * @param min The least value that may be generated. Must not be - * {@code null}. - * @param max The greatest value that may be generated. Must not be - * {@code null}. - * @param random Source of randomness. Must not be {@code null}. - * - * @return A random big integer in the range [min, max]. - */ - protected static BigInteger createRandomBigIntegerInRange(final BigInteger min, - final BigInteger max, - final SecureRandom random) { - - final int cmp = min.compareTo(max); - - if (cmp >= 0) { - - if (cmp > 0) - throw new IllegalArgumentException("'min' may not be greater than 'max'"); - - return min; - } - - if (min.bitLength() > max.bitLength() / 2) - return createRandomBigIntegerInRange(BigInteger.ZERO, max.subtract(min), random).add(min); - - final int MAX_ITERATIONS = 1000; - - for (int i = 0; i < MAX_ITERATIONS; ++i) { - - BigInteger x = new BigInteger(max.bitLength(), random); - - if (x.compareTo(min) >= 0 && x.compareTo(max) <= 0) - return x; - } - - // fall back to a faster (restricted) method - return new BigInteger(max.subtract(min).bitLength() - 1, random).add(min); - } + public static BigInteger generatePrivateValue(BigInteger N, SecureRandom random) { + final int minBits = Math.min(3072, N.bitLength() / 2); + BigInteger min = BigInteger.ONE.shiftLeft(minBits - 1); + BigInteger max = N.subtract(BigInteger.ONE); + + return createRandomBigIntegerInRange(min, max, random); + } + + /** + * Returns a random big integer in the specified range [min, max]. + * + * @param min The least value that may be generated. Must not be {@code null}. + * @param max The greatest value that may be generated. Must not be {@code null}. + * @param random Source of randomness. Must not be {@code null}. + * @return A random big integer in the range [min, max]. + */ + protected static BigInteger createRandomBigIntegerInRange( + final BigInteger min, final BigInteger max, final SecureRandom random) { + + final int cmp = min.compareTo(max); + + if (cmp >= 0) { + + if (cmp > 0) throw new IllegalArgumentException("'min' may not be greater than 'max'"); + + return min; + } + + if (min.bitLength() > max.bitLength() / 2) + return createRandomBigIntegerInRange(BigInteger.ZERO, max.subtract(min), random).add(min); + + final int MAX_ITERATIONS = 1000; + + for (int i = 0; i < MAX_ITERATIONS; ++i) { + + BigInteger x = new BigInteger(max.bitLength(), random); + + if (x.compareTo(min) >= 0 && x.compareTo(max) <= 0) return x; + } + + // fall back to a faster (restricted) method + return new BigInteger(max.subtract(min).bitLength() - 1, random).add(min); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/HomekitSRP6ServerSession.java b/src/main/java/com/beowulfe/hap/impl/pairing/HomekitSRP6ServerSession.java index d2cd948cd..1c24e8fad 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/HomekitSRP6ServerSession.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/HomekitSRP6ServerSession.java @@ -1,8 +1,5 @@ package com.beowulfe.hap.impl.pairing; - -import java.math.BigInteger; - import com.nimbusds.srp6.SRP6ClientEvidenceContext; import com.nimbusds.srp6.SRP6CryptoParams; import com.nimbusds.srp6.SRP6Exception; @@ -10,350 +7,290 @@ import com.nimbusds.srp6.SRP6ServerEvidenceContext; import com.nimbusds.srp6.SRP6Session; import com.nimbusds.srp6.URoutineContext; - +import java.math.BigInteger; /** - * This is a slightly modified version of the SRP6ServerSession class included - * with nimbus. The only change made for homekit compatability is a change to the - * size of the b key. Homekit pairing fails if b is not 3072 bytes. - * - * Stateful server-side Secure Remote Password (SRP-6a) authentication session. - * Handles the computing and storing of SRP-6a variables between the protocol - * steps as well as timeouts. + * This is a slightly modified version of the SRP6ServerSession class included with nimbus. The only + * change made for homekit compatability is a change to the size of the b key. Homekit pairing fails + * if b is not 3072 bytes. + * + *

Stateful server-side Secure Remote Password (SRP-6a) authentication session. Handles the + * computing and storing of SRP-6a variables between the protocol steps as well as timeouts. * *

Usage: * *

    - *
  • Create a new SRP-6a server session for each client authentication - * attempt. - *
  • If you wish to use custom routines for the server evidence message - * 'M1' and / or the client evidence message 'M2' specify them at this - * point. - *
  • Proceed to {@link #step1 step one} on receiving a valid user identity - * 'I' from the authenticating client. Respond with the server public - * value 'B' and password salt 's'. If the SRP-6a crypto parameters 'N', - * 'g' and 'H' were not agreed in advance between server and client - * append them to the response. - *
  • Proceed to {@link #step2 step two} on receiving the public client - * value 'A' and evidence message 'M1'. If the client credentials are - * valid signal success and return the server evidence message 'M2'. The - * established session key 'S' may be {@link #getSessionKey retrieved} to - * encrypt further communication with the client. Else signal an - * authentication failure to the client. + *
  • Create a new SRP-6a server session for each client authentication attempt. + *
  • If you wish to use custom routines for the server evidence message 'M1' and / or the client + * evidence message 'M2' specify them at this point. + *
  • Proceed to {@link #step1 step one} on receiving a valid user identity 'I' from the + * authenticating client. Respond with the server public value 'B' and password salt 's'. If + * the SRP-6a crypto parameters 'N', 'g' and 'H' were not agreed in advance between server and + * client append them to the response. + *
  • Proceed to {@link #step2 step two} on receiving the public client value 'A' and evidence + * message 'M1'. If the client credentials are valid signal success and return the server + * evidence message 'M2'. The established session key 'S' may be {@link #getSessionKey + * retrieved} to encrypt further communication with the client. Else signal an authentication + * failure to the client. *
* * @author Vladimir Dzhuvinov */ public class HomekitSRP6ServerSession extends SRP6Session { - - - /** - * Enumerates the states of a server-side SRP-6a authentication session. - */ - public static enum State { - - - /** - * The session is initialised and ready to begin authentication, - * by proceeding to {@link #STEP_1}. - */ - INIT, - - - /** - * The user identity 'I' is received from the client and the - * server has returned its public value 'B' based on the - * matching password verifier 'v'. The session is ready to - * proceed to {@link #STEP_2}. - */ - STEP_1, - - - /** - * The client public key 'A' and evidence message 'M1' are - * received and the server has replied with its own evidence - * message 'M2'. The session is finished (authentication was - * successful or failed). - */ - STEP_2 - } - - - /** - * Indicates a non-existing use identity and implies mock salt 's' and - * verifier 'v' values. - */ - private boolean noSuchUserIdentity = false; - - - /** - * The password verifier 'v'. - */ - private BigInteger v = null; - - - /** - * The server private value 'b'. - */ - private BigInteger b = null; - - - /** - * The current SRP-6a auth state. - */ - private State state; - - - /** - * Creates a new server-side SRP-6a authentication session and sets its - * state to {@link State#INIT}. - * - * @param config The SRP-6a crypto parameters configuration. Must not - * be {@code null}. - * @param timeout The SRP-6a authentication session timeout in seconds. - * If the authenticating counterparty (server or client) - * fails to respond within the specified time the session - * will be closed. If zero timeouts are disabled. - */ - public HomekitSRP6ServerSession(final SRP6CryptoParams config, final int timeout) { - - super(timeout); - - if (config == null) - throw new IllegalArgumentException("The SRP-6a crypto parameters must not be null"); - - this.config = config; - - digest = config.getMessageDigestInstance(); - - if (digest == null) - throw new IllegalArgumentException("Unsupported hash algorithm 'H': " + config.H); - - state = State.INIT; - - updateLastActivityTime(); - } - - - /** - * Creates a new server-side SRP-6a authentication session and sets its - * state to {@link State#INIT}. Session timeouts are disabled. - * - * @param config The SRP-6a crypto parameters configuration. Must not - * be {@code null}. - */ - public HomekitSRP6ServerSession(final SRP6CryptoParams config) { - - this(config, 0); - } - - - /** - * Increments this SRP-6a authentication session to - * {@link State#STEP_1}. - * - *

Argument origin: - * - *

    - *
  • From client: user identity 'I'. - *
  • From server database: matching salt 's' and password verifier - * 'v' values. - *
- * - * @param userID The identity 'I' of the authenticating user. Must not - * be {@code null} or empty. - * @param s The password salt 's'. Must not be {@code null}. - * @param v The password verifier 'v'. Must not be {@code null}. - * - * @return The server public value 'B'. - * - * @throws IllegalStateException If the mehod is invoked in a state - * other than {@link State#INIT}. - */ - public BigInteger step1(final String userID, final BigInteger s, final BigInteger v) { - - // Check arguments - - if (userID == null || userID.trim().isEmpty()) - throw new IllegalArgumentException("The user identity 'I' must not be null or empty"); - - this.userID = userID; - - - if (s == null) - throw new IllegalArgumentException("The salt 's' must not be null"); - - this.s = s; - - - if (v == null) - throw new IllegalArgumentException("The verifier 'v' must not be null"); - - this.v = v; - - - // Check current state - if (state != State.INIT) - throw new IllegalStateException("State violation: Session must be in INIT state"); - - // Generate server private and public values - k = SRP6Routines.computeK(digest, config.N, config.g); - digest.reset(); - - b = HomekitSRP6Routines.generatePrivateValue(config.N, random); - digest.reset(); - - B = SRP6Routines.computePublicServerValue(config.N, config.g, k, v, b); - - state = State.STEP_1; - - updateLastActivityTime(); - - return B; - } - - - /** - * Increments this SRP-6a authentication session to - * {@link State#STEP_1} indicating a non-existing user identity 'I' - * with mock (simulated) salt 's' and password verifier 'v' values. - * - *

This method can be used to avoid informing the client at step one - * that the user identity is bad and throw instead a guaranteed general - * "bad credentials" SRP-6a exception at step two. - * - *

Argument origin: - * - *

    - *
  • From client: user identity 'I'. - *
  • Simulated by server, preferably consistently for the - * specified identity 'I': salt 's' and password verifier 'v' - * values. - *
- * - * @param userID The identity 'I' of the authenticating user. Must not - * be {@code null} or empty. - * @param s The password salt 's'. Must not be {@code null}. - * @param v The password verifier 'v'. Must not be {@code null}. - * - * @return The server public value 'B'. - * - * @throws IllegalStateException If the method is invoked in a state - * other than {@link State#INIT}. - */ - public BigInteger mockStep1(final String userID, final BigInteger s, final BigInteger v) { - - noSuchUserIdentity = true; - - return step1(userID, s, v); - } - - - /** - * Increments this SRP-6a authentication session to - * {@link State#STEP_2}. - * - *

Argument origin: - * - *

    - *
  • From client: public value 'A' and evidence message 'M1'. - *
- * - * @param A The client public value. Must not be {@code null}. - * @param M1 The client evidence message. Must not be {@code null}. - * - * @return The server evidence message 'M2'. - * - * @throws SRP6Exception If the session has timed out, the client public - * value 'A' is invalid or the user credentials - * are invalid. - * - * @throws IllegalStateException If the method is invoked in a state - * other than {@link State#STEP_1}. - */ - public BigInteger step2(final BigInteger A, final BigInteger M1) - throws SRP6Exception { - - // Check arguments - - if (A == null) - throw new IllegalArgumentException("The client public value 'A' must not be null"); - - this.A = A; - - if (M1 == null) - throw new IllegalArgumentException("The client evidence message 'M1' must not be null"); - - this.M1 = M1; - - // Check current state - if (state != State.STEP_1) - throw new IllegalStateException("State violation: Session must be in STEP_1 state"); - - // Check timeout - if (hasTimedOut()) - throw new SRP6Exception("Session timeout", SRP6Exception.CauseType.TIMEOUT); - - // Check A validity - if (! SRP6Routines.isValidPublicValue(config.N, A)) - throw new SRP6Exception("Bad client public value 'A'", SRP6Exception.CauseType.BAD_PUBLIC_VALUE); - - // Check for previous mock step 1 - if (noSuchUserIdentity) - throw new SRP6Exception("Bad client credentials", SRP6Exception.CauseType.BAD_CREDENTIALS); - - if (hashedKeysRoutine != null) { - URoutineContext hashedKeysContext = new URoutineContext(A, B); - u = hashedKeysRoutine.computeU(config, hashedKeysContext); - } else { - u = SRP6Routines.computeU(digest, config.N, A, B); - digest.reset(); - } - - S = SRP6Routines.computeSessionKey(config.N, v, u, A, b); - - // Compute the own client evidence message 'M1' - BigInteger computedM1; - - if (clientEvidenceRoutine != null) { - - // With custom routine - SRP6ClientEvidenceContext ctx = new SRP6ClientEvidenceContext(userID, s, A, B, S); - computedM1 = clientEvidenceRoutine.computeClientEvidence(config, ctx); - } - else { - // With default routine - computedM1 = SRP6Routines.computeClientEvidence(digest, A, B, S); - digest.reset(); - } - - if (! computedM1.equals(M1)) - throw new SRP6Exception("Bad client credentials", SRP6Exception.CauseType.BAD_CREDENTIALS); - - state = State.STEP_2; - - - if (serverEvidenceRoutine != null) { - - // With custom routine - SRP6ServerEvidenceContext ctx = new SRP6ServerEvidenceContext(A, M1, S); - - M2 = serverEvidenceRoutine.computeServerEvidence(config, ctx); - } - - updateLastActivityTime(); - - return M2; - } - - - /** - * Returns the current state of this SRP-6a authentication session. - * - * @return The current state. - */ - public State getState() { - - return state; - } + + /** Enumerates the states of a server-side SRP-6a authentication session. */ + public static enum State { + + /** + * The session is initialised and ready to begin authentication, by proceeding to {@link + * #STEP_1}. + */ + INIT, + + /** + * The user identity 'I' is received from the client and the server has returned its public + * value 'B' based on the matching password verifier 'v'. The session is ready to proceed to + * {@link #STEP_2}. + */ + STEP_1, + + /** + * The client public key 'A' and evidence message 'M1' are received and the server has replied + * with its own evidence message 'M2'. The session is finished (authentication was successful or + * failed). + */ + STEP_2 + } + + /** Indicates a non-existing use identity and implies mock salt 's' and verifier 'v' values. */ + private boolean noSuchUserIdentity = false; + + /** The password verifier 'v'. */ + private BigInteger v = null; + + /** The server private value 'b'. */ + private BigInteger b = null; + + /** The current SRP-6a auth state. */ + private State state; + + /** + * Creates a new server-side SRP-6a authentication session and sets its state to {@link + * State#INIT}. + * + * @param config The SRP-6a crypto parameters configuration. Must not be {@code null}. + * @param timeout The SRP-6a authentication session timeout in seconds. If the authenticating + * counterparty (server or client) fails to respond within the specified time the session will + * be closed. If zero timeouts are disabled. + */ + public HomekitSRP6ServerSession(final SRP6CryptoParams config, final int timeout) { + + super(timeout); + + if (config == null) + throw new IllegalArgumentException("The SRP-6a crypto parameters must not be null"); + + this.config = config; + + digest = config.getMessageDigestInstance(); + + if (digest == null) + throw new IllegalArgumentException("Unsupported hash algorithm 'H': " + config.H); + + state = State.INIT; + + updateLastActivityTime(); + } + + /** + * Creates a new server-side SRP-6a authentication session and sets its state to {@link + * State#INIT}. Session timeouts are disabled. + * + * @param config The SRP-6a crypto parameters configuration. Must not be {@code null}. + */ + public HomekitSRP6ServerSession(final SRP6CryptoParams config) { + + this(config, 0); + } + + /** + * Increments this SRP-6a authentication session to {@link State#STEP_1}. + * + *

Argument origin: + * + *

    + *
  • From client: user identity 'I'. + *
  • From server database: matching salt 's' and password verifier 'v' values. + *
+ * + * @param userID The identity 'I' of the authenticating user. Must not be {@code null} or empty. + * @param s The password salt 's'. Must not be {@code null}. + * @param v The password verifier 'v'. Must not be {@code null}. + * @return The server public value 'B'. + * @throws IllegalStateException If the mehod is invoked in a state other than {@link State#INIT}. + */ + public BigInteger step1(final String userID, final BigInteger s, final BigInteger v) { + + // Check arguments + + if (userID == null || userID.trim().isEmpty()) + throw new IllegalArgumentException("The user identity 'I' must not be null or empty"); + + this.userID = userID; + + if (s == null) throw new IllegalArgumentException("The salt 's' must not be null"); + + this.s = s; + + if (v == null) throw new IllegalArgumentException("The verifier 'v' must not be null"); + + this.v = v; + + // Check current state + if (state != State.INIT) + throw new IllegalStateException("State violation: Session must be in INIT state"); + + // Generate server private and public values + k = SRP6Routines.computeK(digest, config.N, config.g); + digest.reset(); + + b = HomekitSRP6Routines.generatePrivateValue(config.N, random); + digest.reset(); + + B = SRP6Routines.computePublicServerValue(config.N, config.g, k, v, b); + + state = State.STEP_1; + + updateLastActivityTime(); + + return B; + } + + /** + * Increments this SRP-6a authentication session to {@link State#STEP_1} indicating a non-existing + * user identity 'I' with mock (simulated) salt 's' and password verifier 'v' values. + * + *

This method can be used to avoid informing the client at step one that the user identity is + * bad and throw instead a guaranteed general "bad credentials" SRP-6a exception at step two. + * + *

Argument origin: + * + *

    + *
  • From client: user identity 'I'. + *
  • Simulated by server, preferably consistently for the specified identity 'I': salt 's' and + * password verifier 'v' values. + *
+ * + * @param userID The identity 'I' of the authenticating user. Must not be {@code null} or empty. + * @param s The password salt 's'. Must not be {@code null}. + * @param v The password verifier 'v'. Must not be {@code null}. + * @return The server public value 'B'. + * @throws IllegalStateException If the method is invoked in a state other than {@link + * State#INIT}. + */ + public BigInteger mockStep1(final String userID, final BigInteger s, final BigInteger v) { + + noSuchUserIdentity = true; + + return step1(userID, s, v); + } + + /** + * Increments this SRP-6a authentication session to {@link State#STEP_2}. + * + *

Argument origin: + * + *

    + *
  • From client: public value 'A' and evidence message 'M1'. + *
+ * + * @param A The client public value. Must not be {@code null}. + * @param M1 The client evidence message. Must not be {@code null}. + * @return The server evidence message 'M2'. + * @throws SRP6Exception If the session has timed out, the client public value 'A' is invalid or + * the user credentials are invalid. + * @throws IllegalStateException If the method is invoked in a state other than {@link + * State#STEP_1}. + */ + public BigInteger step2(final BigInteger A, final BigInteger M1) throws SRP6Exception { + + // Check arguments + + if (A == null) + throw new IllegalArgumentException("The client public value 'A' must not be null"); + + this.A = A; + + if (M1 == null) + throw new IllegalArgumentException("The client evidence message 'M1' must not be null"); + + this.M1 = M1; + + // Check current state + if (state != State.STEP_1) + throw new IllegalStateException("State violation: Session must be in STEP_1 state"); + + // Check timeout + if (hasTimedOut()) throw new SRP6Exception("Session timeout", SRP6Exception.CauseType.TIMEOUT); + + // Check A validity + if (!SRP6Routines.isValidPublicValue(config.N, A)) + throw new SRP6Exception( + "Bad client public value 'A'", SRP6Exception.CauseType.BAD_PUBLIC_VALUE); + + // Check for previous mock step 1 + if (noSuchUserIdentity) + throw new SRP6Exception("Bad client credentials", SRP6Exception.CauseType.BAD_CREDENTIALS); + + if (hashedKeysRoutine != null) { + URoutineContext hashedKeysContext = new URoutineContext(A, B); + u = hashedKeysRoutine.computeU(config, hashedKeysContext); + } else { + u = SRP6Routines.computeU(digest, config.N, A, B); + digest.reset(); + } + + S = SRP6Routines.computeSessionKey(config.N, v, u, A, b); + + // Compute the own client evidence message 'M1' + BigInteger computedM1; + + if (clientEvidenceRoutine != null) { + + // With custom routine + SRP6ClientEvidenceContext ctx = new SRP6ClientEvidenceContext(userID, s, A, B, S); + computedM1 = clientEvidenceRoutine.computeClientEvidence(config, ctx); + } else { + // With default routine + computedM1 = SRP6Routines.computeClientEvidence(digest, A, B, S); + digest.reset(); + } + + if (!computedM1.equals(M1)) + throw new SRP6Exception("Bad client credentials", SRP6Exception.CauseType.BAD_CREDENTIALS); + + state = State.STEP_2; + + if (serverEvidenceRoutine != null) { + + // With custom routine + SRP6ServerEvidenceContext ctx = new SRP6ServerEvidenceContext(A, M1, S); + + M2 = serverEvidenceRoutine.computeServerEvidence(config, ctx); + } + + updateLastActivityTime(); + + return M2; + } + + /** + * Returns the current state of this SRP-6a authentication session. + * + * @return The current state. + */ + public State getState() { + + return state; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/MessageType.java b/src/main/java/com/beowulfe/hap/impl/pairing/MessageType.java index 5aec3f00c..b491e8c5a 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/MessageType.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/MessageType.java @@ -1,29 +1,27 @@ package com.beowulfe.hap.impl.pairing; public enum MessageType { + METHOD(0), + USERNAME(1), + SALT(2), + PUBLIC_KEY(3), + PROOF(4), + ENCRYPTED_DATA(5), + STATE(6), + ERROR(7), + SIGNATURE(10); - METHOD(0), - USERNAME(1), - SALT(2), - PUBLIC_KEY(3), - PROOF(4), - ENCRYPTED_DATA(5), - STATE(6), - ERROR(7), - SIGNATURE(10) - ; - - private final short key; - - MessageType(short key) { - this.key = key; - } - - MessageType(int key) { - this.key = (short) key; - } - - public short getKey() { - return key; - } + private final short key; + + MessageType(short key) { + this.key = key; + } + + MessageType(int key) { + this.key = (short) key; + } + + public short getKey() { + return key; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/PairSetupRequest.java b/src/main/java/com/beowulfe/hap/impl/pairing/PairSetupRequest.java index c7877f04e..2e31b10f6 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/PairSetupRequest.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/PairSetupRequest.java @@ -1,92 +1,88 @@ package com.beowulfe.hap.impl.pairing; -import java.math.BigInteger; - import com.beowulfe.hap.impl.pairing.TypeLengthValueUtils.DecodeResult; +import java.math.BigInteger; abstract class PairSetupRequest { - - private final static short VALUE_STAGE_1 = 1; - private final static short VALUE_STAGE_2 = 3; - private final static short VALUE_STAGE_3 = 5; - - public static PairSetupRequest of(byte[] content) throws Exception { - DecodeResult d = TypeLengthValueUtils.decode(content); - short stage = d.getByte(MessageType.STATE); - switch(stage) { - case VALUE_STAGE_1: - return new Stage1Request(); - - case VALUE_STAGE_2: - return new Stage2Request(d); - - case VALUE_STAGE_3: - return new Stage3Request(d); - - default: - throw new Exception("Unknown pair process stage: "+stage); - } - } - - public abstract Stage getStage(); - - public static class Stage1Request extends PairSetupRequest { - @Override - public Stage getStage() { - return Stage.ONE; - } - } - - public static class Stage2Request extends PairSetupRequest { - - private final BigInteger a; - private final BigInteger m1; - - public Stage2Request(DecodeResult d) { - a = d.getBigInt(MessageType.PUBLIC_KEY); - m1 = d.getBigInt(MessageType.PROOF); - } - - public BigInteger getA() { - return a; - } - - public BigInteger getM1() { - return m1; - } - - @Override - public Stage getStage() { - return Stage.TWO; - } - - } - - static class Stage3Request extends PairSetupRequest { - - private final byte[] messageData; - private final byte[] authTagData; - - public Stage3Request(DecodeResult d) { - messageData = new byte[d.getLength(MessageType.ENCRYPTED_DATA) - 16]; - authTagData = new byte[16]; - d.getBytes(MessageType.ENCRYPTED_DATA, messageData, 0); - d.getBytes(MessageType.ENCRYPTED_DATA, authTagData, messageData.length); - } - - public byte[] getMessageData() { - return messageData; - } - - public byte[] getAuthTagData() { - return authTagData; - } - - @Override - public Stage getStage() { - return Stage.THREE; - } - - } + private static final short VALUE_STAGE_1 = 1; + private static final short VALUE_STAGE_2 = 3; + private static final short VALUE_STAGE_3 = 5; + + public static PairSetupRequest of(byte[] content) throws Exception { + DecodeResult d = TypeLengthValueUtils.decode(content); + short stage = d.getByte(MessageType.STATE); + switch (stage) { + case VALUE_STAGE_1: + return new Stage1Request(); + + case VALUE_STAGE_2: + return new Stage2Request(d); + + case VALUE_STAGE_3: + return new Stage3Request(d); + + default: + throw new Exception("Unknown pair process stage: " + stage); + } + } + + public abstract Stage getStage(); + + public static class Stage1Request extends PairSetupRequest { + @Override + public Stage getStage() { + return Stage.ONE; + } + } + + public static class Stage2Request extends PairSetupRequest { + + private final BigInteger a; + private final BigInteger m1; + + public Stage2Request(DecodeResult d) { + a = d.getBigInt(MessageType.PUBLIC_KEY); + m1 = d.getBigInt(MessageType.PROOF); + } + + public BigInteger getA() { + return a; + } + + public BigInteger getM1() { + return m1; + } + + @Override + public Stage getStage() { + return Stage.TWO; + } + } + + static class Stage3Request extends PairSetupRequest { + + private final byte[] messageData; + private final byte[] authTagData; + + public Stage3Request(DecodeResult d) { + messageData = new byte[d.getLength(MessageType.ENCRYPTED_DATA) - 16]; + authTagData = new byte[16]; + d.getBytes(MessageType.ENCRYPTED_DATA, messageData, 0); + d.getBytes(MessageType.ENCRYPTED_DATA, authTagData, messageData.length); + } + + public byte[] getMessageData() { + return messageData; + } + + public byte[] getAuthTagData() { + return authTagData; + } + + @Override + public Stage getStage() { + return Stage.THREE; + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/PairVerificationManager.java b/src/main/java/com/beowulfe/hap/impl/pairing/PairVerificationManager.java index 5a035bf75..57ebf22f3 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/PairVerificationManager.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/PairVerificationManager.java @@ -1,14 +1,5 @@ package com.beowulfe.hap.impl.pairing; -import java.nio.charset.StandardCharsets; -import java.security.SecureRandom; - -import org.bouncycastle.crypto.digests.SHA512Digest; -import org.bouncycastle.crypto.generators.HKDFBytesGenerator; -import org.bouncycastle.crypto.params.HKDFParameters; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.beowulfe.hap.HomekitAuthInfo; import com.beowulfe.hap.impl.HomekitRegistry; import com.beowulfe.hap.impl.crypto.*; @@ -20,124 +11,140 @@ import com.beowulfe.hap.impl.pairing.TypeLengthValueUtils.Encoder; import com.beowulfe.hap.impl.responses.NotFoundResponse; import com.beowulfe.hap.impl.responses.OkResponse; - import djb.Curve25519; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.generators.HKDFBytesGenerator; +import org.bouncycastle.crypto.params.HKDFParameters; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class PairVerificationManager { - - private final static Logger logger = LoggerFactory.getLogger(PairVerificationManager.class); - private static volatile SecureRandom secureRandom; - - private final HomekitAuthInfo authInfo; - private final HomekitRegistry registry; - - private byte[] hkdfKey; - private byte[] clientPublicKey; - private byte[] publicKey; - private byte[] sharedSecret; - - public PairVerificationManager(HomekitAuthInfo authInfo, HomekitRegistry registry) { - this.authInfo = authInfo; - this.registry = registry; - } - - public HttpResponse handle(HttpRequest rawRequest) throws Exception { - PairVerificationRequest request = PairVerificationRequest.of(rawRequest.getBody()); - switch(request.getStage()) { - case ONE: - return stage1((Stage1Request) request); - - case TWO: - return stage2((Stage2Request) request); - - default: - return new NotFoundResponse(); - } - } - - private HttpResponse stage1(Stage1Request request) throws Exception { - logger.debug("Starting pair verification for "+registry.getLabel()); - clientPublicKey = request.getClientPublicKey(); - publicKey = new byte[32]; - byte[] privateKey = new byte[32]; - getSecureRandom().nextBytes(privateKey); - Curve25519.keygen(publicKey, null, privateKey); - - sharedSecret = new byte[32]; - Curve25519.curve(sharedSecret, privateKey, clientPublicKey); - - byte[] material = ByteUtils.joinBytes(publicKey, authInfo.getMac().getBytes(StandardCharsets.UTF_8), - clientPublicKey); - - byte[] proof = new EdsaSigner(authInfo.getPrivateKey()).sign(material); - - HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); - hkdf.init(new HKDFParameters(sharedSecret, "Pair-Verify-Encrypt-Salt".getBytes(StandardCharsets.UTF_8), - "Pair-Verify-Encrypt-Info".getBytes(StandardCharsets.UTF_8))); - hkdfKey = new byte[32]; - hkdf.generateBytes(hkdfKey, 0, 32); - - Encoder encoder = TypeLengthValueUtils.getEncoder(); - encoder.add(MessageType.USERNAME, authInfo.getMac().getBytes(StandardCharsets.UTF_8)); - encoder.add(MessageType.SIGNATURE, proof); - byte[] plaintext = encoder.toByteArray(); - - ChachaEncoder chacha = new ChachaEncoder(hkdfKey, "PV-Msg02".getBytes(StandardCharsets.UTF_8)); - byte[] ciphertext = chacha.encodeCiphertext(plaintext); - - encoder = TypeLengthValueUtils.getEncoder(); - encoder.add(MessageType.STATE, (short) 2); - encoder.add(MessageType.ENCRYPTED_DATA, ciphertext); - encoder.add(MessageType.PUBLIC_KEY, publicKey); - return new PairingResponse(encoder.toByteArray()); - } - - private HttpResponse stage2(Stage2Request request) throws Exception { - ChachaDecoder chacha = new ChachaDecoder(hkdfKey, "PV-Msg03".getBytes(StandardCharsets.UTF_8)); - byte[] plaintext = chacha.decodeCiphertext(request.getAuthTagData(), request.getMessageData()); - - DecodeResult d = TypeLengthValueUtils.decode(plaintext); - byte[] clientUsername = d.getBytes(MessageType.USERNAME); - byte[] clientSignature = d.getBytes(MessageType.SIGNATURE); - - byte[] material = ByteUtils.joinBytes(clientPublicKey, clientUsername, publicKey); - - byte[] clientLtpk = authInfo.getUserPublicKey(authInfo.getMac()+new String(clientUsername, StandardCharsets.UTF_8)); - if (clientLtpk == null) { - throw new Exception("Unknown user: "+new String(clientUsername, StandardCharsets.UTF_8)); - } - - Encoder encoder = TypeLengthValueUtils.getEncoder(); - if (new EdsaVerifier(clientLtpk).verify(material, clientSignature)) { - encoder.add(MessageType.STATE, (short) 4); - logger.debug("Completed pair verification for "+registry.getLabel()); - return new UpgradeResponse(encoder.toByteArray(), createKey("Control-Write-Encryption-Key"), - createKey("Control-Read-Encryption-Key")); - } else { - encoder.add(MessageType.ERROR, (short) 4); - logger.warn("Invalid signature. Could not pair "+registry.getLabel()); - return new OkResponse(encoder.toByteArray()); - } - } - - private byte[] createKey(String info) { - HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); - hkdf.init(new HKDFParameters(sharedSecret, "Control-Salt".getBytes(StandardCharsets.UTF_8), - info.getBytes(StandardCharsets.UTF_8))); - byte[] key = new byte[32]; - hkdf.generateBytes(key, 0, 32); - return key; - } - - private static SecureRandom getSecureRandom() { - if (secureRandom == null) { - synchronized(PairVerificationManager.class) { - if (secureRandom == null) { - secureRandom = new SecureRandom(); - } - } - } - return secureRandom; - } + private static final Logger logger = LoggerFactory.getLogger(PairVerificationManager.class); + private static volatile SecureRandom secureRandom; + + private final HomekitAuthInfo authInfo; + private final HomekitRegistry registry; + + private byte[] hkdfKey; + private byte[] clientPublicKey; + private byte[] publicKey; + private byte[] sharedSecret; + + public PairVerificationManager(HomekitAuthInfo authInfo, HomekitRegistry registry) { + this.authInfo = authInfo; + this.registry = registry; + } + + public HttpResponse handle(HttpRequest rawRequest) throws Exception { + PairVerificationRequest request = PairVerificationRequest.of(rawRequest.getBody()); + switch (request.getStage()) { + case ONE: + return stage1((Stage1Request) request); + + case TWO: + return stage2((Stage2Request) request); + + default: + return new NotFoundResponse(); + } + } + + private HttpResponse stage1(Stage1Request request) throws Exception { + logger.debug("Starting pair verification for " + registry.getLabel()); + clientPublicKey = request.getClientPublicKey(); + publicKey = new byte[32]; + byte[] privateKey = new byte[32]; + getSecureRandom().nextBytes(privateKey); + Curve25519.keygen(publicKey, null, privateKey); + + sharedSecret = new byte[32]; + Curve25519.curve(sharedSecret, privateKey, clientPublicKey); + + byte[] material = + ByteUtils.joinBytes( + publicKey, authInfo.getMac().getBytes(StandardCharsets.UTF_8), clientPublicKey); + + byte[] proof = new EdsaSigner(authInfo.getPrivateKey()).sign(material); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); + hkdf.init( + new HKDFParameters( + sharedSecret, + "Pair-Verify-Encrypt-Salt".getBytes(StandardCharsets.UTF_8), + "Pair-Verify-Encrypt-Info".getBytes(StandardCharsets.UTF_8))); + hkdfKey = new byte[32]; + hkdf.generateBytes(hkdfKey, 0, 32); + + Encoder encoder = TypeLengthValueUtils.getEncoder(); + encoder.add(MessageType.USERNAME, authInfo.getMac().getBytes(StandardCharsets.UTF_8)); + encoder.add(MessageType.SIGNATURE, proof); + byte[] plaintext = encoder.toByteArray(); + + ChachaEncoder chacha = new ChachaEncoder(hkdfKey, "PV-Msg02".getBytes(StandardCharsets.UTF_8)); + byte[] ciphertext = chacha.encodeCiphertext(plaintext); + + encoder = TypeLengthValueUtils.getEncoder(); + encoder.add(MessageType.STATE, (short) 2); + encoder.add(MessageType.ENCRYPTED_DATA, ciphertext); + encoder.add(MessageType.PUBLIC_KEY, publicKey); + return new PairingResponse(encoder.toByteArray()); + } + + private HttpResponse stage2(Stage2Request request) throws Exception { + ChachaDecoder chacha = new ChachaDecoder(hkdfKey, "PV-Msg03".getBytes(StandardCharsets.UTF_8)); + byte[] plaintext = chacha.decodeCiphertext(request.getAuthTagData(), request.getMessageData()); + + DecodeResult d = TypeLengthValueUtils.decode(plaintext); + byte[] clientUsername = d.getBytes(MessageType.USERNAME); + byte[] clientSignature = d.getBytes(MessageType.SIGNATURE); + + byte[] material = ByteUtils.joinBytes(clientPublicKey, clientUsername, publicKey); + + byte[] clientLtpk = + authInfo.getUserPublicKey( + authInfo.getMac() + new String(clientUsername, StandardCharsets.UTF_8)); + if (clientLtpk == null) { + throw new Exception("Unknown user: " + new String(clientUsername, StandardCharsets.UTF_8)); + } + + Encoder encoder = TypeLengthValueUtils.getEncoder(); + if (new EdsaVerifier(clientLtpk).verify(material, clientSignature)) { + encoder.add(MessageType.STATE, (short) 4); + logger.debug("Completed pair verification for " + registry.getLabel()); + return new UpgradeResponse( + encoder.toByteArray(), + createKey("Control-Write-Encryption-Key"), + createKey("Control-Read-Encryption-Key")); + } else { + encoder.add(MessageType.ERROR, (short) 4); + logger.warn("Invalid signature. Could not pair " + registry.getLabel()); + return new OkResponse(encoder.toByteArray()); + } + } + + private byte[] createKey(String info) { + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); + hkdf.init( + new HKDFParameters( + sharedSecret, + "Control-Salt".getBytes(StandardCharsets.UTF_8), + info.getBytes(StandardCharsets.UTF_8))); + byte[] key = new byte[32]; + hkdf.generateBytes(key, 0, 32); + return key; + } + + private static SecureRandom getSecureRandom() { + if (secureRandom == null) { + synchronized (PairVerificationManager.class) { + if (secureRandom == null) { + secureRandom = new SecureRandom(); + } + } + } + return secureRandom; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/PairVerificationRequest.java b/src/main/java/com/beowulfe/hap/impl/pairing/PairVerificationRequest.java index e9a3eccee..bd35df62b 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/PairVerificationRequest.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/PairVerificationRequest.java @@ -2,73 +2,69 @@ import com.beowulfe.hap.impl.pairing.TypeLengthValueUtils.DecodeResult; - abstract class PairVerificationRequest { - - private final static short VALUE_STAGE_1 = 1; - private final static short VALUE_STAGE_2 = 3; - - static PairVerificationRequest of(byte[] content) throws Exception { - DecodeResult d = TypeLengthValueUtils.decode(content); - short stage = d.getByte(MessageType.STATE); - switch(stage) { - case VALUE_STAGE_1: - return new Stage1Request(d); - - case VALUE_STAGE_2: - return new Stage2Request(d); - - default: - throw new Exception("Unknown pair process stage: "+stage); - } - } - - abstract Stage getStage(); - - static class Stage1Request extends PairVerificationRequest { - - private final byte[] clientPublicKey; - - public Stage1Request(DecodeResult d) { - clientPublicKey = d.getBytes(MessageType.PUBLIC_KEY); - } - - public byte[] getClientPublicKey() { - return clientPublicKey; - } - - @Override - Stage getStage() { - return Stage.ONE; - } - - } - - static class Stage2Request extends PairVerificationRequest { - - private final byte[] messageData; - private final byte[] authTagData; - - public Stage2Request(DecodeResult d) { - messageData = new byte[d.getLength(MessageType.ENCRYPTED_DATA) - 16]; - authTagData = new byte[16]; - d.getBytes(MessageType.ENCRYPTED_DATA, messageData, 0); - d.getBytes(MessageType.ENCRYPTED_DATA, authTagData, messageData.length); - } - - public byte[] getMessageData() { - return messageData; - } - - public byte[] getAuthTagData() { - return authTagData; - } - - @Override - public Stage getStage() { - return Stage.TWO; - } - - } + private static final short VALUE_STAGE_1 = 1; + private static final short VALUE_STAGE_2 = 3; + + static PairVerificationRequest of(byte[] content) throws Exception { + DecodeResult d = TypeLengthValueUtils.decode(content); + short stage = d.getByte(MessageType.STATE); + switch (stage) { + case VALUE_STAGE_1: + return new Stage1Request(d); + + case VALUE_STAGE_2: + return new Stage2Request(d); + + default: + throw new Exception("Unknown pair process stage: " + stage); + } + } + + abstract Stage getStage(); + + static class Stage1Request extends PairVerificationRequest { + + private final byte[] clientPublicKey; + + public Stage1Request(DecodeResult d) { + clientPublicKey = d.getBytes(MessageType.PUBLIC_KEY); + } + + public byte[] getClientPublicKey() { + return clientPublicKey; + } + + @Override + Stage getStage() { + return Stage.ONE; + } + } + + static class Stage2Request extends PairVerificationRequest { + + private final byte[] messageData; + private final byte[] authTagData; + + public Stage2Request(DecodeResult d) { + messageData = new byte[d.getLength(MessageType.ENCRYPTED_DATA) - 16]; + authTagData = new byte[16]; + d.getBytes(MessageType.ENCRYPTED_DATA, messageData, 0); + d.getBytes(MessageType.ENCRYPTED_DATA, authTagData, messageData.length); + } + + public byte[] getMessageData() { + return messageData; + } + + public byte[] getAuthTagData() { + return authTagData; + } + + @Override + public Stage getStage() { + return Stage.TWO; + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/PairingManager.java b/src/main/java/com/beowulfe/hap/impl/pairing/PairingManager.java index a4bae90a8..5d775bbc2 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/PairingManager.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/PairingManager.java @@ -1,8 +1,5 @@ package com.beowulfe.hap.impl.pairing; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.beowulfe.hap.HomekitAuthInfo; import com.beowulfe.hap.impl.HomekitRegistry; import com.beowulfe.hap.impl.http.HttpRequest; @@ -10,60 +7,63 @@ import com.beowulfe.hap.impl.jmdns.JmdnsHomekitAdvertiser; import com.beowulfe.hap.impl.responses.NotFoundResponse; import com.beowulfe.hap.impl.responses.UnauthorizedResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class PairingManager { - private final static Logger logger = LoggerFactory.getLogger(PairingManager.class); - - private final HomekitAuthInfo authInfo; - private final HomekitRegistry registry; - private final JmdnsHomekitAdvertiser advertiser; - - private SrpHandler srpHandler; - - public PairingManager(HomekitAuthInfo authInfo, HomekitRegistry registry, JmdnsHomekitAdvertiser advertiser) { - this.authInfo = authInfo; - this.registry = registry; - this.advertiser = advertiser; - } + private static final Logger logger = LoggerFactory.getLogger(PairingManager.class); + + private final HomekitAuthInfo authInfo; + private final HomekitRegistry registry; + private final JmdnsHomekitAdvertiser advertiser; + + private SrpHandler srpHandler; + + public PairingManager( + HomekitAuthInfo authInfo, HomekitRegistry registry, JmdnsHomekitAdvertiser advertiser) { + this.authInfo = authInfo; + this.registry = registry; + this.advertiser = advertiser; + } + + public HttpResponse handle(HttpRequest httpRequest) throws Exception { + PairSetupRequest req = PairSetupRequest.of(httpRequest.getBody()); + + if (req.getStage() == Stage.ONE) { + logger.info("Starting pair for " + registry.getLabel()); + srpHandler = new SrpHandler(authInfo.getPin(), authInfo.getSalt()); + return srpHandler.handle(req); + } else if (req.getStage() == Stage.TWO) { + logger.debug("Entering second stage of pair for " + registry.getLabel()); + if (srpHandler == null) { + logger.warn("Received unexpected stage 2 request for " + registry.getLabel()); + return new UnauthorizedResponse(); + } else { + try { + return srpHandler.handle(req); + } catch (Exception e) { + srpHandler = null; // You don't get to try again - need a new key + logger.error("Exception encountered while processing pairing request", e); + return new UnauthorizedResponse(); + } + } + } else if (req.getStage() == Stage.THREE) { + logger.debug("Entering third stage of pair for " + registry.getLabel()); + if (srpHandler == null) { + logger.warn("Received unexpected stage 3 request for " + registry.getLabel()); + return new UnauthorizedResponse(); + } else { + FinalPairHandler handler = new FinalPairHandler(srpHandler.getK(), authInfo, advertiser); + try { + return handler.handle(req); + } catch (Exception e) { + logger.error("Exception while finalizing pairing", e); + return new UnauthorizedResponse(); + } + } + } - public HttpResponse handle(HttpRequest httpRequest) throws Exception { - PairSetupRequest req = PairSetupRequest.of(httpRequest.getBody()); - - if (req.getStage() == Stage.ONE) { - logger.info("Starting pair for "+registry.getLabel()); - srpHandler = new SrpHandler(authInfo.getPin(), authInfo.getSalt()); - return srpHandler.handle(req); - } else if (req.getStage() == Stage.TWO) { - logger.debug("Entering second stage of pair for "+registry.getLabel()); - if (srpHandler == null) { - logger.warn("Received unexpected stage 2 request for "+registry.getLabel()); - return new UnauthorizedResponse(); - } else { - try { - return srpHandler.handle(req); - } catch (Exception e) { - srpHandler = null; //You don't get to try again - need a new key - logger.error("Exception encountered while processing pairing request", e); - return new UnauthorizedResponse(); - } - } - } else if (req.getStage() == Stage.THREE) { - logger.debug("Entering third stage of pair for "+registry.getLabel()); - if (srpHandler == null) { - logger.warn("Received unexpected stage 3 request for "+registry.getLabel()); - return new UnauthorizedResponse(); - } else { - FinalPairHandler handler = new FinalPairHandler(srpHandler.getK(), authInfo, advertiser); - try { - return handler.handle(req); - } catch (Exception e) { - logger.error("Exception while finalizing pairing", e); - return new UnauthorizedResponse(); - } - } - } - - return new NotFoundResponse(); - } + return new NotFoundResponse(); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/PairingResponse.java b/src/main/java/com/beowulfe/hap/impl/pairing/PairingResponse.java index 051f8765d..7c80e1721 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/PairingResponse.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/PairingResponse.java @@ -1,29 +1,28 @@ package com.beowulfe.hap.impl.pairing; +import com.beowulfe.hap.impl.responses.OkResponse; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import com.beowulfe.hap.impl.responses.OkResponse; - class PairingResponse extends OkResponse { - - private static final Map headers = Collections.unmodifiableMap( - new HashMap() { - private static final long serialVersionUID = 1L; - { - put("Content-type", "application/pairing+tlv8"); - } - }); - - public PairingResponse(byte[] body) { - super(body); - } - - @Override - public Map getHeaders() { - return headers; - } + private static final Map headers = + Collections.unmodifiableMap( + new HashMap() { + private static final long serialVersionUID = 1L; + + { + put("Content-type", "application/pairing+tlv8"); + } + }); + + public PairingResponse(byte[] body) { + super(body); + } + @Override + public Map getHeaders() { + return headers; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/PairingUpdateController.java b/src/main/java/com/beowulfe/hap/impl/pairing/PairingUpdateController.java index 22e9dfcf2..43287fffb 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/PairingUpdateController.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/PairingUpdateController.java @@ -1,42 +1,40 @@ package com.beowulfe.hap.impl.pairing; -import java.io.IOException; -import java.nio.charset.StandardCharsets; - import com.beowulfe.hap.HomekitAuthInfo; import com.beowulfe.hap.impl.http.HttpRequest; import com.beowulfe.hap.impl.http.HttpResponse; import com.beowulfe.hap.impl.jmdns.JmdnsHomekitAdvertiser; import com.beowulfe.hap.impl.pairing.TypeLengthValueUtils.DecodeResult; +import java.io.IOException; +import java.nio.charset.StandardCharsets; public class PairingUpdateController { - private final HomekitAuthInfo authInfo; - private final JmdnsHomekitAdvertiser advertiser; - - public PairingUpdateController(HomekitAuthInfo authInfo, JmdnsHomekitAdvertiser advertiser) { - this.authInfo = authInfo; - this.advertiser = advertiser; - } + private final HomekitAuthInfo authInfo; + private final JmdnsHomekitAdvertiser advertiser; + + public PairingUpdateController(HomekitAuthInfo authInfo, JmdnsHomekitAdvertiser advertiser) { + this.authInfo = authInfo; + this.advertiser = advertiser; + } - public HttpResponse handle(HttpRequest request) throws IOException { - DecodeResult d = TypeLengthValueUtils.decode(request.getBody()); - - int method = d.getByte(MessageType.METHOD); - if (method == 3) { //Add pairing - byte[] username = d.getBytes(MessageType.USERNAME); - byte[] ltpk = d.getBytes(MessageType.PUBLIC_KEY); - authInfo.createUser(authInfo.getMac()+new String(username, StandardCharsets.UTF_8), ltpk); - } else if (method == 4) { //Remove pairing - byte[] username = d.getBytes(MessageType.USERNAME); - authInfo.removeUser(authInfo.getMac()+new String(username, StandardCharsets.UTF_8)); - if (!authInfo.hasUser()) { - advertiser.setDiscoverable(true); - } - } else { - throw new RuntimeException("Unrecognized method: "+method); - } - return new PairingResponse(new byte[] {0x06, 0x01, 0x02}); - } + public HttpResponse handle(HttpRequest request) throws IOException { + DecodeResult d = TypeLengthValueUtils.decode(request.getBody()); + int method = d.getByte(MessageType.METHOD); + if (method == 3) { // Add pairing + byte[] username = d.getBytes(MessageType.USERNAME); + byte[] ltpk = d.getBytes(MessageType.PUBLIC_KEY); + authInfo.createUser(authInfo.getMac() + new String(username, StandardCharsets.UTF_8), ltpk); + } else if (method == 4) { // Remove pairing + byte[] username = d.getBytes(MessageType.USERNAME); + authInfo.removeUser(authInfo.getMac() + new String(username, StandardCharsets.UTF_8)); + if (!authInfo.hasUser()) { + advertiser.setDiscoverable(true); + } + } else { + throw new RuntimeException("Unrecognized method: " + method); + } + return new PairingResponse(new byte[] {0x06, 0x01, 0x02}); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/ServerEvidenceRoutineImpl.java b/src/main/java/com/beowulfe/hap/impl/pairing/ServerEvidenceRoutineImpl.java index 1140671f4..3eb1290cf 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/ServerEvidenceRoutineImpl.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/ServerEvidenceRoutineImpl.java @@ -1,32 +1,31 @@ package com.beowulfe.hap.impl.pairing; -import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - import com.nimbusds.srp6.SRP6CryptoParams; import com.nimbusds.srp6.SRP6ServerEvidenceContext; import com.nimbusds.srp6.ServerEvidenceRoutine; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; class ServerEvidenceRoutineImpl implements ServerEvidenceRoutine { - @Override - public BigInteger computeServerEvidence(SRP6CryptoParams cryptoParams, - SRP6ServerEvidenceContext ctx) { - - MessageDigest digest; - try { - digest = MessageDigest.getInstance(cryptoParams.H); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("Could not locate requested algorithm", e); - } - - byte[] hS = digest.digest(SrpHandler.bigIntegerToUnsignedByteArray(ctx.S)); - - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.A)); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.M1)); - digest.update(hS); - - return new BigInteger(1, digest.digest()); - } + @Override + public BigInteger computeServerEvidence( + SRP6CryptoParams cryptoParams, SRP6ServerEvidenceContext ctx) { + + MessageDigest digest; + try { + digest = MessageDigest.getInstance(cryptoParams.H); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("Could not locate requested algorithm", e); + } + + byte[] hS = digest.digest(SrpHandler.bigIntegerToUnsignedByteArray(ctx.S)); + + digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.A)); + digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.M1)); + digest.update(hS); + + return new BigInteger(1, digest.digest()); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/SrpHandler.java b/src/main/java/com/beowulfe/hap/impl/pairing/SrpHandler.java index 5274ff784..d95cab112 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/SrpHandler.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/SrpHandler.java @@ -1,12 +1,5 @@ package com.beowulfe.hap.impl.pairing; -import java.math.BigInteger; -import java.security.MessageDigest; -import java.util.Arrays; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.beowulfe.hap.impl.http.HttpResponse; import com.beowulfe.hap.impl.pairing.HomekitSRP6ServerSession.State; import com.beowulfe.hap.impl.pairing.PairSetupRequest.Stage2Request; @@ -14,85 +7,91 @@ import com.beowulfe.hap.impl.responses.ConflictResponse; import com.beowulfe.hap.impl.responses.NotFoundResponse; import com.nimbusds.srp6.*; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.util.Arrays; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; class SrpHandler { - // Precomputed safe 3072 bit prime 'N'. Origin RFC 5054, appendix A. - private final static BigInteger N_3072 = new BigInteger("5809605995369958062791915965639201402176612226902900533702900882779736177890990861472094774477339581147373410185646378328043729800750470098210924487866935059164371588168047540943981644516632755067501626434556398193186628990071248660819361205119793693985433297036118232914410171876807536457391277857011849897410207519105333355801121109356897459426271845471397952675959440793493071628394122780510124618488232602464649876850458861245784240929258426287699705312584509625419513463605155428017165714465363094021609290561084025893662561222573202082865797821865270991145082200656978177192827024538990239969175546190770645685893438011714430426409338676314743571154537142031573004276428701433036381801705308659830751190352946025482059931306571004727362479688415574702596946457770284148435989129632853918392117997472632693078113129886487399347796982772784615865232621289656944284216824611318709764535152507354116344703769998514148343807"); - private final static BigInteger G = BigInteger.valueOf(5); - private final static String IDENTIFIER = "Pair-Setup"; - - private final static Logger logger = LoggerFactory.getLogger(SrpHandler.class); - - private final BigInteger salt; - private final HomekitSRP6ServerSession session; - private final SRP6CryptoParams config; - private final String pin; - - public SrpHandler(String pin, BigInteger salt) { - config = new SRP6CryptoParams(N_3072, G, "SHA-512"); - session = new HomekitSRP6ServerSession(config); - session.setClientEvidenceRoutine(new ClientEvidenceRoutineImpl()); - session.setServerEvidenceRoutine(new ServerEvidenceRoutineImpl()); - this.pin = pin; - this.salt = salt; - } - - public HttpResponse handle(PairSetupRequest request) throws Exception { - switch(request.getStage()) { - case ONE: - return step1(); - - case TWO: - return step2((Stage2Request) request); - - default: - return new NotFoundResponse(); - } - } - - private HttpResponse step1() throws Exception { - if (session.getState() != State.INIT) { - logger.error("Session is not in state INIT when receiving step1"); - return new ConflictResponse(); - } - - SRP6VerifierGenerator verifierGenerator = new SRP6VerifierGenerator(config); - verifierGenerator.setXRoutine(new XRoutineWithUserIdentity()); - BigInteger verifier = verifierGenerator.generateVerifier(salt, IDENTIFIER, pin); - - Encoder encoder = TypeLengthValueUtils.getEncoder(); - encoder.add(MessageType.STATE, (short) 0x02); - encoder.add(MessageType.SALT, salt); - encoder.add(MessageType.PUBLIC_KEY, session.step1(IDENTIFIER, salt, verifier)); - return new PairingResponse(encoder.toByteArray()); - } - - private HttpResponse step2(Stage2Request request) throws Exception { - if (session.getState() != State.STEP_1) { - logger.error("Session is not in state Stage 1 when receiving step2"); - return new ConflictResponse(); - } - BigInteger m2 = session.step2(request.getA(), request.getM1()); - Encoder encoder = TypeLengthValueUtils.getEncoder(); - encoder.add(MessageType.STATE, (short) 0x04); - encoder.add(MessageType.PROOF, m2); - return new PairingResponse(encoder.toByteArray()); - } + // Precomputed safe 3072 bit prime 'N'. Origin RFC 5054, appendix A. + private static final BigInteger N_3072 = + new BigInteger( + "5809605995369958062791915965639201402176612226902900533702900882779736177890990861472094774477339581147373410185646378328043729800750470098210924487866935059164371588168047540943981644516632755067501626434556398193186628990071248660819361205119793693985433297036118232914410171876807536457391277857011849897410207519105333355801121109356897459426271845471397952675959440793493071628394122780510124618488232602464649876850458861245784240929258426287699705312584509625419513463605155428017165714465363094021609290561084025893662561222573202082865797821865270991145082200656978177192827024538990239969175546190770645685893438011714430426409338676314743571154537142031573004276428701433036381801705308659830751190352946025482059931306571004727362479688415574702596946457770284148435989129632853918392117997472632693078113129886487399347796982772784615865232621289656944284216824611318709764535152507354116344703769998514148343807"); + private static final BigInteger G = BigInteger.valueOf(5); + private static final String IDENTIFIER = "Pair-Setup"; + + private static final Logger logger = LoggerFactory.getLogger(SrpHandler.class); + + private final BigInteger salt; + private final HomekitSRP6ServerSession session; + private final SRP6CryptoParams config; + private final String pin; + + public SrpHandler(String pin, BigInteger salt) { + config = new SRP6CryptoParams(N_3072, G, "SHA-512"); + session = new HomekitSRP6ServerSession(config); + session.setClientEvidenceRoutine(new ClientEvidenceRoutineImpl()); + session.setServerEvidenceRoutine(new ServerEvidenceRoutineImpl()); + this.pin = pin; + this.salt = salt; + } + + public HttpResponse handle(PairSetupRequest request) throws Exception { + switch (request.getStage()) { + case ONE: + return step1(); + + case TWO: + return step2((Stage2Request) request); + + default: + return new NotFoundResponse(); + } + } + + private HttpResponse step1() throws Exception { + if (session.getState() != State.INIT) { + logger.error("Session is not in state INIT when receiving step1"); + return new ConflictResponse(); + } + + SRP6VerifierGenerator verifierGenerator = new SRP6VerifierGenerator(config); + verifierGenerator.setXRoutine(new XRoutineWithUserIdentity()); + BigInteger verifier = verifierGenerator.generateVerifier(salt, IDENTIFIER, pin); + + Encoder encoder = TypeLengthValueUtils.getEncoder(); + encoder.add(MessageType.STATE, (short) 0x02); + encoder.add(MessageType.SALT, salt); + encoder.add(MessageType.PUBLIC_KEY, session.step1(IDENTIFIER, salt, verifier)); + return new PairingResponse(encoder.toByteArray()); + } + + private HttpResponse step2(Stage2Request request) throws Exception { + if (session.getState() != State.STEP_1) { + logger.error("Session is not in state Stage 1 when receiving step2"); + return new ConflictResponse(); + } + BigInteger m2 = session.step2(request.getA(), request.getM1()); + Encoder encoder = TypeLengthValueUtils.getEncoder(); + encoder.add(MessageType.STATE, (short) 0x04); + encoder.add(MessageType.PROOF, m2); + return new PairingResponse(encoder.toByteArray()); + } - public byte[] getK() { - MessageDigest digest = session.getCryptoParams().getMessageDigestInstance(); - BigInteger S = session.getSessionKey(false); - byte[] sBytes = bigIntegerToUnsignedByteArray(S); - return digest.digest(sBytes); - } + public byte[] getK() { + MessageDigest digest = session.getCryptoParams().getMessageDigestInstance(); + BigInteger S = session.getSessionKey(false); + byte[] sBytes = bigIntegerToUnsignedByteArray(S); + return digest.digest(sBytes); + } - public static byte[] bigIntegerToUnsignedByteArray(BigInteger i) { - byte[] array = i.toByteArray(); - if (array[0] == 0) { - array = Arrays.copyOfRange(array, 1, array.length); - } - return array; - } - + public static byte[] bigIntegerToUnsignedByteArray(BigInteger i) { + byte[] array = i.toByteArray(); + if (array[0] == 0) { + array = Arrays.copyOfRange(array, 1, array.length); + } + return array; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/Stage.java b/src/main/java/com/beowulfe/hap/impl/pairing/Stage.java index 34000e319..68fe3362d 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/Stage.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/Stage.java @@ -1,7 +1,7 @@ package com.beowulfe.hap.impl.pairing; public enum Stage { - ONE, - TWO, - THREE -} \ No newline at end of file + ONE, + TWO, + THREE +} diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/TypeLengthValueUtils.java b/src/main/java/com/beowulfe/hap/impl/pairing/TypeLengthValueUtils.java index 2c5f38206..9e57efa17 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/TypeLengthValueUtils.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/TypeLengthValueUtils.java @@ -9,92 +9,88 @@ import java.util.Map; public class TypeLengthValueUtils { - - private TypeLengthValueUtils() { } - - public static DecodeResult decode(byte[] content) throws IOException { - DecodeResult ret = new DecodeResult(); - ByteArrayInputStream bais = new ByteArrayInputStream(content); - while(bais.available() > 0) { - byte type = (byte) (bais.read() & 0xFF); - int length = bais.read(); - byte[] part = new byte[length]; - bais.read(part); - ret.add(type, part); - } - return ret; - } - - public static Encoder getEncoder() { - return new Encoder(); - } - - public static final class Encoder { - - private final ByteArrayOutputStream baos; - - private Encoder() { - baos = new ByteArrayOutputStream(); - } - - public void add(MessageType type, BigInteger i) throws IOException { - add(type, ByteUtils.toByteArray(i)); - } - - public void add(MessageType type, short b) { - baos.write(type.getKey()); - baos.write(1); - baos.write(b); - } - - public void add(MessageType type, byte[] bytes) throws IOException { - InputStream bais = new ByteArrayInputStream(bytes); - while(bais.available() > 0) { - int toWrite = bais.available(); - toWrite = toWrite > 255 ? 255 : toWrite; - baos.write(type.getKey()); - baos.write(toWrite); - ByteUtils.copyStream(bais, baos, toWrite); - } - } - - public byte[] toByteArray() { - return baos.toByteArray(); - } - - } - - public static final class DecodeResult { - private final Map result = new HashMap<>(); - - private DecodeResult() { - } - - public byte getByte(MessageType type) { - return result.get(type.getKey())[0]; - } - - public BigInteger getBigInt(MessageType type) { - return new BigInteger(1, result.get(type.getKey())); - } - - public byte[] getBytes(MessageType type) { - return result.get(type.getKey()); - } - - public void getBytes(MessageType type, byte[] dest, int srcOffset) { - byte[] b = result.get(type.getKey()); - System.arraycopy(b, srcOffset, dest, 0, Math.min(dest.length, b.length)); - } - - public int getLength(MessageType type) { - return result.get(type.getKey()).length; - } - - private void add(short type, byte[] bytes) { - result.merge(type, bytes, ByteUtils::joinBytes); - } - - } - + + private TypeLengthValueUtils() {} + + public static DecodeResult decode(byte[] content) throws IOException { + DecodeResult ret = new DecodeResult(); + ByteArrayInputStream bais = new ByteArrayInputStream(content); + while (bais.available() > 0) { + byte type = (byte) (bais.read() & 0xFF); + int length = bais.read(); + byte[] part = new byte[length]; + bais.read(part); + ret.add(type, part); + } + return ret; + } + + public static Encoder getEncoder() { + return new Encoder(); + } + + public static final class Encoder { + + private final ByteArrayOutputStream baos; + + private Encoder() { + baos = new ByteArrayOutputStream(); + } + + public void add(MessageType type, BigInteger i) throws IOException { + add(type, ByteUtils.toByteArray(i)); + } + + public void add(MessageType type, short b) { + baos.write(type.getKey()); + baos.write(1); + baos.write(b); + } + + public void add(MessageType type, byte[] bytes) throws IOException { + InputStream bais = new ByteArrayInputStream(bytes); + while (bais.available() > 0) { + int toWrite = bais.available(); + toWrite = toWrite > 255 ? 255 : toWrite; + baos.write(type.getKey()); + baos.write(toWrite); + ByteUtils.copyStream(bais, baos, toWrite); + } + } + + public byte[] toByteArray() { + return baos.toByteArray(); + } + } + + public static final class DecodeResult { + private final Map result = new HashMap<>(); + + private DecodeResult() {} + + public byte getByte(MessageType type) { + return result.get(type.getKey())[0]; + } + + public BigInteger getBigInt(MessageType type) { + return new BigInteger(1, result.get(type.getKey())); + } + + public byte[] getBytes(MessageType type) { + return result.get(type.getKey()); + } + + public void getBytes(MessageType type, byte[] dest, int srcOffset) { + byte[] b = result.get(type.getKey()); + System.arraycopy(b, srcOffset, dest, 0, Math.min(dest.length, b.length)); + } + + public int getLength(MessageType type) { + return result.get(type.getKey()).length; + } + + private void add(short type, byte[] bytes) { + result.merge(type, bytes, ByteUtils::joinBytes); + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/pairing/UpgradeResponse.java b/src/main/java/com/beowulfe/hap/impl/pairing/UpgradeResponse.java index e16cdc147..81bf833ad 100644 --- a/src/main/java/com/beowulfe/hap/impl/pairing/UpgradeResponse.java +++ b/src/main/java/com/beowulfe/hap/impl/pairing/UpgradeResponse.java @@ -4,26 +4,25 @@ public class UpgradeResponse extends PairingResponse { - private final byte[] readKey; - private final byte[] writeKey; - - UpgradeResponse(byte[] body, byte[] readKey, byte[] writeKey) { - super(body); - this.readKey = readKey; - this.writeKey = writeKey; - } + private final byte[] readKey; + private final byte[] writeKey; - @Override - public boolean doUpgrade() { - return true; - } - - public ByteBuffer getReadKey() { - return ByteBuffer.wrap(readKey); - } - - public ByteBuffer getWriteKey() { - return ByteBuffer.wrap(writeKey); - } + UpgradeResponse(byte[] body, byte[] readKey, byte[] writeKey) { + super(body); + this.readKey = readKey; + this.writeKey = writeKey; + } + @Override + public boolean doUpgrade() { + return true; + } + + public ByteBuffer getReadKey() { + return ByteBuffer.wrap(readKey); + } + + public ByteBuffer getWriteKey() { + return ByteBuffer.wrap(writeKey); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/responses/ConflictResponse.java b/src/main/java/com/beowulfe/hap/impl/responses/ConflictResponse.java index 873669e6a..4b3dbcfcf 100644 --- a/src/main/java/com/beowulfe/hap/impl/responses/ConflictResponse.java +++ b/src/main/java/com/beowulfe/hap/impl/responses/ConflictResponse.java @@ -4,9 +4,8 @@ public class ConflictResponse implements HttpResponse { - @Override - public int getStatusCode() { - return 409; - } - + @Override + public int getStatusCode() { + return 409; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/responses/InternalServerErrorResponse.java b/src/main/java/com/beowulfe/hap/impl/responses/InternalServerErrorResponse.java index f2a978e53..ed98c3400 100644 --- a/src/main/java/com/beowulfe/hap/impl/responses/InternalServerErrorResponse.java +++ b/src/main/java/com/beowulfe/hap/impl/responses/InternalServerErrorResponse.java @@ -1,30 +1,28 @@ package com.beowulfe.hap.impl.responses; +import com.beowulfe.hap.impl.http.HttpResponse; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import com.beowulfe.hap.impl.http.HttpResponse; - public class InternalServerErrorResponse implements HttpResponse { - private final Exception e; - - public InternalServerErrorResponse(Exception e) { - this.e = e; - } - - @Override - public int getStatusCode() { - return 500; - } - - @Override - public ByteBuffer getBody() { - return ByteBuffer.wrap(e.getClass().getName().getBytes(StandardCharsets.UTF_8)); - } - - public Exception getException() { - return e; - } + private final Exception e; + + public InternalServerErrorResponse(Exception e) { + this.e = e; + } + + @Override + public int getStatusCode() { + return 500; + } + + @Override + public ByteBuffer getBody() { + return ByteBuffer.wrap(e.getClass().getName().getBytes(StandardCharsets.UTF_8)); + } + public Exception getException() { + return e; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/responses/NotFoundResponse.java b/src/main/java/com/beowulfe/hap/impl/responses/NotFoundResponse.java index 4c806a077..acf6256c8 100644 --- a/src/main/java/com/beowulfe/hap/impl/responses/NotFoundResponse.java +++ b/src/main/java/com/beowulfe/hap/impl/responses/NotFoundResponse.java @@ -4,9 +4,8 @@ public class NotFoundResponse implements HttpResponse { - @Override - public int getStatusCode() { - return 404; - } - + @Override + public int getStatusCode() { + return 404; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/responses/OkResponse.java b/src/main/java/com/beowulfe/hap/impl/responses/OkResponse.java index 34e7d61e6..2baa9a4db 100644 --- a/src/main/java/com/beowulfe/hap/impl/responses/OkResponse.java +++ b/src/main/java/com/beowulfe/hap/impl/responses/OkResponse.java @@ -1,25 +1,23 @@ package com.beowulfe.hap.impl.responses; -import java.nio.ByteBuffer; - import com.beowulfe.hap.impl.http.HttpResponse; +import java.nio.ByteBuffer; public class OkResponse implements HttpResponse { - private final ByteBuffer body; - - public OkResponse(byte[] body) { - this.body = ByteBuffer.wrap(body); - } - - @Override - public ByteBuffer getBody() { - return body; - } - - @Override - public int getStatusCode() { - return 200; - } + private final ByteBuffer body; + + public OkResponse(byte[] body) { + this.body = ByteBuffer.wrap(body); + } + + @Override + public ByteBuffer getBody() { + return body; + } + @Override + public int getStatusCode() { + return 200; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/responses/UnauthorizedResponse.java b/src/main/java/com/beowulfe/hap/impl/responses/UnauthorizedResponse.java index 4d481f366..12fe26d0f 100644 --- a/src/main/java/com/beowulfe/hap/impl/responses/UnauthorizedResponse.java +++ b/src/main/java/com/beowulfe/hap/impl/responses/UnauthorizedResponse.java @@ -4,9 +4,8 @@ public class UnauthorizedResponse implements HttpResponse { - @Override - public int getStatusCode() { - return 401; - } - + @Override + public int getStatusCode() { + return 401; + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/AbstractServiceImpl.java b/src/main/java/com/beowulfe/hap/impl/services/AbstractServiceImpl.java index 844b0ecb6..83d917cba 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/AbstractServiceImpl.java +++ b/src/main/java/com/beowulfe/hap/impl/services/AbstractServiceImpl.java @@ -1,12 +1,5 @@ package com.beowulfe.hap.impl.services; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.beowulfe.hap.HomekitAccessory; import com.beowulfe.hap.Service; import com.beowulfe.hap.accessories.BatteryAccessory; @@ -15,79 +8,82 @@ import com.beowulfe.hap.impl.characteristics.common.BatteryLevelCharacteristic; import com.beowulfe.hap.impl.characteristics.common.LowBatteryStatusCharacteristic; import com.beowulfe.hap.impl.characteristics.common.Name; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; abstract class AbstractServiceImpl implements Service { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final String type; - private final List characteristics = new LinkedList<>(); - - /** - * This constructor has been deprecated and replaced with - * {@link #AbstractServiceImpl(String, HomekitAccessory, String)}. Usages of - * this constructor will need to manually configure {@link Name} characteristic - * and {@link BatteryLevelCharacteristic} if needed. - * - * @param type unique UUID of the service. This information can be obtained from HomeKit Accessory Simulator. - */ - @Deprecated - public AbstractServiceImpl(String type) { - this(type, null, null); - } + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final String type; + private final List characteristics = new LinkedList<>(); - /** - *

- * Creates a new instance of this class with the specified UUID and {@link HomekitAccessory}. - * Download and install HomeKit Accessory Simulator to discover the corresponding UUID for - * the specific service. - *

- * - *

- * The new service will automatically add {@link Name} characteristic. If the accessory - * is battery operated then it must implement {@link BatteryAccessory} and {@link BatteryLevelCharacteristic} - * will be added too. - *

- * - * @param type unique UUID of the service. This information can be obtained from HomeKit Accessory Simulator. - * @param accessory HomeKit accessory exposed as a service. - * @param serviceName name of the service. This information is usually the name of the accessory. - */ - public AbstractServiceImpl(String type, HomekitAccessory accessory, String serviceName) { - this.type = type; + /** + * This constructor has been deprecated and replaced with {@link #AbstractServiceImpl(String, + * HomekitAccessory, String)}. Usages of this constructor will need to manually configure {@link + * Name} characteristic and {@link BatteryLevelCharacteristic} if needed. + * + * @param type unique UUID of the service. This information can be obtained from HomeKit Accessory + * Simulator. + */ + @Deprecated + public AbstractServiceImpl(String type) { + this(type, null, null); + } - if (accessory != null) { - // Add name characteristic - addCharacteristic(new Name(serviceName)); + /** + * Creates a new instance of this class with the specified UUID and {@link HomekitAccessory}. + * Download and install HomeKit Accessory Simulator to discover the corresponding UUID for + * the specific service. + * + *

The new service will automatically add {@link Name} characteristic. If the accessory is + * battery operated then it must implement {@link BatteryAccessory} and {@link + * BatteryLevelCharacteristic} will be added too. + * + * @param type unique UUID of the service. This information can be obtained from HomeKit Accessory + * Simulator. + * @param accessory HomeKit accessory exposed as a service. + * @param serviceName name of the service. This information is usually the name of the accessory. + */ + public AbstractServiceImpl(String type, HomekitAccessory accessory, String serviceName) { + this.type = type; - // If battery operated accessory then add BatteryLevelCharacteristic - if (accessory instanceof BatteryAccessory) { - logger.warn( - "Accessory {} implements BatteryAccessory, which was incorrectly used to advertise battery state and is not recognized by HomeKit. " - + "Battery-powered devices should report their battery status using LowBatteryStatusAccessory", - accessory.getClass()); - } + if (accessory != null) { + // Add name characteristic + addCharacteristic(new Name(serviceName)); - // If battery operated accessory then add LowBatteryStatusAccessory - if (accessory instanceof BatteryStatusAccessory) { - BatteryStatusAccessory batteryStatusAccessory = (BatteryStatusAccessory) accessory; - addCharacteristic(new LowBatteryStatusCharacteristic(batteryStatusAccessory::getLowBatteryState, - batteryStatusAccessory::subscribeLowBatteryState, - batteryStatusAccessory::unsubscribeLowBatteryState)); + // If battery operated accessory then add BatteryLevelCharacteristic + if (accessory instanceof BatteryAccessory) { + logger.warn( + "Accessory {} implements BatteryAccessory, which was incorrectly used to advertise battery state and is not recognized by HomeKit. " + + "Battery-powered devices should report their battery status using LowBatteryStatusAccessory", + accessory.getClass()); + } - } - } + // If battery operated accessory then add LowBatteryStatusAccessory + if (accessory instanceof BatteryStatusAccessory) { + BatteryStatusAccessory batteryStatusAccessory = (BatteryStatusAccessory) accessory; + addCharacteristic( + new LowBatteryStatusCharacteristic( + batteryStatusAccessory::getLowBatteryState, + batteryStatusAccessory::subscribeLowBatteryState, + batteryStatusAccessory::unsubscribeLowBatteryState)); + } } + } - @Override - public List getCharacteristics() { - return Collections.unmodifiableList(characteristics); - } + @Override + public List getCharacteristics() { + return Collections.unmodifiableList(characteristics); + } - @Override - public String getType() { - return type; - } + @Override + public String getType() { + return type; + } - protected void addCharacteristic(Characteristic characteristic) { - this.characteristics.add(characteristic); - } + protected void addCharacteristic(Characteristic characteristic) { + this.characteristics.add(characteristic); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/AccessoryInformationService.java b/src/main/java/com/beowulfe/hap/impl/services/AccessoryInformationService.java index b821f769d..7b22d130b 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/AccessoryInformationService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/AccessoryInformationService.java @@ -8,16 +8,16 @@ public class AccessoryInformationService extends AbstractServiceImpl { - public AccessoryInformationService(HomekitAccessory accessory) throws Exception { - this(accessory, accessory.getLabel()); - } - - public AccessoryInformationService(HomekitAccessory accessory, String serviceName) throws Exception { - super("0000003E-0000-1000-8000-0026BB765291", accessory, serviceName); - addCharacteristic(new Manufacturer(accessory)); - addCharacteristic(new Model(accessory)); - addCharacteristic(new SerialNumber(accessory)); - addCharacteristic(new Identify(accessory)); - } + public AccessoryInformationService(HomekitAccessory accessory) throws Exception { + this(accessory, accessory.getLabel()); + } + public AccessoryInformationService(HomekitAccessory accessory, String serviceName) + throws Exception { + super("0000003E-0000-1000-8000-0026BB765291", accessory, serviceName); + addCharacteristic(new Manufacturer(accessory)); + addCharacteristic(new Model(accessory)); + addCharacteristic(new SerialNumber(accessory)); + addCharacteristic(new Identify(accessory)); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/CarbonMonoxideSensorService.java b/src/main/java/com/beowulfe/hap/impl/services/CarbonMonoxideSensorService.java index c84633af9..8f331e57a 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/CarbonMonoxideSensorService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/CarbonMonoxideSensorService.java @@ -5,12 +5,13 @@ public class CarbonMonoxideSensorService extends AbstractServiceImpl { - public CarbonMonoxideSensorService(CarbonMonoxideSensor carbonMonoxideSensor) { - this(carbonMonoxideSensor, carbonMonoxideSensor.getLabel()); - } + public CarbonMonoxideSensorService(CarbonMonoxideSensor carbonMonoxideSensor) { + this(carbonMonoxideSensor, carbonMonoxideSensor.getLabel()); + } - public CarbonMonoxideSensorService(CarbonMonoxideSensor carbonMonoxideSensor, String serviceName) { - super("0000007F-0000-1000-8000-0026BB765291", carbonMonoxideSensor, serviceName); - addCharacteristic(new CarbonMonoxideDetectedCharacteristic(carbonMonoxideSensor)); - } + public CarbonMonoxideSensorService( + CarbonMonoxideSensor carbonMonoxideSensor, String serviceName) { + super("0000007F-0000-1000-8000-0026BB765291", carbonMonoxideSensor, serviceName); + addCharacteristic(new CarbonMonoxideDetectedCharacteristic(carbonMonoxideSensor)); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/ContactSensorService.java b/src/main/java/com/beowulfe/hap/impl/services/ContactSensorService.java index 5f7ff17fa..98321fd8c 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/ContactSensorService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/ContactSensorService.java @@ -5,12 +5,12 @@ public class ContactSensorService extends AbstractServiceImpl { - public ContactSensorService(ContactSensor contactSensor) { - this(contactSensor, contactSensor.getLabel()); - } + public ContactSensorService(ContactSensor contactSensor) { + this(contactSensor, contactSensor.getLabel()); + } - public ContactSensorService(ContactSensor contactSensor, String serviceName) { - super("00000080-0000-1000-8000-0026BB765291", contactSensor, serviceName); - addCharacteristic(new ContactSensorStateCharacteristic(contactSensor)); - } + public ContactSensorService(ContactSensor contactSensor, String serviceName) { + super("00000080-0000-1000-8000-0026BB765291", contactSensor, serviceName); + addCharacteristic(new ContactSensorStateCharacteristic(contactSensor)); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/FanService.java b/src/main/java/com/beowulfe/hap/impl/services/FanService.java index feb75c1c4..3303118a3 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/FanService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/FanService.java @@ -7,20 +7,19 @@ public class FanService extends AbstractServiceImpl { - public FanService(Fan fan) { - this(fan, fan.getLabel()); - } + public FanService(Fan fan) { + this(fan, fan.getLabel()); + } - public FanService(Fan fan, String serviceName) { - super("00000040-0000-1000-8000-0026BB765291", fan, serviceName); - addCharacteristic(new PowerStateCharacteristic( - () -> fan.getFanPower(), - v -> fan.setFanPower(v), - c -> fan.subscribeFanPower(c), - () -> fan.unsubscribeFanPower() - )); - addCharacteristic(new RotationDirectionCharacteristic(fan)); - addCharacteristic(new RotationSpeedCharacteristic(fan)); - } - -} \ No newline at end of file + public FanService(Fan fan, String serviceName) { + super("00000040-0000-1000-8000-0026BB765291", fan, serviceName); + addCharacteristic( + new PowerStateCharacteristic( + () -> fan.getFanPower(), + v -> fan.setFanPower(v), + c -> fan.subscribeFanPower(c), + () -> fan.unsubscribeFanPower())); + addCharacteristic(new RotationDirectionCharacteristic(fan)); + addCharacteristic(new RotationSpeedCharacteristic(fan)); + } +} diff --git a/src/main/java/com/beowulfe/hap/impl/services/GarageDoorService.java b/src/main/java/com/beowulfe/hap/impl/services/GarageDoorService.java index 6469a2387..8bdfcf85f 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/GarageDoorService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/GarageDoorService.java @@ -7,17 +7,18 @@ public class GarageDoorService extends AbstractServiceImpl { - public GarageDoorService(GarageDoor door) { - this(door, door.getLabel()); - } + public GarageDoorService(GarageDoor door) { + this(door, door.getLabel()); + } - public GarageDoorService(GarageDoor door, String serviceName) { - super("00000041-0000-1000-8000-0026BB765291", door, serviceName); - addCharacteristic(new CurrentDoorStateCharacteristic(door)); - addCharacteristic(new TargetDoorStateCharacteristic(door)); - addCharacteristic(new ObstructionDetectedCharacteristic(() -> door.getObstructionDetected(), - c -> door.subscribeObstructionDetected(c), - () -> door.unsubscribeObstructionDetected())); - } - -} \ No newline at end of file + public GarageDoorService(GarageDoor door, String serviceName) { + super("00000041-0000-1000-8000-0026BB765291", door, serviceName); + addCharacteristic(new CurrentDoorStateCharacteristic(door)); + addCharacteristic(new TargetDoorStateCharacteristic(door)); + addCharacteristic( + new ObstructionDetectedCharacteristic( + () -> door.getObstructionDetected(), + c -> door.subscribeObstructionDetected(c), + () -> door.unsubscribeObstructionDetected())); + } +} diff --git a/src/main/java/com/beowulfe/hap/impl/services/HumiditySensorService.java b/src/main/java/com/beowulfe/hap/impl/services/HumiditySensorService.java index 23b3c354e..4404185f2 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/HumiditySensorService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/HumiditySensorService.java @@ -4,14 +4,13 @@ import com.beowulfe.hap.impl.characteristics.humiditysensor.CurrentRelativeHumidityCharacteristic; public class HumiditySensorService extends AbstractServiceImpl { - - public HumiditySensorService(HumiditySensor sensor) { - this(sensor, sensor.getLabel()); - } - public HumiditySensorService(HumiditySensor sensor, String serviceName) { - super("00000082-0000-1000-8000-0026BB765291", sensor, serviceName); - addCharacteristic(new CurrentRelativeHumidityCharacteristic(sensor)); - } + public HumiditySensorService(HumiditySensor sensor) { + this(sensor, sensor.getLabel()); + } -} \ No newline at end of file + public HumiditySensorService(HumiditySensor sensor, String serviceName) { + super("00000082-0000-1000-8000-0026BB765291", sensor, serviceName); + addCharacteristic(new CurrentRelativeHumidityCharacteristic(sensor)); + } +} diff --git a/src/main/java/com/beowulfe/hap/impl/services/LeakSensorService.java b/src/main/java/com/beowulfe/hap/impl/services/LeakSensorService.java index cf712efa7..e342b0864 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/LeakSensorService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/LeakSensorService.java @@ -5,12 +5,12 @@ public class LeakSensorService extends AbstractServiceImpl { - public LeakSensorService(LeakSensor leakSensor) { - this(leakSensor, leakSensor.getLabel()); - } + public LeakSensorService(LeakSensor leakSensor) { + this(leakSensor, leakSensor.getLabel()); + } - public LeakSensorService(LeakSensor leakSensor, String serviceName) { - super("00000083-0000-1000-8000-0026BB765291", leakSensor, serviceName); - addCharacteristic(new LeakDetectedStateCharacteristic(leakSensor)); - } + public LeakSensorService(LeakSensor leakSensor, String serviceName) { + super("00000083-0000-1000-8000-0026BB765291", leakSensor, serviceName); + addCharacteristic(new LeakDetectedStateCharacteristic(leakSensor)); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/LightSensorService.java b/src/main/java/com/beowulfe/hap/impl/services/LightSensorService.java index b5c1610a3..3c1810371 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/LightSensorService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/LightSensorService.java @@ -5,12 +5,12 @@ public class LightSensorService extends AbstractServiceImpl { - public LightSensorService(LightSensor lightSensor) { - this(lightSensor, lightSensor.getLabel()); - } + public LightSensorService(LightSensor lightSensor) { + this(lightSensor, lightSensor.getLabel()); + } - public LightSensorService(LightSensor lightSensor, String serviceName) { - super("00000084-0000-1000-8000-0026BB765291", lightSensor, serviceName); - addCharacteristic(new AmbientLightLevelCharacteristic(lightSensor)); - } + public LightSensorService(LightSensor lightSensor, String serviceName) { + super("00000084-0000-1000-8000-0026BB765291", lightSensor, serviceName); + addCharacteristic(new AmbientLightLevelCharacteristic(lightSensor)); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/LightbulbService.java b/src/main/java/com/beowulfe/hap/impl/services/LightbulbService.java index 604d7176d..b8173d9d9 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/LightbulbService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/LightbulbService.java @@ -10,27 +10,26 @@ public class LightbulbService extends AbstractServiceImpl { - public LightbulbService(Lightbulb lightbulb) { - this(lightbulb, lightbulb.getLabel()); - } + public LightbulbService(Lightbulb lightbulb) { + this(lightbulb, lightbulb.getLabel()); + } - public LightbulbService(Lightbulb lightbulb, String serviceName) { - super("00000043-0000-1000-8000-0026BB765291", lightbulb, serviceName); - addCharacteristic(new PowerStateCharacteristic( - () -> lightbulb.getLightbulbPowerState(), - v -> lightbulb.setLightbulbPowerState(v), - c -> lightbulb.subscribeLightbulbPowerState(c), - () -> lightbulb.unsubscribeLightbulbPowerState() - )); - - if (lightbulb instanceof DimmableLightbulb) { - addCharacteristic(new BrightnessCharacteristic((DimmableLightbulb) lightbulb)); - } - - if (lightbulb instanceof ColorfulLightbulb) { - addCharacteristic(new HueCharacteristic((ColorfulLightbulb) lightbulb)); - addCharacteristic(new SaturationCharacteristic((ColorfulLightbulb) lightbulb)); - } - } + public LightbulbService(Lightbulb lightbulb, String serviceName) { + super("00000043-0000-1000-8000-0026BB765291", lightbulb, serviceName); + addCharacteristic( + new PowerStateCharacteristic( + () -> lightbulb.getLightbulbPowerState(), + v -> lightbulb.setLightbulbPowerState(v), + c -> lightbulb.subscribeLightbulbPowerState(c), + () -> lightbulb.unsubscribeLightbulbPowerState())); + if (lightbulb instanceof DimmableLightbulb) { + addCharacteristic(new BrightnessCharacteristic((DimmableLightbulb) lightbulb)); + } + + if (lightbulb instanceof ColorfulLightbulb) { + addCharacteristic(new HueCharacteristic((ColorfulLightbulb) lightbulb)); + addCharacteristic(new SaturationCharacteristic((ColorfulLightbulb) lightbulb)); + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/LockMechanismService.java b/src/main/java/com/beowulfe/hap/impl/services/LockMechanismService.java index e2817c1dc..5dc1f868d 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/LockMechanismService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/LockMechanismService.java @@ -7,16 +7,16 @@ public class LockMechanismService extends AbstractServiceImpl { - public LockMechanismService(LockMechanism lock) { - this(lock, lock.getLabel()); - } + public LockMechanismService(LockMechanism lock) { + this(lock, lock.getLabel()); + } - public LockMechanismService(LockMechanism lock, String serviceName) { - super("00000045-0000-1000-8000-0026BB765291", lock, serviceName); - addCharacteristic(new CurrentLockMechanismStateCharacteristic(lock)); - - if (lock instanceof LockableLockMechanism) { - addCharacteristic(new TargetLockMechanismStateCharacteristic((LockableLockMechanism) lock)); - } - } + public LockMechanismService(LockMechanism lock, String serviceName) { + super("00000045-0000-1000-8000-0026BB765291", lock, serviceName); + addCharacteristic(new CurrentLockMechanismStateCharacteristic(lock)); + + if (lock instanceof LockableLockMechanism) { + addCharacteristic(new TargetLockMechanismStateCharacteristic((LockableLockMechanism) lock)); + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/MotionSensorService.java b/src/main/java/com/beowulfe/hap/impl/services/MotionSensorService.java index ed2064f4d..d05a2db1f 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/MotionSensorService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/MotionSensorService.java @@ -5,12 +5,12 @@ public class MotionSensorService extends AbstractServiceImpl { - public MotionSensorService(MotionSensor motionSensor) { - this(motionSensor, motionSensor.getLabel()); - } + public MotionSensorService(MotionSensor motionSensor) { + this(motionSensor, motionSensor.getLabel()); + } - public MotionSensorService(MotionSensor motionSensor, String serviceName) { - super("00000085-0000-1000-8000-0026BB765291", motionSensor, serviceName); - addCharacteristic(new MotionDetectedStateCharacteristic(motionSensor)); - } + public MotionSensorService(MotionSensor motionSensor, String serviceName) { + super("00000085-0000-1000-8000-0026BB765291", motionSensor, serviceName); + addCharacteristic(new MotionDetectedStateCharacteristic(motionSensor)); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/OutletService.java b/src/main/java/com/beowulfe/hap/impl/services/OutletService.java index d7d5a68de..f4d14c384 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/OutletService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/OutletService.java @@ -6,19 +6,18 @@ public class OutletService extends AbstractServiceImpl { - public OutletService(Outlet outlet) { - this(outlet, outlet.getLabel()); - } - - public OutletService(Outlet outlet, String serviceName) { - super("00000047-0000-1000-8000-0026BB765291", outlet, serviceName); - addCharacteristic(new PowerStateCharacteristic( - () -> outlet.getPowerState(), - v -> outlet.setPowerState(v), - c -> outlet.subscribePowerState(c), - () -> outlet.unsubscribePowerState() - )); - addCharacteristic(new OutletInUseCharacteristic(outlet)); - } + public OutletService(Outlet outlet) { + this(outlet, outlet.getLabel()); + } + public OutletService(Outlet outlet, String serviceName) { + super("00000047-0000-1000-8000-0026BB765291", outlet, serviceName); + addCharacteristic( + new PowerStateCharacteristic( + () -> outlet.getPowerState(), + v -> outlet.setPowerState(v), + c -> outlet.subscribePowerState(c), + () -> outlet.unsubscribePowerState())); + addCharacteristic(new OutletInUseCharacteristic(outlet)); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/SecuritySystemService.java b/src/main/java/com/beowulfe/hap/impl/services/SecuritySystemService.java index 6d6f9a6bf..31226a550 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/SecuritySystemService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/SecuritySystemService.java @@ -7,14 +7,14 @@ public class SecuritySystemService extends AbstractServiceImpl { - public SecuritySystemService(SecuritySystem securitySystem) { - this(securitySystem, securitySystem.getLabel()); - } + public SecuritySystemService(SecuritySystem securitySystem) { + this(securitySystem, securitySystem.getLabel()); + } - public SecuritySystemService(SecuritySystem securitySystem, String serviceName) { - super("0000007E-0000-1000-8000-0026BB765291", securitySystem, serviceName); - addCharacteristic(new CurrentSecuritySystemStateCharacteristic(securitySystem)); - addCharacteristic(new TargetSecuritySystemStateCharacteristic(securitySystem)); - addCharacteristic(new SecuritySystemAlarmTypeCharacteristic(securitySystem)); - } + public SecuritySystemService(SecuritySystem securitySystem, String serviceName) { + super("0000007E-0000-1000-8000-0026BB765291", securitySystem, serviceName); + addCharacteristic(new CurrentSecuritySystemStateCharacteristic(securitySystem)); + addCharacteristic(new TargetSecuritySystemStateCharacteristic(securitySystem)); + addCharacteristic(new SecuritySystemAlarmTypeCharacteristic(securitySystem)); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/SmokeSensorService.java b/src/main/java/com/beowulfe/hap/impl/services/SmokeSensorService.java index 2f5c4e993..8e69ba427 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/SmokeSensorService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/SmokeSensorService.java @@ -5,12 +5,12 @@ public class SmokeSensorService extends AbstractServiceImpl { - public SmokeSensorService(SmokeSensor smokeSensor) { - this(smokeSensor, smokeSensor.getLabel()); - } + public SmokeSensorService(SmokeSensor smokeSensor) { + this(smokeSensor, smokeSensor.getLabel()); + } - public SmokeSensorService(SmokeSensor smokeSensor, String serviceName) { - super("00000087-0000-1000-8000-0026BB765291", smokeSensor, serviceName); - addCharacteristic(new SmokeDetectedCharacteristic(smokeSensor)); - } + public SmokeSensorService(SmokeSensor smokeSensor, String serviceName) { + super("00000087-0000-1000-8000-0026BB765291", smokeSensor, serviceName); + addCharacteristic(new SmokeDetectedCharacteristic(smokeSensor)); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/SwitchService.java b/src/main/java/com/beowulfe/hap/impl/services/SwitchService.java index 8bdda8989..01abf1f0d 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/SwitchService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/SwitchService.java @@ -5,18 +5,17 @@ public class SwitchService extends AbstractServiceImpl { - public SwitchService(Switch switchAccessory) { - this(switchAccessory, switchAccessory.getLabel()); - } + public SwitchService(Switch switchAccessory) { + this(switchAccessory, switchAccessory.getLabel()); + } - public SwitchService(Switch switchAccessory, String serviceName) { - super("00000049-0000-1000-8000-0026BB765291", switchAccessory, serviceName); - addCharacteristic(new PowerStateCharacteristic( - () -> switchAccessory.getSwitchState(), - v -> switchAccessory.setSwitchState(v), - c -> switchAccessory.subscribeSwitchState(c), - () -> switchAccessory.unsubscribeSwitchState() - )); - } - -} \ No newline at end of file + public SwitchService(Switch switchAccessory, String serviceName) { + super("00000049-0000-1000-8000-0026BB765291", switchAccessory, serviceName); + addCharacteristic( + new PowerStateCharacteristic( + () -> switchAccessory.getSwitchState(), + v -> switchAccessory.setSwitchState(v), + c -> switchAccessory.subscribeSwitchState(c), + () -> switchAccessory.unsubscribeSwitchState())); + } +} diff --git a/src/main/java/com/beowulfe/hap/impl/services/TemperatureSensorService.java b/src/main/java/com/beowulfe/hap/impl/services/TemperatureSensorService.java index b29bae501..2571b75f2 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/TemperatureSensorService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/TemperatureSensorService.java @@ -4,14 +4,13 @@ import com.beowulfe.hap.impl.characteristics.thermostat.CurrentTemperatureCharacteristic; public class TemperatureSensorService extends AbstractServiceImpl { - - public TemperatureSensorService(TemperatureSensor sensor) { - this(sensor, sensor.getLabel()); - } - public TemperatureSensorService(TemperatureSensor sensor, String serviceName) { - super("0000008A-0000-1000-8000-0026BB765291", sensor, serviceName); - addCharacteristic(new CurrentTemperatureCharacteristic(sensor)); - } + public TemperatureSensorService(TemperatureSensor sensor) { + this(sensor, sensor.getLabel()); + } + public TemperatureSensorService(TemperatureSensor sensor, String serviceName) { + super("0000008A-0000-1000-8000-0026BB765291", sensor, serviceName); + addCharacteristic(new CurrentTemperatureCharacteristic(sensor)); + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/ThermostatService.java b/src/main/java/com/beowulfe/hap/impl/services/ThermostatService.java index 564a28aeb..b15178903 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/ThermostatService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/ThermostatService.java @@ -7,23 +7,24 @@ public class ThermostatService extends AbstractServiceImpl { - public ThermostatService(BasicThermostat thermostat) { - this(thermostat, thermostat.getLabel()); - } - - public ThermostatService(BasicThermostat thermostat, String serviceName) { - super("0000004A-0000-1000-8000-0026BB765291", thermostat, serviceName); - addCharacteristic(new CurrentHeatingCoolingModeCharacteristic(thermostat)); - addCharacteristic(new CurrentTemperatureCharacteristic(thermostat)); - addCharacteristic(new TargetHeatingCoolingModeCharacteristic(thermostat)); - addCharacteristic(new TargetTemperatureCharacteristic(thermostat)); - addCharacteristic(new TemperatureUnitsCharacteristic(thermostat)); - if (thermostat instanceof HeatingThermostat) { - addCharacteristic(new HeatingThresholdTemperatureCharacteristic((HeatingThermostat) thermostat)); - } - if (thermostat instanceof CoolingThermostat) { - addCharacteristic(new CoolingThresholdTemperatureCharacteristic((CoolingThermostat) thermostat)); - } - } + public ThermostatService(BasicThermostat thermostat) { + this(thermostat, thermostat.getLabel()); + } + public ThermostatService(BasicThermostat thermostat, String serviceName) { + super("0000004A-0000-1000-8000-0026BB765291", thermostat, serviceName); + addCharacteristic(new CurrentHeatingCoolingModeCharacteristic(thermostat)); + addCharacteristic(new CurrentTemperatureCharacteristic(thermostat)); + addCharacteristic(new TargetHeatingCoolingModeCharacteristic(thermostat)); + addCharacteristic(new TargetTemperatureCharacteristic(thermostat)); + addCharacteristic(new TemperatureUnitsCharacteristic(thermostat)); + if (thermostat instanceof HeatingThermostat) { + addCharacteristic( + new HeatingThresholdTemperatureCharacteristic((HeatingThermostat) thermostat)); + } + if (thermostat instanceof CoolingThermostat) { + addCharacteristic( + new CoolingThresholdTemperatureCharacteristic((CoolingThermostat) thermostat)); + } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/ValveService.java b/src/main/java/com/beowulfe/hap/impl/services/ValveService.java index 601d55e69..ed4117765 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/ValveService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/ValveService.java @@ -10,23 +10,31 @@ public class ValveService extends AbstractServiceImpl { - public ValveService(Valve valve) { - this(valve, valve.getLabel()); - } + public ValveService(Valve valve) { + this(valve, valve.getLabel()); + } - public ValveService(Valve valve, String serviceName) { - super("000000D0-0000-1000-8000-0026BB765291", valve, serviceName); - addCharacteristic(new ActiveCharacteristic(valve::getValveActive, a -> valve.setValveActive(a), - valve::subscribeValveActive, valve::unsubscribeValveActive)); - addCharacteristic(new ValveTypeCharacteristic(valve)); - addCharacteristic(new InUseCharacteristic(valve::getValveInUse, valve::subscribeValveInUse, - valve::unsubscribeValveInUse)); + public ValveService(Valve valve, String serviceName) { + super("000000D0-0000-1000-8000-0026BB765291", valve, serviceName); + addCharacteristic( + new ActiveCharacteristic( + valve::getValveActive, + a -> valve.setValveActive(a), + valve::subscribeValveActive, + valve::unsubscribeValveActive)); + addCharacteristic(new ValveTypeCharacteristic(valve)); + addCharacteristic( + new InUseCharacteristic( + valve::getValveInUse, valve::subscribeValveInUse, valve::unsubscribeValveInUse)); - if (valve instanceof ValveWithTimer) { - ValveWithTimer vwt = (ValveWithTimer) valve; - addCharacteristic(new SetDurationCharacteristic(vwt)); - addCharacteristic(new RemainingDurationCharacteristic(vwt::getRemainingDuration, - vwt::subscribeRemainingDuration, vwt::unsubscribeRemainingDuration)); - } + if (valve instanceof ValveWithTimer) { + ValveWithTimer vwt = (ValveWithTimer) valve; + addCharacteristic(new SetDurationCharacteristic(vwt)); + addCharacteristic( + new RemainingDurationCharacteristic( + vwt::getRemainingDuration, + vwt::subscribeRemainingDuration, + vwt::unsubscribeRemainingDuration)); } + } } diff --git a/src/main/java/com/beowulfe/hap/impl/services/WindowCoveringService.java b/src/main/java/com/beowulfe/hap/impl/services/WindowCoveringService.java index 18d6499ba..f26cce03d 100644 --- a/src/main/java/com/beowulfe/hap/impl/services/WindowCoveringService.java +++ b/src/main/java/com/beowulfe/hap/impl/services/WindowCoveringService.java @@ -8,31 +8,37 @@ public class WindowCoveringService extends AbstractServiceImpl { - public WindowCoveringService(WindowCovering windowCovering) { - this(windowCovering, windowCovering.getLabel()); - } + public WindowCoveringService(WindowCovering windowCovering) { + this(windowCovering, windowCovering.getLabel()); + } - public WindowCoveringService(WindowCovering windowCovering, String serviceName) { - super("0000008C-0000-1000-8000-0026BB765291", windowCovering, serviceName); - addCharacteristic(new CurrentPositionCharacteristic(windowCovering)); - addCharacteristic(new HoldPositionCharacteristic(windowCovering)); - addCharacteristic(new PositionStateCharacteristic(windowCovering)); - addCharacteristic(new TargetPositionCharacteristic(windowCovering)); - addCharacteristic(new ObstructionDetectedCharacteristic(() -> windowCovering.getObstructionDetected(), - c -> windowCovering.subscribeObstructionDetected(c), - () -> windowCovering.unsubscribeObstructionDetected())); + public WindowCoveringService(WindowCovering windowCovering, String serviceName) { + super("0000008C-0000-1000-8000-0026BB765291", windowCovering, serviceName); + addCharacteristic(new CurrentPositionCharacteristic(windowCovering)); + addCharacteristic(new HoldPositionCharacteristic(windowCovering)); + addCharacteristic(new PositionStateCharacteristic(windowCovering)); + addCharacteristic(new TargetPositionCharacteristic(windowCovering)); + addCharacteristic( + new ObstructionDetectedCharacteristic( + () -> windowCovering.getObstructionDetected(), + c -> windowCovering.subscribeObstructionDetected(c), + () -> windowCovering.unsubscribeObstructionDetected())); - if (windowCovering instanceof HorizontalTiltingWindowCovering) { - addCharacteristic(new CurrentHorizontalTiltAngleCharacteristic( - (HorizontalTiltingWindowCovering) windowCovering)); - addCharacteristic(new TargetHorizontalTiltAngleCharacteristic( - (HorizontalTiltingWindowCovering) windowCovering)); - } - if (windowCovering instanceof VerticalTiltingWindowCovering) { - addCharacteristic(new CurrentVerticalTiltAngleCharacteristic( - (VerticalTiltingWindowCovering) windowCovering)); - addCharacteristic(new TargetVerticalTiltAngleCharacteristic( - (VerticalTiltingWindowCovering) windowCovering)); - } - } + if (windowCovering instanceof HorizontalTiltingWindowCovering) { + addCharacteristic( + new CurrentHorizontalTiltAngleCharacteristic( + (HorizontalTiltingWindowCovering) windowCovering)); + addCharacteristic( + new TargetHorizontalTiltAngleCharacteristic( + (HorizontalTiltingWindowCovering) windowCovering)); + } + if (windowCovering instanceof VerticalTiltingWindowCovering) { + addCharacteristic( + new CurrentVerticalTiltAngleCharacteristic( + (VerticalTiltingWindowCovering) windowCovering)); + addCharacteristic( + new TargetVerticalTiltAngleCharacteristic( + (VerticalTiltingWindowCovering) windowCovering)); + } + } } diff --git a/src/main/java/com/beowulfe/hap/package-info.java b/src/main/java/com/beowulfe/hap/package-info.java index 2a3f7b220..69e95d9d2 100644 --- a/src/main/java/com/beowulfe/hap/package-info.java +++ b/src/main/java/com/beowulfe/hap/package-info.java @@ -1,4 +1,5 @@ /** - * Base package for implementing the Homekit Accessory Protocol. Start with {@link com.beowulfe.hap.HomekitServer}. + * Base package for implementing the Homekit Accessory Protocol. Start with {@link + * com.beowulfe.hap.HomekitServer}. */ -package com.beowulfe.hap; \ No newline at end of file +package com.beowulfe.hap; diff --git a/src/test/java/com/beowulfe/hap/HomekitRootTest.java b/src/test/java/com/beowulfe/hap/HomekitRootTest.java index f6ce00c3e..869cb0e14 100644 --- a/src/test/java/com/beowulfe/hap/HomekitRootTest.java +++ b/src/test/java/com/beowulfe/hap/HomekitRootTest.java @@ -4,97 +4,99 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.*; -import java.util.concurrent.CompletableFuture; - -import org.junit.*; - import com.beowulfe.hap.impl.HomekitWebHandler; import com.beowulfe.hap.impl.http.HomekitClientConnectionFactory; import com.beowulfe.hap.impl.jmdns.JmdnsHomekitAdvertiser; +import java.util.concurrent.CompletableFuture; +import org.junit.*; public class HomekitRootTest { - - private HomekitAccessory accessory; - private HomekitRoot root; - private HomekitWebHandler webHandler; - private JmdnsHomekitAdvertiser advertiser; - private HomekitAuthInfo authInfo; - - private final static int PORT = 12345; - private final static String LABEL = "Test Label"; - - @Before - public void setup() throws Exception { - accessory = mock(HomekitAccessory.class); - when(accessory.getId()).thenReturn(2); - webHandler = mock(HomekitWebHandler.class); - when(webHandler.start(any())).thenReturn(CompletableFuture.completedFuture(PORT)); - advertiser = mock(JmdnsHomekitAdvertiser.class); - authInfo = mock(HomekitAuthInfo.class); - root = new HomekitRoot(LABEL, webHandler, authInfo, advertiser); - } - - @Test - public void verifyRegistryAdded() throws Exception { - root.addAccessory(accessory); - Assert.assertTrue("Registry does not contain accessory", root.getRegistry().getAccessories().contains(accessory)); - } - - @Test - public void verifyRegistryRemoved() throws Exception { - root.addAccessory(accessory); - root.removeAccessory(accessory); - Assert.assertFalse("Registry still contains accessory", root.getRegistry().getAccessories().contains(accessory)); - } - - @Test - public void testWebHandlerStarts() throws Exception { - root.start(); - verify(webHandler).start(any(HomekitClientConnectionFactory.class)); - } - - @Test - public void testWebHandlerStops() throws Exception { - root.start(); - root.stop(); - verify(webHandler).stop(); - } - - @Test - public void testAdvertiserStarts() throws Exception { - 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)); - } - - @Test - public void testAdvertiserStops() throws Exception { - root.start(); - root.stop(); - verify(advertiser).stop(); - } - - @Test - public void testAddAccessoryResetsWeb() { - root.start(); - verify(webHandler, never()).resetConnections(); - root.addAccessory(accessory); - verify(webHandler).resetConnections(); - } - - @Test - public void testRemoveAccessoryResetsWeb() { - root.addAccessory(accessory); - root.start(); - verify(webHandler, never()).resetConnections(); - root.removeAccessory(accessory); - verify(webHandler).resetConnections(); - } - @Test(expected=IndexOutOfBoundsException.class) - public void testAddIndexOneAccessory() throws Exception { - when(accessory.getId()).thenReturn(1); - root.addAccessory(accessory); - } + private HomekitAccessory accessory; + private HomekitRoot root; + private HomekitWebHandler webHandler; + private JmdnsHomekitAdvertiser advertiser; + private HomekitAuthInfo authInfo; + + private static final int PORT = 12345; + private static final String LABEL = "Test Label"; + + @Before + public void setup() throws Exception { + accessory = mock(HomekitAccessory.class); + when(accessory.getId()).thenReturn(2); + webHandler = mock(HomekitWebHandler.class); + when(webHandler.start(any())).thenReturn(CompletableFuture.completedFuture(PORT)); + advertiser = mock(JmdnsHomekitAdvertiser.class); + authInfo = mock(HomekitAuthInfo.class); + root = new HomekitRoot(LABEL, webHandler, authInfo, advertiser); + } + + @Test + public void verifyRegistryAdded() throws Exception { + root.addAccessory(accessory); + Assert.assertTrue( + "Registry does not contain accessory", + root.getRegistry().getAccessories().contains(accessory)); + } + + @Test + public void verifyRegistryRemoved() throws Exception { + root.addAccessory(accessory); + root.removeAccessory(accessory); + Assert.assertFalse( + "Registry still contains accessory", + root.getRegistry().getAccessories().contains(accessory)); + } + + @Test + public void testWebHandlerStarts() throws Exception { + root.start(); + verify(webHandler).start(any(HomekitClientConnectionFactory.class)); + } + + @Test + public void testWebHandlerStops() throws Exception { + root.start(); + root.stop(); + verify(webHandler).stop(); + } + + @Test + public void testAdvertiserStarts() throws Exception { + 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)); + } + + @Test + public void testAdvertiserStops() throws Exception { + root.start(); + root.stop(); + verify(advertiser).stop(); + } + + @Test + public void testAddAccessoryResetsWeb() { + root.start(); + verify(webHandler, never()).resetConnections(); + root.addAccessory(accessory); + verify(webHandler).resetConnections(); + } + + @Test + public void testRemoveAccessoryResetsWeb() { + root.addAccessory(accessory); + root.start(); + verify(webHandler, never()).resetConnections(); + root.removeAccessory(accessory); + verify(webHandler).resetConnections(); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testAddIndexOneAccessory() throws Exception { + when(accessory.getId()).thenReturn(1); + root.addAccessory(accessory); + } }