Skip to content

Commit f75e7ef

Browse files
committed
Add support for ELV-SH-SMSI (#595)
1 parent b1a5755 commit f75e7ef

File tree

8 files changed

+234
-4
lines changed

8 files changed

+234
-4
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [UNRELEASED](https://github.com/hahn-th/homematicip-rest-api/compare/2.2.0..master)
99

10+
### Added
11+
12+
- Add device SoilMoistureSensorInterface to support ELV-SH-SMSI
13+
- Add channel SoilMoistureSensorInterfaceChannel to support ELV-SH-SMSI
14+
1015
### Fixed
1116

1217
- Fix params for sendDoorCommand

homematicip_demo/json_data/home.json

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14956,6 +14956,167 @@
1495614956
"serializedGlobalTradeItemNumber": "3014F71100000000000SHWSM",
1495714957
"type": "WATERING_ACTUATOR",
1495814958
"updateState": "UP_TO_DATE"
14959+
},
14960+
"3014F7110000000ELVSHSMSI": {
14961+
"availableFirmwareVersion": "0.0.0",
14962+
"connectionType": "HMIP_RF",
14963+
"deviceArchetype": "HMIP",
14964+
"firmwareVersion": "1.0.12",
14965+
"firmwareVersionInteger": 65548,
14966+
"functionalChannels": {
14967+
"0": {
14968+
"altitude": null,
14969+
"busConfigMismatch": null,
14970+
"coProFaulty": false,
14971+
"coProRestartNeeded": false,
14972+
"coProUpdateFailure": false,
14973+
"configPending": true,
14974+
"controlsMountingOrientation": null,
14975+
"daliBusState": null,
14976+
"dataDecodingFailedError": null,
14977+
"defaultLinkedGroup": [],
14978+
"deviceAliveSignalEnabled": null,
14979+
"deviceCommunicationError": null,
14980+
"deviceDriveError": null,
14981+
"deviceDriveModeError": null,
14982+
"deviceId": "3014F7110000000ELVSHSMSI",
14983+
"deviceOperationMode": null,
14984+
"deviceOverheated": false,
14985+
"deviceOverloaded": false,
14986+
"devicePowerFailureDetected": false,
14987+
"deviceUndervoltage": false,
14988+
"displayContrast": null,
14989+
"displayMode": null,
14990+
"displayMountingOrientation": null,
14991+
"dutyCycle": false,
14992+
"frostProtectionError": null,
14993+
"frostProtectionErrorAcknowledged": null,
14994+
"functionalChannelType": "DEVICE_BASE",
14995+
"groupIndex": 0,
14996+
"groups": [
14997+
"00000000-0000-0000-0000-000000000057"
14998+
],
14999+
"index": 0,
15000+
"inputLayoutMode": null,
15001+
"invertedDisplayColors": null,
15002+
"label": "",
15003+
"lockJammed": null,
15004+
"lowBat": false,
15005+
"mountingModuleError": null,
15006+
"mountingOrientation": null,
15007+
"multicastRoutingEnabled": false,
15008+
"noDataFromLinkyError": null,
15009+
"operationDays": null,
15010+
"particulateMatterSensorCommunicationError": null,
15011+
"particulateMatterSensorError": null,
15012+
"powerShortCircuit": null,
15013+
"profilePeriodLimitReached": null,
15014+
"routerModuleEnabled": false,
15015+
"routerModuleSupported": false,
15016+
"rssiDeviceValue": -78,
15017+
"rssiPeerValue": null,
15018+
"sensorCommunicationError": null,
15019+
"sensorError": null,
15020+
"shortCircuitDataLine": null,
15021+
"supportedOptionalFeatures": {
15022+
"IFeatureBusConfigMismatch": false,
15023+
"IFeatureDataDecodingFailedError": false,
15024+
"IFeatureDeviceCoProError": false,
15025+
"IFeatureDeviceCoProRestart": false,
15026+
"IFeatureDeviceCoProUpdate": false,
15027+
"IFeatureDeviceCommunicationError": false,
15028+
"IFeatureDeviceDaliBusError": false,
15029+
"IFeatureDeviceDriveError": false,
15030+
"IFeatureDeviceDriveModeError": false,
15031+
"IFeatureDeviceIdentify": false,
15032+
"IFeatureDeviceMountingModuleError": false,
15033+
"IFeatureDeviceOverheated": false,
15034+
"IFeatureDeviceOverloaded": false,
15035+
"IFeatureDeviceParticulateMatterSensorCommunicationError": false,
15036+
"IFeatureDeviceParticulateMatterSensorError": false,
15037+
"IFeatureDevicePowerFailure": false,
15038+
"IFeatureDeviceSensorCommunicationError": false,
15039+
"IFeatureDeviceSensorError": false,
15040+
"IFeatureDeviceTempSensorError": false,
15041+
"IFeatureDeviceTemperatureHumiditySensorCommunicationError": false,
15042+
"IFeatureDeviceTemperatureHumiditySensorError": false,
15043+
"IFeatureDeviceTemperatureOutOfRange": false,
15044+
"IFeatureDeviceUndervoltage": false,
15045+
"IFeatureMulticastRouter": false,
15046+
"IFeatureNoDataFromLinkyError": false,
15047+
"IFeaturePowerShortCircuit": false,
15048+
"IFeatureProfilePeriodLimit": false,
15049+
"IFeatureRssiValue": true,
15050+
"IFeatureShortCircuitDataLine": false,
15051+
"IFeatureTicVersionError": false,
15052+
"IOptionalFeatureAltitude": false,
15053+
"IOptionalFeatureDefaultLinkedGroup": false,
15054+
"IOptionalFeatureDeviceAliveSignalEnabled": false,
15055+
"IOptionalFeatureDeviceErrorLockJammed": false,
15056+
"IOptionalFeatureDeviceFrostProtectionError": false,
15057+
"IOptionalFeatureDeviceInputLayoutMode": false,
15058+
"IOptionalFeatureDeviceOperationMode": false,
15059+
"IOptionalFeatureDeviceSwitchChannelMode": false,
15060+
"IOptionalFeatureDeviceValveError": false,
15061+
"IOptionalFeatureDeviceWaterError": false,
15062+
"IOptionalFeatureDisplayContrast": false,
15063+
"IOptionalFeatureDisplayMode": false,
15064+
"IOptionalFeatureDutyCycle": true,
15065+
"IOptionalFeatureInvertedDisplayColors": false,
15066+
"IOptionalFeatureLowBat": true,
15067+
"IOptionalFeatureMountingOrientation": false,
15068+
"IOptionalFeatureOperationDays": false
15069+
},
15070+
"switchChannelMode": null,
15071+
"temperatureHumiditySensorCommunicationError": null,
15072+
"temperatureHumiditySensorError": null,
15073+
"temperatureOutOfRange": false,
15074+
"temperatureSensorError": null,
15075+
"ticVersionError": null,
15076+
"unreach": false,
15077+
"valveFlowError": null,
15078+
"valveWaterError": null
15079+
},
15080+
"1": {
15081+
"channelRole": "SOIL_MOISTURE_SENSOR",
15082+
"deviceId": "3014F7110000000ELVSHSMSI",
15083+
"functionalChannelType": "SOIL_MOISTURE_SENSOR_INTERFACE_CHANNEL",
15084+
"groupIndex": 1,
15085+
"groups": [
15086+
"00000000-0000-0000-0000-000000000135"
15087+
],
15088+
"index": 1,
15089+
"label": "",
15090+
"measuringInterval": 10,
15091+
"soilMoisture": 56,
15092+
"soilMoistureMaximumReference": 3000,
15093+
"soilMoistureMinimumReference": 3900,
15094+
"soilMoistureNeutralMaximum": 80,
15095+
"soilMoistureNeutralMinimum": 20,
15096+
"soilMoistureRawValue": 3439,
15097+
"soilTemperature": 21.5,
15098+
"soilTemperatureNeutralMaximum": 28.0,
15099+
"soilTemperatureNeutralMinimum": 5.0,
15100+
"supportedOptionalFeatures": {
15101+
"IFeatureLightGroupSensorChannel": false
15102+
}
15103+
}
15104+
},
15105+
"homeId": "00000000-0000-0000-0000-000000000001",
15106+
"id": "3014F7110000000ELVSHSMSI",
15107+
"label": "Bodenfeuchtesensor",
15108+
"lastStatusUpdate": 1754056327352,
15109+
"liveUpdateState": "LIVE_UPDATE_NOT_SUPPORTED",
15110+
"manuallyUpdateForced": false,
15111+
"manufacturerCode": 9,
15112+
"measuredAttributes": {},
15113+
"modelId": 596,
15114+
"modelType": "ELV-SH-SMSI",
15115+
"oem": "eQ-3",
15116+
"permanentlyReachable": false,
15117+
"serializedGlobalTradeItemNumber": "3014F7110000000ELVSHSMSI",
15118+
"type": "SOIL_MOISTURE_SENSOR_INTERFACE",
15119+
"updateState": "UP_TO_DATE"
1495915120
}
1496015121
},
1496115122
"groups": {

src/homematicip/base/enums.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ class DeviceType(AutoNameEnum):
278278
SHUTTER_CONTACT_MAGNETIC = auto()
279279
SHUTTER_CONTACT_OPTICAL_PLUS = auto()
280280
SMOKE_DETECTOR = auto()
281+
SOIL_MOISTURE_SENSOR_INTERFACE = auto()
281282
SWITCH_MEASURING_CABLE_OUTDOOR = auto()
282283
TEMPERATURE_HUMIDITY_SENSOR = auto()
283284
TEMPERATURE_HUMIDITY_SENSOR_COMPACT = auto()
@@ -500,6 +501,7 @@ class FunctionalChannelType(AutoNameEnum):
500501
SHUTTER_CONTACT_CHANNEL = auto()
501502
SINGLE_KEY_CHANNEL = auto()
502503
SMOKE_DETECTOR_CHANNEL = auto()
504+
SOIL_MOISTURE_SENSOR_INTERFACE_CHANNEL = auto()
503505
SWITCH_CHANNEL = auto()
504506
SWITCH_MEASURING_CHANNEL = auto()
505507
TEMPERATURE_SENSOR_2_EXTERNAL_DELTA_CHANNEL = auto()

src/homematicip/base/functionalChannels.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,6 @@ def from_json(self, js, groups: Iterable[Group]):
985985
self.supportingSelfCalibration = js["supportingSelfCalibration"]
986986
self.userDesiredProfileMode = js["userDesiredProfileMode"]
987987

988-
989988
def set_shutter_stop(self):
990989
return self._run_non_async(self.async_set_shutter_stop)
991990

@@ -2180,7 +2179,7 @@ async def set_hue_saturation_dim_level_async(self, hue: int, saturation_level: f
21802179
)
21812180

21822181
async def set_hue_saturation_dim_level_with_time_async(self, hue: int, saturation_level: float, dim_level: float,
2183-
on_time: float, ramp_time: float):
2182+
on_time: float, ramp_time: float):
21842183
return await functional_channel_commands.set_hue_saturation_dim_level_with_time_async(
21852184
self._connection, self.device.id, self.index, hue, saturation_level, dim_level, on_time, ramp_time
21862185
)
@@ -2198,6 +2197,7 @@ async def start_light_scene_async(self, light_scene_id: int, dim_level: float =
21982197
self._connection, self.device.id, self.index, light_scene_id, dim_level
21992198
)
22002199

2200+
22012201
class UniversalLightChannelGroup(UniversalLightChannel):
22022202
"""Universal-Light-Channel-Group."""
22032203

@@ -2281,4 +2281,36 @@ async def toggle_watering_state_async(self):
22812281
"""Toggles the watering state of the specified device."""
22822282
return await functional_channel_commands.toggle_watering_state_async(
22832283
self._connection, self.device.id, self.index
2284-
)
2284+
)
2285+
2286+
2287+
class SoilMoistureSensorInterfaceChannel(FunctionalChannel):
2288+
"""This is the representative of the SOIL_MOISTURE_SENSOR_INTERFACE_CHANNEL channel."""
2289+
2290+
def __init__(self, device, connection):
2291+
super().__init__(device, connection)
2292+
self.measuringInterval: int | None = None
2293+
self.soilMoisture: int | None = None
2294+
self.soilMoistureMaximumReference: int | None = None
2295+
self.soilMoistureMinimumReference: int | None = None
2296+
self.soilMoistureNeutralMaximum: int | None = None
2297+
self.soilMoistureNeutralMinimum: int | None = None
2298+
self.soilMoistureRawValue: int | None = None
2299+
self.soilTemperature: float | None = None
2300+
self.soilTemperatureNeutralMaximum: float | None = None
2301+
self.soilTemperatureNeutralMinimum: float | None = None
2302+
2303+
def from_json(self, js, groups: Iterable[Group]):
2304+
"""Update the channel attributes from a JSON dictionary."""
2305+
2306+
super().from_json(js, groups)
2307+
self.measuringInterval = js.get("measuringInterval", self.measuringInterval)
2308+
self.soilMoisture = js.get("soilMoisture", self.soilMoisture)
2309+
self.soilMoistureMaximumReference = js.get("soilMoistureMaximumReference", self.soilMoistureMaximumReference)
2310+
self.soilMoistureMinimumReference = js.get("soilMoistureMinimumReference", self.soilMoistureMinimumReference)
2311+
self.soilMoistureNeutralMaximum = js.get("soilMoistureNeutralMaximum", self.soilMoistureNeutralMaximum)
2312+
self.soilMoistureNeutralMinimum = js.get("soilMoistureNeutralMinimum", self.soilMoistureNeutralMinimum)
2313+
self.soilMoistureRawValue = js.get("soilMoistureRawValue", self.soilMoistureRawValue)
2314+
self.soilTemperature = js.get("soilTemperature", self.soilTemperature)
2315+
self.soilTemperatureNeutralMaximum = js.get("soilTemperatureNeutralMaximum", self.soilTemperatureNeutralMaximum)
2316+
self.soilTemperatureNeutralMinimum = js.get("soilTemperatureNeutralMinimum", self.soilTemperatureNeutralMinimum)

src/homematicip/class_maps.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
DeviceType.SHUTTER_CONTACT_MAGNETIC: ShutterContactMagnetic,
8686
DeviceType.SHUTTER_CONTACT_OPTICAL_PLUS: ShutterContactOpticalPlus,
8787
DeviceType.SMOKE_DETECTOR: SmokeDetector,
88+
DeviceType.SOIL_MOISTURE_SENSOR_INTERFACE: SoilMoistureSensorInterface,
8889
DeviceType.SWITCH_MEASURING_CABLE_OUTDOOR: SwitchMeasuring,
8990
DeviceType.TEMPERATURE_HUMIDITY_SENSOR: TemperatureHumiditySensorWithoutDisplay,
9091
DeviceType.TEMPERATURE_HUMIDITY_SENSOR_COMPACT: TemperatureHumiditySensorOutdoor,
@@ -249,6 +250,7 @@
249250
FunctionalChannelType.SHUTTER_CONTACT_CHANNEL: ShutterContactChannel,
250251
FunctionalChannelType.SINGLE_KEY_CHANNEL: SingleKeyChannel,
251252
FunctionalChannelType.SMOKE_DETECTOR_CHANNEL: SmokeDetectorChannel,
253+
FunctionalChannelType.SOIL_MOISTURE_SENSOR_INTERFACE_CHANNEL: SoilMoistureSensorInterfaceChannel,
252254
FunctionalChannelType.SWITCH_CHANNEL: SwitchChannel,
253255
FunctionalChannelType.SWITCH_MEASURING_CHANNEL: SwitchMeasuringChannel,
254256
FunctionalChannelType.TEMPERATURE_SENSOR_2_EXTERNAL_DELTA_CHANNEL: TemperatureDifferenceSensor2Channel,

src/homematicip/device.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,10 @@ class BrandSwitch2(Switch):
951951
"""ELV-SH-BS2 (ELV Smart Home ARR-Bausatz Schaltaktor für Markenschalter – 2-fach powered by Homematic IP)"""
952952

953953

954+
class SoilMoistureSensorInterface(Device):
955+
"""ELV-SH-SMSI (Soil Moisture Sensor Interface)"""
956+
957+
954958
class SwitchMeasuring(Switch):
955959
"""Generic class for Switch and Meter"""
956960

tests/test_devices.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1828,7 +1828,14 @@ def test_wall_mounted_keypad(fake_home: Home):
18281828
d = fake_home.search_device_by_id("3014F7110000000000000WKP")
18291829
assert isinstance(d, WallMountedKeyPad)
18301830

1831+
18311832
def test_watering_actuator(fake_home: Home):
18321833
with no_ssl_verification():
18331834
d = fake_home.search_device_by_id("3014F71100000000000SHWSM")
1834-
assert isinstance(d, WateringActuator)
1835+
assert isinstance(d, WateringActuator)
1836+
1837+
1838+
def test_soil_moisture_sensor_interface(fake_home: Home):
1839+
with no_ssl_verification():
1840+
d = fake_home.search_device_by_id("3014F7110000000ELVSHSMSI")
1841+
assert isinstance(d, SoilMoistureSensorInterface)

tests/test_functional_channels.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,3 +541,20 @@ async def test_watering_actuator_channel(fake_home: Home):
541541
await ch.toggle_watering_state_async()
542542

543543
assert len(connection_mock.mock_calls) == 4
544+
545+
546+
def test_soil_moisture_sensor_interface_channel(fake_home: Home):
547+
with no_ssl_verification():
548+
ch = fake_home.search_channel("3014F7110000000ELVSHSMSI", 1)
549+
assert isinstance(ch, SoilMoistureSensorInterfaceChannel)
550+
551+
assert ch.measuringInterval == 10
552+
assert ch.soilMoisture == 56
553+
assert ch.soilMoistureMaximumReference == 3000
554+
assert ch.soilMoistureMinimumReference == 3900
555+
assert ch.soilMoistureNeutralMaximum == 80
556+
assert ch.soilMoistureNeutralMinimum == 20
557+
assert ch.soilMoistureRawValue == 3439
558+
assert ch.soilTemperature == 21.5
559+
assert ch.soilTemperatureNeutralMaximum == 28.0
560+
assert ch.soilTemperatureNeutralMinimum == 5.0

0 commit comments

Comments
 (0)