/**
* Copyright (c) 2010-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.binding.hue.internal.data;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.openhab.binding.hue.internal.hardware.HueBulb;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Contains all information that is provided by the Hue bridge. There are
* different information that can be requested about the connected bulbs.
* <ul>
* <li>Is a bulb switched on?</li>
* <li>How is a bulb's color temperature?</li>
* <li>How is the current brightness of a blub?</li>
* <li>How is the hue of a given bulb?</li>
* <li>How is the saturation of a given bulb?</li>
* </ul>
*
* @author Roman Hartmann
* @author Jos Schering
* @author Markus Mazurczak - Added function to retrieve the model ID of a bulb
* @since 1.2.0
*/
public class HueSettings {
static final Logger logger = LoggerFactory.getLogger(HueSettings.class);
private SettingsTree settingsData = null;
private static final int ERROR_TYPE_UNAUTHORIZED_USER = 1;
private boolean isAuthorized = false;
/**
* Constructor of HueSettings. It takes the settings of the Hue bridge to enable the HueSettings to determine the
* needed information about the bulbs.
*
* @param settings
* This is the settings string in Json format returned by the Hue bridge.
*/
@SuppressWarnings("unchecked")
public HueSettings(String settings) {
ObjectMapper mapper = new ObjectMapper();
try {
JsonNode rootNode = mapper.readTree(settings);
if (!isAuthorizationError(rootNode)) {
settingsData = new SettingsTree(mapper.readValue(rootNode, Map.class));
isAuthorized = true;
}
} catch (IOException e) {
logger.error("Could not read Settings-Json from Hue Bridge.", e);
}
}
/**
* Determines if the Hue Bridge reported an authorization error.
*
* @return true if an authorization error occurred, else false
*/
private boolean isAuthorizationError(JsonNode rootNode) {
boolean isAuthorizationError = false;
// While normal answers from the bridge are of type object, the error message is of type array
if (rootNode.isArray()) {
JsonNode node = rootNode.get(0);
if (node.has("error")) {
if (node.get("error").get("type").getIntValue() == ERROR_TYPE_UNAUTHORIZED_USER) {
isAuthorizationError = true;
}
}
}
return isAuthorizationError;
}
/**
* Returns the model-ID of the bulb
*
* @param deviceId The bulb id the bridge has filed the bulb under.
* @return The model-ID. Null if Hue bridge is not initialized correctly or if the ID was not parsed correctly
*/
public String getModelId(String deviceId) {
if (settingsData == null) {
logger.error("Hue bridge settings not initialized correctly.");
return null;
}
Object modelId = settingsData.node("lights").node(deviceId).value("modelid");
return modelId != null ? modelId.toString() : null;
}
/**
* @return True if openHAB is authorized on the Hue bridge, else false
*/
public boolean isAuthorized() {
return isAuthorized;
}
/**
* Return the keys of lights connected to Hue hub
*
* @return the keys of lights connected to Hue hub
*/
public Set<String> getKeys() {
if (settingsData == null) {
logger.error("Hue bridge settings not initialized correctly.");
return null;
}
return settingsData.node("lights").getKeys();
}
/**
* Determines whether the given bulb is valid in the settings of the bridge.
*
* @param deviceId
* The bulb id the bridge has filed the bulb under.
* @return true if the bulb is turned on, false otherwise.
*/
public boolean isValidId(String deviceId) {
if (settingsData == null) {
logger.error("Hue bridge settings not initialized correctly.");
return false;
}
return settingsData.node("lights").node(deviceId) != null;
}
/**
* Determines whether the given bulb is turned on.
*
* @param deviceId
* The bulb id the bridge has filed the bulb under.
* @return true if the bulb is turned on, false otherwise.
*/
public boolean isBulbOn(String deviceId) {
if (settingsData == null) {
logger.error("Hue bridge settings not initialized correctly.");
return false;
}
return (Boolean) settingsData.node("lights").node(deviceId).node("state").value("on");
}
/**
* Determines whether the given bulb is reachable.
* Once a bulb is physical disconnected it becomes unreachable after around 10 seconds.
* The hearbeat service of the Hue hub device is responsible for this behavior.
*
* @param deviceId
* The bulb id the bridge has filed the bulb under.
* @return true if the bulb is reachable, false otherwise.
*/
public boolean isReachable(String deviceId) {
if (settingsData == null) {
logger.error("Hue bridge settings not initialized correctly.");
return false;
}
return (Boolean) settingsData.node("lights").node(deviceId).node("state").value("reachable");
}
/**
* Determines the color temperature of the given bulb.
*
* @param deviceId
* The bulb id the bridge has filed the bulb under.
* @return The color temperature as a value from 154 - 500
*/
public int getColorTemperature(String deviceId) {
if (settingsData == null) {
logger.error("Hue bridge settings not initialized correctly.");
return 154;
}
Object ct = settingsData.node("lights").node(deviceId).node("state").value("ct");
if (ct instanceof Integer) {
return (Integer) ct;
} else {
return 154;
}
}
/**
* Determines the brightness of the given bulb.
*
* @param deviceId
* The bulb id the bridge has filed the bulb under.
* @return The brightness as a value from 0 - {@link HueBulb#MAX_BRIGHTNESS}
*/
public int getBrightness(String deviceId) {
if (settingsData == null) {
logger.error("Hue bridge settings not initialized correctly.");
return 0;
}
Object bri = settingsData.node("lights").node(deviceId).node("state").value("bri");
if (bri instanceof Integer) {
return (Integer) bri;
} else {
// probably not dimmable, return on state
return isBulbOn(deviceId) ? 254 : 0;
}
}
/**
* Determines the hue of the given bulb.
*
* @param deviceId
* The bulb id the bridge has filed the bulb under.
* @return The hue as a value from 0 - 65535
*/
public int getHue(String deviceId) {
if (settingsData == null) {
logger.error("Hue bridge settings not initialized correctly.");
return 0;
}
Object hue = settingsData.node("lights").node(deviceId).node("state").value("hue");
if (hue instanceof Integer) {
return (Integer) hue;
} else {
return 0;
}
}
/**
* Determines the saturation of the given bulb.
*
* @param deviceId
* The bulb id the bridge has filed the bulb under.
* @return The saturation as a value from 0 - {@link HueBulb#MAX_BRIGHTNESS}
*/
public int getSaturation(String deviceId) {
if (settingsData == null) {
logger.error("Hue bridge settings not initialized correctly.");
return 0;
}
Object sat = settingsData.node("lights").node(deviceId).node("state").value("sat");
if (sat instanceof Integer) {
return (Integer) sat;
} else {
return 0;
}
}
/**
* The SettingsTree represents the settings Json as a tree with some
* convenience methods to get subtrees and the values of interest easily.
*/
class SettingsTree {
private Map<String, Object> dataMap;
/**
* Constructor of the SettingsTree.
*
* @param treeData
* The Json data as it has been returned by the Json object
* mapper.
*/
public SettingsTree(Map<String, Object> treeData) {
this.dataMap = treeData;
}
/**
* @param nodeName
* The name of the child node.
* @return The child node named like nodeName. This will be a sub tree.
*/
@SuppressWarnings("unchecked")
protected SettingsTree node(String nodeName) {
if (dataMap.get(nodeName) == null){
return null;
}
return new SettingsTree((Map<String, Object>) dataMap.get(nodeName));
}
/**
* @return the amount of lights connected to Hue hub
*/
protected int count() {
return dataMap.size();
}
protected Set<String> getKeys() {
return dataMap.keySet();
}
/**
* @param valueName
* The name of the child node.
* @return The child node named like nodeName. This will be an object.
*/
protected Object value(String valueName) {
return dataMap.get(valueName);
}
}
}