diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 000000000..d439198c7 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,38 @@ +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Java CI with Maven and Deploy + +on: + push: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 for Maven Central + uses: actions/setup-java@v1 + with: + java-version: '11' + architecture: x64 + server-id: ossrh + gpg-private-key: ${{ secrets.GPG_SECRET_KEY }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE + server-username: MAVEN_USERNAME + server-password: MAVEN_CENTRAL_TOKEN + - name: Setup git profile + run: | + git config --global user.name github-actions + git config --global user.email github-actions@github.com + - name: Publish Snapshot to Maven Central + run: mvn deploy -B -Possrh + env: + MAVEN_USERNAME: hap-java-dev + MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + - name: Publish site + run: mvn -B site-deploy -Dusername=github-actions -Dpassword=${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 000000000..a07bff253 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,23 @@ +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Java CI with Maven + +on: + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: '11' + architecture: x64 + - name: Build with Maven + run: mvn -B package --file pom.xml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..0aa72794f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,39 @@ +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Stage Release on Master Branch + +on: + workflow_dispatch: + inputs: + releaseVersion: + description: Version to release + required: true + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: '11' + architecture: x64 + server-id: ossrh + gpg-private-key: ${{ secrets.GPG_SECRET_KEY }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE + server-username: MAVEN_USERNAME + server-password: MAVEN_CENTRAL_TOKEN + - name: Setup git profile + run: | + git config user.name github-actions + git config user.email github-actions@github.com + - name: Maven release + run: mvn release:prepare release:perform -B -DreleaseVersion=${{ github.event.inputs.releaseVersion }} -Possrh + env: + MAVEN_USERNAME: hap-java-dev + MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/CHANGES.md b/CHANGES.md index 758ddf6f7..73ecb18af 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,11 @@ * Valid values are supported for enum characteristics instead of min and max values * Supported valid states for Thermostat, SecuritySystem, HeaterCooler and HumidifierDehumidifier [#108] [#120](https://github.com/hap-java/HAP-Java/pull/120) * Support for FilterMaintenance. Can be used as a linked service for an Air Purifier [#124](https://github.com/hap-java/HAP-Java/pull/124) +* Update crypto libs [#130](https://github.com/hap-java/HAP-Java/pull/130) + +## Fixes + +* Fix for re-advertising service when using alternative jMDNS implementations. # HAP-Java 1.1.5 diff --git a/README.md b/README.md index 463f5d49b..03fb0aaba 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ HAP-Java ========= +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.hap-java/hap/badge.svg)](https://search.maven.org/search?q=g:io.github.hap-java%20a:hap) +[![MIT License](https://img.shields.io/github/license/hap-java/HAP-Java)](https://github.com/hap-java/HAP-Java/blob/master/LICENSE) +![Maven Build Status](https://github.com/andylintner/HAP-Java/actions/workflows/maven.yml/badge.svg) + HAP-Java is a Java implementation of the HomeKit Accessory Protocol. Using this library, you can create your own HomeKit Accessory or HomeKit Accessory Bridge. @@ -18,7 +22,8 @@ Include HAP-Java in your project using maven: ``` -After that, check out the [Sample](https://github.com/hap-java/HAP-Java/tree/sample). +After that, check out the [Sample](https://github.com/hap-java/HAP-Java/tree/sample) and +read the [Javadoc](https://hap-java.github.io/HAP-Java/apidocs/index.html) Supported HomeKit Accessories ========= diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 000000000..a3001c9f3 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,7 @@ +# How to release HAP-Java + +These actions can only be performed by someone with maintainer level access to the repository. + +1. Run the [Stage Release on Master Branch](https://github.com/hap-java/HAP-Java/actions/workflows/release.yml) Action +2. After this completes, find the release on the [Releases page](https://github.com/hap-java/HAP-Java/releases) +3. Edit the release to include the changelog details diff --git a/deploy/distribution.xml b/deploy/distribution.xml deleted file mode 100644 index a2cf6d668..000000000 --- a/deploy/distribution.xml +++ /dev/null @@ -1,18 +0,0 @@ - - dir-with-dependencies - - dir - - false - - - / - true - false - ${artifact.groupId}.${artifact.artifactId}-${artifact.version}${dashClassifier?}.jar - runtime - - - \ No newline at end of file diff --git a/deploy/publish.sh b/deploy/publish.sh deleted file mode 100755 index 1fb261646..000000000 --- a/deploy/publish.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -if [[ ( $TRAVIS_PULL_REQUEST == "false" && $TRAVIS_BRANCH == "master" ) ]]; then - mvn deploy --settings deploy/settings.xml -DperformRelease=true -DskipTests=true - exit $? -fi diff --git a/deploy/pubring.gpg.enc b/deploy/pubring.gpg.enc deleted file mode 100644 index 1361f5a9f..000000000 Binary files a/deploy/pubring.gpg.enc and /dev/null differ diff --git a/deploy/secring.gpg.enc b/deploy/secring.gpg.enc deleted file mode 100644 index 1f1c31049..000000000 Binary files a/deploy/secring.gpg.enc and /dev/null differ diff --git a/deploy/settings.xml b/deploy/settings.xml deleted file mode 100644 index f08c008c0..000000000 --- a/deploy/settings.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - ossrh - ${env.SONATYPE_USERNAME} - ${env.SONATYPE_PASSWORD} - - - diff --git a/pom.xml b/pom.xml index 5faf6eafc..8e38a1880 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ scm:git:https://github.com/hap-java/HAP-Java.git - scm:git:git@github.com:hap-java/HAP-Java.git + scm:git:https://github.com/hap-java/HAP-Java.git https://github.com/hap-java/HAP-Java.git HEAD @@ -100,37 +100,31 @@ com.nimbusds srp6a - 1.5.2 + 2.1.0 org.bouncycastle bcprov-jdk15on - 1.51 + 1.69 net.vrallev.ecc ecc-25519-java - 1.0.1 - - - - org.zeromq - curve25519-java - 0.1.0 + 1.0.3 javax.json javax.json-api - 1.0 + 1.1.4 org.glassfish javax.json - 1.0.4 + 1.1.4 @@ -148,8 +142,15 @@ org.mockito - mockito-all - 1.10.19 + mockito-core + 3.8.0 + test + + + + org.assertj + assertj-core + 3.19.0 test @@ -208,28 +209,10 @@ - - maven-assembly-plugin - 3.1.1 - - - deploy/distribution.xml - - - - - make-assembly - package - - single - - - - org.apache.maven.plugins maven-scm-publish-plugin - 3.0.0 + 3.1.0 scm-publish @@ -238,7 +221,7 @@ publish-scm - scm:git:git@github.com:hap-java/HAP-Java.git + scm:git:https://github.com/hap-java/HAP-Java.git gh-pages @@ -284,11 +267,11 @@ ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ ossrh - https://oss.sonatype.org/content/repositories/snapshots + https://s01.oss.sonatype.org/content/repositories/snapshots @@ -305,6 +288,8 @@ 3.0.1 io.github.hapjava.server.impl + 8 + false @@ -325,20 +310,6 @@ ossrh - - gpg - ${env.GPG_KEYNAME} - ${env.GPG_PASSPHRASE} - false - deploy/pubring.gpg - deploy/secring.gpg - - - - performRelease - true - - @@ -354,6 +325,13 @@ + + HAP-Java + + --pinentry-mode + loopback + + org.sonatype.plugins @@ -362,17 +340,12 @@ true ossrh - https://oss.sonatype.org/ + https://s01.oss.sonatype.org/ true - - org.apache.maven.plugins - maven-release-plugin - 2.5.3 - - + diff --git a/src/main/java/io/github/hapjava/accessories/LightSensorAccessory.java b/src/main/java/io/github/hapjava/accessories/LightSensorAccessory.java index bcdab09c4..2087b1e99 100644 --- a/src/main/java/io/github/hapjava/accessories/LightSensorAccessory.java +++ b/src/main/java/io/github/hapjava/accessories/LightSensorAccessory.java @@ -1,6 +1,7 @@ package io.github.hapjava.accessories; import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback; +import io.github.hapjava.characteristics.impl.lightsensor.CurrentAmbientLightLevelCharacteristic; import io.github.hapjava.services.Service; import io.github.hapjava.services.impl.LightSensorService; import java.util.Collection; @@ -31,6 +32,36 @@ public interface LightSensorAccessory extends HomekitAccessory { /** Unsubscribes from changes in the current ambient light level. */ void unsubscribeCurrentAmbientLightLevel(); + /** + * return the min value for current ambient light level. overwrite if you want to change the + * default value. + * + * @return min current ambient light level + */ + default double getMinCurrentAmbientLightLevel() { + return CurrentAmbientLightLevelCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for current ambient light level. overwrite if you want to change the + * default value. + * + * @return max current ambient light level + */ + default double getMaxCurrentAmbientLightLevel() { + return CurrentAmbientLightLevelCharacteristic.DEFAULT_MAX_VALUE; + } + + /** + * return the min step value for current ambient light level. overwrite if you want to change the + * default value. + * + * @return min step current ambient light level + */ + default double getMinStepCurrentAmbientLightLevel() { + return CurrentAmbientLightLevelCharacteristic.DEFAULT_STEP; + } + @Override default Collection getServices() { return Collections.singleton(new LightSensorService(this)); diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithCarbonDioxideLevel.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithCarbonDioxideLevel.java index bd4bb3afc..bd143b22f 100644 --- a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithCarbonDioxideLevel.java +++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithCarbonDioxideLevel.java @@ -1,6 +1,8 @@ package io.github.hapjava.accessories.optionalcharacteristic; import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback; +import io.github.hapjava.characteristics.impl.carbondioxidesensor.CarbonDioxideLevelCharacteristic; +import io.github.hapjava.characteristics.impl.carbondioxidesensor.CarbonDioxidePeakLevelCharacteristic; import java.util.concurrent.CompletableFuture; /** Accessory with carbon dioxide level and peak level characteristic. */ @@ -20,6 +22,66 @@ public interface AccessoryWithCarbonDioxideLevel { */ CompletableFuture getCarbonDioxideLevel(); + /** + * return the min value for carbon dioxide level. overwrite if you want to change the default + * value. + * + * @return min carbon dioxide level + */ + default double getMinCarbonDioxideLevel() { + return CarbonDioxideLevelCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for carbon dioxide level. overwrite if you want to change the default + * value. + * + * @return max carbon dioxide level + */ + default double getMaxCarbonDioxideLevel() { + return CarbonDioxideLevelCharacteristic.DEFAULT_MAX_VALUE; + } + + /** + * return the min step value for carbon dioxide level. overwrite if you want to change the default + * value. + * + * @return min step carbon dioxide level + */ + default double getMinStepCarbonDioxideLevel() { + return CarbonDioxideLevelCharacteristic.DEFAULT_STEP; + } + + /** + * return the min value for carbon dioxide peak level. overwrite if you want to change the default + * value. + * + * @return min carbon dioxide peak level + */ + default double getMinCarbonDioxidePeakLevel() { + return CarbonDioxidePeakLevelCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for carbon dioxide peak level. overwrite if you want to change the default + * value. + * + * @return max carbon dioxide peak level + */ + default double getMaxCarbonDioxidePeakLevel() { + return CarbonDioxidePeakLevelCharacteristic.DEFAULT_MAX_VALUE; + } + + /** + * return the min step value for carbon dioxide peak level. overwrite if you want to change the + * default value. + * + * @return min step carbon dioxide peak level + */ + default double getMinStepCarbonDioxidePeakLevel() { + return CarbonDioxidePeakLevelCharacteristic.DEFAULT_STEP; + } + /** * Subscribes to changes in the carbon dioxide level. * diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithCarbonMonoxideLevel.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithCarbonMonoxideLevel.java index a3946c40b..cbccd9647 100644 --- a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithCarbonMonoxideLevel.java +++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithCarbonMonoxideLevel.java @@ -1,9 +1,11 @@ package io.github.hapjava.accessories.optionalcharacteristic; import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback; +import io.github.hapjava.characteristics.impl.carbonmonoxidesensor.CarbonMonoxideLevelCharacteristic; +import io.github.hapjava.characteristics.impl.carbonmonoxidesensor.CarbonMonoxidePeakLevelCharacteristic; import java.util.concurrent.CompletableFuture; -/** Accessory with carbon dioxide level and peak level characteristic. */ +/** Accessory with carbon monoxide level and peak level characteristic. */ public interface AccessoryWithCarbonMonoxideLevel { /** @@ -20,6 +22,66 @@ public interface AccessoryWithCarbonMonoxideLevel { */ CompletableFuture getCarbonMonoxideLevel(); + /** + * return the min value for carbon monoxide level. overwrite if you want to change the default + * value. + * + * @return min carbon monoxide level + */ + default double getMinCarbonMonoxideLevel() { + return CarbonMonoxideLevelCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for carbon monoxide level. overwrite if you want to change the default + * value. + * + * @return max carbon monoxide level + */ + default double getMaxCarbonMonoxideLevel() { + return CarbonMonoxideLevelCharacteristic.DEFAULT_MAX_VALUE; + } + + /** + * return the min step value for carbon monoxide level. overwrite if you want to change the + * default value. + * + * @return min step carbon monoxide level + */ + default double getMinStepCarbonMonoxideLevel() { + return CarbonMonoxideLevelCharacteristic.DEFAULT_STEP; + } + + /** + * return the min value for carbon monoxide peak level. overwrite if you want to change the + * default value. + * + * @return min carbon monoxide peak level + */ + default double getMinCarbonMonoxidePeakLevel() { + return CarbonMonoxidePeakLevelCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for carbon monoxide peak level. overwrite if you want to change the + * default value. + * + * @return max carbon monoxide peak level + */ + default double getMaxCarbonMonoxidePeakLevel() { + return CarbonMonoxidePeakLevelCharacteristic.DEFAULT_MAX_VALUE; + } + + /** + * return the min step value for carbon monoxide peak level. overwrite if you want to change the + * default value. + * + * @return min step carbon monoxide peak level + */ + default double getMinStepCarbonMonoxidePeakLevel() { + return CarbonMonoxidePeakLevelCharacteristic.DEFAULT_STEP; + } + /** * Subscribes to changes in the carbon monoxide level. * diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithColorTemperature.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithColorTemperature.java index fee36884d..ecf74ba63 100644 --- a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithColorTemperature.java +++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithColorTemperature.java @@ -1,6 +1,7 @@ package io.github.hapjava.accessories.optionalcharacteristic; import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback; +import io.github.hapjava.characteristics.impl.lightbulb.ColorTemperatureCharacteristic; import java.util.concurrent.CompletableFuture; /** Accessory with color temperature. */ @@ -22,6 +23,24 @@ public interface AccessoryWithColorTemperature { */ CompletableFuture setColorTemperature(Integer value) throws Exception; + /** + * return the min value for color temperature. overwrite if you want to change the default value. + * + * @return min color temperature + */ + default int getMinColorTemperature() { + return ColorTemperatureCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for color temperature. overwrite if you want to change the default value. + * + * @return max color temperature + */ + default int getMaxColorTemperature() { + return ColorTemperatureCharacteristic.DEFAULT_MAX_VALUE; + } + /** * Subscribes to changes in color temperature. * diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithDuration.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithDuration.java index e3d310dfd..a5cebf97c 100644 --- a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithDuration.java +++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithDuration.java @@ -1,6 +1,7 @@ package io.github.hapjava.accessories.optionalcharacteristic; import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback; +import io.github.hapjava.characteristics.impl.valve.SetDurationCharacteristic; import java.util.concurrent.CompletableFuture; /** Accessory with duration characteristic. */ @@ -13,6 +14,24 @@ public interface AccessoryWithDuration { */ CompletableFuture getSetDuration(); + /** + * return the min value for duration. overwrite if you want to change the default value. + * + * @return min remaining duration + */ + default int getMinDuration() { + return SetDurationCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for duration. overwrite if you want to change the default value. + * + * @return max duration + */ + default int getMaxDuration() { + return SetDurationCharacteristic.DEFAULT_MAX_VALUE; + } + /** * Sets the duration for which the service should run. * diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithNitrogenDioxideDensity.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithNitrogenDioxideDensity.java index 685edfb5c..6aead4f98 100644 --- a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithNitrogenDioxideDensity.java +++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithNitrogenDioxideDensity.java @@ -1,6 +1,7 @@ package io.github.hapjava.accessories.optionalcharacteristic; import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback; +import io.github.hapjava.characteristics.impl.airquality.NitrogenDioxideDensityCharacteristic; import java.util.concurrent.CompletableFuture; /** Accessory with nitrogen dioxide density characteristic. */ @@ -13,6 +14,36 @@ public interface AccessoryWithNitrogenDioxideDensity { */ CompletableFuture getNitrogenDioxideDensity(); + /** + * return the min value for nitrogen dioxide density. overwrite if you want to change the default + * value. + * + * @return min nitrogen dioxide density + */ + default double getMinNitrogenDioxideDensity() { + return NitrogenDioxideDensityCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for nitrogen dioxide density. overwrite if you want to change the default + * value. + * + * @return max nitrogen dioxide density + */ + default double getMaxNitrogenDioxideDensity() { + return NitrogenDioxideDensityCharacteristic.DEFAULT_MAX_VALUE; + } + + /** + * return the min step value for nitrogen dioxide density. overwrite if you want to change the + * default value. + * + * @return min step nitrogen dioxide density + */ + default double getMinStepNitrogenDioxideDensity() { + return NitrogenDioxideDensityCharacteristic.DEFAULT_STEP; + } + /** * Subscribes to changes in nitrogen dioxide density. * diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithOzoneDensity.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithOzoneDensity.java index 87bb8fa74..efba2a49f 100644 --- a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithOzoneDensity.java +++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithOzoneDensity.java @@ -1,6 +1,7 @@ package io.github.hapjava.accessories.optionalcharacteristic; import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback; +import io.github.hapjava.characteristics.impl.airquality.OzoneDensityCharacteristic; import java.util.concurrent.CompletableFuture; /** Accessory with Ozone Density characteristic. */ @@ -13,6 +14,33 @@ public interface AccessoryWithOzoneDensity { */ CompletableFuture getOzoneDensity(); + /** + * return the min value for ozone density. overwrite if you want to change the default value. + * + * @return min ozone density + */ + default double getMinOzoneDensity() { + return OzoneDensityCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for ozone density. overwrite if you want to change the default value. + * + * @return max ozone density + */ + default double getMaxOzoneDensity() { + return OzoneDensityCharacteristic.DEFAULT_MAX_VALUE; + } + + /** + * return the min step value for ozone density. overwrite if you want to change the default value. + * + * @return min step ozone density + */ + default double getMinStepOzoneDensity() { + return OzoneDensityCharacteristic.DEFAULT_STEP; + } + /** * Subscribes to changes in ozone density. * diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPM10Density.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPM10Density.java index 2bfad14ac..2ae3cded0 100644 --- a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPM10Density.java +++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPM10Density.java @@ -1,6 +1,7 @@ package io.github.hapjava.accessories.optionalcharacteristic; import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback; +import io.github.hapjava.characteristics.impl.airquality.PM10DensityCharacteristic; import java.util.concurrent.CompletableFuture; /** Accessory with PM10 Density characteristic. */ @@ -13,6 +14,33 @@ public interface AccessoryWithPM10Density { */ CompletableFuture getPM10Density(); + /** + * return the min value for PM10 density. overwrite if you want to change the default value. + * + * @return min PM10 density + */ + default double getMinPM10Density() { + return PM10DensityCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for PM10 density. overwrite if you want to change the default value. + * + * @return max PM10 density + */ + default double getMaxPM10Density() { + return PM10DensityCharacteristic.DEFAULT_MAX_VALUE; + } + + /** + * return the min step value for PM10 density. overwrite if you want to change the default value. + * + * @return min step PM10 density + */ + default double getMinStepPM10Density() { + return PM10DensityCharacteristic.DEFAULT_STEP; + } + /** * Subscribes to changes in PM10 density. * diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPM25Density.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPM25Density.java index 11ad2a12e..02488f52d 100644 --- a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPM25Density.java +++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPM25Density.java @@ -1,6 +1,7 @@ package io.github.hapjava.accessories.optionalcharacteristic; import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback; +import io.github.hapjava.characteristics.impl.airquality.PM25DensityCharacteristic; import java.util.concurrent.CompletableFuture; /** Accessory with PM25 Density characteristic. */ @@ -13,6 +14,33 @@ public interface AccessoryWithPM25Density { */ CompletableFuture getPM25Density(); + /** + * return the min value for PM25 density. overwrite if you want to change the default value. + * + * @return min PM25 density + */ + default double getMinPM25Density() { + return PM25DensityCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for PM25 density. overwrite if you want to change the default value. + * + * @return max PM25 density + */ + default double getMaxPM25Density() { + return PM25DensityCharacteristic.DEFAULT_MAX_VALUE; + } + + /** + * return the min step value for PM25 density. overwrite if you want to change the default value. + * + * @return min step PM25 density + */ + default double getMinStepPM25Density() { + return PM25DensityCharacteristic.DEFAULT_STEP; + } + /** * Subscribes to changes in PM25 density. * diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithRemainingDuration.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithRemainingDuration.java index b949b413e..7859fb396 100644 --- a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithRemainingDuration.java +++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithRemainingDuration.java @@ -1,6 +1,7 @@ package io.github.hapjava.accessories.optionalcharacteristic; import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback; +import io.github.hapjava.characteristics.impl.valve.RemainingDurationCharacteristic; import java.util.concurrent.CompletableFuture; /** @@ -17,6 +18,24 @@ public interface AccessoryWithRemainingDuration { */ CompletableFuture getRemainingDuration(); + /** + * return the min value for remaining duration. overwrite if you want to change the default value. + * + * @return min remaining duration + */ + default int getMinRemainingDuration() { + return RemainingDurationCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for remaining duration. overwrite if you want to change the default value. + * + * @return max remaining duration + */ + default int getMaxRemainingDuration() { + return RemainingDurationCharacteristic.DEFAULT_MAX_VALUE; + } + /** * Subscribes to changes in the duration; note it is not necessary to emit a change every second, * homekit infers the countdown progress client side. diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithSulphurDioxideDensity.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithSulphurDioxideDensity.java index 94fad0be4..dbe0cc947 100644 --- a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithSulphurDioxideDensity.java +++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithSulphurDioxideDensity.java @@ -1,6 +1,7 @@ package io.github.hapjava.accessories.optionalcharacteristic; import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback; +import io.github.hapjava.characteristics.impl.airquality.SulphurDioxideDensityCharacteristic; import java.util.concurrent.CompletableFuture; /** Accessory with sulphur dioxide density characteristic. */ @@ -13,6 +14,36 @@ public interface AccessoryWithSulphurDioxideDensity { */ CompletableFuture getSulphurDioxideDensity(); + /** + * return the min value for sulphur dioxide density. overwrite if you want to change the default + * value. + * + * @return min sulphur dioxide density + */ + default double getMinSulphurDioxideDensity() { + return SulphurDioxideDensityCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for sulphur dioxide density. overwrite if you want to change the default + * value. + * + * @return max sulphur dioxide density + */ + default double getMaxSulphurDioxideDensity() { + return SulphurDioxideDensityCharacteristic.DEFAULT_MAX_VALUE; + } + + /** + * return the min step value for sulphur dioxide density. overwrite if you want to change the + * default value. + * + * @return min step sulphur dioxide density + */ + default double getMinStepSulphurDioxideDensity() { + return SulphurDioxideDensityCharacteristic.DEFAULT_STEP; + } + /** * Subscribes to changes in sulphur dioxide density. * diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithVOCDensity.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithVOCDensity.java index b41cc43b7..f8a7bc46b 100644 --- a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithVOCDensity.java +++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithVOCDensity.java @@ -1,6 +1,7 @@ package io.github.hapjava.accessories.optionalcharacteristic; import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback; +import io.github.hapjava.characteristics.impl.airquality.VOCDensityCharacteristic; import java.util.concurrent.CompletableFuture; /** Accessory with VOC Density characteristic. */ @@ -13,6 +14,33 @@ public interface AccessoryWithVOCDensity { */ CompletableFuture getVOCDensity(); + /** + * return the min value for VOC density. overwrite if you want to change the default value. + * + * @return min VOC density + */ + default double getMinVOCDensity() { + return VOCDensityCharacteristic.DEFAULT_MIN_VALUE; + } + + /** + * return the max value for VOC density. overwrite if you want to change the default value. + * + * @return max VOC density + */ + default double getMaxVOCDensity() { + return VOCDensityCharacteristic.DEFAULT_MAX_VALUE; + } + + /** + * return the min step value for VOC density. overwrite if you want to change the default value. + * + * @return min step VOC density + */ + default double getMinStepVOCDensity() { + return VOCDensityCharacteristic.DEFAULT_STEP; + } + /** * Subscribes to changes in VOC density. * diff --git a/src/main/java/io/github/hapjava/characteristics/impl/airquality/NitrogenDioxideDensityCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/airquality/NitrogenDioxideDensityCharacteristic.java index 432a85029..1e37e28b6 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/airquality/NitrogenDioxideDensityCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/airquality/NitrogenDioxideDensityCharacteristic.java @@ -9,21 +9,34 @@ /** This characteristic contains the current NO2 density in micrograms/m3. */ public class NitrogenDioxideDensityCharacteristic extends FloatCharacteristic { + public static final double DEFAULT_MIN_VALUE = 0; + public static final double DEFAULT_MAX_VALUE = 1000; + public static final double DEFAULT_STEP = 1; public NitrogenDioxideDensityCharacteristic( + double minValue, + double maxValue, + double minStep, Supplier> getter, Consumer subscriber, Runnable unsubscriber) { super( "000000C4-0000-1000-8000-0026BB765291", "nitrogen dioxide density", - 0, - 1000, - 1, + minValue, + maxValue, + minStep, "micrograms", Optional.of(getter), Optional.empty(), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public NitrogenDioxideDensityCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, DEFAULT_STEP, getter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/characteristics/impl/airquality/OzoneDensityCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/airquality/OzoneDensityCharacteristic.java index 542dbce0b..577339288 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/airquality/OzoneDensityCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/airquality/OzoneDensityCharacteristic.java @@ -9,21 +9,34 @@ /** This characteristic contains the current ozone density in micrograms/m3. */ public class OzoneDensityCharacteristic extends FloatCharacteristic { + public static final double DEFAULT_MIN_VALUE = 0; + public static final double DEFAULT_MAX_VALUE = 1000; + public static final double DEFAULT_STEP = 1; public OzoneDensityCharacteristic( + double minValue, + double maxValue, + double minStep, Supplier> getter, Consumer subscriber, Runnable unsubscriber) { super( "000000C3-0000-1000-8000-0026BB765291", "ozone density", - 0, - 1000, - 1, + minValue, + maxValue, + minStep, "micrograms", Optional.of(getter), Optional.empty(), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public OzoneDensityCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, DEFAULT_STEP, getter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/characteristics/impl/airquality/PM10DensityCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/airquality/PM10DensityCharacteristic.java index fdb0b9b49..a7b9c1245 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/airquality/PM10DensityCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/airquality/PM10DensityCharacteristic.java @@ -11,21 +11,34 @@ * This characteristic contains the current PM10 micrometer particulate density in micrograms/m3. */ public class PM10DensityCharacteristic extends FloatCharacteristic { + public static final double DEFAULT_MIN_VALUE = 0; + public static final double DEFAULT_MAX_VALUE = 1000; + public static final double DEFAULT_STEP = 1; public PM10DensityCharacteristic( + double minValue, + double maxValue, + double minStep, Supplier> getter, Consumer subscriber, Runnable unsubscriber) { super( "000000C7-0000-1000-8000-0026BB765291", "PM10 density", - 0, - 1000, - 1, + minValue, + maxValue, + minStep, "micrograms", Optional.of(getter), Optional.empty(), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public PM10DensityCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, DEFAULT_STEP, getter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/characteristics/impl/airquality/PM25DensityCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/airquality/PM25DensityCharacteristic.java index c54831553..1667934ef 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/airquality/PM25DensityCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/airquality/PM25DensityCharacteristic.java @@ -11,21 +11,34 @@ * This characteristic contains the current PM2.5 micrometer particulate density in micrograms/m3. */ public class PM25DensityCharacteristic extends FloatCharacteristic { + public static final double DEFAULT_MIN_VALUE = 0; + public static final double DEFAULT_MAX_VALUE = 1000; + public static final double DEFAULT_STEP = 1; public PM25DensityCharacteristic( + double minValue, + double maxValue, + double minStep, Supplier> getter, Consumer subscriber, Runnable unsubscriber) { super( "000000C6-0000-1000-8000-0026BB765291", "PM2.5 density", - 0, - 1000, - 1, + minValue, + maxValue, + minStep, "micrograms", Optional.of(getter), Optional.empty(), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public PM25DensityCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, DEFAULT_STEP, getter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/characteristics/impl/airquality/SulphurDioxideDensityCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/airquality/SulphurDioxideDensityCharacteristic.java index 03f668757..81df2c64b 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/airquality/SulphurDioxideDensityCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/airquality/SulphurDioxideDensityCharacteristic.java @@ -9,21 +9,34 @@ /** This characteristic contains the current SO2 density in micrograms/m3. */ public class SulphurDioxideDensityCharacteristic extends FloatCharacteristic { + public static final double DEFAULT_MIN_VALUE = 0; + public static final double DEFAULT_MAX_VALUE = 1000; + public static final double DEFAULT_STEP = 1; public SulphurDioxideDensityCharacteristic( + double minValue, + double maxValue, + double minStep, Supplier> getter, Consumer subscriber, Runnable unsubscriber) { super( "000000C5-0000-1000-8000-0026BB765291", "sulphur dioxide density", - 0, - 1000, - 1, + minValue, + maxValue, + minStep, "micrograms", Optional.of(getter), Optional.empty(), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public SulphurDioxideDensityCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, DEFAULT_STEP, getter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/characteristics/impl/airquality/VOCDensityCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/airquality/VOCDensityCharacteristic.java index 76e062f45..a752161c9 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/airquality/VOCDensityCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/airquality/VOCDensityCharacteristic.java @@ -12,21 +12,34 @@ * micrograms/m3. */ public class VOCDensityCharacteristic extends FloatCharacteristic { + public static final double DEFAULT_MIN_VALUE = 0; + public static final double DEFAULT_MAX_VALUE = 1000; + public static final double DEFAULT_STEP = 1; public VOCDensityCharacteristic( + double minValue, + double maxValue, + double minStep, Supplier> getter, Consumer subscriber, Runnable unsubscriber) { super( "000000C8-0000-1000-8000-0026BB765291", "VOC density", - 0, - 1000, - 1, + minValue, + maxValue, + minStep, "micrograms", Optional.of(getter), Optional.empty(), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public VOCDensityCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, DEFAULT_STEP, getter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/characteristics/impl/base/BaseCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/base/BaseCharacteristic.java index 73ce32df4..a90f1fadc 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/base/BaseCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/base/BaseCharacteristic.java @@ -113,7 +113,6 @@ protected CompletableFuture makeBuilder(int instanceId) { .add("type", shortType) .add("perms", perms.build()) .add("format", format) - .add("ev", false) .add("description", description); if (isReadable) setJsonValue(builder, value); return builder; diff --git a/src/main/java/io/github/hapjava/characteristics/impl/carbondioxidesensor/CarbonDioxideLevelCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/carbondioxidesensor/CarbonDioxideLevelCharacteristic.java index 7d1d8d440..b9b320564 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/carbondioxidesensor/CarbonDioxideLevelCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/carbondioxidesensor/CarbonDioxideLevelCharacteristic.java @@ -11,21 +11,34 @@ * This characteristic indicates the detected level of Carbon Dioxide in parts per million (ppm). */ public class CarbonDioxideLevelCharacteristic extends FloatCharacteristic { + public static final double DEFAULT_MIN_VALUE = 0; + public static final double DEFAULT_MAX_VALUE = 100000; + public static final double DEFAULT_STEP = 1; public CarbonDioxideLevelCharacteristic( + double minValue, + double maxValue, + double minStep, Supplier> getter, Consumer subscriber, Runnable unsubscriber) { super( "00000093-0000-1000-8000-0026BB765291", "Carbon Dioxide Level", - 0, - 100000, - 1, + minValue, + maxValue, + minStep, "ppm", Optional.of(getter), Optional.empty(), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public CarbonDioxideLevelCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, DEFAULT_STEP, getter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/characteristics/impl/carbondioxidesensor/CarbonDioxidePeakLevelCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/carbondioxidesensor/CarbonDioxidePeakLevelCharacteristic.java index a2ad994fc..1a1793773 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/carbondioxidesensor/CarbonDioxidePeakLevelCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/carbondioxidesensor/CarbonDioxidePeakLevelCharacteristic.java @@ -9,21 +9,34 @@ /** This characteristic indicates the highest detected level (ppm) of carbon dioxide. */ public class CarbonDioxidePeakLevelCharacteristic extends FloatCharacteristic { + public static final double DEFAULT_MIN_VALUE = 0; + public static final double DEFAULT_MAX_VALUE = 100000; + public static final double DEFAULT_STEP = 1; public CarbonDioxidePeakLevelCharacteristic( + double minValue, + double maxValue, + double minStep, Supplier> getter, Consumer subscriber, Runnable unsubscriber) { super( "00000094-0000-1000-8000-0026BB765291", "Carbon Dioxide Level", - 0, - 100000, - 1, + minValue, + maxValue, + minStep, "ppm", Optional.of(getter), Optional.empty(), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public CarbonDioxidePeakLevelCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, DEFAULT_STEP, getter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/characteristics/impl/carbonmonoxidesensor/CarbonMonoxideLevelCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/carbonmonoxidesensor/CarbonMonoxideLevelCharacteristic.java index 554638a22..e35171b38 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/carbonmonoxidesensor/CarbonMonoxideLevelCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/carbonmonoxidesensor/CarbonMonoxideLevelCharacteristic.java @@ -9,21 +9,34 @@ /** This characteristic contains the Carbon Monoxide levels in parts per million (ppm). */ public class CarbonMonoxideLevelCharacteristic extends FloatCharacteristic { + public static final double DEFAULT_MIN_VALUE = 0; + public static final double DEFAULT_MAX_VALUE = 100; + public static final double DEFAULT_STEP = 1; public CarbonMonoxideLevelCharacteristic( + double minValue, + double maxValue, + double minStep, Supplier> getter, Consumer subscriber, Runnable unsubscriber) { super( "00000090-0000-1000-8000-0026BB765291", "Carbon Monoxide Level", - 0, - 100, - 1, + minValue, + maxValue, + minStep, "ppm", Optional.of(getter), Optional.empty(), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public CarbonMonoxideLevelCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, DEFAULT_STEP, getter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/characteristics/impl/carbonmonoxidesensor/CarbonMonoxidePeakLevelCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/carbonmonoxidesensor/CarbonMonoxidePeakLevelCharacteristic.java index 3a714674a..892901866 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/carbonmonoxidesensor/CarbonMonoxidePeakLevelCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/carbonmonoxidesensor/CarbonMonoxidePeakLevelCharacteristic.java @@ -9,21 +9,34 @@ /** This characteristic indicates the highest detected level (ppm) of Carbon Monoxide. */ public class CarbonMonoxidePeakLevelCharacteristic extends FloatCharacteristic { + public static final double DEFAULT_MIN_VALUE = 0; + public static final double DEFAULT_MAX_VALUE = 100; + public static final double DEFAULT_STEP = 1; public CarbonMonoxidePeakLevelCharacteristic( + double minValue, + double maxValue, + double minStep, Supplier> getter, Consumer subscriber, Runnable unsubscriber) { super( "00000091-0000-1000-8000-0026BB765291", "Carbon Monoxide Peak Level", - 0, - 100000, - 1, + minValue, + maxValue, + minStep, "ppm", Optional.of(getter), Optional.empty(), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public CarbonMonoxidePeakLevelCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, DEFAULT_STEP, getter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/characteristics/impl/garagedoor/CurrentDoorStateEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/garagedoor/CurrentDoorStateEnum.java index 9d2b145ab..88474e6cc 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/garagedoor/CurrentDoorStateEnum.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/garagedoor/CurrentDoorStateEnum.java @@ -15,7 +15,7 @@ public enum CurrentDoorStateEnum implements CharacteristicEnum { CLOSED(1), OPENING(2), CLOSING(3), - SOPPED(4); + STOPPED(4); private static final Map reverse; diff --git a/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/ColorTemperatureCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/ColorTemperatureCharacteristic.java index c7779233a..12886c7a1 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/ColorTemperatureCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/ColorTemperatureCharacteristic.java @@ -12,8 +12,12 @@ /** This characteristic describes color temperature in Kelvin */ public class ColorTemperatureCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { + public static final int DEFAULT_MIN_VALUE = 50; + public static final int DEFAULT_MAX_VALUE = 400; public ColorTemperatureCharacteristic( + int minValue, + int maxValue, Supplier> getter, ExceptionalConsumer setter, Consumer subscriber, @@ -21,12 +25,20 @@ public ColorTemperatureCharacteristic( super( "000000CE-0000-1000-8000-0026BB765291", "color temperature", - 50, - 400, + minValue, + maxValue, "K", Optional.of(getter), Optional.of(setter), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public ColorTemperatureCharacteristic( + Supplier> getter, + ExceptionalConsumer setter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, getter, setter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/characteristics/impl/lightsensor/CurrentAmbientLightLevelCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/lightsensor/CurrentAmbientLightLevelCharacteristic.java index aee5e24d5..afec35ce6 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/lightsensor/CurrentAmbientLightLevelCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/lightsensor/CurrentAmbientLightLevelCharacteristic.java @@ -9,21 +9,34 @@ /** This characteristic indicates the current light level in Lux */ public class CurrentAmbientLightLevelCharacteristic extends FloatCharacteristic { + public static final double DEFAULT_MIN_VALUE = 0.0001; + public static final double DEFAULT_MAX_VALUE = 100000; + public static final double DEFAULT_STEP = 0.0001; public CurrentAmbientLightLevelCharacteristic( + double minValue, + double maxValue, + double minStep, Supplier> getter, Consumer subscriber, Runnable unsubscriber) { super( "0000006B-0000-1000-8000-0026BB765291", "ambient light level", - 0.0001, - 100000, - 0.0001, + minValue, + maxValue, + minStep, "lux", Optional.of(getter), Optional.empty(), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public CurrentAmbientLightLevelCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, DEFAULT_STEP, getter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/characteristics/impl/valve/RemainingDurationCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/valve/RemainingDurationCharacteristic.java index 4866be230..828fafab1 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/valve/RemainingDurationCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/valve/RemainingDurationCharacteristic.java @@ -15,20 +15,31 @@ */ public class RemainingDurationCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { + public static final int DEFAULT_MIN_VALUE = 0; + public static final int DEFAULT_MAX_VALUE = 3600; public RemainingDurationCharacteristic( + int minValue, + int maxValue, Supplier> getter, Consumer subscriber, Runnable unsubscriber) { super( "000000D4-0000-1000-8000-0026BB765291", "remaining duration", - 0, - 3600, + minValue, + maxValue, "s", Optional.of(getter), Optional.empty(), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public RemainingDurationCharacteristic( + Supplier> getter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, getter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/characteristics/impl/valve/SetDurationCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/valve/SetDurationCharacteristic.java index a372d0515..59cef5646 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/valve/SetDurationCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/valve/SetDurationCharacteristic.java @@ -12,8 +12,12 @@ /** This characteristic describes the duration, how long an accessory should be set to "InUse". */ public class SetDurationCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { + public static final int DEFAULT_MIN_VALUE = 0; + public static final int DEFAULT_MAX_VALUE = 3600; public SetDurationCharacteristic( + int minValue, + int maxValue, Supplier> getter, ExceptionalConsumer setter, Consumer subscriber, @@ -21,12 +25,20 @@ public SetDurationCharacteristic( super( "000000D3-0000-1000-8000-0026BB765291", "set duration", - 0, - 3600, + minValue, + maxValue, "s", Optional.of(getter), Optional.of(setter), Optional.of(subscriber), Optional.of(unsubscriber)); } + + public SetDurationCharacteristic( + Supplier> getter, + ExceptionalConsumer setter, + Consumer subscriber, + Runnable unsubscriber) { + this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, getter, setter, subscriber, unsubscriber); + } } diff --git a/src/main/java/io/github/hapjava/server/impl/HomekitUtils.java b/src/main/java/io/github/hapjava/server/impl/HomekitUtils.java index 9b5b2b8ee..20a697ff9 100644 --- a/src/main/java/io/github/hapjava/server/impl/HomekitUtils.java +++ b/src/main/java/io/github/hapjava/server/impl/HomekitUtils.java @@ -2,7 +2,6 @@ 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; @@ -14,11 +13,12 @@ public class HomekitUtils { private static volatile SecureRandom secureRandom; public static BigInteger generateSalt() { - return new BigInteger(SRP6Routines.generateRandomSalt(16)); + return new BigInteger(new SRP6Routines().generateRandomSalt(16)); } - public static byte[] generateKey() throws InvalidAlgorithmParameterException { - EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512"); + public static byte[] generateKey() { + EdDSAParameterSpec spec = + EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512); byte[] seed = new byte[spec.getCurve().getField().getb() / 8]; getSecureRandom().nextBytes(seed); return seed; diff --git a/src/main/java/io/github/hapjava/server/impl/crypto/ChachaDecoder.java b/src/main/java/io/github/hapjava/server/impl/crypto/ChachaDecoder.java index 4c74a469d..9b9c2cc5d 100644 --- a/src/main/java/io/github/hapjava/server/impl/crypto/ChachaDecoder.java +++ b/src/main/java/io/github/hapjava/server/impl/crypto/ChachaDecoder.java @@ -5,8 +5,6 @@ import org.bouncycastle.crypto.generators.Poly1305KeyGenerator; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.crypto.tls.AlertDescription; -import org.bouncycastle.crypto.tls.TlsFatalAlert; import org.bouncycastle.util.Arrays; public class ChachaDecoder { @@ -28,7 +26,7 @@ public byte[] decodeCiphertext(byte[] receivedMAC, byte[] additionalData, byte[] byte[] calculatedMAC = PolyKeyCreator.create(macKey, additionalData, ciphertext); if (!Arrays.constantTimeAreEqual(calculatedMAC, receivedMAC)) { - throw new TlsFatalAlert(AlertDescription.bad_record_mac); + throw new IOException("received an incorrect MAC"); } byte[] output = new byte[ciphertext.length]; @@ -45,9 +43,7 @@ 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); + KeyParameter macKey = new KeyParameter(firstBlock, 0, 32); Poly1305KeyGenerator.clamp(macKey.getKey()); return macKey; } diff --git a/src/main/java/io/github/hapjava/server/impl/crypto/ChachaEncoder.java b/src/main/java/io/github/hapjava/server/impl/crypto/ChachaEncoder.java index 3304e7d9a..3649844eb 100644 --- a/src/main/java/io/github/hapjava/server/impl/crypto/ChachaEncoder.java +++ b/src/main/java/io/github/hapjava/server/impl/crypto/ChachaEncoder.java @@ -39,9 +39,7 @@ 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); + KeyParameter macKey = new KeyParameter(firstBlock, 0, 32); Poly1305KeyGenerator.clamp(macKey.getKey()); return macKey; } diff --git a/src/main/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiser.java b/src/main/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiser.java index a178d2cfc..04016561e 100644 --- a/src/main/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiser.java +++ b/src/main/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiser.java @@ -26,6 +26,7 @@ public class JmdnsHomekitAdvertiser { private String setupId; private int port; private int configurationIndex; + private ServiceInfo serviceInfo; public JmdnsHomekitAdvertiser(JmDNS jmdns) { this.jmdns = jmdns; @@ -87,12 +88,20 @@ public synchronized void setConfigurationIndex(int revision) throws IOException } private void unregisterService() { - jmdns.unregisterService(buildServiceInfo()); + if (serviceInfo != null) { + jmdns.unregisterService(serviceInfo); + serviceInfo = null; + } } private void registerService() throws IOException { logger.info("Registering " + SERVICE_TYPE + " on port " + port); - jmdns.registerService(buildServiceInfo()); + if (this.serviceInfo != null) { + throw new AssertionError( + "Registering an already registered service without unregistering first is not allowed"); + } + serviceInfo = buildServiceInfo(); + jmdns.registerService(serviceInfo); } private ServiceInfo buildServiceInfo() { diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/ByteUtils.java b/src/main/java/io/github/hapjava/server/impl/pairing/ByteUtils.java index 6516e2e29..e65beec3c 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/ByteUtils.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/ByteUtils.java @@ -22,7 +22,7 @@ public static byte[] joinBytes(byte[]... piece) { return ret; } - public static byte[] toByteArray(BigInteger i) { + public static byte[] toUnsignedByteArray(BigInteger i) { byte[] array = i.toByteArray(); if (array[0] == 0) { array = Arrays.copyOfRange(array, 1, array.length); diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/ClientEvidenceRoutineImpl.java b/src/main/java/io/github/hapjava/server/impl/pairing/ClientEvidenceRoutineImpl.java index 16c514707..7e139296c 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/ClientEvidenceRoutineImpl.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/ClientEvidenceRoutineImpl.java @@ -1,5 +1,7 @@ package io.github.hapjava.server.impl.pairing; +import static io.github.hapjava.server.impl.pairing.ByteUtils.toUnsignedByteArray; + import com.nimbusds.srp6.*; import java.math.BigInteger; import java.nio.charset.StandardCharsets; @@ -8,9 +10,7 @@ class ClientEvidenceRoutineImpl implements ClientEvidenceRoutine { - public ClientEvidenceRoutineImpl() { - // TODO Auto-generated constructor stub - } + public ClientEvidenceRoutineImpl() {} /** * Calculates M1 according to the following formula: @@ -27,10 +27,10 @@ public BigInteger computeClientEvidence( } catch (NoSuchAlgorithmException e) { throw new RuntimeException("Could not locate requested algorithm", e); } - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(cryptoParams.N)); + digest.update(toUnsignedByteArray(cryptoParams.N)); byte[] hN = digest.digest(); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(cryptoParams.g)); + digest.update(toUnsignedByteArray(cryptoParams.g)); byte[] hg = digest.digest(); byte[] hNhg = xor(hN, hg); @@ -38,14 +38,14 @@ public BigInteger computeClientEvidence( digest.update(ctx.userID.getBytes(StandardCharsets.UTF_8)); byte[] hu = digest.digest(); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.S)); + digest.update(toUnsignedByteArray(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(toUnsignedByteArray(ctx.s)); + digest.update(toUnsignedByteArray(ctx.A)); + digest.update(toUnsignedByteArray(ctx.B)); digest.update(hS); BigInteger ret = new BigInteger(1, digest.digest()); return ret; diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/HomekitSRP6ServerSession.java b/src/main/java/io/github/hapjava/server/impl/pairing/HomekitSRP6ServerSession.java index 3841d9fb7..116fced13 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/HomekitSRP6ServerSession.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/HomekitSRP6ServerSession.java @@ -8,6 +8,7 @@ import com.nimbusds.srp6.SRP6Session; import com.nimbusds.srp6.URoutineContext; import java.math.BigInteger; +import java.security.MessageDigest; /** * This is a slightly modified version of the SRP6ServerSession class included with nimbus. The only @@ -74,6 +75,8 @@ public static enum State { /** The current SRP-6a auth state. */ private State state; + private MessageDigest digest; + /** * Creates a new server-side SRP-6a authentication session and sets its state to {@link * State#INIT}. @@ -92,7 +95,7 @@ public HomekitSRP6ServerSession(final SRP6CryptoParams config, final int timeout this.config = config; - digest = config.getMessageDigestInstance(); + this.digest = config.getMessageDigestInstance(); if (digest == null) throw new IllegalArgumentException("Unsupported hash algorithm 'H': " + config.H); @@ -151,13 +154,13 @@ public BigInteger step1(final String userID, final BigInteger s, final BigIntege 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); + k = new 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); + B = new SRP6Routines().computePublicServerValue(config.N, config.g, k, v, b); state = State.STEP_1; @@ -234,7 +237,7 @@ public BigInteger step2(final BigInteger A, final BigInteger M1) throws SRP6Exce if (hasTimedOut()) throw new SRP6Exception("Session timeout", SRP6Exception.CauseType.TIMEOUT); // Check A validity - if (!SRP6Routines.isValidPublicValue(config.N, A)) + if (!new SRP6Routines().isValidPublicValue(config.N, A)) throw new SRP6Exception( "Bad client public value 'A'", SRP6Exception.CauseType.BAD_PUBLIC_VALUE); @@ -246,11 +249,11 @@ public BigInteger step2(final BigInteger A, final BigInteger M1) throws SRP6Exce URoutineContext hashedKeysContext = new URoutineContext(A, B); u = hashedKeysRoutine.computeU(config, hashedKeysContext); } else { - u = SRP6Routines.computeU(digest, config.N, A, B); + u = new SRP6Routines().computeU(digest, config.N, A, B); digest.reset(); } - S = SRP6Routines.computeSessionKey(config.N, v, u, A, b); + S = new SRP6Routines().computeSessionKey(config.N, v, u, A, b); // Compute the own client evidence message 'M1' BigInteger computedM1; @@ -262,7 +265,7 @@ public BigInteger step2(final BigInteger A, final BigInteger M1) throws SRP6Exce computedM1 = clientEvidenceRoutine.computeClientEvidence(config, ctx); } else { // With default routine - computedM1 = SRP6Routines.computeClientEvidence(digest, A, B, S); + computedM1 = new SRP6Routines().computeClientEvidence(digest, A, B, S); digest.reset(); } diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/PairingManager.java b/src/main/java/io/github/hapjava/server/impl/pairing/PairingManager.java index af6a6e01f..ee4b772f9 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/PairingManager.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/PairingManager.java @@ -29,7 +29,7 @@ public HttpResponse handle(HttpRequest httpRequest) throws Exception { if (req.getStage() == Stage.ONE) { logger.trace("Starting pair for " + registry.getLabel()); srpHandler = new SrpHandler(authInfo.getPin(), authInfo.getSalt()); - return srpHandler.handle(req); + return srpHandler.step1(); } else if (req.getStage() == Stage.TWO) { logger.trace("Entering second stage of pair for " + registry.getLabel()); if (srpHandler == null) { @@ -37,7 +37,7 @@ public HttpResponse handle(HttpRequest httpRequest) throws Exception { return new UnauthorizedResponse(); } else { try { - return srpHandler.handle(req); + return srpHandler.step2((PairSetupRequest.Stage2Request) req); } catch (Exception e) { srpHandler = null; // You don't get to try again - need a new key logger.warn("Exception encountered while processing pairing request", e); diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/ServerEvidenceRoutineImpl.java b/src/main/java/io/github/hapjava/server/impl/pairing/ServerEvidenceRoutineImpl.java index 7cf7b3164..77739e9b2 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/ServerEvidenceRoutineImpl.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/ServerEvidenceRoutineImpl.java @@ -1,5 +1,7 @@ package io.github.hapjava.server.impl.pairing; +import static io.github.hapjava.server.impl.pairing.ByteUtils.toUnsignedByteArray; + import com.nimbusds.srp6.SRP6CryptoParams; import com.nimbusds.srp6.SRP6ServerEvidenceContext; import com.nimbusds.srp6.ServerEvidenceRoutine; @@ -20,10 +22,10 @@ public BigInteger computeServerEvidence( throw new RuntimeException("Could not locate requested algorithm", e); } - byte[] hS = digest.digest(SrpHandler.bigIntegerToUnsignedByteArray(ctx.S)); + byte[] hS = digest.digest(toUnsignedByteArray(ctx.S)); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.A)); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.M1)); + digest.update(toUnsignedByteArray(ctx.A)); + digest.update(toUnsignedByteArray(ctx.M1)); digest.update(hS); return new BigInteger(1, digest.digest()); diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/SrpHandler.java b/src/main/java/io/github/hapjava/server/impl/pairing/SrpHandler.java index e02ccdb90..ec4b34c97 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/SrpHandler.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/SrpHandler.java @@ -1,25 +1,22 @@ package io.github.hapjava.server.impl.pairing; +import static io.github.hapjava.server.impl.pairing.ByteUtils.toUnsignedByteArray; + import com.nimbusds.srp6.*; import io.github.hapjava.server.impl.http.HttpResponse; import io.github.hapjava.server.impl.pairing.HomekitSRP6ServerSession.State; import io.github.hapjava.server.impl.pairing.PairSetupRequest.Stage2Request; import io.github.hapjava.server.impl.pairing.TypeLengthValueUtils.Encoder; import io.github.hapjava.server.impl.responses.ConflictResponse; -import io.github.hapjava.server.impl.responses.NotFoundResponse; 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 static final BigInteger N_3072 = - new BigInteger( - "5809605995369958062791915965639201402176612226902900533702900882779736177890990861472094774477339581147373410185646378328043729800750470098210924487866935059164371588168047540943981644516632755067501626434556398193186628990071248660819361205119793693985433297036118232914410171876807536457391277857011849897410207519105333355801121109356897459426271845471397952675959440793493071628394122780510124618488232602464649876850458861245784240929258426287699705312584509625419513463605155428017165714465363094021609290561084025893662561222573202082865797821865270991145082200656978177192827024538990239969175546190770645685893438011714430426409338676314743571154537142031573004276428701433036381801705308659830751190352946025482059931306571004727362479688415574702596946457770284148435989129632853918392117997472632693078113129886487399347796982772784615865232621289656944284216824611318709764535152507354116344703769998514148343807"); - private static final BigInteger G = BigInteger.valueOf(5); + private static final int BIT_SIZE = 3072; + private static final String HASH_ALG_H = "SHA-512"; private static final String IDENTIFIER = "Pair-Setup"; private static final Logger logger = LoggerFactory.getLogger(SrpHandler.class); @@ -30,7 +27,7 @@ class SrpHandler { private final String pin; public SrpHandler(String pin, BigInteger salt) { - config = new SRP6CryptoParams(N_3072, G, "SHA-512"); + config = SRP6CryptoParams.getInstance(BIT_SIZE, HASH_ALG_H); session = new HomekitSRP6ServerSession(config); session.setClientEvidenceRoutine(new ClientEvidenceRoutineImpl()); session.setServerEvidenceRoutine(new ServerEvidenceRoutineImpl()); @@ -38,20 +35,7 @@ public SrpHandler(String pin, BigInteger salt) { 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 { + HttpResponse step1() throws Exception { if (session.getState() != State.INIT) { logger.warn("Session is not in state INIT when receiving step1"); return new ConflictResponse(); @@ -68,7 +52,7 @@ private HttpResponse step1() throws Exception { return new PairingResponse(encoder.toByteArray()); } - private HttpResponse step2(Stage2Request request) throws Exception { + HttpResponse step2(Stage2Request request) throws Exception { if (session.getState() != State.STEP_1) { logger.warn("Session is not in state Stage 1 when receiving step2"); return new ConflictResponse(); @@ -80,18 +64,10 @@ private HttpResponse step2(Stage2Request request) throws Exception { return new PairingResponse(encoder.toByteArray()); } - public byte[] getK() { + byte[] getK() { MessageDigest digest = session.getCryptoParams().getMessageDigestInstance(); - BigInteger S = session.getSessionKey(false); - byte[] sBytes = bigIntegerToUnsignedByteArray(S); + BigInteger S = session.getSessionKey(); + byte[] sBytes = toUnsignedByteArray(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; - } } diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/TypeLengthValueUtils.java b/src/main/java/io/github/hapjava/server/impl/pairing/TypeLengthValueUtils.java index 396829d34..03665d94d 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/TypeLengthValueUtils.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/TypeLengthValueUtils.java @@ -38,7 +38,7 @@ private Encoder() { } public void add(MessageType type, BigInteger i) throws IOException { - add(type, ByteUtils.toByteArray(i)); + add(type, ByteUtils.toUnsignedByteArray(i)); } public void add(MessageType type, short b) { diff --git a/src/main/java/io/github/hapjava/services/impl/AirQualityService.java b/src/main/java/io/github/hapjava/services/impl/AirQualityService.java index c9ccd6d62..4aa74c88f 100644 --- a/src/main/java/io/github/hapjava/services/impl/AirQualityService.java +++ b/src/main/java/io/github/hapjava/services/impl/AirQualityService.java @@ -53,6 +53,9 @@ public AirQualityService(AirQualityAccessory accessory) { if (accessory instanceof AccessoryWithNitrogenDioxideDensity) { addOptionalCharacteristic( new NitrogenDioxideDensityCharacteristic( + ((AccessoryWithNitrogenDioxideDensity) accessory).getMinNitrogenDioxideDensity(), + ((AccessoryWithNitrogenDioxideDensity) accessory).getMaxNitrogenDioxideDensity(), + ((AccessoryWithNitrogenDioxideDensity) accessory).getMinStepNitrogenDioxideDensity(), ((AccessoryWithNitrogenDioxideDensity) accessory)::getNitrogenDioxideDensity, ((AccessoryWithNitrogenDioxideDensity) accessory)::subscribeNitrogenDioxideDensity, ((AccessoryWithNitrogenDioxideDensity) accessory) @@ -62,6 +65,9 @@ public AirQualityService(AirQualityAccessory accessory) { if (accessory instanceof AccessoryWithSulphurDioxideDensity) { addOptionalCharacteristic( new SulphurDioxideDensityCharacteristic( + ((AccessoryWithSulphurDioxideDensity) accessory).getMinSulphurDioxideDensity(), + ((AccessoryWithSulphurDioxideDensity) accessory).getMaxSulphurDioxideDensity(), + ((AccessoryWithSulphurDioxideDensity) accessory).getMinStepSulphurDioxideDensity(), ((AccessoryWithSulphurDioxideDensity) accessory)::getSulphurDioxideDensity, ((AccessoryWithSulphurDioxideDensity) accessory)::subscribeSulphurDioxideDensity, ((AccessoryWithSulphurDioxideDensity) accessory)::unsubscribeSulphurDioxideDensity)); @@ -69,6 +75,9 @@ public AirQualityService(AirQualityAccessory accessory) { if (accessory instanceof AccessoryWithPM25Density) { addOptionalCharacteristic( new PM25DensityCharacteristic( + ((AccessoryWithPM25Density) accessory).getMinPM25Density(), + ((AccessoryWithPM25Density) accessory).getMaxPM25Density(), + ((AccessoryWithPM25Density) accessory).getMinStepPM25Density(), ((AccessoryWithPM25Density) accessory)::getPM25Density, ((AccessoryWithPM25Density) accessory)::subscribePM25Density, ((AccessoryWithPM25Density) accessory)::unsubscribePM25Density)); @@ -76,6 +85,9 @@ public AirQualityService(AirQualityAccessory accessory) { if (accessory instanceof AccessoryWithPM10Density) { addOptionalCharacteristic( new PM10DensityCharacteristic( + ((AccessoryWithPM10Density) accessory).getMinPM10Density(), + ((AccessoryWithPM10Density) accessory).getMaxPM10Density(), + ((AccessoryWithPM10Density) accessory).getMinStepPM10Density(), ((AccessoryWithPM10Density) accessory)::getPM10Density, ((AccessoryWithPM10Density) accessory)::subscribePM10Density, ((AccessoryWithPM10Density) accessory)::unsubscribePM10Density)); @@ -83,6 +95,9 @@ public AirQualityService(AirQualityAccessory accessory) { if (accessory instanceof AccessoryWithVOCDensity) { addOptionalCharacteristic( new VOCDensityCharacteristic( + ((AccessoryWithVOCDensity) accessory).getMinVOCDensity(), + ((AccessoryWithVOCDensity) accessory).getMaxVOCDensity(), + ((AccessoryWithVOCDensity) accessory).getMinStepVOCDensity(), ((AccessoryWithVOCDensity) accessory)::getVOCDensity, ((AccessoryWithVOCDensity) accessory)::subscribeVOCDensity, ((AccessoryWithVOCDensity) accessory)::unsubscribeVOCDensity)); diff --git a/src/main/java/io/github/hapjava/services/impl/CarbonDioxideSensorService.java b/src/main/java/io/github/hapjava/services/impl/CarbonDioxideSensorService.java index b329e5f8f..b61e91b91 100644 --- a/src/main/java/io/github/hapjava/services/impl/CarbonDioxideSensorService.java +++ b/src/main/java/io/github/hapjava/services/impl/CarbonDioxideSensorService.java @@ -34,11 +34,17 @@ public CarbonDioxideSensorService(CarbonDioxideSensorAccessory accessory) { if (accessory instanceof AccessoryWithCarbonDioxideLevel) { addOptionalCharacteristic( new CarbonDioxideLevelCharacteristic( + ((AccessoryWithCarbonDioxideLevel) accessory).getMinCarbonDioxideLevel(), + ((AccessoryWithCarbonDioxideLevel) accessory).getMaxCarbonDioxideLevel(), + ((AccessoryWithCarbonDioxideLevel) accessory).getMinStepCarbonDioxideLevel(), ((AccessoryWithCarbonDioxideLevel) accessory)::getCarbonDioxideLevel, ((AccessoryWithCarbonDioxideLevel) accessory)::subscribeCarbonDioxideLevel, ((AccessoryWithCarbonDioxideLevel) accessory)::unsubscribeCarbonDioxideLevel)); addOptionalCharacteristic( new CarbonDioxidePeakLevelCharacteristic( + ((AccessoryWithCarbonDioxideLevel) accessory).getMinCarbonDioxidePeakLevel(), + ((AccessoryWithCarbonDioxideLevel) accessory).getMaxCarbonDioxidePeakLevel(), + ((AccessoryWithCarbonDioxideLevel) accessory).getMinStepCarbonDioxidePeakLevel(), ((AccessoryWithCarbonDioxideLevel) accessory)::getCarbonDioxidePeakLevel, ((AccessoryWithCarbonDioxideLevel) accessory)::subscribeCarbonDioxidePeakLevel, ((AccessoryWithCarbonDioxideLevel) accessory)::unsubscribeCarbonDioxidePeakLevel)); diff --git a/src/main/java/io/github/hapjava/services/impl/LightSensorService.java b/src/main/java/io/github/hapjava/services/impl/LightSensorService.java index b40b4a43e..6aef8cd34 100644 --- a/src/main/java/io/github/hapjava/services/impl/LightSensorService.java +++ b/src/main/java/io/github/hapjava/services/impl/LightSensorService.java @@ -24,6 +24,9 @@ public LightSensorService(CurrentAmbientLightLevelCharacteristic lightLevel) { public LightSensorService(LightSensorAccessory accessory) { this( new CurrentAmbientLightLevelCharacteristic( + accessory.getMinCurrentAmbientLightLevel(), + accessory.getMaxCurrentAmbientLightLevel(), + accessory.getMinStepCurrentAmbientLightLevel(), accessory::getCurrentAmbientLightLevel, accessory::subscribeCurrentAmbientLightLevel, accessory::unsubscribeCurrentAmbientLightLevel)); diff --git a/src/main/java/io/github/hapjava/services/impl/LightbulbService.java b/src/main/java/io/github/hapjava/services/impl/LightbulbService.java index 387a2b092..b37ca4d2c 100644 --- a/src/main/java/io/github/hapjava/services/impl/LightbulbService.java +++ b/src/main/java/io/github/hapjava/services/impl/LightbulbService.java @@ -55,6 +55,8 @@ public LightbulbService(LightbulbAccessory accessory) { if (accessory instanceof AccessoryWithColorTemperature) { addOptionalCharacteristic( new ColorTemperatureCharacteristic( + ((AccessoryWithColorTemperature) accessory).getMinColorTemperature(), + ((AccessoryWithColorTemperature) accessory).getMaxColorTemperature(), ((AccessoryWithColorTemperature) accessory)::getColorTemperature, ((AccessoryWithColorTemperature) accessory)::setColorTemperature, ((AccessoryWithColorTemperature) accessory)::subscribeColorTemperature, diff --git a/src/main/java/io/github/hapjava/services/impl/ThermostatService.java b/src/main/java/io/github/hapjava/services/impl/ThermostatService.java index 232d9c487..c775a41d5 100644 --- a/src/main/java/io/github/hapjava/services/impl/ThermostatService.java +++ b/src/main/java/io/github/hapjava/services/impl/ThermostatService.java @@ -73,6 +73,12 @@ public ThermostatService(ThermostatAccessory accessory) { if (accessory instanceof AccessoryWithCoolingThresholdTemperature) { addOptionalCharacteristic( new CoolingThresholdTemperatureCharacteristic( + ((AccessoryWithCoolingThresholdTemperature) accessory) + .getMinCoolingThresholdTemperature(), + ((AccessoryWithCoolingThresholdTemperature) accessory) + .getMaxCoolingThresholdTemperature(), + ((AccessoryWithCoolingThresholdTemperature) accessory) + .getStepCoolingThresholdTemperature(), ((AccessoryWithCoolingThresholdTemperature) accessory) ::getCoolingThresholdTemperature, ((AccessoryWithCoolingThresholdTemperature) accessory) @@ -85,6 +91,12 @@ public ThermostatService(ThermostatAccessory accessory) { if (accessory instanceof AccessoryWithHeatingThresholdTemperature) { addOptionalCharacteristic( new HeatingThresholdTemperatureCharacteristic( + ((AccessoryWithHeatingThresholdTemperature) accessory) + .getMinHeatingThresholdTemperature(), + ((AccessoryWithHeatingThresholdTemperature) accessory) + .getMaxHeatingThresholdTemperature(), + ((AccessoryWithHeatingThresholdTemperature) accessory) + .getStepHeatingThresholdTemperature(), ((AccessoryWithHeatingThresholdTemperature) accessory) ::getHeatingThresholdTemperature, ((AccessoryWithHeatingThresholdTemperature) accessory) diff --git a/src/main/java/io/github/hapjava/services/impl/ValveService.java b/src/main/java/io/github/hapjava/services/impl/ValveService.java index b45c48ef4..519502a3c 100644 --- a/src/main/java/io/github/hapjava/services/impl/ValveService.java +++ b/src/main/java/io/github/hapjava/services/impl/ValveService.java @@ -58,6 +58,8 @@ public ValveService(ValveAccessory accessory) { if (accessory instanceof AccessoryWithDuration) { addOptionalCharacteristic( new SetDurationCharacteristic( + ((AccessoryWithDuration) accessory).getMinDuration(), + ((AccessoryWithDuration) accessory).getMaxDuration(), ((AccessoryWithDuration) accessory)::getSetDuration, ((AccessoryWithDuration) accessory)::setSetDuration, ((AccessoryWithDuration) accessory)::subscribeSetDuration, @@ -66,6 +68,8 @@ public ValveService(ValveAccessory accessory) { if (accessory instanceof AccessoryWithRemainingDuration) { addOptionalCharacteristic( new RemainingDurationCharacteristic( + ((AccessoryWithRemainingDuration) accessory).getMinRemainingDuration(), + ((AccessoryWithRemainingDuration) accessory).getMaxRemainingDuration(), ((AccessoryWithRemainingDuration) accessory)::getRemainingDuration, ((AccessoryWithRemainingDuration) accessory)::subscribeRemainingDuration, ((AccessoryWithRemainingDuration) accessory)::unsubscribeRemainingDuration)); diff --git a/src/test/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiserTest.java b/src/test/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiserTest.java new file mode 100644 index 000000000..1c04b2868 --- /dev/null +++ b/src/test/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiserTest.java @@ -0,0 +1,66 @@ +package io.github.hapjava.server.impl.jmdns; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.io.IOException; +import java.net.UnknownHostException; +import javax.jmdns.JmDNS; +import javax.jmdns.ServiceInfo; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +public class JmdnsHomekitAdvertiserTest { + + JmdnsHomekitAdvertiser subject; + JmDNS jmdns; + + @Before + public void setup() throws UnknownHostException, IOException { + jmdns = mock(JmDNS.class); + subject = new JmdnsHomekitAdvertiser(jmdns); + } + + @Test + public void testAdvertiseTwiceFails() throws Exception { + advertise(); + assertThatThrownBy(() -> advertise()).isNotNull(); + } + + /* + * Verify that the unregister call is for the initial registered service + * when changing discoverability causes advertising to be toggled. + */ + @Test + public void testSetDiscoverableAfterAdvertise() throws Exception { + subject.setDiscoverable(false); + advertise(); + subject.setDiscoverable(true); + assertThat(getArgumentFromUnregister().getPropertyString("sf")).isEqualTo("0"); + } + + /* + * Verify that the unregister call is for the initial registered service + * when changing the config index causes advertising to be toggled. + */ + @Test + public void testSetConfigurationIndex() throws Exception { + subject.setConfigurationIndex(1); + advertise(); + subject.setConfigurationIndex(2); + assertThat(getArgumentFromUnregister().getPropertyString("c#")).isEqualTo("1"); + } + + private ServiceInfo getArgumentFromUnregister() { + ArgumentCaptor serviceInfoCaptor = ArgumentCaptor.forClass(ServiceInfo.class); + verify(jmdns).unregisterService(serviceInfoCaptor.capture()); + return serviceInfoCaptor.getValue(); + } + + private void advertise() throws Exception { + subject.advertise("test", "00:00:00:00:00:00", 1234, 1, "1"); + } +}