Huemulator state fixes

draft active logger control
This commit is contained in:
bsamuels
2018-01-16 13:20:49 -06:00
parent 37b381085c
commit 27dd8475e9
4 changed files with 115 additions and 38 deletions

View File

@@ -4,7 +4,7 @@ import java.util.List;
import java.util.Map;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.bwssystems.HABridge.api.NameValue;
import com.bwssystems.HABridge.api.hue.HueConstants;
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
@@ -108,6 +108,9 @@ public class BridgeSettingsDescriptor {
@SerializedName("fhemaddress")
@Expose
private IpList fhemaddress;
@SerializedName("activeloggers")
@Expose
private List<NameValue> activeloggers;
private boolean settingsChanged;
private boolean veraconfigured;
@@ -155,6 +158,7 @@ public class BridgeSettingsDescriptor {
this.webaddress = "0.0.0.0";
this.hubversion = HueConstants.HUB_VERSION;
this.hubmac = null;
this.activeloggers = null;
this.upnpsenddelay = 1500;
}
public String getUpnpConfigAddress() {
@@ -463,6 +467,12 @@ public class BridgeSettingsDescriptor {
public void setFhemconfigured(boolean fhemconfigured) {
this.fhemconfigured = fhemconfigured;
}
public List<NameValue> getActiveloggers() {
return activeloggers;
}
public void setActiveloggers(List<NameValue> activeloggers) {
this.activeloggers = activeloggers;
}
public Boolean isValidVera() {
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
return false;

View File

@@ -14,15 +14,19 @@ import java.net.InetAddress;
import java.net.MulticastSocket;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Timer;
import java.util.Base64;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.api.NameValue;
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
import com.bwssystems.HABridge.dao.BackupFilename;
import com.bwssystems.HABridge.util.JsonTransformer;
@@ -36,6 +40,7 @@ import com.google.gson.reflect.TypeToken;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.read.CyclicBufferAppender;
public class SystemControl {
@@ -55,7 +60,7 @@ public class SystemControl {
this.version = theVersion;
this.lc = (LoggerContext) LoggerFactory.getILoggerFactory();
this.dateFormat = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss.SSS");
reacquireCBA();
setupLoggerSettings();
theLogServiceMgr = new LoggingManager();
theLogServiceMgr.init();
}
@@ -88,7 +93,7 @@ public class SystemControl {
String logMsgs;
int count = -1;
if(cyclicBufferAppender == null)
reacquireCBA();
setupLoggerSettings();
if (cyclicBufferAppender != null) {
count = cyclicBufferAppender.getLength();
}
@@ -356,6 +361,8 @@ public class SystemControl {
log.debug("bridge settings requested from " + request.ip());
response.status(HttpStatus.SC_OK);
response.type("application/json");
if(bridgeSettings.getBridgeSettingsDescriptor().getActiveloggers() == null)
bridgeSettings.getBridgeSettingsDescriptor().setActiveloggers(getLogAppenders());
return bridgeSettings.getBridgeSettingsDescriptor();
}, new JsonTransformer());
@@ -484,11 +491,42 @@ public class SystemControl {
}, new JsonTransformer());
}
void reacquireCBA() {
cyclicBufferAppender = (CyclicBufferAppender<ILoggingEvent>) lc.getLogger(
private void setupLoggerSettings() {
final ch.qos.logback.classic.Logger logger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
cyclicBufferAppender = (CyclicBufferAppender<ILoggingEvent>) lc.getLogger(
Logger.ROOT_LOGGER_NAME).getAppender(CYCLIC_BUFFER_APPENDER_NAME);
cyclicBufferAppender.setMaxSize(bridgeSettings.getBridgeSettingsDescriptor().getNumberoflogmessages());
}
if(bridgeSettings.getBridgeSettingsDescriptor().getActiveloggers() != null) {
for (NameValue temp : bridgeSettings.getBridgeSettingsDescriptor().getActiveloggers()) {
if(temp.getValue().equals("false"))
logger.detachAppender(temp.getName());
}
}
}
private List<NameValue> getLogAppenders() {
final ch.qos.logback.classic.Logger logger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
final Iterator<Appender<ILoggingEvent>> it = logger.iteratorForAppenders();
List<NameValue> theLoggers = new ArrayList<NameValue>();
while (it.hasNext()) {
final Appender<ILoggingEvent> appender = it.next();
if (!(appender instanceof CyclicBufferAppender)) {
NameValue theLogger = new NameValue();
theLogger.setName(appender.getName());
theLogger.setValue("true");
theLoggers.add(theLogger);
}
}
return theLoggers;
}
protected void pingListener() {
try {

View File

@@ -445,8 +445,9 @@ public class HueMulator {
});
}
@SuppressWarnings("unchecked")
private String formatSuccessHueResponse(StateChangeBody stateChanges, String body, String lightId,
DeviceState deviceState, Integer targetBri, Integer targetBriInc, boolean offState) {
DeviceState deviceState, Integer targetBri, Integer targetBriInc, ColorData colorData, boolean offState) {
String responseString = "[";
boolean notFirstChange = false;
@@ -534,7 +535,7 @@ public class HueMulator {
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/xy_inc\":"
+ stateChanges.getXy_inc() + "}}";
if (deviceState != null)
deviceState.setXy(stateChanges.getXy());
deviceState.setXy((List<Double>) colorData.getData());
notFirstChange = true;
} else if (body.contains("\"ct_inc\"")) {
if (notFirstChange)
@@ -1047,16 +1048,17 @@ public class HueMulator {
DeviceState state = null;
Integer targetBri = null;
Integer targetBriInc = null;
ColorData colorData = null;
log.debug("Update state requested: " + userId + " from " + ipAddress + " body: " + body);
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
if (theErrors != null)
return aGsonHandler.toJson(theErrors);
try {
theStateChanges = aGsonHandler.fromJson(body, StateChangeBody.class);
} catch (Exception e) {
theStateChanges = null;
}
if (theStateChanges == null) {
log.warn("Could not parse state change body. Light state not changed.");
return aGsonHandler.toJson(HueErrorResponse.createResponse("2", "/lights/" + lightId,
"Could not parse state change body.", null, null, null).getTheErrors(), HueError[].class);
@@ -1080,7 +1082,26 @@ public class HueMulator {
if (state == null)
state = DeviceState.createDeviceState(device.isColorDevice());
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc, device.isOffState());
if (body.contains("\"xy\"") || body.contains("\"ct\"") || body.contains("\"hue\"") || body.contains("\"xy_inc\"") || body.contains("\"ct_inc\"") || body.contains("\"hue_inc\"")) {
List<Double> xy = theStateChanges.getXy();
List<Double> xyInc = theStateChanges.getXy_inc();
Integer ct = theStateChanges.getCt();
Integer ctInc = theStateChanges.getCt_inc();
if (xy != null && xy.size() == 2) {
colorData = new ColorData(ColorData.ColorMode.XY, xy);
} else if (xyInc != null && xyInc.size() == 2) {
List<Double> current = state.getXy();
current.set(0, current.get(0) + xyInc.get(0));
current.set(1, current.get(1) + xyInc.get(1));
colorData = new ColorData(ColorData.ColorMode.XY, current);
} else if (ct != null && ct != 0) {
colorData = new ColorData(ColorData.ColorMode.CT, ct);
} else if (ctInc != null && ctInc != 0) {
colorData = new ColorData(ColorData.ColorMode.CT, state.getCt() + ctInc);
}
}
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc, colorData, device.isOffState());
device.setDeviceState(state);
return responseString;
@@ -1099,7 +1120,6 @@ public class HueMulator {
boolean isColorRequest = false;
boolean isDimRequest = false;
boolean isOnRequest = false;
boolean previousError = false;
ColorData colorData = null;
log.debug("hue state change requested: " + userId + " from " + ipAddress + " body: " + body);
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
@@ -1199,21 +1219,14 @@ public class HueMulator {
if (url != null && !url.equals("")) {
responseString = callUrl(url, device, userId, lightId, body, ipAddress, ignoreRequester, targetBri, targetBriInc, colorData);
} else {
log.warn("Could not find on/off url: " + lightId + " for hue state change request: " + userId + " from "
+ ipAddress + " body: " + body);
responseString = aGsonHandler.toJson(HueErrorResponse.createResponse("3", "/lights/" + lightId,
"Could not find on/off url.", "/lights/" + lightId, null, null).getTheErrors(), HueError[].class);
previousError = true;
log.info("On/off url not available for state change, lightId: " + lightId + ", userId: " + userId + ", from IP: "
+ ipAddress + ", body: " + body);
}
}
if (isDimRequest && !previousError) {
if (isDimRequest) {
log.debug("Calling dim as requested.");
if(!device.isOnFirstDim() )
url = device.getDimUrl();
if (url == null || url.length() == 0)
url = device.getOnUrl();
url = device.getDimUrl();
// code for backwards compatibility
if(device.getMapType() != null && device.getMapType().equalsIgnoreCase(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
@@ -1231,15 +1244,12 @@ public class HueMulator {
}
responseString = callUrl(url, device, userId, lightId, body, ipAddress, ignoreRequester, targetBri, targetBriInc, colorData);
} else {
log.warn("Could not find dim url: " + lightId + " for hue state change request: " + userId + " from "
+ ipAddress + " body: " + body);
responseString = aGsonHandler.toJson(HueErrorResponse.createResponse("3", "/lights/" + lightId,
"Could not find dim url.", "/lights/" + lightId, null, null).getTheErrors(), HueError[].class);
previousError = true;
log.info("Dim url not available for state change, lightId: " + lightId + ", userId: " + userId + ", from IP: "
+ ipAddress + ", body: " + body);
}
}
if (isColorRequest && !previousError) {
if (isColorRequest) {
log.debug("Calling color as requested.");
url = device.getColorUrl();
// code for backwards compatibility
@@ -1258,21 +1268,18 @@ public class HueMulator {
}
responseString = callUrl(url, device, userId, lightId, body, ipAddress, ignoreRequester, targetBri, targetBriInc, colorData);
} else {
log.warn("Could not find color url: " + lightId + " for hue state change request: " + userId + " from "
+ ipAddress + " body: " + body);
responseString = aGsonHandler.toJson(HueErrorResponse.createResponse("3", "/lights/" + lightId,
"Could not find color url.", "/lights/" + lightId, null, null).getTheErrors(), HueError[].class);
previousError = true;
log.info("Color url not available for state change, lightId: " + lightId + ", userId: " + userId + ", from IP: "
+ ipAddress + ", body: " + body);
}
}
if (responseString == null || !responseString.contains("[{\"error\":")) {
if(!device.isNoState()) {
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc, device.isOffState());
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc, colorData, device.isOffState());
device.setDeviceState(state);
} else {
DeviceState dummyState = DeviceState.createDeviceState(device.isColorDevice());
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, dummyState, targetBri, targetBriInc, device.isOffState());
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, dummyState, targetBri, targetBriInc, colorData, device.isOffState());
}
}
@@ -1283,6 +1290,7 @@ public class HueMulator {
@SuppressWarnings("unchecked")
private String changeGroupState(String userId, String groupId, String body, String ipAddress, boolean fakeLightResponse) {
ColorData colorData = null;
log.debug("PUT action to group " + groupId + " from " + ipAddress + " user " + userId + " with body " + body);
HueError[] theErrors = null;
theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
@@ -1363,7 +1371,7 @@ public class HueMulator {
// construct success response: one success message per changed property, but not per light
if (group != null) { // if not group 0
String response = formatSuccessHueResponse(theStateChanges, body, String.valueOf(Integer.parseInt(groupId) + 10000),
state, targetBri, targetBriInc, true);
state, targetBri, targetBriInc, colorData, true);
group.setAction(state);
if (fakeLightResponse) {
return response;

View File

@@ -742,6 +742,27 @@
ng-model="bridge.settings.numberoflogmessages" min="100"
max="65535"></td>
</tr>
<tr>
<td>Log Output Control</td>
<td><table
class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Name</th>
<th>Active</th>
</tr>
</thead>
<tr ng-repeat="thePair in bridge.settings.activeloggers">
<td><input id="bridge-settings-next-logger-name"
class="form-control" type="text" ng-model="thePair.name"
disabled></td>
<td><input type="checkbox"
ng-model="thePair.value" ng-true-value="'true'"
ng-false-value="'false'"></td>
</tr>
</table>
</td>
</tr>
<tr>
<td>Trace UPNP Calls</td>
<td><input type="checkbox"