From a9e3a492090c3af4c47e40b7ebbbaf97e734c36f Mon Sep 17 00:00:00 2001 From: Dmitry Jerusalimsky Date: Fri, 9 Dec 2016 22:09:05 -0800 Subject: [PATCH 1/2] Added configuration for OpenHAB Minor cleanup and refactor Added ability to specify username and password for use with basic auth Added ability to run as a service on Linux machines with systemd --- .gitignore | 1 + README.md | 18 ++++++ echo-ha-bridge.service | 13 ++++ pom.xml | 2 +- .../java/com/armzilla/ha/SpringbootEntry.java | 7 --- .../com/armzilla/ha/TomcatConnectorBean.java | 6 -- .../com/armzilla/ha/dao/DeviceRepository.java | 1 - .../java/com/armzilla/ha/hue/HueMulator.java | 16 +++-- src/main/resources/static/app.js | 61 ++++++++++++++++--- src/main/resources/static/configurator.html | 47 ++++++++++---- 10 files changed, 131 insertions(+), 41 deletions(-) create mode 100644 echo-ha-bridge.service diff --git a/.gitignore b/.gitignore index 77b7014..92a0f85 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ buildNumber.properties *.iml data .idea +config/ \ No newline at end of file diff --git a/README.md b/README.md index 884f24c..ee53aca 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,24 @@ You can now control devices with your Amazon Echo by saying "Alexa, Turn on the To view or remove devices that Alexa knows about, you can use the mobile app Menu / Settings / Connected Home, This is needed if you remove a device from the Amazon Echo Bridge. +## Running as a service + +If you are running this on Linux with `systemd`, do the following: +1. Modify `echo-ha-bridge.service` by changing the name of the jar file to execute and location of the working directory +2. Copy `echo-ha-bridge.service` to `/lib/systemd/system/` +3. Run `sudo systemctl enable echo-ha-bridge.service` +4. Navigate to the location of `amazon-ha-bridge-*.jar` and create a file called `application.properties` with the following content: +``` +upnp.response.port=50000 +upnp.config.address=ip address of your machine +emulator.portbase=should be same as server.port +emulator.portcount=3 +upnp.disable=false +server.port=port number you want the server to be listening on +logging.file=full path to the file where logs will be written to +``` + + ## Build In case you would like to internally configure your own build of the Amazon Echo Bridge, a few requisites are required. diff --git a/echo-ha-bridge.service b/echo-ha-bridge.service new file mode 100644 index 0000000..f367467 --- /dev/null +++ b/echo-ha-bridge.service @@ -0,0 +1,13 @@ +[Unit] +Description=Amazon Echo HA Bridge +After=syslog.target + +[Service] +Type=simple +PIDFile=/var/run/echo-ha-bridge/echo-ha-bridge.pid +WorkingDirectory=/opt/echo-ha-bridge/ +ExecStart=/usr/bin/java -jar amazon-echo-bridge.jar & > /dev/null +SuccessExitStatus=143 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/pom.xml b/pom.xml index 52dab98..5c9e6c4 100755 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.armzilla.ha amazon-echo-bridge - 0.4.0 + 0.4.1 jar Amazon Echo Bridge diff --git a/src/main/java/com/armzilla/ha/SpringbootEntry.java b/src/main/java/com/armzilla/ha/SpringbootEntry.java index 93009c1..a27b9f5 100644 --- a/src/main/java/com/armzilla/ha/SpringbootEntry.java +++ b/src/main/java/com/armzilla/ha/SpringbootEntry.java @@ -1,17 +1,10 @@ package com.armzilla.ha; -import org.apache.catalina.connector.Connector; -import org.apache.coyote.http11.Http11NioProtocol; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; -import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableScheduling; -import java.io.IOException; @SpringBootApplication @EnableScheduling diff --git a/src/main/java/com/armzilla/ha/TomcatConnectorBean.java b/src/main/java/com/armzilla/ha/TomcatConnectorBean.java index e802566..d4ef35f 100644 --- a/src/main/java/com/armzilla/ha/TomcatConnectorBean.java +++ b/src/main/java/com/armzilla/ha/TomcatConnectorBean.java @@ -1,17 +1,12 @@ package com.armzilla.ha; import org.apache.catalina.connector.Connector; -import org.apache.coyote.http11.Http11NioProtocol; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; -import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; -import java.util.Set; - /** * Created by arm on 9/12/15. */ @@ -37,7 +32,6 @@ public EmbeddedServletContainerFactory servletContainer() { private Connector createConnector(int portNumber) { Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); - Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler(); connector.setScheme("http"); connector.setPort(portNumber); return connector; diff --git a/src/main/java/com/armzilla/ha/dao/DeviceRepository.java b/src/main/java/com/armzilla/ha/dao/DeviceRepository.java index 3b0a80d..ba2b0ca 100644 --- a/src/main/java/com/armzilla/ha/dao/DeviceRepository.java +++ b/src/main/java/com/armzilla/ha/dao/DeviceRepository.java @@ -1,7 +1,6 @@ package com.armzilla.ha.dao; import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; diff --git a/src/main/java/com/armzilla/ha/hue/HueMulator.java b/src/main/java/com/armzilla/ha/hue/HueMulator.java index 5934c4c..c98a52e 100644 --- a/src/main/java/com/armzilla/ha/hue/HueMulator.java +++ b/src/main/java/com/armzilla/ha/hue/HueMulator.java @@ -62,13 +62,20 @@ public HueMulator(){ mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } + private Page getDevices(HttpServletRequest request) { + int pageNumber = request.getLocalPort()-portBase; + Page result = repository.findByDeviceType("switch", new PageRequest(pageNumber, 25)); + log.info("Found " + result.getNumberOfElements() + " devices for page " + result.getNumber()); + + return result; + } + @RequestMapping(value = "/{userId}/lights", method = RequestMethod.GET, produces = "application/json") public ResponseEntity> getUpnpConfiguration(@PathVariable(value = "userId") String userId, HttpServletRequest request) { - log.info("hue lights list requested: " + userId + " from " + request.getRemoteAddr() + request.getLocalPort()); + log.info("hue lights list requested: " + userId + " from " + request.getRemoteAddr() + ":" + request.getLocalPort()); - int pageNumber = request.getLocalPort()-portBase; - Page deviceList = repository.findByDeviceType("switch", new PageRequest(pageNumber, 25)); + Page deviceList = this.getDevices(request); Map deviceResponseMap = new HashMap<>(); for (DeviceDescriptor device : deviceList) { deviceResponseMap.put(device.getId(), device.getName()); @@ -85,8 +92,7 @@ public ResponseEntity postAPI(HttpServletRequest request) { @RequestMapping(value = "/{userId}", method = RequestMethod.GET, produces = "application/json") public ResponseEntity getApi(@PathVariable(value = "userId") String userId, HttpServletRequest request) { log.info("hue api root requested: " + userId + " from " + request.getRemoteAddr()); - int pageNumber = request.getLocalPort()-portBase; - Page descriptorList = repository.findByDeviceType("switch", new PageRequest(pageNumber, 25)); + Page descriptorList = this.getDevices(request); if (descriptorList == null) { return new ResponseEntity<>(null, null, HttpStatus.NOT_FOUND); } diff --git a/src/main/resources/static/app.js b/src/main/resources/static/app.js index 572b287..0925dca 100755 --- a/src/main/resources/static/app.js +++ b/src/main/resources/static/app.js @@ -107,20 +107,61 @@ angular.module('configurator', []) $scope.bridge = bridgeService.state; $scope.device = {id: "", name: "", type: "switch", onUrl: "", offUrl: ""}; - $scope.vera = {base: "", port: "3480", id: ""}; + $scope.hubs = { + vera: { + base: "" + , port: "3480" + , id: "" + , onUrl: "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum={deviceId}" + , offUrl: "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum={deviceId}" + , user: "" + , pass: "" + } + , openhab: { + base: "" + , port: "8080" + , id: "" + , onUrl: "/CMD?{deviceId}=ON" + , offUrl: "/CMD?{deviceId}=OFF" + , user: "" + , pass: "" + } + } + // set default system to Vera + $scope.selectedHub = "vera"; + $scope.system = $scope.hubs.vera; bridgeService.device = $scope.device; + $scope.selectHub = function (hubName) { + console.log('Selecting hub', $scope.selectedHub) + if (hubName === "openhab") { + $scope.system = $scope.hubs.openhab; + } + else { + $scope.system = $scope.hubs.vera; + } + } + $scope.buildUrls = function () { - if ($scope.vera.base.indexOf("http") < 0) { - $scope.vera.base = "http://" + $scope.vera.base; + var base = "" + if ($scope.system.base.indexOf("http") < 0) { + base = "http://"; } - $scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port - + "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum=" - + $scope.vera.id; - $scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port - + "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=" - + $scope.vera.id; - }; + base += $scope.system.base; + + var user = $scope.system.user.trim(); + var pass = $scope.system.pass.trim(); + var creds = ""; + if (user.length > 0 && pass.length > 0) { + creds = encodeURIComponent(user) + ":" + encodeURIComponent(pass) + "@"; + } + + var index = base.indexOf("//") + 2; + base = base.slice(0, index) + creds + base.slice(index); + + $scope.device.onUrl = base + ":" + $scope.system.port + $scope.system.onUrl.replace("{deviceId}", $scope.system.id); + $scope.device.offUrl = base + ":" + $scope.system.port + $scope.system.offUrl.replace("{deviceId}", $scope.system.id); + }; $scope.testUrl = function (url) { window.open(url, "_blank"); diff --git a/src/main/resources/static/configurator.html b/src/main/resources/static/configurator.html index 8dabf1d..c02b67f 100755 --- a/src/main/resources/static/configurator.html +++ b/src/main/resources/static/configurator.html @@ -95,38 +95,63 @@

ERROR

+
+

Select Hub Type

+
    +
  • + + + +
  • + +
+

Add a new device

  • -

    You can generate on/off URLs by filling in a Vera server URL, port, and +

    You can generate on/off URLs by filling in a hub server URL, port, and device ID; or you can fill them out manually in the lower section.

    - +
    - +
    - +
    - +
    - - + +
    + +
    + +
    + +
    +
    +
    +
    -
    From cff82d2d95932fc389cf2d3aed34f2faff802074 Mon Sep 17 00:00:00 2001 From: Dmitry Jerusalimsky Date: Fri, 9 Dec 2016 22:14:43 -0800 Subject: [PATCH 2/2] fixed a log message --- src/main/java/com/armzilla/ha/hue/HueMulator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/armzilla/ha/hue/HueMulator.java b/src/main/java/com/armzilla/ha/hue/HueMulator.java index c98a52e..a688d69 100644 --- a/src/main/java/com/armzilla/ha/hue/HueMulator.java +++ b/src/main/java/com/armzilla/ha/hue/HueMulator.java @@ -65,7 +65,7 @@ public HueMulator(){ private Page getDevices(HttpServletRequest request) { int pageNumber = request.getLocalPort()-portBase; Page result = repository.findByDeviceType("switch", new PageRequest(pageNumber, 25)); - log.info("Found " + result.getNumberOfElements() + " devices for page " + result.getNumber()); + log.info("Found " + result.getNumberOfElements() + " devices on port " + request.getLocalPort()); return result; }