diff --git a/bundles/org.openhab.binding.shelly/README.md b/bundles/org.openhab.binding.shelly/README.md index 6de414e9d..73cf2c711 100644 --- a/bundles/org.openhab.binding.shelly/README.md +++ b/bundles/org.openhab.binding.shelly/README.md @@ -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 | |--------------------|--------------------------------------------------------|-----------| diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyBindingConstants.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyBindingConstants.java index 7179eed18..c9ae998c3 100755 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyBindingConstants.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyBindingConstants.java @@ -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"; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyHandlerFactory.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyHandlerFactory.java index 2ec06f032..ac4d88bd6 100755 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyHandlerFactory.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyHandlerFactory.java @@ -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) { diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyDeviceProfile.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyDeviceProfile.java index 8b0965ea3..c42c42cf5 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyDeviceProfile.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyDeviceProfile.java @@ -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; } diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1ApiJsonDTO.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1ApiJsonDTO.java index ed3257bff..d968ce50f 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1ApiJsonDTO.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1ApiJsonDTO.java @@ -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 diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTProtocol.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTProtocol.java index f54461675..37ced711c 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTProtocol.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTProtocol.java @@ -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 = ""; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTVersion2.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTVersion2.java index cd84004b2..2e937f8c2 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTVersion2.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTVersion2.java @@ -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 blkMap, Map 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 diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyBaseHandler.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyBaseHandler.java index 025c8f53e..e9d65b091 100755 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyBaseHandler.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyBaseHandler.java @@ -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 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> 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 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 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 getStateOptions(ChannelTypeUID uid) { + List 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; } diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyComponents.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyComponents.java index b22666754..7b5bcc0b3 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyComponents.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyComponents.java @@ -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, diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyLightHandler.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyLightHandler.java index 6a1944338..3ca5a3437 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyLightHandler.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyLightHandler.java @@ -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<>(); } diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyProtectedHandler.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyProtectedHandler.java index f941638c5..88f99133a 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyProtectedHandler.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyProtectedHandler.java @@ -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 diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyRelayHandler.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyRelayHandler.java index 174817a99..bb5034aea 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyRelayHandler.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyRelayHandler.java @@ -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; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyThingInterface.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyThingInterface.java index 0adb1f040..b7a28f9fb 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyThingInterface.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyThingInterface.java @@ -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 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(); diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/provider/ShellyChannelDefinitions.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/provider/ShellyChannelDefinitions.java index 51a0141ec..46ed9b560 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/provider/ShellyChannelDefinitions.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/provider/ShellyChannelDefinitions.java @@ -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 newChannels, boolean supported, String group, String channelName) throws IllegalArgumentException { if (supported) { diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/provider/ShellyStateDescriptionProvider.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/provider/ShellyStateDescriptionProvider.java new file mode 100644 index 000000000..d16eaf719 --- /dev/null +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/provider/ShellyStateDescriptionProvider.java @@ -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); + } +} diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/util/ShellyUtils.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/util/ShellyUtils.java index e04bf160d..b5a0b4cfe 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/util/ShellyUtils.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/util/ShellyUtils.java @@ -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); } diff --git a/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/i18n/shelly.properties b/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/i18n/shelly.properties index 317c56245..8bb4f01ed 100644 --- a/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/i18n/shelly.properties +++ b/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/i18n/shelly.properties @@ -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