[hueemulation] Changes to fix pairing and device discovery with Alexa ()

Signed-off-by: Mike Major <mike_j_major@hotmail.com>
This commit is contained in:
Mike Major 2020-11-29 03:46:35 +00:00 committed by GitHub
parent be61a70030
commit ab7ac79fab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 33 additions and 11 deletions
bundles/org.openhab.io.hueemulation
README.md
src
main/java/org/openhab/io/hueemulation/internal
test/java/org/openhab/io/hueemulation/internal

@ -167,6 +167,15 @@ You must either
```
* or let openHAB run on port 80 (the entire java process requires elevated privileges).
* For Amazon Echo the pairing process may fail due to a 302 response from openHAB, this can be resolved by using a reverse proxy to change the request url from `/api` to `/api/`, for example nginx with the following configuration:
```
server {
listen 80;
location /api {
proxy_pass http://localhost:8080/api/;
}
}
```
Please open port 80 tcp and port 1900 udp in your firewall installation.
You can test if the hue emulation does its job by enabling pairing mode including the option "Amazon Echo device discovery fix".

@ -17,8 +17,8 @@ import java.net.UnknownHostException;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@ -147,7 +147,7 @@ public class ConfigStore {
determineHighestAssignedHueID();
if (config.uuid.isEmpty()) {
config.uuid = UUID.randomUUID().toString();
config.uuid = getHueUUID();
writeUUIDFuture = scheduler.schedule(() -> {
logger.info("No unique ID assigned yet. Assigning {} and restarting...", config.uuid);
WriteConfig.setUUID(configAdmin, config.uuid);
@ -158,6 +158,19 @@ public class ConfigStore {
}
}
private static String getHueUUID() {
// Hue API example is AA:BB:CC:DD:EE:FF:00:11-XX
// XX is generated from the item.
final Random r = new Random();
int n = r.nextInt(255);
final StringBuilder uuid = new StringBuilder(String.format("%02X", n));
for (int i = 0; i < 7; i++) {
n = r.nextInt(255);
uuid.append(String.format(":%02X", n));
}
return uuid.toString();
}
private @Nullable InetAddress byName(@Nullable String address) {
if (address == null) {
return null;
@ -311,7 +324,7 @@ public class ConfigStore {
metadataRegistry.add(new Metadata(key, String.valueOf(hueId), null));
}
return String.valueOf(hueId);
return String.format("%02X", hueId);
}
public boolean isReady() {

@ -126,7 +126,7 @@ public class HueEmulationService implements EventHandler {
@Override
public Set<Object> getSingletons() {
return Set.of(userManagement, configurationAccess, lightItems, sensors, scenes, schedules, rules,
statusResource, accessInterceptor);
statusResource, accessInterceptor, requestCleaner);
}
Dictionary<String, String> serviceProperties() {

@ -95,8 +95,7 @@ class HueEmulationConfigWithRuntime extends Thread implements Runnable {
}
}
public synchronized CompletableFuture<@Nullable HueEmulationConfigWithRuntime> startNow(
@Nullable HueEmulationConfigWithRuntime ignored) {
public synchronized CompletableFuture<@Nullable HueEmulationConfigWithRuntime> startNow() {
if (hasAlreadyBeenStarted) {
logger.debug("Cannot restart thread");
return future;

@ -349,8 +349,9 @@ public class UpnpServer extends HttpServlet implements Consumer<HueEmulationConf
}
configChangeFuture = root.thenApply(this::createConfiguration)
.thenApplyAsync(this::performAddressTest, executor).thenApply(this::applyConfiguration)
.thenCompose(config::startNow)
.whenComplete((HueEmulationConfigWithRuntime config, @Nullable Throwable e) -> {
.thenCompose(c -> {
return c.startNow();
}).whenComplete((HueEmulationConfigWithRuntime config, @Nullable Throwable e) -> {
if (e != null) {
logger.warn("Upnp server: Address test failed", e);
}

@ -88,7 +88,7 @@ public class ItemUIDtoHueIDMappingTests {
itemRegistry.add(item);
String hueID = cs.mapItemUIDtoHueID(item);
assertThat(hueID, CoreMatchers.is("2"));
assertThat(hueID, CoreMatchers.is("02"));
HueLightEntry device = cs.ds.lights.get(hueID);
assertThat(device.item, is(item));
@ -108,7 +108,7 @@ public class ItemUIDtoHueIDMappingTests {
itemRegistry.add(item);
String hueID = cs.mapItemUIDtoHueID(item);
assertThat(hueID, CoreMatchers.is("10"));
assertThat(hueID, CoreMatchers.is("0A"));
HueLightEntry device = cs.ds.lights.get(hueID);
assertThat(device.item, is(item));

@ -123,7 +123,7 @@ public class UpnpTests {
}
// UDP thread started?
r.startNow(r).get(5, TimeUnit.SECONDS);
r.startNow().get(5, TimeUnit.SECONDS);
assertThat(subject.upnpAnnouncementThreadRunning(), is(true));
// Send M-SEARCH UPNP "packet" and check if the result contains our bridge ID