mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-18 16:17:30 +00:00
First Beta of Harmony configuration for testing.
This commit is contained in:
22
pom.xml
22
pom.xml
@@ -17,7 +17,19 @@
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.bwssytems</groupId>
|
||||
<artifactId>harmony-java-client</artifactId>
|
||||
<version>1.0.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sparkjava</groupId>
|
||||
<artifactId>spark-core</artifactId>
|
||||
@@ -58,6 +70,16 @@
|
||||
<artifactId>eval</artifactId>
|
||||
<version>0.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>4.0-beta4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.igniterealtime.smack</groupId>
|
||||
<artifactId>smack-core</artifactId>
|
||||
<version>4.0.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -90,6 +90,10 @@ public class BridgeSettings {
|
||||
public Boolean isValidHarmony() {
|
||||
if(this.harmonyaddress.contains(Configuration.DEFAULT_HARMONY_ADDRESS))
|
||||
return false;
|
||||
if(this.harmonypwd == null || this.harmonypwd == "")
|
||||
return false;
|
||||
if(this.harmonyuser == null || this.harmonyuser == "")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.bwssystems.HABridge.devicemanagmeent.*;
|
||||
import com.bwssystems.HABridge.hue.HueMulator;
|
||||
import com.bwssystems.HABridge.upnp.UpnpListener;
|
||||
import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
|
||||
import com.bwssystems.harmony.HarmonyServer;
|
||||
|
||||
public class HABridge {
|
||||
|
||||
@@ -33,6 +34,7 @@ public class HABridge {
|
||||
public static void main(String[] args) {
|
||||
Logger log = LoggerFactory.getLogger(HABridge.class);
|
||||
DeviceResource theResources;
|
||||
HarmonyServer myHarmonyServer;
|
||||
HueMulator theHueMulator;
|
||||
UpnpSettingsResource theSettingResponder;
|
||||
UpnpListener theUpnpListener;
|
||||
@@ -69,10 +71,17 @@ public class HABridge {
|
||||
port(Integer.valueOf(bridgeSettings.getServerPort()));
|
||||
// sparkjava config directive to set html static file location for Jetty
|
||||
staticFileLocation("/public");
|
||||
//setup the harmony connection if available
|
||||
try {
|
||||
myHarmonyServer = HarmonyServer.setup(bridgeSettings);
|
||||
} catch (Exception e) {
|
||||
log.error("Cannot get harmony client setup, Exiting with message: " + e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
// setup the class to handle the resource setup rest api
|
||||
theResources = new DeviceResource(bridgeSettings);
|
||||
theResources = new DeviceResource(bridgeSettings, myHarmonyServer.getMyHarmony());
|
||||
// setup the class to handle the hue emulator rest api
|
||||
theHueMulator = new HueMulator(theResources.getDeviceRepository());
|
||||
theHueMulator = new HueMulator(theResources.getDeviceRepository(), myHarmonyServer.getMyHarmony());
|
||||
theHueMulator.setupServer();
|
||||
// setup the class to handle the upnp response rest api
|
||||
theSettingResponder = new UpnpSettingsResource(bridgeSettings);
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.JsonTransformer;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.dao.DeviceRepository;
|
||||
import com.bwssystems.harmony.HarmonyHandler;
|
||||
import com.bwssystems.luupRequests.Sdata;
|
||||
import com.bwssystems.vera.VeraInfo;
|
||||
import com.google.gson.Gson;
|
||||
@@ -31,12 +32,14 @@ public class DeviceResource {
|
||||
|
||||
private DeviceRepository deviceRepository;
|
||||
private VeraInfo veraInfo;
|
||||
private HarmonyHandler myHarmonyHandler;
|
||||
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
||||
|
||||
public DeviceResource(BridgeSettings theSettings) {
|
||||
public DeviceResource(BridgeSettings theSettings, HarmonyHandler myHarmony) {
|
||||
super();
|
||||
deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
||||
veraInfo = new VeraInfo(theSettings.getVeraAddress(), theSettings.isValidVera());
|
||||
myHarmonyHandler = myHarmony;
|
||||
setupEndpoints();
|
||||
}
|
||||
|
||||
@@ -150,5 +153,13 @@ public class DeviceResource {
|
||||
return sData.getScenes();
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/harmony/activities", "application/json", (request, response) -> {
|
||||
log.debug("Get harmony activities");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
if(myHarmonyHandler != null)
|
||||
return myHarmonyHandler.getActivities();
|
||||
return "";
|
||||
}, new JsonTransformer());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||
import com.bwssystems.HABridge.api.hue.DeviceState;
|
||||
import com.bwssystems.HABridge.api.hue.HueApiResponse;
|
||||
import com.bwssystems.HABridge.dao.*;
|
||||
import com.bwssystems.harmony.HarmonyHandler;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
@@ -51,15 +52,17 @@ public class HueMulator {
|
||||
private static final String HUE_CONTEXT = "/api";
|
||||
|
||||
private DeviceRepository repository;
|
||||
private HarmonyHandler myHarmony;
|
||||
private HttpClient httpClient;
|
||||
private ObjectMapper mapper;
|
||||
|
||||
|
||||
public HueMulator(DeviceRepository aDeviceRepository){
|
||||
public HueMulator(DeviceRepository aDeviceRepository, HarmonyHandler theHandler){
|
||||
httpClient = HttpClients.createDefault();
|
||||
mapper = new ObjectMapper(); //armzilla: work around Echo incorrect content type and breaking mapping. Map manually
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
repository = aDeviceRepository;
|
||||
myHarmony = theHandler;
|
||||
}
|
||||
|
||||
// This function sets up the sparkjava rest calls for the hue api
|
||||
@@ -209,18 +212,27 @@ public class HueMulator {
|
||||
url = device.getOffUrl();
|
||||
}
|
||||
|
||||
//quick template
|
||||
String body;
|
||||
url = replaceIntensityValue(url, state.getBri());
|
||||
if (state.isOn())
|
||||
body = replaceIntensityValue(device.getContentBody(), state.getBri());
|
||||
if(device.getDeviceType() == "activity")
|
||||
{
|
||||
log.debug("executing activity to Harmony: " + url);
|
||||
myHarmony.startActivity(url);
|
||||
}
|
||||
else
|
||||
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
|
||||
//make call
|
||||
if(!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)){
|
||||
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
|
||||
log.error("Error on calling url to change device state: " + url);
|
||||
return null;
|
||||
{
|
||||
log.debug("executing activity to Http: " + url);
|
||||
// quick template
|
||||
String body;
|
||||
url = replaceIntensityValue(url, state.getBri());
|
||||
if (state.isOn())
|
||||
body = replaceIntensityValue(device.getContentBody(), state.getBri());
|
||||
else
|
||||
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
|
||||
// make call
|
||||
if (!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)) {
|
||||
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
|
||||
log.error("Error on calling url to change device state: " + url);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
response.type("application/json; charset=utf-8");
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.bwssystems.harmony;
|
||||
|
||||
public class HarmonyActivities {
|
||||
|
||||
}
|
||||
89
src/main/java/com/bwssystems/harmony/HarmonyHandler.java
Normal file
89
src/main/java/com/bwssystems/harmony/HarmonyHandler.java
Normal file
@@ -0,0 +1,89 @@
|
||||
package com.bwssystems.harmony;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.whistlingfish.harmony.HarmonyClient;
|
||||
import net.whistlingfish.harmony.config.Activity;
|
||||
import net.whistlingfish.harmony.config.Device;
|
||||
import net.whistlingfish.harmony.config.HarmonyConfig;
|
||||
|
||||
public class HarmonyHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(HarmonyHandler.class);
|
||||
private HarmonyClient harmonyClient;
|
||||
private Boolean noopCalls;
|
||||
|
||||
public HarmonyHandler(HarmonyClient theClient, Boolean noopCallsSetting) {
|
||||
super();
|
||||
noopCalls = noopCallsSetting;
|
||||
harmonyClient = theClient;
|
||||
}
|
||||
|
||||
public List<Activity> getActivities() {
|
||||
log.debug("Harmony api activities list requested.");
|
||||
return harmonyClient.getConfig().getActivities();
|
||||
}
|
||||
|
||||
public List<Device> getDevices() {
|
||||
log.debug("Harmony api device list requested.");
|
||||
return harmonyClient.getConfig().getDevices();
|
||||
}
|
||||
|
||||
public HarmonyConfig getConfig() {
|
||||
log.debug("Harmony api config requested.");
|
||||
return harmonyClient.getConfig();
|
||||
}
|
||||
|
||||
public Activity getCurrentActivity() {
|
||||
log.debug("Harmony api current sctivity requested.");
|
||||
return harmonyClient.getCurrentActivity();
|
||||
}
|
||||
|
||||
public Boolean startActivity(String anActivity) {
|
||||
log.debug("Harmony api start activity requested for: " + anActivity + " noop mode: " + noopCalls);
|
||||
if (anActivity != null && !anActivity.isEmpty()) {
|
||||
try {
|
||||
if (!noopCalls)
|
||||
harmonyClient.startActivity(Integer.parseInt(anActivity));
|
||||
} catch (IllegalArgumentException e) {
|
||||
try {
|
||||
if (!noopCalls)
|
||||
harmonyClient.startActivityByName(anActivity);
|
||||
} catch (IllegalArgumentException ei) {
|
||||
log.error("Error in finding activity: " + anActivity);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.error("Error in finding activity: " + anActivity);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean pressButton(String aDevice, String aDeviceButton) {
|
||||
log.debug("Harmony api press a button requested for device: " + aDevice + " and a for button: " + aDeviceButton + " noop mode: " + noopCalls);
|
||||
if (aDeviceButton != null && !aDeviceButton.isEmpty()) {
|
||||
try {
|
||||
if (!noopCalls)
|
||||
harmonyClient.pressButton(Integer.parseInt(aDevice), aDeviceButton);
|
||||
} catch (IllegalArgumentException e) {
|
||||
try {
|
||||
if (!noopCalls)
|
||||
harmonyClient.pressButton(aDevice, aDeviceButton);
|
||||
} catch (IllegalArgumentException ei) {
|
||||
log.error("Error in finding device: " + aDevice +" and a button: " + aDeviceButton);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.error("Error in finding device: " + aDevice +" and a button: " + aDeviceButton);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
60
src/main/java/com/bwssystems/harmony/HarmonyServer.java
Normal file
60
src/main/java/com/bwssystems/harmony/HarmonyServer.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package com.bwssystems.harmony;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
import net.whistlingfish.harmony.ActivityChangeListener;
|
||||
import net.whistlingfish.harmony.HarmonyClient;
|
||||
import net.whistlingfish.harmony.HarmonyClientModule;
|
||||
import net.whistlingfish.harmony.config.Activity;
|
||||
|
||||
public class HarmonyServer {
|
||||
@Inject
|
||||
private HarmonyClient harmonyClient;
|
||||
|
||||
private HarmonyHandler myHarmony;
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(HarmonyServer.class);
|
||||
|
||||
public HarmonyServer() {
|
||||
super();
|
||||
myHarmony = null;
|
||||
}
|
||||
|
||||
public static HarmonyServer setup(BridgeSettings bridgeSettings) throws Exception {
|
||||
if(!bridgeSettings.isValidHarmony()) {
|
||||
return new HarmonyServer();
|
||||
}
|
||||
Injector injector = null;
|
||||
injector = Guice.createInjector(new HarmonyClientModule());
|
||||
HarmonyServer mainObject = new HarmonyServer();
|
||||
injector.injectMembers(mainObject);
|
||||
mainObject.execute(bridgeSettings);
|
||||
return mainObject;
|
||||
}
|
||||
|
||||
private void execute(BridgeSettings mySettings) throws Exception {
|
||||
log.debug("setup initiated....");
|
||||
harmonyClient.addListener(new ActivityChangeListener() {
|
||||
@Override
|
||||
public void activityStarted(Activity activity) {
|
||||
log.info(format("activity changed: [%d] %s", activity.getId(), activity.getLabel()));
|
||||
}
|
||||
});
|
||||
harmonyClient.connect(mySettings.getHarmonyAddress(), mySettings.getHarmonyUser(), mySettings.getHarmonyPwd());
|
||||
Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
|
||||
myHarmony = new HarmonyHandler(harmonyClient, noopCalls);
|
||||
}
|
||||
|
||||
public HarmonyHandler getMyHarmony() {
|
||||
return myHarmony;
|
||||
}
|
||||
}
|
||||
@@ -149,15 +149,15 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
|
||||
|
||||
this.updateShowHarmony = function () {
|
||||
if(self.BridgeSettings.harmonyaddress == "1.1.1.1" || self.BridgeSettings.harmonyaddress == "")
|
||||
self.state.showHarmony = false;
|
||||
this.state.showHarmony = false;
|
||||
else
|
||||
self.state.showHarmony = true;
|
||||
this.state.showHarmony = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.viewVeraDevices = function () {
|
||||
this.state.error = "";
|
||||
if(BridgeSettings.veraaddress == "1.1.1.1" || BridgeSettings.veraaddress == "")
|
||||
if(!this.state.showVera)
|
||||
return;
|
||||
this.state.error = "";
|
||||
return $http.get(this.state.base + "/vera/devices").then(
|
||||
@@ -176,7 +176,7 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
|
||||
|
||||
this.viewVeraScenes = function () {
|
||||
this.state.error = "";
|
||||
if(BridgeSettings.veraaddress == "1.1.1.1" || BridgeSettings.veraaddress == "")
|
||||
if(!this.state.showVera)
|
||||
return;
|
||||
return $http.get(this.state.base + "/vera/scenes").then(
|
||||
function (response) {
|
||||
@@ -192,8 +192,28 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
|
||||
);
|
||||
};
|
||||
|
||||
this.viewHarmonyActivities = function () {
|
||||
this.state.error = "";
|
||||
if(!this.state.showHarmony)
|
||||
return;
|
||||
return $http.get(this.state.base + "/harmony/activities").then(
|
||||
function (response) {
|
||||
self.state.harmonyactivities = response.data;
|
||||
},
|
||||
function (error) {
|
||||
if (error.data) {
|
||||
$window.alert("Get Harmony Activities Error: " + error.data.message);
|
||||
} else {
|
||||
$window.alert("Get Harmony Activities Error: unknown");
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.addDevice = function (id, name, type, onUrl, offUrl, httpVerb, contentType, contentBody, contentBodyOff) {
|
||||
this.state.error = "";
|
||||
if(httpVerb != null && httpVerb != "")
|
||||
type = "custom";
|
||||
if (id) {
|
||||
var putUrl = this.state.base + "/" + id;
|
||||
return $http.put(putUrl, {
|
||||
@@ -220,6 +240,8 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
|
||||
} else {
|
||||
if(type == null || type == "")
|
||||
type = "switch";
|
||||
if(httpVerb != null && httpVerb != "")
|
||||
type = "custom";
|
||||
return $http.post(this.state.base, {
|
||||
name: name,
|
||||
deviceType: type,
|
||||
@@ -280,6 +302,8 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
|
||||
bridgeService.deleteDevice(device.id);
|
||||
};
|
||||
$scope.testUrl = function (device, type) {
|
||||
if(device.deviceType == "activity")
|
||||
return;
|
||||
if(type == "on") {
|
||||
if(device.httpVerb == "PUT")
|
||||
$http.put(device.onUrl, device.contentBody).then(
|
||||
@@ -343,6 +367,7 @@ app.controller('AddingController', function ($scope, $location, $http, bridgeSer
|
||||
bridgeService.device = $scope.device;
|
||||
bridgeService.viewVeraDevices();
|
||||
bridgeService.viewVeraScenes();
|
||||
bridgeService.viewHarmonyActivities();
|
||||
$scope.bridge = bridgeService.state;
|
||||
bridgeService.updateShowVera();
|
||||
bridgeService.updateShowHarmony();
|
||||
@@ -423,20 +448,15 @@ app.controller('AddingController', function ($scope, $location, $http, bridgeSer
|
||||
};
|
||||
|
||||
$scope.buildActivityUrls = function (harmonyactivity) {
|
||||
if ($scope.vera.base.indexOf("http") < 0) {
|
||||
$scope.vera.base = "http://" + $scope.vera.base;
|
||||
}
|
||||
$scope.device.deviceType = "scene";
|
||||
$scope.device.name = verascene.name;
|
||||
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum="
|
||||
+ verascene.id;
|
||||
$scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum="
|
||||
+ verascene.id;
|
||||
$scope.device.deviceType = "activity";
|
||||
$scope.device.name = harmonyactivity.label;
|
||||
$scope.device.onUrl = harmonyactivity.id;
|
||||
$scope.device.offUrl = "-1";
|
||||
};
|
||||
|
||||
$scope.testUrl = function (url) {
|
||||
$scope.testUrl = function (device, type) {
|
||||
if(device.deviceType == "activity")
|
||||
return;
|
||||
if(type == "on") {
|
||||
if(device.httpVerb == "PUT")
|
||||
$http.put(device.onUrl, device.contentBody).then(
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="harmonyactivitye in bridge.harmonyactivities | orderBy:predicate:reverse">
|
||||
<td>{{harmonyactivity.name}}</td>
|
||||
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | orderBy:predicate:reverse">
|
||||
<td>{{harmonyactivity.label}}</td>
|
||||
<td>{{harmonyactivity.id}}</td>
|
||||
<td>
|
||||
<button class="btn btn-success" type="submit"
|
||||
|
||||
Reference in New Issue
Block a user