[shelly] Support for Shelly Plus HT Gen3 (#16625)

Signed-off-by: Markus Michels <markus7017@gmail.com>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
Markus Michels 2024-05-11 23:30:06 +02:00 committed by Ciprian Pascu
parent bf5413f68b
commit 47aeaf60ae
10 changed files with 74 additions and 52 deletions

View File

@ -37,7 +37,7 @@ The binding provides the same feature set across all devices as good as possible
### Generation 1 ### Generation 1
| thing-type | Model | Vendor ID | | thing-type | Model | Vendor ID |
| ----------------- | ------------------------------------------------------ | --------- | | ----------------- | ------------------------------------------------------ | ------------------- |
| shelly1 | Shelly 1 Single Relay Switch | SHSW-1 | | shelly1 | Shelly 1 Single Relay Switch | SHSW-1 |
| shelly1l | Shelly 1L Single Relay Switch | SHSW-L | | shelly1l | Shelly 1L Single Relay Switch | SHSW-L |
| shelly1pm | Shelly Single Relay Switch with integrated Power Meter | SHSW-PM | | shelly1pm | Shelly Single Relay Switch with integrated Power Meter | SHSW-PM |
@ -49,7 +49,7 @@ The binding provides the same feature set across all devices as good as possible
| shellydimmer | Shelly Dimmer | SHDM-1 | | shellydimmer | Shelly Dimmer | SHDM-1 |
| shellydimmer2 | Shelly Dimmer2 | SHDM-2 | | shellydimmer2 | Shelly Dimmer2 | SHDM-2 |
| shellyix3 | Shelly ix3 | SHIX3-1 | | shellyix3 | Shelly ix3 | SHIX3-1 |
| shellyuni | Shelly UNI | SHUNI-1 | | shellyuni | Shelly UNI, Shelly Plus UNI | SHUNI-1, SNSN-0043X |
| shellyplug | Shelly Plug | SHPLG2-1 | | shellyplug | Shelly Plug | SHPLG2-1 |
| shellyplugs | Shelly Plug-S | SHPLG-S | | shellyplugs | Shelly Plug-S | SHPLG-S |
| shellyem | Shelly EM with integrated Power Meters | SHEM | | shellyem | Shelly EM with integrated Power Meters | SHEM |
@ -91,6 +91,7 @@ The binding provides the same feature set across all devices as good as possible
| shellyplusi4 | Shelly Plus i4 with 4x AC input | SNSN-0024X | | shellyplusi4 | Shelly Plus i4 with 4x AC input | SNSN-0024X |
| shellyplusi4dc | Shelly Plus i4 with 4x DC input | SNSN-0D24X | | shellyplusi4dc | Shelly Plus i4 with 4x DC input | SNSN-0D24X |
| shellyplusht | Shelly Plus HT with temperature + humidity sensor | SNSN-0013A | | shellyplusht | Shelly Plus HT with temperature + humidity sensor | SNSN-0013A |
| shellyhtg3 | Shelly Plus HT Gen 3 with temperature + humidity sensor | S3SN-0U12A |
| shellyplussmoke | Shelly Plus Smoke sensor | SNSN-0031Z | | shellyplussmoke | Shelly Plus Smoke sensor | SNSN-0031Z |
| shellypluswdus | Shelly Plus Wall Dimmer US | SNDM-0013US | | shellypluswdus | Shelly Plus Wall Dimmer US | SNDM-0013US |
| shellywalldisplay | Shelly Plus Wall Display | SAWD-0A1XX10EU1 | | shellywalldisplay | Shelly Plus Wall Display | SAWD-0A1XX10EU1 |
@ -746,7 +747,7 @@ Using the Thing configuration option `brightnessAutoOn` you could decide if the
Channels lastEvent and eventCount are only available if input type is set to momentary button Channels lastEvent and eventCount are only available if input type is set to momentary button
### Shelly UNI (thing-type: shellyuni) ### Shelly UNI, Shelly Plus UNI (thing-type: shellyuni)
| Group | Channel | Type | read-only | Description | | Group | Channel | Type | read-only | Description |
| ------- | ------------ | ------- | --------- | ------------------------------------------------------------------------ | | ------- | ------------ | ------- | --------- | ------------------------------------------------------------------------ |
@ -1255,7 +1256,7 @@ Using the Thing configuration option `brightnessAutoOn` you could decide if the
Channels lastEvent and eventCount are only available if input type is set to momentary button Channels lastEvent and eventCount are only available if input type is set to momentary button
### Shelly Plus HT (thing-type: shellyplusht) ### Shelly Plus HT (thing-type: shellyplusht), Plus HT Gen 3 (thing-type: shellyhtg3)
| Group | Channel | Type | read-only | Description | | Group | Channel | Type | read-only | Description |
| ------- | ------------ | -------- | --------- | ------------------------------------------------------- | | ------- | ------------ | -------- | --------- | ------------------------------------------------------- |

View File

@ -77,6 +77,7 @@ public class ShellyBindingConstants {
THING_TYPE_SHELLYPLUSI4DC, // THING_TYPE_SHELLYPLUSI4DC, //
THING_TYPE_SHELLYPLUSDIMMER10V, // THING_TYPE_SHELLYPLUSDIMMER10V, //
THING_TYPE_SHELLYPLUSHT, // THING_TYPE_SHELLYPLUSHT, //
THING_TYPE_SHELLYPLUSHTG3, //
THING_TYPE_SHELLYPLUSSMOKE, // THING_TYPE_SHELLYPLUSSMOKE, //
THING_TYPE_SHELLYPLUSPLUGS, // THING_TYPE_SHELLYPLUSPLUGS, //
THING_TYPE_SHELLYPLUSPLUGUS, // THING_TYPE_SHELLYPLUSPLUGUS, //

View File

@ -197,8 +197,8 @@ public class ShellyDeviceProfile {
return; return;
} }
isGen2 = isGeneration2(thingType);
isBlu = isBluSeries(thingType); // e.g. SBBT for BLU Button isBlu = isBluSeries(thingType); // e.g. SBBT for BLU Button
isGen2 = isGeneration2(thingType) || isBlu;
String type = getString(device.type); String type = getString(device.type);
isDimmer = type.equalsIgnoreCase(SHELLYDT_DIMMER) || type.equalsIgnoreCase(SHELLYDT_DIMMER2) isDimmer = type.equalsIgnoreCase(SHELLYDT_DIMMER) || type.equalsIgnoreCase(SHELLYDT_DIMMER2)
@ -219,7 +219,7 @@ public class ShellyDeviceProfile {
boolean isGas = thingType.equals(THING_TYPE_SHELLYGAS_STR); boolean isGas = thingType.equals(THING_TYPE_SHELLYGAS_STR);
boolean isUNI = thingType.equals(THING_TYPE_SHELLYUNI_STR); boolean isUNI = thingType.equals(THING_TYPE_SHELLYUNI_STR);
isHT = thingType.equals(THING_TYPE_SHELLYHT_STR) || thingType.equals(THING_TYPE_SHELLYPLUSHT_STR) isHT = thingType.equals(THING_TYPE_SHELLYHT_STR) || thingType.equals(THING_TYPE_SHELLYPLUSHT_STR)
|| thingType.equals(THING_TYPE_SHELLYBLUHT_STR); || thingType.equals(THING_TYPE_SHELLYPLUSHTG3_STR) || thingType.equals(THING_TYPE_SHELLYBLUHT_STR);
isDW = thingType.equals(THING_TYPE_SHELLYDOORWIN_STR) || thingType.equals(THING_TYPE_SHELLYDOORWIN2_STR) isDW = thingType.equals(THING_TYPE_SHELLYDOORWIN_STR) || thingType.equals(THING_TYPE_SHELLYDOORWIN2_STR)
|| thingType.equals(THING_TYPE_SHELLYBLUDW_STR); || thingType.equals(THING_TYPE_SHELLYBLUDW_STR);
isMotion = thingType.startsWith(THING_TYPE_SHELLYMOTION_STR) isMotion = thingType.startsWith(THING_TYPE_SHELLYMOTION_STR)
@ -405,7 +405,7 @@ public class ShellyDeviceProfile {
public static boolean isGeneration2(String thingType) { public static boolean isGeneration2(String thingType) {
return thingType.startsWith("shellyplus") || thingType.startsWith("shellypro") || thingType.contains("mini") return thingType.startsWith("shellyplus") || thingType.startsWith("shellypro") || thingType.contains("mini")
|| isBluSeries(thingType); || (thingType.startsWith("shelly") && thingType.contains("g3")) || isBluSeries(thingType);
} }
public static boolean isBluSeries(String thingType) { public static boolean isBluSeries(String thingType) {

View File

@ -775,7 +775,7 @@ public class Shelly2ApiClient extends ShellyHttpClient {
protected Shelly2RpcBaseMessage buildRequest(String method, @Nullable Object params) throws ShellyApiException { protected Shelly2RpcBaseMessage buildRequest(String method, @Nullable Object params) throws ShellyApiException {
Shelly2RpcBaseMessage request = new Shelly2RpcBaseMessage(); Shelly2RpcBaseMessage request = new Shelly2RpcBaseMessage();
request.id = Math.abs(random.nextInt()); request.id = Math.abs(random.nextInt());
request.src = thingName; request.src = "openhab-" + config.localIp; // use a unique identifier;
request.method = !method.contains(".") ? SHELLYRPC_METHOD_CLASS_SHELLY + "." + method : method; request.method = !method.contains(".") ? SHELLYRPC_METHOD_CLASS_SHELLY + "." + method : method;
request.params = params; request.params = params;
request.auth = authReq; request.auth = authReq;

View File

@ -599,9 +599,11 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
// no device temp available // no device temp available
status.temperature = null; status.temperature = null;
} else { } else {
if (status.tmp != null) {
updated |= updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_ITEMP, updated |= updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_ITEMP,
toQuantityType(getDouble(status.tmp.tC), DIGITS_NONE, SIUnits.CELSIUS)); toQuantityType(getDouble(status.tmp.tC), DIGITS_NONE, SIUnits.CELSIUS));
} }
}
profile.status = status; profile.status = status;
if (updated) { if (updated) {

View File

@ -24,6 +24,7 @@ import javax.jmdns.ServiceInfo;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile;
import org.openhab.binding.shelly.internal.config.ShellyBindingConfiguration; import org.openhab.binding.shelly.internal.config.ShellyBindingConfiguration;
import org.openhab.binding.shelly.internal.config.ShellyThingConfiguration; import org.openhab.binding.shelly.internal.config.ShellyThingConfiguration;
import org.openhab.binding.shelly.internal.provider.ShellyTranslationProvider; import org.openhab.binding.shelly.internal.provider.ShellyTranslationProvider;
@ -99,7 +100,6 @@ public class ShellyDiscoveryParticipant implements MDNSDiscoveryParticipant {
try { try {
String address = ""; String address = "";
name = service.getName().toLowerCase();
Inet4Address[] hostAddresses = service.getInet4Addresses(); Inet4Address[] hostAddresses = service.getInet4Addresses();
if ((hostAddresses != null) && (hostAddresses.length > 0)) { if ((hostAddresses != null) && (hostAddresses.length > 0)) {
address = substringAfter(hostAddresses[0].toString(), "/"); address = substringAfter(hostAddresses[0].toString(), "/");
@ -125,7 +125,7 @@ public class ShellyDiscoveryParticipant implements MDNSDiscoveryParticipant {
config.password = bindingConfig.defaultPassword; config.password = bindingConfig.defaultPassword;
String gen = getString(service.getPropertyString("gen")); String gen = getString(service.getPropertyString("gen"));
boolean gen2 = "2".equals(gen) || "3".equals(gen); boolean gen2 = "2".equals(gen) || "3".equals(gen) || ShellyDeviceProfile.isGeneration2(name);
return ShellyBasicDiscoveryService.createResult(gen2, name, address, bindingConfig, httpClient, messages); return ShellyBasicDiscoveryService.createResult(gen2, name, address, bindingConfig, httpClient, messages);
} catch (IOException | NullPointerException e) { } catch (IOException | NullPointerException e) {
// maybe some format description was buggy // maybe some format description was buggy

View File

@ -79,6 +79,7 @@ public class ShellyThingCreator {
public static final String SHELLYDT_PLUSI4 = "SNSN-0024X"; public static final String SHELLYDT_PLUSI4 = "SNSN-0024X";
public static final String SHELLYDT_PLUSI4DC = "SNSN-0D24X"; public static final String SHELLYDT_PLUSI4DC = "SNSN-0D24X";
public static final String SHELLYDT_PLUSHT = "SNSN-0013A"; public static final String SHELLYDT_PLUSHT = "SNSN-0013A";
public static final String SHELLYDT_PLUSHTG3 = "S3SN-0U12A";
public static final String SHELLYDT_PLUSSMOKE = "SNSN-0031Z"; public static final String SHELLYDT_PLUSSMOKE = "SNSN-0031Z";
public static final String SHELLYDT_PLUSUNI = "SNSN-0043X"; public static final String SHELLYDT_PLUSUNI = "SNSN-0043X";
public static final String SHELLYDT_PLUSDIMMERUS = "SNDM-0013US"; public static final String SHELLYDT_PLUSDIMMERUS = "SNDM-0013US";
@ -173,6 +174,7 @@ public class ShellyThingCreator {
public static final String THING_TYPE_SHELLYPLUSI4_STR = "shellyplusi4"; public static final String THING_TYPE_SHELLYPLUSI4_STR = "shellyplusi4";
public static final String THING_TYPE_SHELLYPLUSI4DC_STR = "shellyplusi4dc"; public static final String THING_TYPE_SHELLYPLUSI4DC_STR = "shellyplusi4dc";
public static final String THING_TYPE_SHELLYPLUSHT_STR = "shellyplusht"; public static final String THING_TYPE_SHELLYPLUSHT_STR = "shellyplusht";
public static final String THING_TYPE_SHELLYPLUSHTG3_STR = "shellyhtg3";
public static final String THING_TYPE_SHELLYPLUSSMOKE_STR = "shellyplussmoke"; public static final String THING_TYPE_SHELLYPLUSSMOKE_STR = "shellyplussmoke";
public static final String THING_TYPE_SHELLYPLUSUNI_STR = "shellyplusuni"; public static final String THING_TYPE_SHELLYPLUSUNI_STR = "shellyplusuni";
public static final String THING_TYPE_SHELLYPLUSPLUGS_STR = "shellyplusplug"; public static final String THING_TYPE_SHELLYPLUSPLUGS_STR = "shellyplusplug";
@ -281,6 +283,8 @@ public class ShellyThingCreator {
THING_TYPE_SHELLYPLUSI4DC_STR); THING_TYPE_SHELLYPLUSI4DC_STR);
public static final ThingTypeUID THING_TYPE_SHELLYPLUSHT = new ThingTypeUID(BINDING_ID, public static final ThingTypeUID THING_TYPE_SHELLYPLUSHT = new ThingTypeUID(BINDING_ID,
THING_TYPE_SHELLYPLUSHT_STR); THING_TYPE_SHELLYPLUSHT_STR);
public static final ThingTypeUID THING_TYPE_SHELLYPLUSHTG3 = new ThingTypeUID(BINDING_ID,
THING_TYPE_SHELLYPLUSHTG3_STR);
public static final ThingTypeUID THING_TYPE_SHELLYPLUSSMOKE = new ThingTypeUID(BINDING_ID, public static final ThingTypeUID THING_TYPE_SHELLYPLUSSMOKE = new ThingTypeUID(BINDING_ID,
THING_TYPE_SHELLYPLUSSMOKE_STR); THING_TYPE_SHELLYPLUSSMOKE_STR);
public static final ThingTypeUID THING_TYPE_SHELLYPLUSPLUGS = new ThingTypeUID(BINDING_ID, public static final ThingTypeUID THING_TYPE_SHELLYPLUSPLUGS = new ThingTypeUID(BINDING_ID,
@ -375,6 +379,7 @@ public class ShellyThingCreator {
THING_TYPE_MAPPING.put(SHELLYDT_PLUSI4DC, THING_TYPE_SHELLYPLUSI4DC_STR); THING_TYPE_MAPPING.put(SHELLYDT_PLUSI4DC, THING_TYPE_SHELLYPLUSI4DC_STR);
THING_TYPE_MAPPING.put(SHELLYDT_PLUSI4, THING_TYPE_SHELLYPLUSI4_STR); THING_TYPE_MAPPING.put(SHELLYDT_PLUSI4, THING_TYPE_SHELLYPLUSI4_STR);
THING_TYPE_MAPPING.put(SHELLYDT_PLUSHT, THING_TYPE_SHELLYPLUSHT_STR); THING_TYPE_MAPPING.put(SHELLYDT_PLUSHT, THING_TYPE_SHELLYPLUSHT_STR);
THING_TYPE_MAPPING.put(SHELLYDT_PLUSHTG3, THING_TYPE_SHELLYPLUSHTG3_STR);
THING_TYPE_MAPPING.put(SHELLYDT_PLUSSMOKE, THING_TYPE_SHELLYPLUSSMOKE_STR); THING_TYPE_MAPPING.put(SHELLYDT_PLUSSMOKE, THING_TYPE_SHELLYPLUSSMOKE_STR);
THING_TYPE_MAPPING.put(SHELLYDT_PLUSUNI, THING_TYPE_SHELLYUNI_STR); THING_TYPE_MAPPING.put(SHELLYDT_PLUSUNI, THING_TYPE_SHELLYUNI_STR);
THING_TYPE_MAPPING.put(SHELLYDT_PLUSDIMMERUS, THING_TYPE_SHELLYPLUSDIMMERUS_STR); THING_TYPE_MAPPING.put(SHELLYDT_PLUSDIMMERUS, THING_TYPE_SHELLYPLUSDIMMERUS_STR);

View File

@ -155,7 +155,7 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
Map<String, String> properties = thing.getProperties(); Map<String, String> properties = thing.getProperties();
String gen = getString(properties.get(PROPERTY_DEV_GEN)); String gen = getString(properties.get(PROPERTY_DEV_GEN));
String thingType = getThingType(); String thingType = getThingType();
gen2 = "2".equals(gen) || "3".equals(gen) || ShellyDeviceProfile.isGeneration2(thingType); gen2 = !"1".equals(gen) || ShellyDeviceProfile.isGeneration2(thingType);
blu = ShellyDeviceProfile.isBluSeries(thingType); blu = ShellyDeviceProfile.isBluSeries(thingType);
this.api = !blu ? !gen2 ? new Shelly1HttpApi(thingName, this) : new Shelly2ApiRpc(thingName, thingTable, this) this.api = !blu ? !gen2 ? new Shelly1HttpApi(thingName, this) : new Shelly2ApiRpc(thingName, thingTable, this)
: new ShellyBluApi(thingName, thingTable, this); : new ShellyBluApi(thingName, thingTable, this);
@ -1356,10 +1356,8 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
*/ */
public void updateProperties(ShellyDeviceProfile profile, ShellySettingsStatus status) { public void updateProperties(ShellyDeviceProfile profile, ShellySettingsStatus status) {
Map<String, Object> properties = fillDeviceProperties(profile); Map<String, Object> properties = fillDeviceProperties(profile);
properties.put(PROPERTY_SERVICE_NAME, config.serviceName);
String deviceName = getString(profile.settings.name); String deviceName = getString(profile.settings.name);
properties.put(PROPERTY_SERVICE_NAME, config.serviceName); properties.put(PROPERTY_SERVICE_NAME, config.serviceName);
properties.put(PROPERTY_DEV_GEN, !profile.isGen2 ? "1" : "2");
properties.put(PROPERTY_DEV_AUTH, getBool(profile.device.auth) ? "yes" : "no"); properties.put(PROPERTY_DEV_AUTH, getBool(profile.device.auth) ? "yes" : "no");
if (!deviceName.isEmpty()) { if (!deviceName.isEmpty()) {
properties.put(PROPERTY_DEV_NAME, deviceName); properties.put(PROPERTY_DEV_NAME, deviceName);

View File

@ -98,6 +98,7 @@ thing-type.shelly.shellyplusplug.description = Shelly Plus Plug S/IT/UK/US . Out
thing-type.shelly.shellyplusi4.description = Shelly Plus i4 - 4xInput Device thing-type.shelly.shellyplusi4.description = Shelly Plus i4 - 4xInput Device
thing-type.shelly.shellyplusi4dc.description = Shelly Plus i4DC - 4xDC Input Device thing-type.shelly.shellyplusi4dc.description = Shelly Plus i4DC - 4xDC Input Device
thing-type.shelly.shellyplusht.description = Shelly Plus HT - Humidity and Temperature sensor with display thing-type.shelly.shellyplusht.description = Shelly Plus HT - Humidity and Temperature sensor with display
thing-type.shelly.shellyplushtg3.description = Shelly Plus HT Gen 3 - Humidity and Temperature sensor with display
thing-type.shelly.shellyplussmoke.description = Shelly Plus Smoke - Smoke Detector with Alarm thing-type.shelly.shellyplussmoke.description = Shelly Plus Smoke - Smoke Detector with Alarm
thing-type.shelly.shellypluswdus.description = Shelly Wall Dimmer US Device thing-type.shelly.shellypluswdus.description = Shelly Wall Dimmer US Device
thing-type.shelly.shellyplus10v.description = Shelly Plus Dimmer 10V thing-type.shelly.shellyplus10v.description = Shelly Plus Dimmer 10V

View File

@ -18,6 +18,20 @@
<config-description-ref uri="thing-type:shelly:battery-gen2"/> <config-description-ref uri="thing-type:shelly:battery-gen2"/>
</thing-type> </thing-type>
<thing-type id="shellyhtg3">
<label>ShellyPlus H&amp;T Gen 3</label>
<description>@text/thing-type.shelly.shellypludhtg3.description</description>
<category>Sensor</category>
<channel-groups>
<channel-group id="sensors" typeId="sensorData"/>
<channel-group id="battery" typeId="batteryStatus"/>
<channel-group id="device" typeId="deviceStatus"/>
</channel-groups>
<representation-property>serviceName</representation-property>
<config-description-ref uri="thing-type:shelly:battery-gen2"/>
</thing-type>
<thing-type id="shellyplussmoke"> <thing-type id="shellyplussmoke">
<label>Shelly Plus Smoke</label> <label>Shelly Plus Smoke</label>
<description>@text/thing-type.shelly.shellyplussmoke.description</description> <description>@text/thing-type.shelly.shellyplussmoke.description</description>