[somfytahoma] Setting of channels at init + UoM for channels (#10300)

Fix #10291
Fix #10285

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
lolodomo 2021-03-14 14:20:52 +01:00 committed by GitHub
parent 286bced20e
commit 849442cd47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 164 additions and 13 deletions

View File

@ -18,12 +18,30 @@ import java.util.HashMap;
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;
@ -38,6 +56,7 @@ import org.slf4j.LoggerFactory;
* 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 {
@ -46,23 +65,57 @@ 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() {
@ -178,11 +231,49 @@ public abstract class SomfyTahomaBaseThingHandler extends BaseThingHandler {
}
}
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;
}
@ -205,14 +296,32 @@ public abstract class SomfyTahomaBaseThingHandler extends BaseThingHandler {
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);
@ -247,9 +356,11 @@ public abstract class SomfyTahomaBaseThingHandler extends BaseThingHandler {
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":

View File

@ -17,7 +17,12 @@ import static org.openhab.binding.somfytahoma.internal.SomfyTahomaBindingConstan
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;
@ -35,9 +40,25 @@ import org.eclipse.jetty.http.HttpHeader;
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;
@ -106,6 +127,9 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
*/
private String eventsId = "";
private ExpiringCache<List<SomfyTahomaDevice>> cachedDevices = new ExpiringCache<>(Duration.ofSeconds(30),
this::getDevices);
// Gson & parser
private final Gson gson = new Gson();
@ -331,6 +355,16 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
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()) {

View File

@ -22,6 +22,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
* to TahomaLink account.
*
* @author Ondrej Pecta - Initial contribution
* @author Laurent Garnier - Add attributes data
*/
@NonNullByDefault
public class SomfyTahomaDevice {
@ -33,6 +34,7 @@ public class SomfyTahomaDevice {
private String oid = "";
private SomfyTahomaDeviceDefinition definition = new SomfyTahomaDeviceDefinition();
private List<SomfyTahomaState> states = new ArrayList<>();
private List<SomfyTahomaState> attributes = new ArrayList<>();
public String getLabel() {
return label;
@ -61,4 +63,8 @@ public class SomfyTahomaDevice {
public List<SomfyTahomaState> getStates() {
return states;
}
public List<SomfyTahomaState> getAttributes() {
return attributes;
}
}