Skip to content

Commit

Permalink
Checks for accepted command typs for HSB and Decimal types as well a…
Browse files Browse the repository at this point in the history
…s reports on HSB types, also adds support for returning the main system group ("0"). fixes openhab#1261, fixes openhab#1266

Signed-off-by: Dan Cunningham <dan@digitaldan.com>
  • Loading branch information
digitaldan committed Sep 29, 2016
1 parent 79e9245 commit 88040e6
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
Expand All @@ -41,14 +39,17 @@
import org.eclipse.smarthome.core.items.ItemRegistry;
import org.eclipse.smarthome.core.items.events.ItemEventFactory;
import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.library.types.HSBType;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.library.types.PercentType;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.State;
import org.eclipse.smarthome.core.types.TypeParser;
import org.openhab.io.hueemulation.internal.api.HueCreateUser;
import org.openhab.io.hueemulation.internal.api.HueDataStore;
import org.openhab.io.hueemulation.internal.api.HueDevice;
import org.openhab.io.hueemulation.internal.api.HueErrorResponse;
import org.openhab.io.hueemulation.internal.api.HueGroup;
import org.openhab.io.hueemulation.internal.api.HueState;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.http.HttpService;
Expand Down Expand Up @@ -82,12 +83,6 @@ public class HueEmulationServlet extends HttpServlet {

private static final String[] SUPPORTED_TAGS = new String[] { "Switchable", "Lighting", "TargetTemperature" };

/**
* This parses "/api/{username}/{lights}/{id}/{state}"
*/
private static final Pattern PATH_PATTERN = Pattern
.compile(PATH + "/([^/]+)(?:(?:/(lights)/?([^/]+)?/?(state)?)?)?");

private Gson gson = new Gson();
private HttpService httpService;
private ItemRegistry itemRegistry;
Expand Down Expand Up @@ -196,12 +191,10 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) throws
}

// All other API requests
Matcher m = PATH_PATTERN.matcher(path);
if (m.matches()) {
String userName = m.group(1);
boolean lightsReq = m.group(2) != null;
String id = m.group(3);
boolean stateReq = m.group(4) != null;
String[] pathParts = path.replace("/api/", "").split("/");

if (pathParts.length > 0) {
String userName = pathParts[0];

/**
* Some devices (Amazon Echo) seem to rely on the bridge to add an unknown user if pairing is on
Expand All @@ -214,31 +207,60 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) throws
return;
}

if (stateReq) {
/**
* /api/{username}/{lights}/{id}/{state}
*/
apiState(id, req, resp);
} else if (id != null) {
/**
* /api/{username}/{lights}/{id}
*/
apiLight(id, req, resp);
} else if (lightsReq) {
/**
* /api/{username}/{lights}
*/
apiLights(req, resp);
} else if (userName != null) {
if (pathParts.length == 1) {
/**
* /api/{username}
*/
apiDataStore(req, resp);
} else {
apiServerError(req, resp, HueErrorResponse.NOT_AVAILABLE, "Hue resource not available");
String function = pathParts[1];
if ("lights".equals(function)) {
switch (pathParts.length) {
case 2:
/**
* /api/{username}/lights
*/
apiLights(req, resp);
break;
case 3:
/**
* /api/{username}/lights/{id}
*/
apiLight(pathParts[2], req, resp);
break;
case 4:
/**
* /api/{username}/lights/{id}/state
*/
apiState(pathParts[2], req, resp);
break;
default:
break;
}
} else if ("groups".equals(function)) {
switch (pathParts.length) {
case 2:
/**
* /api/{username}/group
*/
emptyResponse(req, resp);
break;
case 3:
/**
* /api/{username}/group/{id}
*/
if ("0".equals(pathParts[2])) {
apiGroupZero(req, resp);
}
break;
default:
break;
}
} else {
apiServerError(req, resp, HueErrorResponse.NOT_AVAILABLE, "Hue resource not available");
}
}
}

}

/**
Expand All @@ -258,15 +280,22 @@ private void apiState(String id, HttpServletRequest req, HttpServletResponse res
// will throw exception if not found
Item item = itemRegistry.getItem(id);
HueState state = gson.fromJson(req.getReader(), HueState.class);

logger.debug("State " + state);

String value;
if (state.bri > -1) {
if (item.getAcceptedCommandTypes().contains(HSBType.class)) {
value = String.format("%d,%d,%d", state.hue, state.sat, state.bri);
} else if (state.bri > -1 && (item.getAcceptedCommandTypes().contains(DecimalType.class)
|| item.getAcceptedCommandTypes().contains(PercentType.class))) {
value = String.valueOf(Math.round(state.bri / 255.0 * 100));
} else {
value = state.on ? "ON" : "OFF";
}

Command command = TypeParser.parseCommand(item.getAcceptedCommandTypes(), value);
eventPublisher.post(ItemEventFactory.createCommandEvent(id, command));

PrintWriter out = resp.getWriter();
out.write(String.format(STATE_RESP, id, String.valueOf(state.on)));
out.close();
Expand Down Expand Up @@ -309,6 +338,21 @@ public void apiLights(HttpServletRequest req, HttpServletResponse resp) throws I
out.close();
}

/**
* Hue API call to get a listing of Group 0
*
* @param req
* @param resp
* @throws IOException
*/
public void apiGroupZero(HttpServletRequest req, HttpServletResponse resp) throws IOException {
PrintWriter out = resp.getWriter();
String[] lights = getHueDeviceNames().keySet().toArray(new String[0]);
HueState action = new HueState();
out.write(gson.toJson(new HueGroup("0", lights, action)));
out.close();
}

/**
* HUE API call to get the Data Store of the bridge (only lights supported for now)
*
Expand Down Expand Up @@ -365,6 +409,19 @@ public void apiServerError(HttpServletRequest req, HttpServletResponse resp, int
out.write(gson.toJson(e));
}

/**
* Returns a empty ("{}") JSON response
*
* @param req
* @param resp
* @throws IOException
*/
public void emptyResponse(HttpServletRequest req, HttpServletResponse resp) throws IOException {
PrintWriter out = resp.getWriter();
out.write("{}");
out.close();
}

/**
* Generates the XML Discovery document
*
Expand Down Expand Up @@ -434,13 +491,21 @@ public Map<String, String> getHueDeviceNames() {
*/
private HueDevice itemToDevice(Item item) {
State itemState = item.getState();
short bri = 0;
if (itemState instanceof DecimalType) {
bri = (short) ((((DecimalType) itemState).intValue() * 255) / 100);
HueState hueState;
if (itemState instanceof HSBType) {
HSBType color = (HSBType) itemState;
hueState = new HueState(color.getHue().intValue(), color.getSaturation().shortValue(),
color.getBrightness().shortValue());
} else if (itemState instanceof DecimalType) {
short bri = (short) ((((DecimalType) itemState).intValue() * 255) / 100);
hueState = new HueState(bri > 0, bri);
} else if (itemState instanceof OnOffType) {
bri = (short) (((OnOffType) itemState) == OnOffType.ON ? 255 : 0);
short bri = (short) (((OnOffType) itemState) == OnOffType.ON ? 255 : 0);
hueState = new HueState(bri > 0, bri);
} else {
hueState = new HueState(false, (short) 0);
}
HueState hueState = new HueState(bri > 0, bri);

HueDevice d = new HueDevice(hueState, item.getLabel(), item.getName());
return d;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.openhab.io.hueemulation.internal.api;

/**
* Hue API group object
*
* @author Dan Cunningham
*
*/
public class HueGroup {
public HueState state;
public String type = "LightGroup";
public String name;
public String[] lights;
public HueState action;

public HueGroup(String name, String[] lights, HueState action) {
this.name = name;
this.lights = lights;
this.action = action;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ public HueState(boolean on, short bri) {
this.bri = bri;
}

public HueState(int h, short s, short b) {
super();
this.on = b > 0;
this.hue = h;
this.sat = s;
this.bri = b;
}

@Override
public String toString() {
String xyString = "{";
Expand Down

0 comments on commit 88040e6

Please sign in to comment.