[shelly] Improved TRV profile handling (selectable list via dynamic state options (#13227)

provider); some improvements & fixes

Signed-off-by: Markus Michels <markus7017@gmail.com>
This commit is contained in:
Markus Michels 2022-08-09 10:04:07 +02:00 committed by GitHub
parent 6c78fb3161
commit 5b038786d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 212 additions and 82 deletions

View File

@ -27,7 +27,7 @@ Also check out the [Shelly Manager](doc/ShellyManager.md), which
## Supported Devices
### Generation 1:
### Generation 1
| thing-type | Model | Vendor ID |
|--------------------|--------------------------------------------------------|-----------|

View File

@ -138,10 +138,10 @@ public class ShellyBindingConstants {
public static final String CHANNEL_CONTROL_SETTEMP = "targetTemp";
public static final String CHANNEL_CONTROL_POSITION = "position";
public static final String CHANNEL_CONTROL_MODE = "mode";
public static final String CHANNEL_CONTROL_PROFILE = "selectedProfile";
public static final String CHANNEL_CONTROL_BCONTROL = "boost";
public static final String CHANNEL_CONTROL_BTIMER = "boostTimer";
public static final String CHANNEL_CONTROL_SCHEDULE = "schedule";
public static final String CHANNEL_CONTROL_PROFILE = "selectedProfile";
// External sensors for Shelly1/1PM
public static final String CHANNEL_ESENDOR_TEMP1 = CHANNEL_SENSOR_TEMP + "1";

View File

@ -65,8 +65,6 @@ public class ShellyHandlerFactory extends BaseThingHandlerFactory {
private final Shelly1CoapServer coapServer;
private final ShellyThingTable thingTable;
private ShellyBindingConfiguration bindingConfig = new ShellyBindingConfiguration();
private String localIP = "";
private int httpPort = -1;
/**
* Activate the bundle: save properties
@ -85,7 +83,7 @@ public class ShellyHandlerFactory extends BaseThingHandlerFactory {
this.thingTable = thingTable;
bindingConfig.updateFromProperties(configProperties);
localIP = bindingConfig.localIP;
String localIP = bindingConfig.localIP;
if (localIP.isEmpty()) {
localIP = ShellyUtils.getString(networkAddressService.getPrimaryIpv4HostAddress());
}
@ -94,11 +92,13 @@ public class ShellyHandlerFactory extends BaseThingHandlerFactory {
}
this.httpClient = httpClientFactory.getCommonHttpClient();
httpPort = HttpServiceUtil.getHttpServicePort(componentContext.getBundleContext());
int httpPort = HttpServiceUtil.getHttpServicePort(componentContext.getBundleContext());
if (httpPort == -1) {
httpPort = 8080;
}
logger.debug("Using OH HTTP port {}", httpPort);
bindingConfig.localIP = localIP;
bindingConfig.httpPort = httpPort;
this.coapServer = new Shelly1CoapServer();
}
@ -117,8 +117,7 @@ public class ShellyHandlerFactory extends BaseThingHandlerFactory {
if (thingType.equals(THING_TYPE_SHELLYPROTECTED_STR)) {
logger.debug("{}: Create new thing of type {} using ShellyProtectedHandler", thing.getLabel(),
thingTypeUID.toString());
handler = new ShellyProtectedHandler(thing, messages, bindingConfig, coapServer, localIP, httpPort,
httpClient);
handler = new ShellyProtectedHandler(thing, messages, bindingConfig, thingTable, coapServer, httpClient);
} else if (thingType.equals(THING_TYPE_SHELLYBULB_STR) || thingType.equals(THING_TYPE_SHELLYDUO_STR)
|| thingType.equals(THING_TYPE_SHELLYRGBW2_COLOR_STR)
|| thingType.equals(THING_TYPE_SHELLYRGBW2_WHITE_STR)
@ -126,11 +125,11 @@ public class ShellyHandlerFactory extends BaseThingHandlerFactory {
|| thingType.equals(THING_TYPE_SHELLYVINTAGE_STR)) {
logger.debug("{}: Create new thing of type {} using ShellyLightHandler", thing.getLabel(),
thingTypeUID.toString());
handler = new ShellyLightHandler(thing, messages, bindingConfig, coapServer, localIP, httpPort, httpClient);
handler = new ShellyLightHandler(thing, messages, bindingConfig, thingTable, coapServer, httpClient);
} else if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
logger.debug("{}: Create new thing of type {} using ShellyRelayHandler", thing.getLabel(),
thingTypeUID.toString());
handler = new ShellyRelayHandler(thing, messages, bindingConfig, coapServer, localIP, httpPort, httpClient);
handler = new ShellyRelayHandler(thing, messages, bindingConfig, thingTable, coapServer, httpClient);
}
if (handler != null) {

View File

@ -330,17 +330,19 @@ public class ShellyDeviceProfile {
return -1;
}
public String getValueProfile(int profileId) {
int id = profileId;
if (settings.thermostats != null) {
ShellyThermnostat t = settings.thermostats.get(0);
id = profileId == 0 ? getInteger(t.profile) : profileId;
if (id <= 0) {
return "DISABLED";
}
return id <= t.profileNames.length ? getString(t.profileNames[id - 1]) : "" + id;
public String[] getValveProfileList(int valveId) {
if (isTRV && settings.thermostats != null && valveId <= settings.thermostats.size()) {
ShellyThermnostat t = settings.thermostats.get(valveId);
return t.profileNames;
}
return new String[0];
}
public String getValueProfile(int valveId, int profileId) {
int id = profileId;
if (id <= 0 && settings.thermostats != null) {
id = settings.thermostats.get(0).profile;
}
return "" + id;
}

View File

@ -1143,7 +1143,7 @@ public class Shelly1ApiJsonDTO {
/**
* Shelly Dimmer returns light[]. However, the structure doesn't match the lights[] of a Bulb/RGBW2.
* The tag lights[] will be replaced with dimmers[] so this could be mapped to a different Gson structure.
* The tag lights[] will be replaced with dimmers[] so this could be mapped to a different Gson structure.
* The function requires that it's only called when the device is a dimmer - on get settings and get status
*
* @param json Input Json as received by the API

View File

@ -58,7 +58,6 @@ public class Shelly1CoIoTProtocol {
// Due to the fact that the device reports only the current/last status, but no real events, we need to distinguish
// between a real update or just a repeated status on periodic updates
protected int lastCfgCount = -1;
protected int[] lastEventCount = { -1, -1, -1, -1, -1, -1, -1, -1 }; // 4Pro has 4 relays, so 8 should be fine
protected String[] inputEvent = { "", "", "", "", "", "", "", "" };
protected String lastWakeup = "";

View File

@ -48,6 +48,7 @@ import org.slf4j.LoggerFactory;
@NonNullByDefault
public class Shelly1CoIoTVersion2 extends Shelly1CoIoTProtocol implements Shelly1CoIoTInterface {
private final Logger logger = LoggerFactory.getLogger(Shelly1CoIoTVersion2.class);
private int lastCfgCount = -1;
public Shelly1CoIoTVersion2(String thingName, ShellyThingInterface thingHandler, Map<String, CoIotDescrBlk> blkMap,
Map<String, CoIotDescrSen> sensorMap) {
@ -107,7 +108,7 @@ public class Shelly1CoIoTVersion2 extends Shelly1CoIoTProtocol implements Shelly
case "3117": // S, mode, 0-5 (0=disabled)
value = getDouble(s.value).intValue();
updateChannel(updates, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_PROFILE,
getStringType(profile.getValueProfile((int) value)));
getStringType(profile.getValueProfile(0, (int) value)));
updateChannel(updates, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_SCHEDULE, getOnOff(value > 0));
break;
case "3118": // Valve state

View File

@ -21,9 +21,13 @@ import static org.openhab.core.thing.Thing.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@ -39,7 +43,6 @@ import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyInputSta
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyOtaCheckResult;
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsDevice;
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsStatus;
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyThermnostat;
import org.openhab.binding.shelly.internal.api1.Shelly1CoapHandler;
import org.openhab.binding.shelly.internal.api1.Shelly1CoapJSonDTO;
import org.openhab.binding.shelly.internal.api1.Shelly1CoapServer;
@ -48,6 +51,7 @@ import org.openhab.binding.shelly.internal.config.ShellyBindingConfiguration;
import org.openhab.binding.shelly.internal.config.ShellyThingConfiguration;
import org.openhab.binding.shelly.internal.discovery.ShellyThingCreator;
import org.openhab.binding.shelly.internal.provider.ShellyChannelDefinitions;
import org.openhab.binding.shelly.internal.provider.ShellyStateDescriptionProvider;
import org.openhab.binding.shelly.internal.provider.ShellyTranslationProvider;
import org.openhab.binding.shelly.internal.util.ShellyChannelCache;
import org.openhab.binding.shelly.internal.util.ShellyVersionDTO;
@ -62,10 +66,13 @@ import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.StateOption;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -79,8 +86,21 @@ import org.slf4j.LoggerFactory;
@NonNullByDefault
public class ShellyBaseHandler extends BaseThingHandler
implements ShellyDeviceListener, ShellyManagerInterface, ShellyThingInterface {
private class OptionEntry {
public ChannelTypeUID uid;
public String key;
public String value;
public OptionEntry(ChannelTypeUID uid, String key, String value) {
this.uid = uid;
this.key = key;
this.value = value;
}
}
protected final Logger logger = LoggerFactory.getLogger(ShellyBaseHandler.class);
protected final ShellyChannelDefinitions channelDefinitions;
private final CopyOnWriteArrayList<OptionEntry> stateOptions = new CopyOnWriteArrayList<>();
public String thingName = "";
public String thingType = "";
@ -111,9 +131,6 @@ public class ShellyBaseHandler extends BaseThingHandler
private final int cacheCount = UPDATE_SETTINGS_INTERVAL_SECONDS / UPDATE_STATUS_INTERVAL_SECONDS;
private final ShellyChannelCache cache;
private String localIP = "";
private String localPort = "";
private String lastWakeupReason = "";
private int vibrationFilter = 0;
@ -128,8 +145,8 @@ public class ShellyBaseHandler extends BaseThingHandler
* @param httpPort from httpService
*/
public ShellyBaseHandler(final Thing thing, final ShellyTranslationProvider translationProvider,
final ShellyBindingConfiguration bindingConfig, final Shelly1CoapServer coapServer, final String localIP,
int httpPort, final HttpClient httpClient) {
final ShellyBindingConfiguration bindingConfig, ShellyThingTable thingTable,
final Shelly1CoapServer coapServer, final HttpClient httpClient) {
super(thing);
this.thingName = getString(thing.getLabel());
@ -140,8 +157,6 @@ public class ShellyBaseHandler extends BaseThingHandler
this.config = getConfigAs(ShellyThingConfiguration.class);
this.httpClient = httpClient;
this.localIP = localIP;
this.localPort = String.valueOf(httpPort);
this.api = new Shelly1HttpApi(thingName, config, httpClient);
coap = new Shelly1CoapHandler(this, coapServer);
@ -153,6 +168,11 @@ public class ShellyBaseHandler extends BaseThingHandler
|| key.equalsIgnoreCase(config.serviceName) || key.equalsIgnoreCase(thing.getUID().getAsString());
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Set.of(ShellyStateDescriptionProvider.class);
}
public String getUID() {
return getThing().getUID().getAsString();
}
@ -213,7 +233,9 @@ public class ShellyBaseHandler extends BaseThingHandler
public void handleConfigurationUpdate(Map<String, Object> configurationParameters) {
super.handleConfigurationUpdate(configurationParameters);
logger.debug("{}: Thing config updated, re-initialize", thingName);
coap.stop();
if (coap != null) {
coap.stop();
}
requestUpdates(1, true);// force re-initialization
}
@ -231,8 +253,6 @@ public class ShellyBaseHandler extends BaseThingHandler
stopping = false;
refreshSettings = false;
lastWakeupReason = "";
profile.initFromThingType(thingType);
api.setConfig(thingName, config);
cache.setThingName(thingName);
cache.clear();
@ -260,6 +280,8 @@ public class ShellyBaseHandler extends BaseThingHandler
config.serviceName = getString(profile.hostname).toLowerCase();
}
api.setConfig(thingName, config);
api.initialize();
ShellyDeviceProfile tmpPrf = api.getDeviceProfile(thingType);
if (this.getThing().getThingTypeUID().equals(THING_TYPE_SHELLYPROTECTED)) {
changeThingType(thingName, tmpPrf.mode);
@ -293,8 +315,18 @@ public class ShellyBaseHandler extends BaseThingHandler
tmpPrf.status = api.getStatus();
tmpPrf.updateFromStatus(tmpPrf.status);
if (tmpPrf.isTRV) {
String[] profileNames = tmpPrf.getValveProfileList(0);
String channelId = mkChannelId(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_PROFILE);
logger.debug("{}: Adding TRV profile names to channel description: {}", thingName, profileNames);
clearStateOptions(channelId);
addStateOption(channelId, "0", "DISABLED");
for (int i = 0; i < profileNames.length; i++) {
addStateOption(channelId, "" + (i + 1), profileNames[i]);
}
}
showThingConfig(tmpPrf);
// update thing properties
checkVersion(tmpPrf, tmpPrf.status);
if (config.eventsCoIoT && (tmpPrf.settings.coiot != null) && (tmpPrf.settings.coiot.enabled != null)) {
@ -411,24 +443,8 @@ public class ShellyBaseHandler extends BaseThingHandler
break;
case CHANNEL_CONTROL_PROFILE:
logger.debug("{}: Select profile {}", thingName, command);
int id = -1;
if (command instanceof Number) {
id = (int) getNumber(command);
} else {
String cmd = command.toString();
if (isDigit(cmd.charAt(0))) {
id = Integer.parseInt(cmd);
} else if (cmd.equalsIgnoreCase("DISABLED")) {
id = 0;
} else if (profile.settings.thermostats != null) {
ShellyThermnostat t = profile.settings.thermostats.get(0);
for (int i = 0; i < t.profileNames.length; i++) {
if (t.profileNames[i].equalsIgnoreCase(cmd)) {
id = i + 1;
}
}
}
}
String cmd = command.toString();
int id = Integer.parseInt(cmd);
if (id < 0 || id > 5) {
logger.warn("{}: Invalid profile Id {} requested", thingName, profile);
} else {
@ -463,7 +479,6 @@ public class ShellyBaseHandler extends BaseThingHandler
restartWatchdog();
if (update && !autoCoIoT && !isUpdateScheduled()) {
logger.debug("{}: Command processed, request status update", thingName);
requestUpdates(1, false);
}
} catch (ShellyApiException e) {
@ -517,8 +532,6 @@ public class ShellyBaseHandler extends BaseThingHandler
initializeThing(); // may fire an exception if initialization failed
}
// Get profile, if refreshSettings == true reload settings from device
logger.trace("{}: Updating status (scheduledUpdates={}, refreshSettings={})", thingName,
scheduledUpdates, refreshSettings);
ShellySettingsStatus status = api.getStatus();
boolean restarted = checkRestarted(status);
profile = getProfile(refreshSettings || restarted);
@ -590,6 +603,17 @@ public class ShellyBaseHandler extends BaseThingHandler
}
}
@Override
public ThingStatus getThingStatus() {
return getThing().getStatus();
}
@Override
public ThingStatusDetail getThingStatusDetail() {
return getThing().getStatusInfo().getStatusDetail();
}
@Override
public boolean isThingOnline() {
return getThing().getStatus() == ThingStatus.ONLINE;
}
@ -699,9 +723,10 @@ public class ShellyBaseHandler extends BaseThingHandler
if (status.uptime != null) {
stats.lastUptime = getLong(status.uptime);
}
stats.coiotMessages = coap.getMessageCount();
stats.coiotErrors = coap.getErrorCount();
if (coap != null) {
stats.coiotMessages = coap.getMessageCount();
stats.coiotErrors = coap.getErrorCount();
}
if (!alarm.isEmpty()) {
postEvent(alarm, false);
}
@ -911,7 +936,7 @@ public class ShellyBaseHandler extends BaseThingHandler
InetAddress addr = InetAddress.getByName(config.deviceIp);
String saddr = addr.getHostAddress();
if (!config.deviceIp.equals(saddr)) {
logger.debug("{}: hostname {} resolved to IP address {}", thingName, config.deviceIp, saddr);
logger.debug("{}: hostname {} resolved to IP address {}", thingName, config.deviceIp, saddr);
config.deviceIp = saddr;
}
} catch (UnknownHostException e) {
@ -919,8 +944,8 @@ public class ShellyBaseHandler extends BaseThingHandler
}
config.serviceName = getString(properties.get(PROPERTY_SERVICE_NAME));
config.localIp = localIP;
config.localPort = localPort;
config.localIp = bindingConfig.localIP;
config.localPort = String.valueOf(bindingConfig.httpPort);
if (config.userId.isEmpty() && !bindingConfig.defaultUserId.isEmpty()) {
config.userId = bindingConfig.defaultUserId;
config.password = bindingConfig.defaultPassword;
@ -1221,8 +1246,7 @@ public class ShellyBaseHandler extends BaseThingHandler
* @param profile The device profile
* @param status the /status result
*/
protected void updateProperties(ShellyDeviceProfile profile, ShellySettingsStatus status) {
logger.debug("{}: Update properties", thingName);
public void updateProperties(ShellyDeviceProfile profile, ShellySettingsStatus status) {
Map<String, Object> properties = fillDeviceProperties(profile);
String deviceName = getString(profile.settings.name);
properties.put(PROPERTY_SERVICE_NAME, config.serviceName);
@ -1347,6 +1371,35 @@ public class ShellyBaseHandler extends BaseThingHandler
return profile;
}
@Override
public List<StateOption> getStateOptions(ChannelTypeUID uid) {
List<StateOption> options = new ArrayList<>();
for (OptionEntry oe : stateOptions) {
if (oe.uid.equals(uid)) {
options.add(new StateOption(oe.key, oe.value));
}
}
if (!options.isEmpty()) {
logger.debug("{}: Return {} state options for channel uid {}", thingName, options.size(), uid.getId());
}
return options;
}
private void addStateOption(String channelId, String key, String value) {
ChannelTypeUID uid = channelDefinitions.getChannelTypeUID(channelId);
stateOptions.addIfAbsent(new OptionEntry(uid, key, value));
}
private void clearStateOptions(String channelId) {
ChannelTypeUID uid = channelDefinitions.getChannelTypeUID(channelId);
for (OptionEntry oe : stateOptions) {
if (oe.uid.equals(uid)) {
stateOptions.remove(oe);
}
}
}
protected ShellyDeviceProfile getDeviceProfile() {
return profile;
}
@ -1361,7 +1414,7 @@ public class ShellyBaseHandler extends BaseThingHandler
logger.debug("{}: Duplicate vibration events will be absorbed for the next {} sec", thingName,
vibrationFilter * UPDATE_STATUS_INTERVAL_SECONDS);
} else {
logger.debug("{}: Vibration event absorbed, {} sec remaining", thingName,
logger.debug("{}: Vibration event absorbed, {} sec remaining", thingName,
vibrationFilter * UPDATE_STATUS_INTERVAL_SECONDS);
return;
}
@ -1379,7 +1432,9 @@ public class ShellyBaseHandler extends BaseThingHandler
logger.debug("{}: Shelly statusJob stopped", thingName);
}
coap.stop();
if (coap != null) {
coap.stop();
}
profile.initialized = false;
}

View File

@ -398,7 +398,7 @@ public class ShellyComponents {
updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_SCHEDULE,
getOnOff(t.schedule));
updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_PROFILE,
getStringType(profile.getValueProfile(pid)));
getStringType(profile.getValueProfile(0, pid)));
if (t.tmp != null) {
Double temp = convertToC(t.tmp.value, getString(t.tmp.units));
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP,

View File

@ -66,9 +66,9 @@ public class ShellyLightHandler extends ShellyBaseHandler {
* @param httpPort port of the openHAB HTTP API
*/
public ShellyLightHandler(final Thing thing, final ShellyTranslationProvider translationProvider,
final ShellyBindingConfiguration bindingConfig, final Shelly1CoapServer coapServer, final String localIP,
int httpPort, final HttpClient httpClient) {
super(thing, translationProvider, bindingConfig, coapServer, localIP, httpPort, httpClient);
final ShellyBindingConfiguration bindingConfig, final ShellyThingTable thingTable,
final Shelly1CoapServer coapServer, final HttpClient httpClient) {
super(thing, translationProvider, bindingConfig, thingTable, coapServer, httpClient);
channelColors = new TreeMap<>();
}

View File

@ -36,9 +36,9 @@ public class ShellyProtectedHandler extends ShellyBaseHandler {
* @param httpPort port of the openHAB HTTP API
*/
public ShellyProtectedHandler(final Thing thing, final ShellyTranslationProvider translationProvider,
final ShellyBindingConfiguration bindingConfig, final Shelly1CoapServer coapServer, final String localIP,
int httpPort, final HttpClient httpClient) {
super(thing, translationProvider, bindingConfig, coapServer, localIP, httpPort, httpClient);
final ShellyBindingConfiguration bindingConfig, ShellyThingTable thingTable,
final Shelly1CoapServer coapService, final HttpClient httpClient) {
super(thing, translationProvider, bindingConfig, thingTable, coapService, httpClient);
}
@Override

View File

@ -64,9 +64,9 @@ public class ShellyRelayHandler extends ShellyBaseHandler {
* @param httpPort port of the openHAB HTTP API
*/
public ShellyRelayHandler(final Thing thing, final ShellyTranslationProvider translationProvider,
final ShellyBindingConfiguration bindingConfig, final Shelly1CoapServer coapServer, final String localIP,
int httpPort, final HttpClient httpClient) {
super(thing, translationProvider, bindingConfig, coapServer, localIP, httpPort, httpClient);
final ShellyBindingConfiguration bindingConfig, ShellyThingTable thingTable,
final Shelly1CoapServer coapServer, final HttpClient httpClient) {
super(thing, translationProvider, bindingConfig, thingTable, coapServer, httpClient);
}
@Override
@ -329,7 +329,7 @@ public class ShellyRelayHandler extends ShellyBaseHandler {
*/
public boolean updateRelays(ShellySettingsStatus status) throws ShellyApiException {
boolean updated = false;
// Check for Relay in Standard Mode
if (profile.hasRelays && !profile.isDimmer) {
double voltage = -1;
if (status.voltage == null && profile.settings.supplyVoltage != null) {
@ -384,7 +384,7 @@ public class ShellyRelayHandler extends ShellyBaseHandler {
ShellySettingsStatus dstatus = fromJson(gson, Shelly1ApiJsonDTO.fixDimmerJson(orgStatus.json),
ShellySettingsStatus.class);
logger.trace("{}: Updating {} dimmers(s)", thingName, dstatus.dimmers.size());
logger.trace("{}: Updating {} dimmers(s)", thingName, dstatus.dimmers.size());
int l = 0;
for (ShellyShortLightStatus dimmer : dstatus.dimmers) {
Integer r = l + 1;

View File

@ -25,8 +25,11 @@ import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettings
import org.openhab.binding.shelly.internal.config.ShellyThingConfiguration;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.State;
import org.openhab.core.types.StateOption;
/**
* The {@link ShellyThingInterface} implements the interface for Shelly Manager to access the thing handler
@ -38,6 +41,8 @@ public interface ShellyThingInterface {
public ShellyDeviceProfile getProfile(boolean forceRefresh) throws ShellyApiException;
public List<StateOption> getStateOptions(ChannelTypeUID uid);
public double getChannelDouble(String group, String channel);
public boolean updateChannel(String group, String channel, State value);
@ -48,6 +53,12 @@ public interface ShellyThingInterface {
public void setThingOffline(ThingStatusDetail detail, String messageKey);
public ThingStatus getThingStatus();
public ThingStatusDetail getThingStatusDetail();
public boolean isThingOnline();
public boolean requestUpdates(int requestCount, boolean refreshSettings);
public void triggerUpdateFromCoap();

View File

@ -514,6 +514,11 @@ public class ShellyChannelDefinitions {
return newChannels;
}
public ChannelTypeUID getChannelTypeUID(String channelId) {
ShellyChannel channelDef = getDefinition(channelId);
return new ChannelTypeUID(BINDING_ID, channelDef.typeId);
}
private static void addChannel(Thing thing, Map<String, Channel> newChannels, boolean supported, String group,
String channelName) throws IllegalArgumentException {
if (supported) {

View File

@ -0,0 +1,58 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.shelly.internal.provider;
import java.util.Locale;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.shelly.internal.handler.ShellyThingInterface;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.StateDescription;
/**
* This class provides the list of valid inputs for the input channel of a source.
*
* @author Markus Michels - Initial contribution
*
*/
@NonNullByDefault
public class ShellyStateDescriptionProvider extends BaseDynamicStateDescriptionProvider implements ThingHandlerService {
private @Nullable ShellyThingInterface handler;
@Override
public void setThingHandler(ThingHandler handler) {
this.handler = (ShellyThingInterface) handler;
}
@Override
public @Nullable ThingHandler getThingHandler() {
return (ThingHandler) handler;
}
@SuppressWarnings("null")
@Override
public @Nullable StateDescription getStateDescription(Channel channel, @Nullable StateDescription original,
@Nullable Locale locale) {
ChannelTypeUID uid = channel.getChannelTypeUID();
if (uid != null && handler != null) {
setStateOptions(channel.getUID(), handler.getStateOptions(uid));
}
return super.getStateDescription(channel, original, locale);
}
}

View File

@ -81,7 +81,7 @@ public class ShellyUtils {
if (classOfT.isInstance(json)) {
return wrap(classOfT).cast(json);
} else if (json.isEmpty()) { // update GSON might return null
throw new ShellyApiException(PRE + className + "from empty JSON");
throw new ShellyApiException(PRE + className + " from empty JSON");
} else {
try {
@Nullable
@ -92,7 +92,7 @@ public class ShellyUtils {
return obj;
} catch (JsonSyntaxException e) {
throw new ShellyApiException(
PRE + className + "from JSON (syntax/format error: " + e.getMessage() + "): " + json, e);
PRE + className + " from JSON (syntax/format error: " + e.getMessage() + "): " + json, e);
} catch (RuntimeException e) {
throw new ShellyApiException(PRE + className + " from JSON: " + json, e);
}

View File

@ -388,10 +388,10 @@ channel-type.shelly.controlMode.label = Mode
channel-type.shelly.controlMode.description = Sensor/Control Mode
channel-type.shelly.controlMode.state.option.manual = Manual
channel-type.shelly.controlMode.state.option.automatic = Automatic
channel-type.shelly.controlSchedule.label = Schedule active
channel-type.shelly.controlSchedule.description = ON: A scheduled program is active
channel-type.shelly.controlProfile.label = Selected Profile
channel-type.shelly.controlProfile.description = Selected Profile configured in the Shelly App
channel-type.shelly.controlProfile.description = Id of the selected Profile configured in the Shelly App
channel-type.shelly.controlSchedule.label = Schedule Active
channel-type.shelly.controlSchedule.description = ON: A scheduled program is active
channel-type.shelly.boostControl.label = Boost Mode
channel-type.shelly.boostControl.description = ON: Boost mode is activated (overwrites automatic temperature mode)
channel-type.shelly.boostTimer.label = Boost Timer