mirror of
https://github.com/danieldemus/openhab-addons
synced 2026-07-29 12:34:21 +02:00
[shelly] Fix stopping sensor updates when using combo sensor connected to Shelly Addon (#20932)
* Fix externalTemp channel updates, improve test coverage Signed-off-by: Markus Michels <markus7017@gmail.com>
This commit is contained in:
@@ -530,6 +530,7 @@ Depending on the device type and firmware release channels might be not availabl
|
||||
| | temperature2 | Number | yes | Temperature value of external sensor #2 (if connected to temp/hum addon) |
|
||||
| | temperature3 | Number | yes | Temperature value of external sensor #3 (if connected to temp/hum addon) |
|
||||
| | humidity | Number | yes | Humidity in percent (if connected to temp/hum addon) |
|
||||
| | lastUpdate | DateTime | yes | Timestamp of the last sensor update (heartbeat) |
|
||||
| | input1 | Contact | yes | Status of the reed contact (OPEN/CLOSE), only with external switch add-on |
|
||||
|
||||
### Shelly 1L (thing-type: shelly1l)
|
||||
@@ -555,6 +556,7 @@ Depending on the device type and firmware release channels might be not availabl
|
||||
| | temperature2 | Number | yes | Temperature value of external sensor #2 (if connected to temp/hum addon) |
|
||||
| | temperature3 | Number | yes | Temperature value of external sensor #3 (if connected to temp/hum addon) |
|
||||
| | humidity | Number | yes | Humidity in percent (if connected to temp/hum addon) |
|
||||
| | lastUpdate | DateTime | yes | Timestamp of the last sensor update (heartbeat) |
|
||||
| | input1 | Contact | yes | Status of the reed contact (OPEN/CLOSE), only with external switch add-on |
|
||||
|
||||
`Note:`
|
||||
@@ -580,6 +582,7 @@ In this case the is no real measurement based on power consumption, but the Shel
|
||||
| | temperature2 | Number | yes | Temperature value of external sensor #2 (if connected to temp/hum addon) |
|
||||
| | temperature3 | Number | yes | Temperature value of external sensor #3 (if connected to temp/hum addon) |
|
||||
| | humidity | Number | yes | Humidity in percent (if connected to temp/hum addon) |
|
||||
| | lastUpdate | DateTime | yes | Timestamp of the last sensor update (heartbeat) |
|
||||
| | input1 | Contact | yes | Status of the reed contact (OPEN/CLOSE), only with external switch add-on |
|
||||
|
||||
### Shelly EM (thing-type: shellyem)
|
||||
@@ -815,6 +818,7 @@ Channels lastEvent and eventCount are only available if input type is set to mom
|
||||
| | temperature2 | Number | yes | Temperature value of external sensor #2 (if connected to temp/hum addon) |
|
||||
| | temperature3 | Number | yes | Temperature value of external sensor #3 (if connected to temp/hum addon) |
|
||||
| | humidity | Number | yes | Humidity in percent (if connected to temp/hum addon) |
|
||||
| | lastUpdate | DateTime | yes | Timestamp of the last sensor update (heartbeat) |
|
||||
| | voltage | Number | yes | ADCS voltage |
|
||||
| status | input1 | Switch | yes | State of Input 1 |
|
||||
| | input2 | Switch | yes | State of Input 2 |
|
||||
@@ -1186,6 +1190,7 @@ If the Shelly Add-On is installed:
|
||||
| | voltage | Number | yes | Measured voltage |
|
||||
| | analogInput | Number | yes | Percentage of reference voltage (VREF) at analogous input |
|
||||
| | digitalInput | Switch | yes | State of digital input (ON/OFF) |
|
||||
| | lastUpdate | DateTime | yes | Timestamp of the last sensor update (heartbeat) |
|
||||
|
||||
### Shelly Plus 1PM (thing-type: shellyplus1pm)
|
||||
|
||||
@@ -1216,6 +1221,7 @@ If the Shelly Add-On is installed:
|
||||
| | voltage | Number | yes | Measured voltage |
|
||||
| | analogInput | Number | yes | Percentage of reference voltage (VREF) at analogous input |
|
||||
| | digitalInput | Switch | yes | State of digital input (ON/OFF) |
|
||||
| | lastUpdate | DateTime | yes | Timestamp of the last sensor update (heartbeat) |
|
||||
|
||||
### Shelly Plus 2PM - relay mode (thing-type: shellyplus2pm-relay)
|
||||
|
||||
|
||||
+41
-36
@@ -663,12 +663,13 @@ public class Shelly1ApiJsonDTO {
|
||||
@SerializedName("ext_switch")
|
||||
public ShellyStatusSensor.ShellyExtSwitchSettings extSwitch;
|
||||
@SerializedName("ext_temperature")
|
||||
public ShellyStatusSensor.ShellyExtTemperature extTemperature; // Shelly 1/1PM: sensor values
|
||||
public ShellyStatusSensor.@Nullable ShellyExtTemperature extTemperature; // Shelly 1/1PM: sensor values
|
||||
@SerializedName("ext_humidity")
|
||||
public ShellyStatusSensor.ShellyExtHumidity extHumidity; // Shelly 1/1PM: sensor values
|
||||
public ShellyStatusSensor.ShellyExtVoltage extVoltage; // Shelly ´Plus 1/1PM: sensor values
|
||||
public ShellyStatusSensor.ShellyExtAnalogInput extAnalogInput; // Shelly ´Plus 1/1PM: sensor values
|
||||
public ShellyStatusSensor.ShellyExtDigitalInput extDigitalInput; // Shelly ´Plus 1/1PM: state of digital input
|
||||
public ShellyStatusSensor.@Nullable ShellyExtHumidity extHumidity; // Shelly 1/1PM: sensor values
|
||||
public ShellyStatusSensor.@Nullable ShellyExtVoltage extVoltage; // Shelly ´Plus 1/1PM: sensor values
|
||||
public ShellyStatusSensor.@Nullable ShellyExtAnalogInput extAnalogInput; // Shelly ´Plus 1/1PM: sensor values
|
||||
public ShellyStatusSensor.@Nullable ShellyExtDigitalInput extDigitalInput; // Shelly ´Plus 1/1PM: state of
|
||||
// digital input
|
||||
|
||||
@SerializedName("temperature_units")
|
||||
public String temperatureUnits = "C"; // Either'C'or'F'
|
||||
@@ -792,12 +793,12 @@ public class Shelly1ApiJsonDTO {
|
||||
public Double totalReturned;
|
||||
|
||||
@SerializedName("ext_temperature")
|
||||
public ShellyStatusSensor.ShellyExtTemperature extTemperature; // Shelly 1/1PM: sensor values
|
||||
public ShellyStatusSensor.@Nullable ShellyExtTemperature extTemperature; // Shelly 1/1PM: sensor values
|
||||
@SerializedName("ext_humidity")
|
||||
public ShellyStatusSensor.ShellyExtHumidity extHumidity; // Shelly 1/1PM: sensor values
|
||||
public ShellyStatusSensor.ShellyExtVoltage extVoltage; // Shelly ´Plus 1/1PM: sensor values
|
||||
public ShellyStatusSensor.ShellyExtAnalogInput extAnalogInput; // Shelly ´Plus 1/1PM: sensor values
|
||||
public ShellyStatusSensor.ShellyExtDigitalInput extDigitalInput; // Shelly ´Plus 1/1PM: sensor values
|
||||
public ShellyStatusSensor.@Nullable ShellyExtHumidity extHumidity; // Shelly 1/1PM: sensor values
|
||||
public ShellyStatusSensor.@Nullable ShellyExtVoltage extVoltage; // Shelly ´Plus 1/1PM: sensor values
|
||||
public ShellyStatusSensor.@Nullable ShellyExtAnalogInput extAnalogInput; // Shelly ´Plus 1/1PM: sensor values
|
||||
public ShellyStatusSensor.@Nullable ShellyExtDigitalInput extDigitalInput; // Shelly ´Plus 1/1PM: sensor values
|
||||
@SerializedName("ext_switch")
|
||||
public ShellyStatusSensor.ShellyExtSwitchStatus extSwitch;
|
||||
|
||||
@@ -895,9 +896,9 @@ public class Shelly1ApiJsonDTO {
|
||||
public ArrayList<ShellyInputState> inputs; // Firmware 1.5.6+
|
||||
|
||||
@SerializedName("ext_temperature")
|
||||
public ShellyStatusSensor.ShellyExtTemperature extTemperature; // Shelly 1/1PM: sensor values
|
||||
public ShellyStatusSensor.@Nullable ShellyExtTemperature extTemperature; // Shelly 1/1PM: sensor values
|
||||
@SerializedName("ext_humidity")
|
||||
public ShellyStatusSensor.ShellyExtHumidity extHumidity; // Shelly 1/1PM: sensor values
|
||||
public ShellyStatusSensor.@Nullable ShellyExtHumidity extHumidity; // Shelly 1/1PM: sensor values
|
||||
|
||||
public Double temperature; // device temp acc. on the selected temp unit
|
||||
public ShellySensorTmp tmp;
|
||||
@@ -1046,91 +1047,95 @@ public class Shelly1ApiJsonDTO {
|
||||
|
||||
public static class ShellyExtTemperature {
|
||||
public static class ShellyShortTemp {
|
||||
public String hwID; // e.g. "2882379497020381",
|
||||
public Double tC; // temperature in deg C
|
||||
public Double tF; // temperature in deg F
|
||||
public @Nullable String hwID; // e.g. "2882379497020381"
|
||||
public @Nullable Double tC; // temperature in deg C
|
||||
public @Nullable Double tF; // temperature in deg F
|
||||
}
|
||||
|
||||
// Shelly 1/1PM have up to 3 sensors
|
||||
// for whatever reasons it's not an array, but 3 independent elements
|
||||
@SerializedName("0")
|
||||
public ShellyShortTemp sensor1;
|
||||
public @Nullable ShellyShortTemp sensor1;
|
||||
@SerializedName("1")
|
||||
public ShellyShortTemp sensor2;
|
||||
public @Nullable ShellyShortTemp sensor2;
|
||||
@SerializedName("2")
|
||||
public ShellyShortTemp sensor3;
|
||||
public @Nullable ShellyShortTemp sensor3;
|
||||
@SerializedName("3")
|
||||
public ShellyShortTemp sensor4;
|
||||
public @Nullable ShellyShortTemp sensor4;
|
||||
@SerializedName("4")
|
||||
public ShellyShortTemp sensor5;
|
||||
public @Nullable ShellyShortTemp sensor5;
|
||||
}
|
||||
|
||||
public static class ShellyExtHumidity {
|
||||
public static class ShellyShortHum {
|
||||
public Double hum; // Humidity reading of sensor 0, percent
|
||||
public @Nullable Double hum; // Humidity reading of sensor 0, percent
|
||||
}
|
||||
|
||||
public ShellyExtHumidity() {
|
||||
}
|
||||
|
||||
public ShellyExtHumidity(double hum) {
|
||||
sensor1 = new ShellyShortHum();
|
||||
sensor1.hum = hum;
|
||||
ShellyShortHum s = new ShellyShortHum();
|
||||
s.hum = hum;
|
||||
sensor1 = s;
|
||||
}
|
||||
|
||||
@SerializedName("0")
|
||||
public ShellyShortHum sensor1;
|
||||
public @Nullable ShellyShortHum sensor1;
|
||||
}
|
||||
|
||||
public static class ShellyExtVoltage {
|
||||
public static class ShellyShortVoltage {
|
||||
public Double voltage;
|
||||
public @Nullable Double voltage;
|
||||
}
|
||||
|
||||
public ShellyExtVoltage() {
|
||||
}
|
||||
|
||||
public ShellyExtVoltage(double voltage) {
|
||||
sensor1 = new ShellyShortVoltage();
|
||||
sensor1.voltage = voltage;
|
||||
ShellyShortVoltage s = new ShellyShortVoltage();
|
||||
s.voltage = voltage;
|
||||
sensor1 = s;
|
||||
}
|
||||
|
||||
@SerializedName("0")
|
||||
public ShellyShortVoltage sensor1;
|
||||
public @Nullable ShellyShortVoltage sensor1;
|
||||
}
|
||||
|
||||
public static class ShellyExtDigitalInput {
|
||||
public static class ShellyShortDigitalInput {
|
||||
public Boolean state;
|
||||
public @Nullable Boolean state;
|
||||
}
|
||||
|
||||
public ShellyExtDigitalInput() {
|
||||
}
|
||||
|
||||
public ShellyExtDigitalInput(boolean state) {
|
||||
sensor1 = new ShellyShortDigitalInput();
|
||||
sensor1.state = state;
|
||||
ShellyShortDigitalInput s = new ShellyShortDigitalInput();
|
||||
s.state = state;
|
||||
sensor1 = s;
|
||||
}
|
||||
|
||||
@SerializedName("0")
|
||||
public ShellyShortDigitalInput sensor1;
|
||||
public @Nullable ShellyShortDigitalInput sensor1;
|
||||
}
|
||||
|
||||
public static class ShellyExtAnalogInput {
|
||||
public static class ShellyShortAnalogInput {
|
||||
public Double percent;
|
||||
public @Nullable Double percent;
|
||||
}
|
||||
|
||||
public ShellyExtAnalogInput() {
|
||||
}
|
||||
|
||||
public ShellyExtAnalogInput(double percent) {
|
||||
sensor1 = new ShellyShortAnalogInput();
|
||||
sensor1.percent = percent;
|
||||
ShellyShortAnalogInput s = new ShellyShortAnalogInput();
|
||||
s.percent = percent;
|
||||
sensor1 = s;
|
||||
}
|
||||
|
||||
@SerializedName("0")
|
||||
public ShellyShortAnalogInput sensor1;
|
||||
public @Nullable ShellyShortAnalogInput sensor1;
|
||||
}
|
||||
|
||||
public static class ShellyADC {
|
||||
|
||||
+10
-5
@@ -203,12 +203,17 @@ public class Shelly1CoIoTVersion2 extends Shelly1CoIoTProtocol implements Shelly
|
||||
case "3201": // sensor_1: T, extTemp, C, -55/125; unknown 999
|
||||
case "3301": // sensor_2: T, extTemp, C, -55/125; unknown 999
|
||||
int idx = getExtTempId(sen.id);
|
||||
if (idx >= 0 && value != SHELLY_API_INVTEMP) {
|
||||
// H&T, Fllod, DW only have 1 channel, 1/1PM with Addon have up to to 3 sensors
|
||||
if (idx >= 0) {
|
||||
// H&T, Flood, DW only have 1 channel; 1/1PM with Addon have up to 3 sensors
|
||||
String channel = profile.isSensor ? CHANNEL_SENSOR_TEMP : CHANNEL_SENSOR_TEMP + idx;
|
||||
// Some devices report values = -999 or 99 during fw update
|
||||
updateChannel(updates, CHANNEL_GROUP_SENSOR, channel,
|
||||
toQuantityType(value, DIGITS_TEMP, SIUnits.CELSIUS));
|
||||
if (value == SHELLY_API_INVTEMP) {
|
||||
// Sensor present but reading invalid: publish UNDEF so the cache doesn't
|
||||
// block the next valid reading when the sensor recovers.
|
||||
updateChannel(updates, CHANNEL_GROUP_SENSOR, channel, UnDefType.UNDEF);
|
||||
} else {
|
||||
updateChannel(updates, CHANNEL_GROUP_SENSOR, channel,
|
||||
toQuantityType(value, DIGITS_TEMP, SIUnits.CELSIUS));
|
||||
}
|
||||
} else {
|
||||
logger.debug("{}: Unable to get extSensorId {} from {}/{}", thingName, sen.id, sen.type, sen.desc);
|
||||
}
|
||||
|
||||
+9
@@ -471,8 +471,12 @@ public class Shelly1CoapHandler implements Shelly1CoapListener {
|
||||
|
||||
if (!updates.isEmpty()) {
|
||||
int updated = 0;
|
||||
boolean sensorGroupUpdated = false;
|
||||
for (Map.Entry<String, State> u : updates.entrySet()) {
|
||||
String key = u.getKey();
|
||||
if (key.startsWith(CHANNEL_GROUP_SENSOR + "#")) {
|
||||
sensorGroupUpdated = true;
|
||||
}
|
||||
updated += thingHandler.updateChannel(key, u.getValue(), false) ? 1 : 0;
|
||||
}
|
||||
if (updated > 0) {
|
||||
@@ -482,6 +486,11 @@ public class Shelly1CoapHandler implements Shelly1CoapListener {
|
||||
thingHandler.updateChannel(profile.getControlGroup(0), CHANNEL_LAST_UPDATE, getTimestamp());
|
||||
}
|
||||
}
|
||||
if (sensorGroupUpdated && !profile.isSensor && !profile.isRoller) {
|
||||
// Relay device with addon sensors: always refresh sensors#lastUpdate so the channel acts
|
||||
// as a heartbeat even when temperature values are unchanged (and thus cache-deduplicated)
|
||||
thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_LAST_UPDATE, getTimestamp());
|
||||
}
|
||||
|
||||
if (profile.isLight && profile.inColor && col.isRgbValid()) {
|
||||
// Update color picker from single values
|
||||
|
||||
+19
-10
@@ -1140,20 +1140,28 @@ public class Shelly2ApiClient extends ShellyHttpClient implements ShellyDiscover
|
||||
}
|
||||
|
||||
if (ds.temperature100 != null) {
|
||||
if (status.extTemperature == null) {
|
||||
status.extTemperature = new ShellyExtTemperature();
|
||||
ShellyExtTemperature extTemp = status.extTemperature;
|
||||
if (extTemp == null) {
|
||||
extTemp = new ShellyExtTemperature();
|
||||
status.extTemperature = extTemp;
|
||||
}
|
||||
status.extTemperature.sensor1 = updateExtTempSensor(ds.temperature100);
|
||||
status.extTemperature.sensor2 = updateExtTempSensor(ds.temperature101);
|
||||
status.extTemperature.sensor3 = updateExtTempSensor(ds.temperature102);
|
||||
status.extTemperature.sensor4 = updateExtTempSensor(ds.temperature103);
|
||||
status.extTemperature.sensor5 = updateExtTempSensor(ds.temperature104);
|
||||
extTemp.sensor1 = updateExtTempSensor(ds.temperature100);
|
||||
extTemp.sensor2 = updateExtTempSensor(ds.temperature101);
|
||||
extTemp.sensor3 = updateExtTempSensor(ds.temperature102);
|
||||
extTemp.sensor4 = updateExtTempSensor(ds.temperature103);
|
||||
extTemp.sensor5 = updateExtTempSensor(ds.temperature104);
|
||||
}
|
||||
if (ds.humidity100 != null) {
|
||||
status.extHumidity = new ShellyExtHumidity(ds.humidity100.rh);
|
||||
Double rh = ds.humidity100.rh;
|
||||
if (rh != null) {
|
||||
status.extHumidity = new ShellyExtHumidity(rh);
|
||||
}
|
||||
}
|
||||
if (ds.voltmeter100 != null) {
|
||||
status.extVoltage = new ShellyExtVoltage(ds.voltmeter100.voltage);
|
||||
Double voltage = ds.voltmeter100.voltage;
|
||||
if (voltage != null) {
|
||||
status.extVoltage = new ShellyExtVoltage(voltage);
|
||||
}
|
||||
}
|
||||
if (ds.input100 != null) {
|
||||
if (ds.input100.state != null) {
|
||||
@@ -1167,7 +1175,8 @@ public class Shelly2ApiClient extends ShellyHttpClient implements ShellyDiscover
|
||||
private @Nullable ShellyShortTemp updateExtTempSensor(@Nullable Shelly2DeviceStatusTempId value) {
|
||||
if (value != null) {
|
||||
ShellyShortTemp temp = new ShellyShortTemp();
|
||||
temp.hwID = value.id != null ? value.id.toString() : "999";
|
||||
Integer idBox = value.id;
|
||||
temp.hwID = idBox != null ? idBox.toString() : "999";
|
||||
temp.tC = getDouble(value.tC);
|
||||
temp.tF = getDouble(value.tF);
|
||||
return temp;
|
||||
|
||||
+5
-5
@@ -653,8 +653,8 @@ public class Shelly2ApiJsonDTO {
|
||||
}
|
||||
|
||||
public class Shelly2DeviceStatusHumidity {
|
||||
public Integer id;
|
||||
public Double rh;
|
||||
public @Nullable Integer id;
|
||||
public @Nullable Double rh;
|
||||
}
|
||||
|
||||
public class Shelly2DeviceStatusIlluminance {
|
||||
@@ -664,12 +664,12 @@ public class Shelly2ApiJsonDTO {
|
||||
}
|
||||
|
||||
public class Shelly2DeviceStatusVoltage {
|
||||
public Integer id;
|
||||
public Double voltage;
|
||||
public @Nullable Integer id;
|
||||
public @Nullable Double voltage;
|
||||
}
|
||||
|
||||
public class Shelly2DeviceStatusTempId extends Shelly2DeviceStatusTemp {
|
||||
public Integer id;
|
||||
public @Nullable Integer id;
|
||||
}
|
||||
|
||||
public static class Shelly2DeviceStatusPower {
|
||||
|
||||
+67
-21
@@ -36,7 +36,16 @@ import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettings
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyShortLightStatus;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyADC;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtAnalogInput;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtAnalogInput.ShellyShortAnalogInput;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtDigitalInput;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtDigitalInput.ShellyShortDigitalInput;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtHumidity;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtHumidity.ShellyShortHum;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtTemperature;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtTemperature.ShellyShortTemp;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtVoltage;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtVoltage.ShellyShortVoltage;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyThermnostat;
|
||||
import org.openhab.binding.shelly.internal.provider.ShellyChannelDefinitions;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
@@ -577,31 +586,55 @@ public class ShellyComponents {
|
||||
}
|
||||
}
|
||||
|
||||
// Update Add-On channeös
|
||||
if (status.extTemperature != null) {
|
||||
// Update Add-On channels (Shelly 1/1PM and Plus 1/1PM with sensor addon)
|
||||
boolean hasAddon = hasAddon(status);
|
||||
ShellyExtTemperature extTemperature = status.extTemperature;
|
||||
if (extTemperature != null) {
|
||||
// Shelly 1/1PM support up to 3 external sensors
|
||||
// for whatever reason those are not represented as an array, but 3 elements
|
||||
updated |= updateTempChannel(status.extTemperature.sensor1, thingHandler, CHANNEL_ESENSOR_TEMP1);
|
||||
updated |= updateTempChannel(status.extTemperature.sensor2, thingHandler, CHANNEL_ESENSOR_TEMP2);
|
||||
updated |= updateTempChannel(status.extTemperature.sensor3, thingHandler, CHANNEL_ESENSOR_TEMP3);
|
||||
updated |= updateTempChannel(status.extTemperature.sensor4, thingHandler, CHANNEL_ESENSOR_TEMP4);
|
||||
updated |= updateTempChannel(status.extTemperature.sensor5, thingHandler, CHANNEL_ESENSOR_TEMP5);
|
||||
updated |= updateTempChannel(extTemperature.sensor1, thingHandler, CHANNEL_ESENSOR_TEMP1);
|
||||
updated |= updateTempChannel(extTemperature.sensor2, thingHandler, CHANNEL_ESENSOR_TEMP2);
|
||||
updated |= updateTempChannel(extTemperature.sensor3, thingHandler, CHANNEL_ESENSOR_TEMP3);
|
||||
updated |= updateTempChannel(extTemperature.sensor4, thingHandler, CHANNEL_ESENSOR_TEMP4);
|
||||
updated |= updateTempChannel(extTemperature.sensor5, thingHandler, CHANNEL_ESENSOR_TEMP5);
|
||||
}
|
||||
if ((status.extHumidity != null) && (status.extHumidity.sensor1 != null)) {
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_HUMIDITY,
|
||||
toQuantityType(getDouble(status.extHumidity.sensor1.hum), DIGITS_PERCENT, Units.PERCENT));
|
||||
ShellyExtHumidity extHumidity = status.extHumidity;
|
||||
if (extHumidity != null) {
|
||||
ShellyShortHum humSensor = extHumidity.sensor1;
|
||||
if (humSensor != null) {
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_HUMIDITY,
|
||||
toQuantityType(getDouble(humSensor.hum), DIGITS_PERCENT, Units.PERCENT));
|
||||
}
|
||||
}
|
||||
if ((status.extVoltage != null) && (status.extVoltage.sensor1 != null)) {
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_VOLTAGE,
|
||||
toQuantityType(getDouble(status.extVoltage.sensor1.voltage), 4, Units.VOLT));
|
||||
ShellyExtVoltage extVoltage = status.extVoltage;
|
||||
if (extVoltage != null) {
|
||||
ShellyShortVoltage voltSensor = extVoltage.sensor1;
|
||||
if (voltSensor != null) {
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_VOLTAGE,
|
||||
toQuantityType(getDouble(voltSensor.voltage), 4, Units.VOLT));
|
||||
}
|
||||
}
|
||||
if ((status.extDigitalInput != null) && (status.extDigitalInput.sensor1 != null)) {
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_DIGITALINPUT,
|
||||
getOnOff(status.extDigitalInput.sensor1.state));
|
||||
ShellyExtDigitalInput extDigitalInput = status.extDigitalInput;
|
||||
if (extDigitalInput != null) {
|
||||
ShellyShortDigitalInput digSensor = extDigitalInput.sensor1;
|
||||
if (digSensor != null) {
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_DIGITALINPUT,
|
||||
getOnOff(digSensor.state));
|
||||
}
|
||||
}
|
||||
if ((status.extAnalogInput != null) && (status.extAnalogInput.sensor1 != null)) {
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_ANALOGINPUT,
|
||||
toQuantityType(getDouble(status.extAnalogInput.sensor1.percent), DIGITS_PERCENT, Units.PERCENT));
|
||||
ShellyExtAnalogInput extAnalogInput = status.extAnalogInput;
|
||||
if (extAnalogInput != null) {
|
||||
ShellyShortAnalogInput anaSensor = extAnalogInput.sensor1;
|
||||
if (anaSensor != null) {
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_ANALOGINPUT,
|
||||
toQuantityType(getDouble(anaSensor.percent), DIGITS_PERCENT, Units.PERCENT));
|
||||
}
|
||||
}
|
||||
if (hasAddon && !(profile.isSensor || profile.hasBattery)) {
|
||||
// Relay devices with addon sensors: always refresh lastUpdate so the channel shows
|
||||
// when sensor data was last received, even when temperature values are unchanged
|
||||
thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_LAST_UPDATE, getTimestamp());
|
||||
updated = true;
|
||||
}
|
||||
|
||||
return updated;
|
||||
@@ -687,16 +720,29 @@ public class ShellyComponents {
|
||||
return updated;
|
||||
}
|
||||
|
||||
public static boolean hasAddon(ShellySettingsStatus status) {
|
||||
return status.extTemperature != null || status.extHumidity != null || status.extVoltage != null
|
||||
|| status.extDigitalInput != null || status.extAnalogInput != null;
|
||||
}
|
||||
|
||||
public static boolean updateTempChannel(@Nullable ShellyShortTemp sensor, ShellyThingInterface thingHandler,
|
||||
String channel) {
|
||||
return sensor != null ? updateTempChannel(thingHandler, CHANNEL_GROUP_SENSOR, channel, sensor.tC, "") : false;
|
||||
if (sensor == null) {
|
||||
return false;
|
||||
}
|
||||
return updateTempChannel(thingHandler, CHANNEL_GROUP_SENSOR, channel, sensor.tC, "");
|
||||
}
|
||||
|
||||
public static boolean updateTempChannel(ShellyThingInterface thingHandler, String group, String channel,
|
||||
@Nullable Double temp, @Nullable String unit) {
|
||||
if (temp == null || temp == SHELLY_API_INVTEMP) {
|
||||
if (temp == null) {
|
||||
return false;
|
||||
}
|
||||
if (temp == SHELLY_API_INVTEMP) {
|
||||
// Sensor present but reading invalid (e.g. disconnected wire): publish UNDEF so that
|
||||
// the cache does not block the next valid reading when the sensor recovers.
|
||||
return thingHandler.updateChannel(group, channel, UnDefType.UNDEF);
|
||||
}
|
||||
return thingHandler.updateChannel(group, channel,
|
||||
toQuantityType(convertToC(temp, unit), DIGITS_TEMP, SIUnits.CELSIUS));
|
||||
}
|
||||
|
||||
+12
-8
@@ -40,6 +40,7 @@ import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettings
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyShortLightStatus;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusLightChannel;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyComponents;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyThingInterface;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
@@ -443,19 +444,22 @@ public class ShellyChannelDefinitions {
|
||||
addChannel(thing, add, addon, CHGR_SENSOR,
|
||||
CHANNEL_ESENSOR_INPUT + (profile.settings.extSwitch.input0.relayNum + 1));
|
||||
}
|
||||
if (profile.status.extTemperature != null) {
|
||||
addChannel(thing, add, profile.status.extTemperature.sensor1 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP1);
|
||||
addChannel(thing, add, profile.status.extTemperature.sensor2 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP2);
|
||||
addChannel(thing, add, profile.status.extTemperature.sensor3 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP3);
|
||||
addChannel(thing, add, profile.status.extTemperature.sensor4 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP4);
|
||||
addChannel(thing, add, profile.status.extTemperature.sensor5 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP5);
|
||||
ShellyStatusSensor.ShellyExtTemperature extTemp = profile.status.extTemperature;
|
||||
if (extTemp != null) {
|
||||
addChannel(thing, add, extTemp.sensor1 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP1);
|
||||
addChannel(thing, add, extTemp.sensor2 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP2);
|
||||
addChannel(thing, add, extTemp.sensor3 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP3);
|
||||
addChannel(thing, add, extTemp.sensor4 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP4);
|
||||
addChannel(thing, add, extTemp.sensor5 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP5);
|
||||
}
|
||||
addChannel(thing, add, profile.status.extHumidity != null && profile.status.extHumidity.sensor1 != null,
|
||||
CHGR_SENSOR, CHANNEL_ESENSOR_HUMIDITY);
|
||||
ShellyStatusSensor.ShellyExtHumidity extHum = profile.status.extHumidity;
|
||||
addChannel(thing, add, extHum != null && extHum.sensor1 != null, CHGR_SENSOR, CHANNEL_ESENSOR_HUMIDITY);
|
||||
|
||||
addChannel(thing, add, profile.status.extVoltage != null, CHGR_SENSOR, CHANNEL_ESENSOR_VOLTAGE);
|
||||
addChannel(thing, add, profile.status.extDigitalInput != null, CHGR_SENSOR, CHANNEL_ESENSOR_DIGITALINPUT);
|
||||
addChannel(thing, add, profile.status.extAnalogInput != null, CHGR_SENSOR, CHANNEL_ESENSOR_ANALOGINPUT);
|
||||
|
||||
addChannel(thing, add, ShellyComponents.hasAddon(profile.status), CHGR_SENSOR, CHANNEL_LAST_UPDATE);
|
||||
}
|
||||
|
||||
public static Map<String, Channel> createDimmerChannels(final Thing thing, final ShellyDeviceProfile profile,
|
||||
|
||||
+316
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2026 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.handler;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*;
|
||||
import static org.openhab.binding.shelly.internal.ShellyDevices.*;
|
||||
import static org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.SHELLY_API_INVTEMP;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsStatus;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtAnalogInput;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtDigitalInput;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtHumidity;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtTemperature;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtTemperature.ShellyShortTemp;
|
||||
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtVoltage;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* Tests for {@link ShellyComponents} — addon sensor update path.
|
||||
*
|
||||
* Covers:
|
||||
* - {@link ShellyComponents#hasAddon} detection logic
|
||||
* - {@link ShellyComponents#updateTempChannel} INVTEMP → UNDEF promotion
|
||||
* - {@link ShellyComponents#updateSensors} lastUpdate heartbeat for relay+addon devices
|
||||
*
|
||||
* @author Markus Michels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ShellyComponentsTest {
|
||||
|
||||
// ── hasAddon ─────────────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void hasAddon_allNull_returnsFalse() {
|
||||
assertThat(ShellyComponents.hasAddon(new ShellySettingsStatus()), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAddon_extTemperature_returnsTrue() {
|
||||
ShellySettingsStatus s = new ShellySettingsStatus();
|
||||
s.extTemperature = new ShellyExtTemperature();
|
||||
assertThat(ShellyComponents.hasAddon(s), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAddon_extHumidity_returnsTrue() {
|
||||
ShellySettingsStatus s = new ShellySettingsStatus();
|
||||
s.extHumidity = new ShellyExtHumidity();
|
||||
assertThat(ShellyComponents.hasAddon(s), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAddon_extVoltage_returnsTrue() {
|
||||
ShellySettingsStatus s = new ShellySettingsStatus();
|
||||
s.extVoltage = new ShellyExtVoltage();
|
||||
assertThat(ShellyComponents.hasAddon(s), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAddon_extDigitalInput_returnsTrue() {
|
||||
ShellySettingsStatus s = new ShellySettingsStatus();
|
||||
s.extDigitalInput = new ShellyExtDigitalInput();
|
||||
assertThat(ShellyComponents.hasAddon(s), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAddon_extAnalogInput_returnsTrue() {
|
||||
ShellySettingsStatus s = new ShellySettingsStatus();
|
||||
s.extAnalogInput = new ShellyExtAnalogInput();
|
||||
assertThat(ShellyComponents.hasAddon(s), is(true));
|
||||
}
|
||||
|
||||
// ── updateTempChannel ─────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void updateTempChannel_nullSensor_returnsFalse() {
|
||||
ShellyThingInterface handler = mock(ShellyThingInterface.class);
|
||||
assertThat(ShellyComponents.updateTempChannel(null, handler, CHANNEL_ESENSOR_TEMP1), is(false));
|
||||
verify(handler, never()).updateChannel(anyString(), anyString(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateTempChannel_invTemp_publishesUndef() {
|
||||
ShellyThingInterface handler = mock(ShellyThingInterface.class);
|
||||
when(handler.updateChannel(anyString(), anyString(), any())).thenReturn(true);
|
||||
|
||||
ShellyShortTemp sensor = new ShellyShortTemp();
|
||||
sensor.tC = SHELLY_API_INVTEMP;
|
||||
|
||||
assertThat(ShellyComponents.updateTempChannel(sensor, handler, CHANNEL_ESENSOR_TEMP1), is(true));
|
||||
verify(handler).updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_TEMP1, UnDefType.UNDEF);
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateTempChannel_validTemp_publishesQuantityType() {
|
||||
ShellyThingInterface handler = mock(ShellyThingInterface.class);
|
||||
when(handler.updateChannel(anyString(), anyString(), any())).thenReturn(true);
|
||||
|
||||
ShellyShortTemp sensor = new ShellyShortTemp();
|
||||
sensor.tC = 22.5;
|
||||
|
||||
assertThat(ShellyComponents.updateTempChannel(sensor, handler, CHANNEL_ESENSOR_TEMP1), is(true));
|
||||
verify(handler).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_ESENSOR_TEMP1),
|
||||
argThat(s -> s instanceof QuantityType<?>));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateTempChannel_nullTc_returnsFalse() {
|
||||
ShellyThingInterface handler = mock(ShellyThingInterface.class);
|
||||
|
||||
ShellyShortTemp sensor = new ShellyShortTemp();
|
||||
sensor.tC = null;
|
||||
|
||||
assertThat(ShellyComponents.updateTempChannel(sensor, handler, CHANNEL_ESENSOR_TEMP1), is(false));
|
||||
verify(handler, never()).updateChannel(anyString(), anyString(), any());
|
||||
}
|
||||
|
||||
// ── updateSensors — relay + addon ─────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void updateSensors_relayWithAddonTemp_updatesLastUpdate() throws Exception {
|
||||
ShellyThingInterface handler = relayHandlerWith(new ShellySettingsStatus());
|
||||
ShellySettingsStatus status = new ShellySettingsStatus();
|
||||
ShellyExtTemperature ext1 = new ShellyExtTemperature();
|
||||
ext1.sensor1 = sensorAt(20.0);
|
||||
status.extTemperature = ext1;
|
||||
|
||||
ShellyComponents.updateSensors(handler, status);
|
||||
|
||||
verify(handler).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_LAST_UPDATE), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateSensors_relayWithoutAddon_noLastUpdate() throws Exception {
|
||||
ShellyThingInterface handler = relayHandlerWith(new ShellySettingsStatus());
|
||||
ShellySettingsStatus status = new ShellySettingsStatus();
|
||||
// no extTemperature, extHumidity, etc.
|
||||
|
||||
ShellyComponents.updateSensors(handler, status);
|
||||
|
||||
verify(handler, never()).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_LAST_UPDATE), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateSensors_relayWithInvTemp_publishesUndefAndUpdatesLastUpdate() throws Exception {
|
||||
ShellyThingInterface handler = relayHandlerWith(new ShellySettingsStatus());
|
||||
ShellySettingsStatus status = new ShellySettingsStatus();
|
||||
ShellyExtTemperature ext2 = new ShellyExtTemperature();
|
||||
ext2.sensor1 = sensorAt(SHELLY_API_INVTEMP);
|
||||
status.extTemperature = ext2;
|
||||
|
||||
ShellyComponents.updateSensors(handler, status);
|
||||
|
||||
verify(handler).updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_TEMP1, UnDefType.UNDEF);
|
||||
verify(handler).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_LAST_UPDATE), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateSensors_pureRelayNoAddon_lastUpdateNeverWritten() throws Exception {
|
||||
ShellyThingInterface handler = relayHandlerWith(new ShellySettingsStatus());
|
||||
|
||||
ShellyComponents.updateSensors(handler, new ShellySettingsStatus());
|
||||
|
||||
verify(handler, never()).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_LAST_UPDATE), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateSensors_lastUpdateWrittenEvenWhenTempValueUnchanged() throws Exception {
|
||||
// Critical heartbeat test: even when the temperature channel is cache-deduplicated
|
||||
// (updateChannel returns false), sensors#lastUpdate must still be written so the
|
||||
// channel acts as a "sensor alive" indicator.
|
||||
ShellyThingInterface handler = relayHandlerWith(new ShellySettingsStatus());
|
||||
when(handler.updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_ESENSOR_TEMP1), any())).thenReturn(false); // simulate
|
||||
// cache
|
||||
// dedup
|
||||
|
||||
ShellySettingsStatus status = new ShellySettingsStatus();
|
||||
ShellyExtTemperature ext3 = new ShellyExtTemperature();
|
||||
ext3.sensor1 = sensorAt(22.5);
|
||||
status.extTemperature = ext3;
|
||||
|
||||
boolean result = ShellyComponents.updateSensors(handler, status);
|
||||
|
||||
assertThat("updated must be true even when temp is deduplicated", result, is(true));
|
||||
verify(handler).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_LAST_UPDATE), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateSensors_nullSensorSlot_skipsPublish() throws Exception {
|
||||
// sensor1 valid, sensor2 null — only sensor1 published, sensor2 not touched
|
||||
ShellyThingInterface handler = relayHandlerWith(new ShellySettingsStatus());
|
||||
ShellySettingsStatus status = new ShellySettingsStatus();
|
||||
ShellyExtTemperature ext4 = new ShellyExtTemperature();
|
||||
ext4.sensor1 = sensorAt(21.0);
|
||||
ext4.sensor2 = null;
|
||||
status.extTemperature = ext4;
|
||||
|
||||
ShellyComponents.updateSensors(handler, status);
|
||||
|
||||
verify(handler).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_ESENSOR_TEMP1), any());
|
||||
verify(handler, never()).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_ESENSOR_TEMP2), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateSensors_addonHumidity_updatesLastUpdate() throws Exception {
|
||||
ShellyThingInterface handler = relayHandlerWith(new ShellySettingsStatus());
|
||||
ShellySettingsStatus status = new ShellySettingsStatus();
|
||||
status.extHumidity = new ShellyExtHumidity(55.0);
|
||||
|
||||
ShellyComponents.updateSensors(handler, status);
|
||||
|
||||
verify(handler).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_LAST_UPDATE), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAddon_multipleFieldsSet_returnsTrue() {
|
||||
ShellySettingsStatus s = new ShellySettingsStatus();
|
||||
s.extTemperature = new ShellyExtTemperature();
|
||||
s.extHumidity = new ShellyExtHumidity();
|
||||
assertThat(ShellyComponents.hasAddon(s), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateSensors_voltage_updatesVoltageChannel() throws Exception {
|
||||
ShellyThingInterface handler = relayHandlerWith(new ShellySettingsStatus());
|
||||
ShellySettingsStatus status = new ShellySettingsStatus();
|
||||
status.extVoltage = new ShellyExtVoltage(3.3);
|
||||
|
||||
ShellyComponents.updateSensors(handler, status);
|
||||
|
||||
verify(handler).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_ESENSOR_VOLTAGE),
|
||||
argThat(s -> s instanceof QuantityType<?> && ((QuantityType<?>) s).doubleValue() == 3.3));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateSensors_digitalInput_updatesDigitalInputChannel() throws Exception {
|
||||
ShellyThingInterface handler = relayHandlerWith(new ShellySettingsStatus());
|
||||
ShellySettingsStatus status = new ShellySettingsStatus();
|
||||
status.extDigitalInput = new ShellyExtDigitalInput(true);
|
||||
|
||||
ShellyComponents.updateSensors(handler, status);
|
||||
|
||||
verify(handler).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_ESENSOR_DIGITALINPUT), eq(OnOffType.ON));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateSensors_analogInput_updatesAnalogInputChannel() throws Exception {
|
||||
ShellyThingInterface handler = relayHandlerWith(new ShellySettingsStatus());
|
||||
ShellySettingsStatus status = new ShellySettingsStatus();
|
||||
status.extAnalogInput = new ShellyExtAnalogInput(75.0);
|
||||
|
||||
ShellyComponents.updateSensors(handler, status);
|
||||
|
||||
verify(handler).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_ESENSOR_ANALOGINPUT),
|
||||
argThat(s -> s instanceof QuantityType<?> && ((QuantityType<?>) s).doubleValue() == 75.0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateSensors_multipleExtTempSlots_allPublished() throws Exception {
|
||||
ShellyThingInterface handler = relayHandlerWith(new ShellySettingsStatus());
|
||||
ShellySettingsStatus status = new ShellySettingsStatus();
|
||||
ShellyExtTemperature ext = new ShellyExtTemperature();
|
||||
ext.sensor1 = sensorAt(20.0);
|
||||
ext.sensor2 = sensorAt(21.0);
|
||||
status.extTemperature = ext;
|
||||
|
||||
ShellyComponents.updateSensors(handler, status);
|
||||
|
||||
verify(handler).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_ESENSOR_TEMP1), any());
|
||||
verify(handler).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_ESENSOR_TEMP2), any());
|
||||
verify(handler, never()).updateChannel(eq(CHANNEL_GROUP_SENSOR), eq(CHANNEL_ESENSOR_TEMP3), any());
|
||||
}
|
||||
|
||||
// ── helpers ───────────────────────────────────────────────────────────────
|
||||
|
||||
private static ShellyThingInterface relayHandlerWith(ShellySettingsStatus profileStatus) {
|
||||
ShellyDeviceProfile profile = new ShellyDeviceProfile(THING_TYPE_SHELLYPLUS1PM);
|
||||
profile.isSensor = false;
|
||||
profile.hasBattery = false;
|
||||
profile.status = profileStatus;
|
||||
|
||||
ShellyThingInterface handler = mock(ShellyThingInterface.class);
|
||||
when(handler.getProfile()).thenReturn(profile);
|
||||
when(handler.areChannelsCreated()).thenReturn(true);
|
||||
when(handler.updateChannel(anyString(), anyString(), any())).thenReturn(true);
|
||||
return handler;
|
||||
}
|
||||
|
||||
private static ShellyShortTemp sensorAt(double tC) {
|
||||
ShellyShortTemp s = new ShellyShortTemp();
|
||||
s.tC = tC;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user