mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-16 18:24:36 +00:00
Updated upnp response for M-SEARCH again. Updated devices to have
numbering more in line with how the hue bridge is done. Added special generation of hue device unique id as the philips api spec shows. Added a renumber function to convert id's.
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>3.1.0b</version>
|
||||
<version>3.1.0c</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HA Bridge</name>
|
||||
|
||||
@@ -84,7 +84,7 @@ public class DeviceResponse {
|
||||
response.setState(device.getDeviceState());
|
||||
|
||||
response.setName(device.getName());
|
||||
response.setUniqueid(device.getId());
|
||||
response.setUniqueid(device.getUniqueid());
|
||||
response.setManufacturername("Philips");
|
||||
response.setType("Dimmable light");
|
||||
response.setModelid("LWB004");
|
||||
|
||||
@@ -11,6 +11,9 @@ public class DeviceDescriptor{
|
||||
@SerializedName("id")
|
||||
@Expose
|
||||
private String id;
|
||||
@SerializedName("uniqueid")
|
||||
@Expose
|
||||
private String uniqueid;
|
||||
@SerializedName("name")
|
||||
@Expose
|
||||
private String name;
|
||||
@@ -128,6 +131,14 @@ public class DeviceDescriptor{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUniqueid() {
|
||||
return uniqueid;
|
||||
}
|
||||
|
||||
public void setUniqueid(String uniqueid) {
|
||||
this.uniqueid = uniqueid;
|
||||
}
|
||||
|
||||
public String getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.bwssystems.HABridge.dao;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -9,8 +10,11 @@ import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -29,7 +33,7 @@ public class DeviceRepository extends BackupHandler {
|
||||
private Map<String, DeviceDescriptor> devices;
|
||||
private Path repositoryPath;
|
||||
private Gson gson;
|
||||
final private Random random = new Random();
|
||||
private Integer maxId;
|
||||
private Logger log = LoggerFactory.getLogger(DeviceRepository.class);
|
||||
|
||||
public DeviceRepository(String deviceDb) {
|
||||
@@ -41,6 +45,7 @@ public class DeviceRepository extends BackupHandler {
|
||||
repositoryPath = null;
|
||||
repositoryPath = Paths.get(deviceDb);
|
||||
setupParams(repositoryPath, ".bk", "device.db-");
|
||||
maxId = 1;
|
||||
_loadRepository(repositoryPath);
|
||||
}
|
||||
|
||||
@@ -57,6 +62,9 @@ public class DeviceRepository extends BackupHandler {
|
||||
DeviceDescriptor list[] = gson.fromJson(jsonContent, DeviceDescriptor[].class);
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
put(list[i].getId(), list[i]);
|
||||
if(Integer.decode(list[i].getId()) > maxId) {
|
||||
maxId = Integer.decode(list[i].getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,8 +92,17 @@ public class DeviceRepository extends BackupHandler {
|
||||
for(int i = 0; i < descriptors.length; i++) {
|
||||
if(descriptors[i].getId() != null && descriptors[i].getId().length() > 0)
|
||||
devices.remove(descriptors[i].getId());
|
||||
else
|
||||
descriptors[i].setId(String.valueOf(random.nextInt(Integer.MAX_VALUE)));
|
||||
else {
|
||||
descriptors[i].setId(String.valueOf(maxId));
|
||||
maxId++;
|
||||
}
|
||||
if(descriptors[i].getUniqueid() == null || descriptors[i].getUniqueid().length() == 0) {
|
||||
BigInteger bigInt = BigInteger.valueOf(Integer.decode(descriptors[i].getId()));
|
||||
byte[] theBytes = bigInt.toByteArray();
|
||||
String hexValue = DatatypeConverter.printHexBinary(theBytes);
|
||||
|
||||
descriptors[i].setUniqueid("00:17:88:5E:D3:" + hexValue + "-" + hexValue);
|
||||
}
|
||||
put(descriptors[i].getId(), descriptors[i]);
|
||||
theNames = theNames + " " + descriptors[i].getName() + ", ";
|
||||
}
|
||||
@@ -94,6 +111,28 @@ public class DeviceRepository extends BackupHandler {
|
||||
log.debug("Save device(s): " + theNames);
|
||||
}
|
||||
|
||||
public void renumber() {
|
||||
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
|
||||
Iterator<DeviceDescriptor> deviceIterator = list.iterator();
|
||||
Map<String, DeviceDescriptor> newdevices = new HashMap<String, DeviceDescriptor>();;
|
||||
maxId = 1;
|
||||
log.debug("Renumber devices.");
|
||||
while(deviceIterator.hasNext()) {
|
||||
DeviceDescriptor theDevice = deviceIterator.next();
|
||||
theDevice.setId(String.valueOf(maxId));
|
||||
BigInteger bigInt = BigInteger.valueOf(maxId);
|
||||
byte[] theBytes = bigInt.toByteArray();
|
||||
String hexValue = DatatypeConverter.printHexBinary(theBytes);
|
||||
|
||||
theDevice.setUniqueid("00:17:88:5E:D3:" + hexValue + "-" + hexValue);
|
||||
newdevices.put(theDevice.getId(), theDevice);
|
||||
maxId++;
|
||||
}
|
||||
devices = newdevices;
|
||||
String jsonValue = gson.toJson(findAll());
|
||||
repositoryWriter(jsonValue, repositoryPath);
|
||||
}
|
||||
|
||||
public String delete(DeviceDescriptor aDescriptor) {
|
||||
if (aDescriptor != null) {
|
||||
devices.remove(aDescriptor.getId());
|
||||
|
||||
@@ -8,6 +8,7 @@ import static spark.Spark.delete;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -280,6 +281,21 @@ public class DeviceResource {
|
||||
return halHome.getDevices();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/api/devices/exec/renumber CORS request
|
||||
options(API_CONTEXT + "/exec/renumber", "application/json", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "POST");
|
||||
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||
response.header("Content-Type", "text/html; charset=utf-8");
|
||||
return "";
|
||||
});
|
||||
post (API_CONTEXT + "/exec/renumber", "application/json", (request, response) -> {
|
||||
log.debug("Renumber devices.");
|
||||
deviceRepository.renumber();
|
||||
return null;
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/backup/available", "application/json", (request, response) -> {
|
||||
log.debug("Get backup filenames");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.slf4j.LoggerFactory;
|
||||
import com.bwssystems.HABridge.BridgeControlDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.Configuration;
|
||||
import com.bwssystems.HABridge.api.hue.HuePublicConfig;
|
||||
// import com.bwssystems.HABridge.api.hue.HuePublicConfig;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
@@ -24,6 +24,14 @@ public class UpnpListener {
|
||||
private boolean traceupnp;
|
||||
private BridgeControlDescriptor bridgeControl;
|
||||
private boolean discoveryTemplateLatest;
|
||||
private String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
|
||||
"CACHE-CONTROL: max-age=86400\r\n" +
|
||||
"EXT:\r\n" +
|
||||
"LOCATION: http://%s:%s/description.xml\r\n" +
|
||||
"SERVER: FreeRTOS/7.4.2 UPnP/1.0 IpBridge/1.10.0\r\n" +
|
||||
"ST: upnp:rootdevice\r\n" +
|
||||
"USN: uuid:2f402f80-da50-11e1-9b23-001788102201\r\n\r\n";
|
||||
/*
|
||||
private String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
|
||||
"HOST: %s:%s\r\n" +
|
||||
"CACHE-CONTROL: max-age=86400\r\n" +
|
||||
@@ -33,6 +41,9 @@ public class UpnpListener {
|
||||
"hue-bridgeid: %s\r\n" +
|
||||
"ST: upnp:rootdevice\r\n" +
|
||||
"USN: uuid:2f402f80-da50-11e1-9b23-001788102201\r\n\r\n";
|
||||
|
||||
discoveryResponse = String.format(discoveryTemplate, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, HuePublicConfig.createConfig("temp", responseAddress).getBridgeid());
|
||||
*/
|
||||
private String discoveryTemplate091516 = "HTTP/1.1 200 OK\r\n" +
|
||||
"CACHE-CONTROL: max-age=86400\r\n" +
|
||||
"EXT:\r\n" +
|
||||
@@ -40,6 +51,7 @@ public class UpnpListener {
|
||||
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.10.0\r\n" +
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
|
||||
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
|
||||
/*
|
||||
private String discoveryTemplateOld = "HTTP/1.1 200 OK\r\n" +
|
||||
"CACHE-CONTROL: max-age=86400\r\n" +
|
||||
"EXT:\r\n" +
|
||||
@@ -48,7 +60,7 @@ public class UpnpListener {
|
||||
"01-NLS: %s\r\n" +
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
|
||||
"USN: uuid:Socket-1_0-221438K0100073::urn:Belkin:device:**\r\n\r\n";
|
||||
|
||||
*/
|
||||
public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl) {
|
||||
super();
|
||||
upnpResponsePort = theSettings.getUpnpResponsePort();
|
||||
@@ -225,7 +237,7 @@ public class UpnpListener {
|
||||
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
|
||||
String discoveryResponse = null;
|
||||
if(discoveryTemplateLatest)
|
||||
discoveryResponse = String.format(discoveryTemplate, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, HuePublicConfig.createConfig("temp", responseAddress).getBridgeid());
|
||||
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort);
|
||||
else
|
||||
discoveryResponse = String.format(discoveryTemplate091516, responseAddress, httpServerPort);
|
||||
if(traceupnp) {
|
||||
|
||||
@@ -115,12 +115,24 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
);
|
||||
};
|
||||
|
||||
this.renumberDevices = function () {
|
||||
return $http.post(this.state.base + "/exec/renumber").then(
|
||||
function (response) {
|
||||
self.viewDevices();
|
||||
},
|
||||
function (error) {
|
||||
self.displayError("Cannot renumber devices from habridge: ", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.clearDevice = function () {
|
||||
if(self.state.device == null)
|
||||
self.state.device = [];
|
||||
self.state.device.id = "";
|
||||
self.state.device.mapType = null;
|
||||
self.state.device.mapId = null;
|
||||
self.state.device.uniqueid = null;
|
||||
self.state.device.name = "";
|
||||
self.state.device.onUrl = "";
|
||||
self.state.device.dimUrl = "";
|
||||
@@ -785,6 +797,9 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
|
||||
bridgeService.editDevice(device);
|
||||
$location.path('/editdevice');
|
||||
};
|
||||
$scope.renumberDevices = function() {
|
||||
bridgeService.renumberDevices();
|
||||
};
|
||||
$scope.backupDeviceDb = function (optionalbackupname) {
|
||||
bridgeService.backupDeviceDb(optionalbackupname);
|
||||
};
|
||||
|
||||
@@ -25,6 +25,11 @@
|
||||
<h2 class="panel-title">Current devices
|
||||
({{bridge.devices.length}})</h2>
|
||||
</div>
|
||||
<form name="form">
|
||||
<p>
|
||||
<button class="btn btn-primary" type="submit" ng-click="renumberDevices()">Renumber Devices</button>
|
||||
</p>
|
||||
</form>
|
||||
<scrollable-table watch="bridge.devices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
|
||||
@@ -107,6 +107,14 @@
|
||||
Clear Device</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-unique-id">Unique Id (used for Hue responses) </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<input type="text" class="form-control" id="device-unique-id"
|
||||
ng-model="device.uniqueid" placeholder="AA:BB:CC:DD:EE:FF-XX" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="device.mapType" class="form-group">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-map-id">Map
|
||||
ID </label>
|
||||
|
||||
Reference in New Issue
Block a user