diff --git a/README.md b/README.md index a102214..2a39b25 100644 --- a/README.md +++ b/README.md @@ -61,17 +61,17 @@ ATTENTION: This requires JDK 1.8 to run ATTENTION: Due to port 80 being the default, Linux restricts this to super user. Use the instructions below. ``` -java -jar ha-bridge-4.5.5.jar +java -jar ha-bridge-4.5.6.jar ``` ### Automation on Linux systems To have this configured and running automatically there are a few resources to use. One is using Docker and a docker container has been built for this and can be gotten here: https://github.com/aptalca/docker-ha-bridge -Create the directory and make sure that ha-bridge-4.5.5.jar is in your /home/pi/habridge directory. +Create the directory and make sure that ha-bridge-4.5.6.jar is in your /home/pi/habridge directory. ``` pi@raspberrypi:~ $ mkdir habridge pi@raspberrypi:~ $ cd habridge -pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.5.5/ha-bridge-4.5.5.jar +pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.5.6/ha-bridge-4.5.6.jar ``` #### System Control Setup on a pi (preferred) @@ -92,7 +92,7 @@ After=network.target [Service] Type=simple WorkingDirectory=/home/pi/habridge -ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.5.5.jar +ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.5.6.jar [Install] WantedBy=multi-user.target @@ -127,7 +127,7 @@ Then cut and past this, modify any locations that are not correct ``` cd /home/pi/habridge rm /home/pi/habridge/habridge-log.txt -nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.5.5.jar > /home/pi/habridge/habridge-log.txt 2>&1 & +nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.5.6.jar > /home/pi/habridge/habridge-log.txt 2>&1 & chmod 777 /home/pi/habridge/habridge-log.txt ``` diff --git a/pom.xml b/pom.xml index e371c8d..55d97c2 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 4.5.5a + 4.5.5b jar HA Bridge @@ -33,7 +33,7 @@ com.github.bwssytems harmony-java-client - 1.1.1 + 1.1.5 org.slf4j diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSecurity.java b/src/main/java/com/bwssystems/HABridge/BridgeSecurity.java index 0f2c917..0c6fb70 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSecurity.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSecurity.java @@ -201,12 +201,15 @@ public class BridgeSecurity { public void setSettingsChanged(boolean settingsChanged) { this.settingsChanged = settingsChanged; } + public Map getWhitelist() { + return securityDescriptor.getWhitelist(); + } public HueError[] validateWhitelistUser(String aUser, String userDescription, boolean strict) { String validUser = null; boolean found = false; if (aUser != null && !aUser.equalsIgnoreCase("undefined") && !aUser.equalsIgnoreCase("null") - && !aUser.equalsIgnoreCase("")) { + && !aUser.equalsIgnoreCase("") && !aUser.equals(DEPRACATED_INTERNAL_USER)) { if (securityDescriptor.getWhitelist() != null) { Set theUserIds = securityDescriptor.getWhitelist().keySet(); Iterator userIterator = theUserIds.iterator(); @@ -218,26 +221,24 @@ public class BridgeSecurity { } } } - } - if(!found && !strict) { - log.debug("validateWhitelistUser: a user was not found and it is not strict rules <" + aUser + "> being created"); - newWhitelistUser(aUser, userDescription); - - found = true; + if(!found && !strict) { + log.debug("validateWhitelistUser: a user was not found and it is not strict rules <" + aUser + "> being created"); + newWhitelistUser(aUser, userDescription); + + found = true; + } } if (!found) { - log.debug("validateWhitelistUser: a user was not found and it is strict rules <" + aUser + ">"); + log.debug("validateWhitelistUser: a user was not found and strict rules is set to: " + strict + "for user <" + aUser + ">"); return HueErrorResponse.createResponse("1", "/api/" + aUser == null ? "" : aUser, "unauthorized user", null, null, null).getTheErrors(); } return null; } - public void newWhitelistUser(String aUser, String userDescription) { - if(aUser.equals(DEPRACATED_INTERNAL_USER)) - return; + private void newWhitelistUser(String aUser, String userDescription) { if (securityDescriptor.getWhitelist() == null) { securityDescriptor.setWhitelist(new HashMap<>()); } @@ -278,9 +279,8 @@ public class BridgeSecurity { Iterator> it = securityDescriptor.getWhitelist().entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = it.next(); - it.remove(); // avoids a ConcurrentModificationException if(pair.getValue().getName().equals(TEST_USER_TYPE)) { - securityDescriptor.getWhitelist().remove(pair.getKey()); + it.remove(); // avoids a ConcurrentModificationException setSettingsChanged(true); } } diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index 30be3c2..038bdce 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -70,7 +70,7 @@ public class HueMulator { public void setupServer() { log.info("Hue emulator service started...."); before(HUE_CONTEXT + "/*", (request, response) -> { - log.debug("HueMulator GET called on api/* with request <" + request.pathInfo() + ">"); + log.debug("HueMulator " + request.requestMethod() + " called on api/* with request <<<" + request.pathInfo() + ">>>, and body <<<" + request.body() + ">>>"); if(bridgeSettingMaster.getBridgeSecurity().isSecure()) { String pathInfo = request.pathInfo(); if(pathInfo != null && pathInfo.contains(HUE_CONTEXT + "/devices")) { @@ -755,7 +755,9 @@ public class HueMulator { log.debug("hue api user create requested for device type: " + aDeviceType + " and username: " + newUser + (followingSlash ? " /api/ called" : "")); return "[{\"success\":{\"username\":\"" + newUser + "\"}}]"; } - return aGsonHandler.toJson(HueErrorResponse.createResponse("1", "/api/", "unauthorized user", null, null, null).getTheErrors()); + else + log.debug("user add toContinue was false, returning not authorized"); + return aGsonHandler.toJson(HueErrorResponse.createResponse("101", "/api/", "link button not pressed", null, null, null).getTheErrors()); } private Object getConfig(String userId, String ipAddress) { @@ -763,14 +765,14 @@ public class HueMulator { log.info("Traceupnp: hue api/:userid/config config requested: " + userId + " from " + ipAddress); log.debug("hue api config requested: " + userId + " from " + ipAddress); if (bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton()) != null) { - log.debug("hue api config requested, No User supplied, returning public config"); + log.debug("hue api config requested, User invalid, returning public config"); HuePublicConfig apiResponse = HuePublicConfig.createConfig("Philips hue", bridgeSettings.getUpnpConfigAddress(), bridgeSettings.getHubversion()); return apiResponse; } HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), - bridgeSettings.getWhitelist(), bridgeSettings.getHubversion(), bridgeSettingMaster.getBridgeControl().isLinkButton()); + bridgeSettingMaster.getBridgeSecurity().getWhitelist(), bridgeSettings.getHubversion(), bridgeSettingMaster.getBridgeControl().isLinkButton()); log.debug("api response config <<<" + aGsonHandler.toJson(apiResponse.getConfig()) + ">>>"); return apiResponse.getConfig(); } @@ -779,11 +781,13 @@ public class HueMulator { private Object getFullState(String userId, String ipAddress) { log.debug("hue api full state requested: " + userId + " from " + ipAddress); HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton()); - if (theErrors != null) + if (theErrors != null) { + log.debug("full state error occurred <<<" + aGsonHandler.toJson(theErrors) + ">>>"); return theErrors; + } HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), - bridgeSettings.getWhitelist(), bridgeSettings.getHubversion(), bridgeSettingMaster.getBridgeControl().isLinkButton()); + bridgeSettingMaster.getBridgeSecurity().getWhitelist(), bridgeSettings.getHubversion(), bridgeSettingMaster.getBridgeControl().isLinkButton()); apiResponse.setLights((Map) this.lightsListHandler(userId, ipAddress)); apiResponse.setGroups((Map) this.groupsListHandler(userId, ipAddress)); diff --git a/src/main/java/com/bwssystems/HABridge/plugins/harmony/ButtonPress.java b/src/main/java/com/bwssystems/HABridge/plugins/harmony/ButtonPress.java index 0c08344..f853af5 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/harmony/ButtonPress.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/harmony/ButtonPress.java @@ -6,6 +6,7 @@ public class ButtonPress { private Integer delay; private Integer count; private String hub; + private Integer pressTime; public String getDevice() { return device; } @@ -43,4 +44,10 @@ public class ButtonPress { public void setHub(String hub) { this.hub = hub; } + public Integer getPressTime() { + return pressTime; + } + public void setPressTime(Integer pressTime) { + this.pressTime = pressTime; + } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHandler.java index af6516a..3cf189c 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHandler.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHandler.java @@ -62,7 +62,7 @@ public class HarmonyHandler { } public Boolean startActivity(RunActivity anActivity) { - log.debug("Harmony api start activity requested for: " + anActivity.getName() + " noop mode: " + noopCalls); + log.debug("Harmony api start activity requested for: " + anActivity.getName() + " for a hub: " + anActivity.getHub() + " noop mode: " + noopCalls); if (anActivity.isValid()) { try { if (noopCalls || devMode) { @@ -72,7 +72,7 @@ public class HarmonyHandler { devResponse.setCurrentActivity(devResponse.getConfig().getActivityByName(anActivity.getName())); } - log.info("noop mode: Harmony api start activity requested for: " + anActivity.getName()); + log.info("noop mode: Harmony api start activity requested for: " + anActivity.getName() + " for a hub: " + anActivity.getHub()); } else harmonyClient.startActivity(Integer.parseInt(anActivity.getName())); @@ -81,12 +81,12 @@ public class HarmonyHandler { if (!noopCalls) harmonyClient.startActivityByName(anActivity.getName()); } catch (IllegalArgumentException ei) { - log.error("Error in finding activity: " + anActivity.getName()); + log.error("Error in finding activity: " + anActivity.getName() + " for a hub: " + anActivity.getHub()); return false; } } } else { - log.error("Error in finding activity: " + anActivity.getName()); + log.error("Error in finding activity: " + anActivity.getName() + " for a hub: " + anActivity.getHub()); return false; } @@ -94,26 +94,30 @@ public class HarmonyHandler { } public Boolean pressButton(ButtonPress aDeviceButton) { - log.debug("Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton() + " noop mode: " + noopCalls); + log.debug("Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton() + " for a hub: " + aDeviceButton.getHub() + " noop mode: " + noopCalls); if (aDeviceButton.isValid()) { try { if (noopCalls || devMode) { - log.info("noop mode: Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton()); + log.info("noop mode: Harmony api press a button requested for device: " + aDeviceButton.getDevice() + " and a for button: " + aDeviceButton.getButton() + + " with a pressTime of: " + aDeviceButton.getPressTime() + " for a hub: " + aDeviceButton.getHub()); } - else - harmonyClient.pressButton(Integer.parseInt(aDeviceButton.getDevice()), aDeviceButton.getButton()); - + else { + if(aDeviceButton.getPressTime() != null && aDeviceButton.getPressTime() > 0) + harmonyClient.pressButton(Integer.parseInt(aDeviceButton.getDevice()), aDeviceButton.getButton(), aDeviceButton.getPressTime()); + else + harmonyClient.pressButton(Integer.parseInt(aDeviceButton.getDevice()), aDeviceButton.getButton()); + } } catch (IllegalArgumentException e) { try { if (!noopCalls) harmonyClient.pressButton(aDeviceButton.getDevice(), aDeviceButton.getButton()); } catch (IllegalArgumentException ei) { - log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton()); + log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton() + " for a hub: " + aDeviceButton.getHub()); return false; } } } else { - log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton()); + log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton() + " for a hub: " + aDeviceButton.getHub()); return false; } diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js index db4d876..f2443bf 100644 --- a/src/main/resources/public/scripts/app.js +++ b/src/main/resources/public/scripts/app.js @@ -1930,10 +1930,17 @@ app.controller('HarmonyController', function ($scope, $location, bridgeService, $location.path('/editdevice'); }; - $scope.buildButtonUrls = function (harmonydevice, onbutton, offbutton) { + $scope.buildButtonUrls = function (harmonydevice, onbutton, offbutton, onpresstime, offpresstime) { var actionOn = angular.fromJson(onbutton); var actionOff = angular.fromJson(offbutton); + var postCmd = "\"}"; + if(onpresstime !== undefined && onpresstime !== "0") + postCmd = "\",\"pressTime\":" + onpresstime + "}"; onpayload = "{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOn.command + "\",\"hub\":\"" + harmonydevice.hub + "\"}"; + if(offpresstime !== undefined && offpresstime !== "0") + postCmd = "\",\"pressTime\":" + offpresstime + "}"; + else + postCmd = "\"}"; offpayload = "{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOff.command + "\",\"hub\":\"" + harmonydevice.hub + "\"}"; bridgeService.buildUrls(onpayload, null, offpayload, true, actionOn.command, harmonydevice.device.label, harmonydevice.hub, "button", "harmonyButton", null, null); @@ -3058,7 +3065,7 @@ app.controller('EditController', function ($scope, $location, bridgeService) { $scope.onDevices = null; $scope.dimDevices = null; $scope.offDevices = null; - if ($scope.device !== undefined && $scope.device.name !== undefined) { + if ($scope.devicec && $scope.device.name !== undefined) { if($scope.bridge.device.onUrl !== undefined) $scope.onDevices = bridgeService.getCallObjects($scope.bridge.device.onUrl); if($scope.bridge.device.dimUrl !== undefined) diff --git a/src/main/resources/public/views/harmonydevice.html b/src/main/resources/public/views/harmonydevice.html index a4f51d2..5fbb3d3 100644 --- a/src/main/resources/public/views/harmonydevice.html +++ b/src/main/resources/public/views/harmonydevice.html @@ -37,6 +37,7 @@ 'Add Bridge Device' to finish that selection setup. The 'Already Configured Harmony Buttons' list below will show what is already setup for your Harmony Hubs.

+

Note: The press time areas are for adding a press time in milliseconds to handle various long press scenarios. If left alone it will default to the original 200ms.

@@ -47,7 +48,9 @@ + + @@ -64,6 +67,10 @@ value="{{funcon.action}}">{{funcon.label}} + +
Id Hub On ButtonOn Press Time Off ButtonOff Press Time Build Actions
+ + + +