From 1a3c8cdf961893c12abb5e6b8e459223ba281887 Mon Sep 17 00:00:00 2001 From: Andy Lintner Date: Sun, 22 Feb 2015 23:27:32 -0500 Subject: [PATCH 1/7] Initial sample checkin --- LICENSE | 21 ++++++ README.md | 6 ++ pom.xml | 28 ++++++++ .../java/com/beowulfe/hap/sample/Main.java | 22 ++++++ .../com/beowulfe/hap/sample/MockAuthInfo.java | 72 +++++++++++++++++++ .../com/beowulfe/hap/sample/MockSwitch.java | 70 ++++++++++++++++++ 6 files changed, 219 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/com/beowulfe/hap/sample/Main.java create mode 100644 src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java create mode 100644 src/main/java/com/beowulfe/hap/sample/MockSwitch.java diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..5e566f239 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andy Lintner + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 000000000..4f01a51f1 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +HAP-Java-Sample +========= +A sample implementation of a simple accessory using [HAP-Java](https://github.com/beowulfe/HAP-Java). + +This is for demonstration purposes only and lacks any kind of persistence. An actual implementation will need to persist the accessory +authentication information between app launches to maintain pairing information with the iOS devices. \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 000000000..04484cf57 --- /dev/null +++ b/pom.xml @@ -0,0 +1,28 @@ + + 4.0.0 + com.beowulfe.hap + hap-sample + 0.0.1-SNAPSHOT + hap-java-sample + + + com.beowulfe.hap + hap + 0.0.1-SNAPSHOT + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.1 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/src/main/java/com/beowulfe/hap/sample/Main.java b/src/main/java/com/beowulfe/hap/sample/Main.java new file mode 100644 index 000000000..8c10c07b8 --- /dev/null +++ b/src/main/java/com/beowulfe/hap/sample/Main.java @@ -0,0 +1,22 @@ +package com.beowulfe.hap.sample; + +import com.beowulfe.hap.HomekitRoot; +import com.beowulfe.hap.HomekitServer; + +public class Main { + + private static final int PORT = 9123; + + public static void main(String[] args) { + try { + HomekitServer homekit = new HomekitServer(PORT); + HomekitRoot bridge = homekit.createBridge(new MockAuthInfo(), "Test Bridge", "TestBridge, Inc.", "G6", "111abe234"); + bridge.addAccessory(new MockSwitch()); + bridge.start(); + } catch (Exception e) { + e.printStackTrace(); + } + + } + +} \ No newline at end of file diff --git a/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java b/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java new file mode 100644 index 000000000..de5f4cea0 --- /dev/null +++ b/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java @@ -0,0 +1,72 @@ +package com.beowulfe.hap.sample; + +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import com.beowulfe.hap.HomekitAuthInfo; +import com.beowulfe.hap.HomekitServer; + +/** + * This is a simple implementation that should never be used in actual production. The mac, salt, and privateKey + * are being regenerated every time the application is started. The user store is also not persisted. This means pairing + * needs to be re-done every time the app restarts. + * + * @author Andy Lintner + */ +public class MockAuthInfo implements HomekitAuthInfo { + + private static final String PIN = "031-45-154"; + + private final String mac; + private final BigInteger salt; + private final byte[] privateKey; + private final ConcurrentMap userKeyMap = new ConcurrentHashMap<>(); + + public MockAuthInfo() throws InvalidAlgorithmParameterException { + mac = HomekitServer.generateMac(); + salt = HomekitServer.generateSalt(); + privateKey = HomekitServer.generateKey(); + System.out.println("Auth info is generated each time the sample application is started. Pairings are not persisted."); + System.out.println("The PIN for pairing is "+PIN); + } + + @Override + public String getPin() { + return PIN; + } + + @Override + public String getMac() { + return mac; + } + + @Override + public BigInteger getSalt() { + return salt; + } + + @Override + public byte[] getPrivateKey() { + return privateKey; + } + + @Override + public void createUser(String username, byte[] publicKey) { + userKeyMap.putIfAbsent(username, publicKey); + System.out.println("Added pairing for "+username); + } + + @Override + public void removeUser(String username) { + userKeyMap.remove(username); + System.out.println("Removed pairing for "+username); + } + + @Override + public byte[] getUserPublicKey(String username) { + return userKeyMap.get(username); + } + +} diff --git a/src/main/java/com/beowulfe/hap/sample/MockSwitch.java b/src/main/java/com/beowulfe/hap/sample/MockSwitch.java new file mode 100644 index 000000000..b770737bb --- /dev/null +++ b/src/main/java/com/beowulfe/hap/sample/MockSwitch.java @@ -0,0 +1,70 @@ +package com.beowulfe.hap.sample; + +import java.util.concurrent.CompletableFuture; + +import com.beowulfe.hap.HomekitCharacteristicChangeCallback; +import com.beowulfe.hap.accessories.Lightbulb; + +public class MockSwitch implements Lightbulb { + + private boolean powerState = false; + private HomekitCharacteristicChangeCallback subscribeCallback = null; + + @Override + public int getId() { + return 2; + } + + @Override + public String getLabel() { + return "Test Lightbulb"; + } + + @Override + public void identify() { + System.out.println("Identifying light"); + } + + @Override + public String getSerialNumber() { + return "none"; + } + + @Override + public String getModel() { + return "none"; + } + + @Override + public String getManufacturer() { + return "none"; + } + + @Override + public CompletableFuture getLightbulbPowerState() { + return CompletableFuture.completedFuture(powerState); + } + + @Override + public CompletableFuture setLightbulbPowerState(boolean powerState) + throws Exception { + this.powerState = powerState; + if (subscribeCallback != null) { + subscribeCallback.changed(); + } + System.out.println("The lightbulb is now "+(powerState ? "on" : "off")); + return CompletableFuture.completedFuture(null); + } + + @Override + public void subscribeLightbulbPowerState( + HomekitCharacteristicChangeCallback callback) { + this.subscribeCallback = callback; + } + + @Override + public void unsubscribeLightbulbPowerState() { + this.subscribeCallback = null; + } + +} From f1c0c054baad2cb3b5cd0829e6b2a36e78cf1dfe Mon Sep 17 00:00:00 2001 From: Andy Lintner Date: Wed, 27 May 2015 23:18:42 -0400 Subject: [PATCH 2/7] Added basic logging configuration to sample. --- pom.xml | 5 +++++ src/main/resources/logback.xml | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/main/resources/logback.xml diff --git a/pom.xml b/pom.xml index 04484cf57..af8e41da1 100644 --- a/pom.xml +++ b/pom.xml @@ -10,6 +10,11 @@ hap 0.0.1-SNAPSHOT + + ch.qos.logback + logback-classic + 1.0.13 + diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 000000000..0e383f4ac --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,30 @@ + + + + true + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + application.log + + %date - [%level] - from %logger in %thread + %n%message%n%xException%n + + + + + + + + + + \ No newline at end of file From c2e3789ade2dc2aa480fe4a5b69395fb29f4b9ca Mon Sep 17 00:00:00 2001 From: Tim Harper Date: Wed, 2 Jan 2019 01:45:30 -0700 Subject: [PATCH 3/7] Implement basic persistence mechanism This makes the sample project a more viable test-bed for testing out new devices and characteristics --- README.md | 5 +- .../com/beowulfe/hap/sample/AuthState.java | 22 ++++ .../java/com/beowulfe/hap/sample/Main.java | 68 +++++++--- .../com/beowulfe/hap/sample/MockAuthInfo.java | 122 ++++++++++-------- 4 files changed, 145 insertions(+), 72 deletions(-) create mode 100644 src/main/java/com/beowulfe/hap/sample/AuthState.java diff --git a/README.md b/README.md index 4f01a51f1..5ebd1ed0f 100644 --- a/README.md +++ b/README.md @@ -2,5 +2,6 @@ HAP-Java-Sample ========= A sample implementation of a simple accessory using [HAP-Java](https://github.com/beowulfe/HAP-Java). -This is for demonstration purposes only and lacks any kind of persistence. An actual implementation will need to persist the accessory -authentication information between app launches to maintain pairing information with the iOS devices. \ No newline at end of file +This is for demonstration purposes only. The persistence implementation is very primitive and should not be used except +for convenience in testing purposes, so information between app launches will maintain pairing information with the iOS +devices. Persisted data is written to a file `auth-state.bin` in the current working directory. diff --git a/src/main/java/com/beowulfe/hap/sample/AuthState.java b/src/main/java/com/beowulfe/hap/sample/AuthState.java new file mode 100644 index 000000000..b57b79973 --- /dev/null +++ b/src/main/java/com/beowulfe/hap/sample/AuthState.java @@ -0,0 +1,22 @@ +package com.beowulfe.hap.sample; + +import java.io.Serializable; +import java.math.BigInteger; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +class AuthState implements Serializable { + private static final long serialVersionUID = 1L; + String PIN; + final String mac; + final BigInteger salt; + final byte[] privateKey; + final ConcurrentMap userKeyMap = new ConcurrentHashMap<>(); + + public AuthState(String _PIN, String _mac, BigInteger _salt, byte[] _privateKey) { + PIN = _PIN; + salt = _salt; + privateKey = _privateKey; + mac = _mac; + } +} \ No newline at end of file diff --git a/src/main/java/com/beowulfe/hap/sample/Main.java b/src/main/java/com/beowulfe/hap/sample/Main.java index 8c10c07b8..eb332b69b 100644 --- a/src/main/java/com/beowulfe/hap/sample/Main.java +++ b/src/main/java/com/beowulfe/hap/sample/Main.java @@ -1,22 +1,58 @@ package com.beowulfe.hap.sample; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + import com.beowulfe.hap.HomekitRoot; import com.beowulfe.hap.HomekitServer; public class Main { - - private static final int PORT = 9123; - - public static void main(String[] args) { - try { - HomekitServer homekit = new HomekitServer(PORT); - HomekitRoot bridge = homekit.createBridge(new MockAuthInfo(), "Test Bridge", "TestBridge, Inc.", "G6", "111abe234"); - bridge.addAccessory(new MockSwitch()); - bridge.start(); - } catch (Exception e) { - e.printStackTrace(); - } - - } - -} \ No newline at end of file + + private static final int PORT = 9123; + + public static void main(String[] args) { + try { + File authFile = new File("auth-state.bin"); + MockAuthInfo mockAuth; + if (authFile.exists()) { + FileInputStream fileInputStream = new FileInputStream(authFile); + ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); + try { + System.out.println("Using persisted auth"); + AuthState authState = (AuthState) objectInputStream.readObject(); + mockAuth = new MockAuthInfo(authState); + } finally { + objectInputStream.close(); + } + } else { + mockAuth = new MockAuthInfo(); + } + + HomekitServer homekit = new HomekitServer(PORT); + HomekitRoot bridge = homekit.createBridge(mockAuth, "Test Bridge", "TestBridge, Inc.", "G6", "111abe234"); + + mockAuth.onChange(state -> { + try { + System.out.println("State has changed! Writing"); + FileOutputStream fileOutputStream = new FileOutputStream(authFile); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); + objectOutputStream.writeObject(state); + objectOutputStream.flush(); + objectOutputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + }); + bridge.addAccessory(new MockSwitch()); + bridge.start(); + } catch (Exception e) { + e.printStackTrace(); + } + + } + +} diff --git a/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java b/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java index de5f4cea0..b38b8a977 100644 --- a/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java +++ b/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java @@ -2,8 +2,7 @@ import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; +import java.util.function.Consumer; import com.beowulfe.hap.HomekitAuthInfo; import com.beowulfe.hap.HomekitServer; @@ -16,57 +15,72 @@ * @author Andy Lintner */ public class MockAuthInfo implements HomekitAuthInfo { - - private static final String PIN = "031-45-154"; - - private final String mac; - private final BigInteger salt; - private final byte[] privateKey; - private final ConcurrentMap userKeyMap = new ConcurrentHashMap<>(); - - public MockAuthInfo() throws InvalidAlgorithmParameterException { - mac = HomekitServer.generateMac(); - salt = HomekitServer.generateSalt(); - privateKey = HomekitServer.generateKey(); - System.out.println("Auth info is generated each time the sample application is started. Pairings are not persisted."); - System.out.println("The PIN for pairing is "+PIN); - } - - @Override - public String getPin() { - return PIN; - } - - @Override - public String getMac() { - return mac; - } - - @Override - public BigInteger getSalt() { - return salt; - } - - @Override - public byte[] getPrivateKey() { - return privateKey; - } - - @Override - public void createUser(String username, byte[] publicKey) { - userKeyMap.putIfAbsent(username, publicKey); - System.out.println("Added pairing for "+username); - } - - @Override - public void removeUser(String username) { - userKeyMap.remove(username); - System.out.println("Removed pairing for "+username); - } - - @Override - public byte[] getUserPublicKey(String username) { - return userKeyMap.get(username); - } + private final AuthState authState; + + Consumer callback; + + public MockAuthInfo() throws InvalidAlgorithmParameterException { + this(new AuthState("031-45-154", HomekitServer.generateMac(), HomekitServer.generateSalt(), + HomekitServer.generateKey())); + } + + public MockAuthInfo(AuthState _authState) { + authState = _authState; + System.out.println("The PIN for pairing is " + authState.PIN); + } + + @Override + public String getPin() { + return authState.PIN; + } + + @Override + public String getMac() { + return authState.mac; + } + + @Override + public BigInteger getSalt() { + return authState.salt; + } + + @Override + public byte[] getPrivateKey() { + return authState.privateKey; + } + + @Override + public void createUser(String username, byte[] publicKey) { + if (!authState.userKeyMap.containsKey(username)) { + authState.userKeyMap.putIfAbsent(username, publicKey); + System.out.println("Added pairing for " + username); + notifyChange(); + } else { + System.out.println("Already have a user for " + username); + } + } + + @Override + public void removeUser(String username) { + authState.userKeyMap.remove(username); + System.out.println("Removed pairing for " + username); + notifyChange(); + } + + @Override + public byte[] getUserPublicKey(String username) { + return authState.userKeyMap.get(username); + } + + public void onChange(Consumer _callback) { + callback = _callback; + notifyChange(); + } + + private void notifyChange() { + if (callback != null) { + callback.accept(authState); + } + } } From 7d8e17e297fe9ce04ba1b60ccd9b11ac09151186 Mon Sep 17 00:00:00 2001 From: Eugen Freiter Date: Sun, 17 Nov 2019 23:08:55 +0100 Subject: [PATCH 4/7] upgrade sample to java hap 1.2.0 --- pom.xml | 8 ++++---- src/main/java/com/beowulfe/hap/sample/Main.java | 7 +++---- src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java | 7 +++---- src/main/java/com/beowulfe/hap/sample/MockSwitch.java | 5 ++--- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/pom.xml b/pom.xml index af8e41da1..5e2c24e5d 100644 --- a/pom.xml +++ b/pom.xml @@ -2,13 +2,13 @@ 4.0.0 com.beowulfe.hap hap-sample - 0.0.1-SNAPSHOT + 1.2.0-SNAPSHOT hap-java-sample - com.beowulfe.hap + io.github.hap-java hap - 0.0.1-SNAPSHOT + 1.2.0-snapshot ch.qos.logback @@ -30,4 +30,4 @@ - \ No newline at end of file + diff --git a/src/main/java/com/beowulfe/hap/sample/Main.java b/src/main/java/com/beowulfe/hap/sample/Main.java index eb332b69b..733a47b31 100644 --- a/src/main/java/com/beowulfe/hap/sample/Main.java +++ b/src/main/java/com/beowulfe/hap/sample/Main.java @@ -6,9 +6,8 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; - -import com.beowulfe.hap.HomekitRoot; -import com.beowulfe.hap.HomekitServer; +import io.github.hapjava.HomekitRoot; +import io.github.hapjava.HomekitServer; public class Main { @@ -33,7 +32,7 @@ public static void main(String[] args) { } HomekitServer homekit = new HomekitServer(PORT); - HomekitRoot bridge = homekit.createBridge(mockAuth, "Test Bridge", "TestBridge, Inc.", "G6", "111abe234"); + HomekitRoot bridge = homekit.createBridge(mockAuth, "TestBridge", "TestBridge, Inc.", "G6", "111abe234"); mockAuth.onChange(state -> { try { diff --git a/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java b/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java index b38b8a977..cf47956c4 100644 --- a/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java +++ b/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java @@ -3,9 +3,8 @@ import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; import java.util.function.Consumer; - -import com.beowulfe.hap.HomekitAuthInfo; -import com.beowulfe.hap.HomekitServer; +import io.github.hapjava.HomekitAuthInfo; +import io.github.hapjava.HomekitServer; /** * This is a simple implementation that should never be used in actual production. The mac, salt, and privateKey @@ -22,7 +21,7 @@ public class MockAuthInfo implements HomekitAuthInfo { public MockAuthInfo() throws InvalidAlgorithmParameterException { this(new AuthState("031-45-154", HomekitServer.generateMac(), HomekitServer.generateSalt(), - HomekitServer.generateKey())); + HomekitServer.generateKey())); } public MockAuthInfo(AuthState _authState) { diff --git a/src/main/java/com/beowulfe/hap/sample/MockSwitch.java b/src/main/java/com/beowulfe/hap/sample/MockSwitch.java index b770737bb..a44e4a30f 100644 --- a/src/main/java/com/beowulfe/hap/sample/MockSwitch.java +++ b/src/main/java/com/beowulfe/hap/sample/MockSwitch.java @@ -1,9 +1,8 @@ package com.beowulfe.hap.sample; import java.util.concurrent.CompletableFuture; - -import com.beowulfe.hap.HomekitCharacteristicChangeCallback; -import com.beowulfe.hap.accessories.Lightbulb; +import io.github.hapjava.HomekitCharacteristicChangeCallback; +import io.github.hapjava.accessories.Lightbulb; public class MockSwitch implements Lightbulb { From 454fdfe82fa215eefcb5826b937f0bb341f667d2 Mon Sep 17 00:00:00 2001 From: Eugen Freiter Date: Sun, 15 Mar 2020 23:55:09 +0100 Subject: [PATCH 5/7] refactoring to new HAP 2.0 --- pom.xml | 37 +++++++++++++++++-- .../java/com/beowulfe/hap/sample/Main.java | 7 ++-- .../com/beowulfe/hap/sample/MockAuthInfo.java | 7 ++-- .../com/beowulfe/hap/sample/MockSwitch.java | 33 +++++++++++------ src/main/resources/log4j2.xml | 17 +++++++++ src/main/resources/logback.xml | 2 +- src/main/resources/simplelogger.properties | 1 + 7 files changed, 79 insertions(+), 25 deletions(-) create mode 100644 src/main/resources/log4j2.xml create mode 100644 src/main/resources/simplelogger.properties diff --git a/pom.xml b/pom.xml index af8e41da1..a288948ca 100644 --- a/pom.xml +++ b/pom.xml @@ -2,13 +2,13 @@ 4.0.0 com.beowulfe.hap hap-sample - 0.0.1-SNAPSHOT + 0.0.2-SNAPSHOT hap-java-sample - com.beowulfe.hap + io.github.hap-java hap - 0.0.1-SNAPSHOT + 2.0.0-snapshot ch.qos.logback @@ -28,6 +28,35 @@ 1.8 + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + + true + lib/ + com.beowulfe.hap.sample.Main + + + + + + maven-dependency-plugin + + + install + + copy-dependencies + + + ${project.build.directory}/lib + + + + - \ No newline at end of file + diff --git a/src/main/java/com/beowulfe/hap/sample/Main.java b/src/main/java/com/beowulfe/hap/sample/Main.java index eb332b69b..b74bb57a7 100644 --- a/src/main/java/com/beowulfe/hap/sample/Main.java +++ b/src/main/java/com/beowulfe/hap/sample/Main.java @@ -6,9 +6,8 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; - -import com.beowulfe.hap.HomekitRoot; -import com.beowulfe.hap.HomekitServer; +import io.github.hapjava.server.impl.HomekitRoot; +import io.github.hapjava.server.impl.HomekitServer; public class Main { @@ -33,7 +32,7 @@ public static void main(String[] args) { } HomekitServer homekit = new HomekitServer(PORT); - HomekitRoot bridge = homekit.createBridge(mockAuth, "Test Bridge", "TestBridge, Inc.", "G6", "111abe234"); + HomekitRoot bridge = homekit.createBridge(mockAuth, "Test Bridge", "TestBridge, Inc.", "G6", "111abe234", "1.1", "1.2"); mockAuth.onChange(state -> { try { diff --git a/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java b/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java index b38b8a977..ed152ce6f 100644 --- a/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java +++ b/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java @@ -3,9 +3,8 @@ import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; import java.util.function.Consumer; - -import com.beowulfe.hap.HomekitAuthInfo; -import com.beowulfe.hap.HomekitServer; +import io.github.hapjava.server.HomekitAuthInfo; +import io.github.hapjava.server.impl.HomekitServer; /** * This is a simple implementation that should never be used in actual production. The mac, salt, and privateKey @@ -22,7 +21,7 @@ public class MockAuthInfo implements HomekitAuthInfo { public MockAuthInfo() throws InvalidAlgorithmParameterException { this(new AuthState("031-45-154", HomekitServer.generateMac(), HomekitServer.generateSalt(), - HomekitServer.generateKey())); + HomekitServer.generateKey())); } public MockAuthInfo(AuthState _authState) { diff --git a/src/main/java/com/beowulfe/hap/sample/MockSwitch.java b/src/main/java/com/beowulfe/hap/sample/MockSwitch.java index b770737bb..585f4cff7 100644 --- a/src/main/java/com/beowulfe/hap/sample/MockSwitch.java +++ b/src/main/java/com/beowulfe/hap/sample/MockSwitch.java @@ -1,11 +1,11 @@ package com.beowulfe.hap.sample; import java.util.concurrent.CompletableFuture; +import io.github.hapjava.accessories.LightbulbAccessory; +import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithHardwareRevision; +import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback; -import com.beowulfe.hap.HomekitCharacteristicChangeCallback; -import com.beowulfe.hap.accessories.Lightbulb; - -public class MockSwitch implements Lightbulb { +public class MockSwitch implements LightbulbAccessory, AccessoryWithHardwareRevision { private boolean powerState = false; private HomekitCharacteristicChangeCallback subscribeCallback = null; @@ -16,8 +16,8 @@ public int getId() { } @Override - public String getLabel() { - return "Test Lightbulb"; + public CompletableFuture getName() { + return CompletableFuture.completedFuture("Test Switch Name"); } @Override @@ -26,18 +26,23 @@ public void identify() { } @Override - public String getSerialNumber() { - return "none"; + public CompletableFuture getSerialNumber() { + return CompletableFuture.completedFuture("Test SwitchSN"); + } + + @Override + public CompletableFuture getModel() { + return CompletableFuture.completedFuture("TestSwitch Model"); } @Override - public String getModel() { - return "none"; + public CompletableFuture getManufacturer() { + return CompletableFuture.completedFuture("Test SwitchManufacturer"); } @Override - public String getManufacturer() { - return "none"; + public CompletableFuture getFirmwareRevision() { + return CompletableFuture.completedFuture("Test Switch Firmware"); } @Override @@ -67,4 +72,8 @@ public void unsubscribeLightbulbPowerState() { this.subscribeCallback = null; } + @Override + public CompletableFuture getHardwareRevision() { + return CompletableFuture.completedFuture("Test Switch Hardware"); + } } diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 000000000..83266680b --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 0e383f4ac..dc8dfec8a 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -21,7 +21,7 @@ - + diff --git a/src/main/resources/simplelogger.properties b/src/main/resources/simplelogger.properties new file mode 100644 index 000000000..5c89a5a26 --- /dev/null +++ b/src/main/resources/simplelogger.properties @@ -0,0 +1 @@ +org.slf4j.simpleLogger.defaultLogLevel=DEBUG \ No newline at end of file From 5232da85192d9843e8f108cc6af68df80644ab87 Mon Sep 17 00:00:00 2001 From: Gert-Jan van der Heiden Date: Fri, 11 Dec 2020 15:13:41 +0100 Subject: [PATCH 6/7] #126(https://github.com/hap-java/HAP-Java/pull/126) --- pom.xml | 5 ++ .../com/beowulfe/hap/sample/AuthState.java | 4 +- .../java/com/beowulfe/hap/sample/Main.java | 10 ++++ .../com/beowulfe/hap/sample/MockAuthInfo.java | 14 +++++- .../com/beowulfe/hap/sample/QRtoConsole.java | 47 +++++++++++++++++++ src/main/resources/log4j2.xml | 2 +- src/main/resources/logback.xml | 2 +- src/main/resources/simplelogger.properties | 2 +- 8 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/beowulfe/hap/sample/QRtoConsole.java diff --git a/pom.xml b/pom.xml index a288948ca..67c1a362d 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,11 @@ logback-classic 1.0.13 + + com.google.zxing + core + 3.4.1 + diff --git a/src/main/java/com/beowulfe/hap/sample/AuthState.java b/src/main/java/com/beowulfe/hap/sample/AuthState.java index b57b79973..1cca02778 100644 --- a/src/main/java/com/beowulfe/hap/sample/AuthState.java +++ b/src/main/java/com/beowulfe/hap/sample/AuthState.java @@ -11,12 +11,14 @@ class AuthState implements Serializable { final String mac; final BigInteger salt; final byte[] privateKey; + final String setupId; final ConcurrentMap userKeyMap = new ConcurrentHashMap<>(); - public AuthState(String _PIN, String _mac, BigInteger _salt, byte[] _privateKey) { + public AuthState(String _PIN, String _mac, BigInteger _salt, byte[] _privateKey, String _setupId) { PIN = _PIN; salt = _salt; privateKey = _privateKey; mac = _mac; + setupId = _setupId; } } \ No newline at end of file diff --git a/src/main/java/com/beowulfe/hap/sample/Main.java b/src/main/java/com/beowulfe/hap/sample/Main.java index 078a45d45..02438e2c5 100644 --- a/src/main/java/com/beowulfe/hap/sample/Main.java +++ b/src/main/java/com/beowulfe/hap/sample/Main.java @@ -8,6 +8,7 @@ import java.io.ObjectOutputStream; import io.github.hapjava.server.impl.HomekitRoot; import io.github.hapjava.server.impl.HomekitServer; +import io.github.hapjava.server.impl.crypto.HAPSetupCodeUtils; public class Main { @@ -34,6 +35,9 @@ public static void main(String[] args) { HomekitServer homekit = new HomekitServer(PORT); HomekitRoot bridge = homekit.createBridge(mockAuth, "Test Bridge", "TestBridge, Inc.", "G6", "111abe234", "1.1", "1.2"); + String setupURI = HAPSetupCodeUtils.getSetupURI(mockAuth.getPin().replace("-",""), mockAuth.getSetupId(), 2); + QRtoConsole.printQR(setupURI); + mockAuth.onChange(state -> { try { @@ -49,6 +53,12 @@ public static void main(String[] args) { }); bridge.addAccessory(new MockSwitch()); bridge.start(); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + System.out.println("Stopping homekit server."); + homekit.stop(); + })); + } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java b/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java index e445398b2..f0b667f16 100644 --- a/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java +++ b/src/main/java/com/beowulfe/hap/sample/MockAuthInfo.java @@ -6,6 +6,7 @@ import io.github.hapjava.server.HomekitAuthInfo; import io.github.hapjava.server.impl.HomekitServer; +import io.github.hapjava.server.impl.crypto.HAPSetupCodeUtils; /** * This is a simple implementation that should never be used in actual production. The mac, salt, and privateKey @@ -22,7 +23,7 @@ public class MockAuthInfo implements HomekitAuthInfo { public MockAuthInfo() throws InvalidAlgorithmParameterException { this(new AuthState("031-45-154", HomekitServer.generateMac(), HomekitServer.generateSalt(), - HomekitServer.generateKey())); + HomekitServer.generateKey(), HAPSetupCodeUtils.generateSetupId())); } public MockAuthInfo(AuthState _authState) { @@ -50,6 +51,11 @@ public byte[] getPrivateKey() { return authState.privateKey; } + @Override + public String getSetupId() { + return authState.setupId; + } + @Override public void createUser(String username, byte[] publicKey) { if (!authState.userKeyMap.containsKey(username)) { @@ -83,4 +89,10 @@ private void notifyChange() { callback.accept(authState); } } + @Override + public boolean hasUser() { + return !authState.userKeyMap.isEmpty(); + } + + } diff --git a/src/main/java/com/beowulfe/hap/sample/QRtoConsole.java b/src/main/java/com/beowulfe/hap/sample/QRtoConsole.java new file mode 100644 index 000000000..a09c96144 --- /dev/null +++ b/src/main/java/com/beowulfe/hap/sample/QRtoConsole.java @@ -0,0 +1,47 @@ +package com.beowulfe.hap.sample; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ported code from https://github.com/gtanner/qrcode-terminal + */ +public class QRtoConsole { + private static final Logger logger = LoggerFactory.getLogger(QRtoConsole.class); + + private static final char WHITE_ALL = '\u2588'; + private static final char WHITE_BLACK = '\u2580'; + private static final char BLACK_WHITE = '\u2584'; + private static final char BLACK_ALL = ' '; + + + public static void printQR(String setupURI) { + try { + BitMatrix matrix = new MultiFormatWriter().encode( + setupURI, BarcodeFormat.QR_CODE, 10, + 30); + for(int y = 0; y < matrix.getHeight();y+=2) { + for(int x = 0; x < matrix.getWidth(); x++) { + boolean firstRow = matrix.get(x,y); + boolean secondRow = matrix.get(x,y+1); + if(firstRow && secondRow) { + System.out.print(BLACK_ALL); + } else if(firstRow) { + System.out.print(BLACK_WHITE); + } else if(secondRow) { + System.out.print(WHITE_BLACK); + } else { + System.out.print(WHITE_ALL); + } + } + System.out.println(); + } + } catch(WriterException e) { + logger.error("error creating qr code", e); + } + } +} diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index 83266680b..65087d6a3 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -7,7 +7,7 @@ - + diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index dc8dfec8a..e4680b944 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -21,7 +21,7 @@ - + diff --git a/src/main/resources/simplelogger.properties b/src/main/resources/simplelogger.properties index 5c89a5a26..895eeb271 100644 --- a/src/main/resources/simplelogger.properties +++ b/src/main/resources/simplelogger.properties @@ -1 +1 @@ -org.slf4j.simpleLogger.defaultLogLevel=DEBUG \ No newline at end of file +org.slf4j.simpleLogger.defaultLogLevel=INFO \ No newline at end of file From a886762c2e1b6663f9a4a9e01c5ce1afd484dcb0 Mon Sep 17 00:00:00 2001 From: Eugen Freiter Date: Sat, 29 Jan 2022 15:46:32 +0100 Subject: [PATCH 7/7] make use of latest Java-HAP snapshot Signed-off-by: Eugen Freiter --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 67c1a362d..13ae12f91 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ io.github.hap-java hap - 2.0.0-snapshot + 2.0.1-snapshot ch.qos.logback