Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 4 commits into from
Mar 14, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,30 @@
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;
Expand All @@ -38,6 +56,7 @@
* 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 {
Expand All @@ -46,23 +65,59 @@ 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();
logger.debug("initializing thing handler for thing {}", getThing().getUID());
lolodomo marked this conversation as resolved.
Show resolved Hide resolved
Bridge bridge = getBridge();
initializeThing(bridge != null ? bridge.getStatus() : null);
}

@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
logger.debug("bridgeStatusChanged {} for thing {}", bridgeStatusInfo, getThing().getUID());
lolodomo marked this conversation as resolved.
Show resolved Hide resolved
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);
fwolter marked this conversation as resolved.
Show resolved Hide resolved
}
updateStatus(ThingStatus.ONLINE);
}

private void createRSSIChannel() {
Expand Down Expand Up @@ -178,11 +233,49 @@ protected void cacheStateType(String stateName, int type) {
}
}

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":
lolodomo marked this conversation as resolved.
Show resolved Hide resolved
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;
}
Expand All @@ -205,14 +298,32 @@ protected void cacheStateType(String stateName, int type) {
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);
Expand Down Expand Up @@ -247,9 +358,11 @@ private State parseStringState(String 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":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@
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;
Expand All @@ -35,9 +40,25 @@
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;
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -331,6 +355,16 @@ public List<SomfyTahomaDevice> getDevices() {
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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* to TahomaLink account.
*
* @author Ondrej Pecta - Initial contribution
* @author Laurent Garnier - Add attributes data
*/
@NonNullByDefault
public class SomfyTahomaDevice {
Expand All @@ -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;
Expand Down Expand Up @@ -61,4 +63,8 @@ public SomfyTahomaDeviceDefinition getDefinition() {
public List<SomfyTahomaState> getStates() {
return states;
}

public List<SomfyTahomaState> getAttributes() {
return attributes;
}
}