package com.kuxhausen.huemore.net.hue; import android.support.annotation.Nullable; import com.kuxhausen.huemore.persistence.Utils; import com.kuxhausen.huemore.state.BulbState; public class HueUtils { enum Gamut { /** * Color light. Supports: on, transitiontime, alert, bri, effect, xy */ COLOR_A, /** * Extended color light. Supports: on, transitiontime, alert, bri, ct, effect, xy */ COLOR_B, /** * Extended color light. Supports: on, transitiontime, alert, bri, ct, effect, xy */ COLOR_C, /** * Color temperature light. Supports: on, transitiontime, alert, bri, ct */ COLOR_TEMP, /** * Dimmable light. Supports: on, transitiontime, alert, bri */ DIMMABLE, UNKNOWN } private static Gamut getGamut(@Nullable String modelid) { if (modelid == null) { return Gamut.UNKNOWN; } switch (modelid) { case "LCT001": case "LCT007": case "LCT002": case "LCT003": case "LLM001": case "HBL001": case "HBL002": case "HBL003": case "HEL001": case "HEL002": case "HIL001": case "HIL002": return Gamut.COLOR_B; case "LST001": case "LLC010": case "LLC011": case "LLC012": case "LLC006": case "LLC007": case "LLC013": return Gamut.COLOR_A; case "LLC020": case "LST002": return Gamut.COLOR_C; case "LLM010": case "LLM011": case "LLM012": case "HML001": case "HML002": case "HML003": case "HML007": return Gamut.COLOR_TEMP; case "LWB004": case "LWB006": case "LWB007": return Gamut.DIMMABLE; default: return Gamut.UNKNOWN; } } /** * @return cie xy bounds for the gammut. Ordered: [xRed, yRed, xGreen, yGreen, xBlue, yBlue]. */ private static float[] getBounds(Gamut gammut) { switch (gammut) { case COLOR_A: return new float[]{0.704f, 0.296f, 0.2151f, 0.7106f, 0.138f, 0.08f}; case COLOR_B: return new float[]{0.675f, 0.322f, 0.409f, 0.518f, 0.167f, 0.04f}; case COLOR_C: return new float[]{0.692f, 0.308f, 0.17f, 0.7f, 0.153f, 0.048f}; default: return new float[]{1f, 0f, 0f, 1f, 0f, 0f}; } } public static BulbState toReachableState(HueBulbData bulbData, BulbState target) { BulbState adjusted = target.clone(); Gamut gamut = getGamut(bulbData.modelid); switch (gamut) { case COLOR_A: if (target.hasXY()) { adjusted.setXY(Utils.toReachableXY(getBounds(gamut), target.getXY())); } else if (target.hasCT()) { adjusted.setXY(Utils.ctTOxy(target.getMiredCT())); adjusted.setMiredCT(null); } adjusted.setEffect(null); case COLOR_B: if (target.hasXY()) { adjusted.setXY(Utils.toReachableXY(getBounds(gamut), target.getXY())); } case COLOR_C: if (target.hasXY()) { adjusted.setXY(Utils.toReachableXY(getBounds(gamut), target.getXY())); } break; case COLOR_TEMP: adjusted.setXY(null); // TODO opportunistically convert from XY to CT when no CT specified adjusted.setEffect(null); break; case DIMMABLE: adjusted.setXY(null); adjusted.setEffect(null); adjusted.setMiredCT(null); adjusted.setAlert(null); break; } return adjusted; } /** * @return The number of ZigBee commands that will be required to send all of the state parameters * to a single bulb in the hue network. Note: ZigBee can do at most 1 command per 40ms. */ public static int countZibBeeCommandsRequired(BulbState state) { int result = 0; if (state.hasOn()) { result += 1; } if (state.hasBri()) { result += 1; } if (state.hasXY()) { result += 1; } if (state.hasCT()) { result += 1; } if (state.hasAlert()) { result += 2; // Hue docs don't cover this, so play conservative here } if (state.hasEffect()) { result += 2; // Hue docs don't cover this, so play conservative here } if (state.hasTransitionTime()) { result += 0; // Hue docs have a missing footnote about this, so probably need further testing } return result; } }