import java.util.List;
import java.util.Map;
+import javax.measure.Unit;
+
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaDevice;
import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaState;
import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaStatus;
-import org.openhab.core.library.types.*;
-import org.openhab.core.thing.*;
+import org.openhab.core.library.CoreItemFactory;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.OpenClosedType;
+import org.openhab.core.library.types.PercentType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.library.unit.ImperialUnits;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.library.unit.Units;
+import org.openhab.core.thing.Bridge;
+import org.openhab.core.thing.Channel;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.binding.builder.ThingBuilder;
* The {@link SomfyTahomaBaseThingHandler} is base thing handler for all things.
*
* @author Ondrej Pecta - Initial contribution
+ * @author Laurent Garnier - Setting of channels at init + UoM for channels
*/
@NonNullByDefault
public abstract class SomfyTahomaBaseThingHandler extends BaseThingHandler {
private HashMap<String, Integer> typeTable = new HashMap<>();
protected HashMap<String, String> stateNames = new HashMap<>();
+ protected String url = "";
+
+ private Map<String, Unit<?>> units = new HashMap<>();
+
public SomfyTahomaBaseThingHandler(Thing thing) {
super(thing);
+ // Define default units
+ units.put("Number:Temperature", SIUnits.CELSIUS);
+ units.put("Number:Energy", Units.WATT_HOUR);
+ units.put("Number:Illuminance", Units.LUX);
+ units.put("Number:Dimensionless", Units.PERCENT);
}
public HashMap<String, String> getStateNames() {
return stateNames;
}
- protected String url = "";
-
@Override
public void initialize() {
- url = getURL();
- if (getThing().getProperties().containsKey(RSSI_LEVEL_STATE)) {
- createRSSIChannel();
+ Bridge bridge = getBridge();
+ initializeThing(bridge != null ? bridge.getStatus() : null);
+ }
+
+ @Override
+ public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
+ initializeThing(bridgeStatusInfo.getStatus());
+ }
+
+ public void initializeThing(@Nullable ThingStatus bridgeStatus) {
+ SomfyTahomaBridgeHandler bridgeHandler = getBridgeHandler();
+ if (bridgeHandler != null && bridgeStatus != null) {
+ url = getURL();
+ if (getThing().getProperties().containsKey(RSSI_LEVEL_STATE)) {
+ createRSSIChannel();
+ }
+ if (bridgeStatus == ThingStatus.ONLINE) {
+ SomfyTahomaDevice device = bridgeHandler.getCachedDevice(url);
+ if (device != null) {
+ updateUnits(device.getAttributes());
+ List<SomfyTahomaState> states = device.getStates();
+ updateThingStatus(states);
+ updateThingChannels(states);
+ } else {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, UNAVAILABLE);
+ }
+ } else {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
+ }
+ } else {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
- updateStatus(ThingStatus.ONLINE);
}
private void createRSSIChannel() {
}
}
+ private void updateUnits(List<SomfyTahomaState> attributes) {
+ for (SomfyTahomaState attr : attributes) {
+ if ("core:MeasuredValueType".equals(attr.getName()) && attr.getType() == TYPE_STRING) {
+ switch ((String) attr.getValue()) {
+ case "core:TemperatureInCelcius":
+ case "core:TemperatureInCelsius":
+ units.put("Number:Temperature", SIUnits.CELSIUS);
+ break;
+ case "core:TemperatureInKelvin":
+ units.put("Number:Temperature", Units.KELVIN);
+ break;
+ case "core:TemperatureInFahrenheit":
+ units.put("Number:Temperature", ImperialUnits.FAHRENHEIT);
+ break;
+ case "core:RelativeValueInPercentage":
+ units.put("Number:Dimensionless", Units.PERCENT);
+ break;
+ case "core:LuminanceInLux":
+ units.put("Number:Illuminance", Units.LUX);
+ break;
+ case "core:ElectricalEnergyInWh":
+ units.put("Number:Energy", Units.WATT_HOUR);
+ break;
+ case "core:ElectricalEnergyInKWh":
+ units.put("Number:Energy", Units.KILOWATT_HOUR);
+ break;
+ case "core:ElectricalEnergyInMWh":
+ units.put("Number:Energy", Units.MEGAWATT_HOUR);
+ break;
+ default:
+ logger.warn("Unhandled value \"{}\" for attribute \"core:MeasuredValueType\"", attr.getValue());
+ break;
+ }
+ break;
+ }
+ }
+ }
+
protected @Nullable State parseTahomaState(@Nullable SomfyTahomaState state) {
return parseTahomaState(null, state);
}
- protected @Nullable State parseTahomaState(@Nullable String acceptedState, @Nullable SomfyTahomaState state) {
+ protected @Nullable State parseTahomaState(@Nullable String acceptedItemType, @Nullable SomfyTahomaState state) {
if (state == null) {
return UnDefType.NULL;
}
switch (type) {
case TYPE_PERCENT:
Double valPct = Double.parseDouble(state.getValue().toString());
+ if (acceptedItemType != null && acceptedItemType.startsWith(CoreItemFactory.NUMBER + ":")) {
+ Unit<?> unit = units.get(acceptedItemType);
+ if (unit != null) {
+ return new QuantityType<>(normalizePercent(valPct), unit);
+ } else {
+ logger.warn("Do not return a quantity for {} because the unit is unknown",
+ acceptedItemType);
+ }
+ }
return new PercentType(normalizePercent(valPct));
case TYPE_DECIMAL:
Double valDec = Double.parseDouble(state.getValue().toString());
+ if (acceptedItemType != null && acceptedItemType.startsWith(CoreItemFactory.NUMBER + ":")) {
+ Unit<?> unit = units.get(acceptedItemType);
+ if (unit != null) {
+ return new QuantityType<>(valDec, unit);
+ } else {
+ logger.warn("Do not return a quantity for {} because the unit is unknown",
+ acceptedItemType);
+ }
+ }
return new DecimalType(valDec);
case TYPE_STRING:
case TYPE_BOOLEAN:
String value = state.getValue().toString();
- if ("String".equals(acceptedState)) {
+ if ("String".equals(acceptedItemType)) {
return new StringType(value);
} else {
return parseStringState(value);
switch (value.toLowerCase()) {
case "on":
case "true":
+ case "active":
return OnOffType.ON;
case "off":
case "false":
+ case "inactive":
return OnOffType.OFF;
case "notdetected":
case "nopersoninside":
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
-import java.util.*;
+import java.time.Duration;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture;
import org.eclipse.jetty.http.HttpMethod;
import org.openhab.binding.somfytahoma.internal.config.SomfyTahomaConfig;
import org.openhab.binding.somfytahoma.internal.discovery.SomfyTahomaItemDiscoveryService;
-import org.openhab.binding.somfytahoma.internal.model.*;
+import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaAction;
+import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaActionGroup;
+import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaApplyResponse;
+import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaDevice;
+import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaEvent;
+import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaLoginResponse;
+import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaRegisterEventsResponse;
+import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaSetup;
+import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaState;
+import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaStatus;
+import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaStatusResponse;
+import org.openhab.core.cache.ExpiringCache;
import org.openhab.core.io.net.http.HttpClientFactory;
-import org.openhab.core.thing.*;
+import org.openhab.core.thing.Bridge;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
*/
private String eventsId = "";
+ private ExpiringCache<List<SomfyTahomaDevice>> cachedDevices = new ExpiringCache<>(Duration.ofSeconds(30),
+ this::getDevices);
+
// Gson & parser
private final Gson gson = new Gson();
return response != null ? List.of(response) : List.of();
}
+ public synchronized @Nullable SomfyTahomaDevice getCachedDevice(String url) {
+ List<SomfyTahomaDevice> devices = cachedDevices.getValue();
+ for (SomfyTahomaDevice device : devices) {
+ if (url.equals(device.getDeviceURL())) {
+ return device;
+ }
+ }
+ return null;
+ }
+
private void getTahomaUpdates() {
logger.debug("Getting Tahoma Updates...");
if (ThingStatus.OFFLINE == thing.getStatus() && !reLogin()) {