Skip to content

Commit a0cef80

Browse files
authored
Add sensors for switchbot cloud integration (home-assistant#147663)
1 parent 343b177 commit a0cef80

File tree

12 files changed

+1047
-72
lines changed

12 files changed

+1047
-72
lines changed

homeassistant/components/switchbot_cloud/__init__.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,27 @@ async def make_device_data(
189189
hass, entry, api, device, coordinators_by_id
190190
)
191191
devices_data.fans.append((device, coordinator))
192+
if isinstance(device, Device) and device.device_type in [
193+
"Motion Sensor",
194+
"Contact Sensor",
195+
]:
196+
coordinator = await coordinator_for_device(
197+
hass, entry, api, device, coordinators_by_id, True
198+
)
199+
devices_data.sensors.append((device, coordinator))
200+
devices_data.binary_sensors.append((device, coordinator))
201+
if isinstance(device, Device) and device.device_type in ["Hub 3"]:
202+
coordinator = await coordinator_for_device(
203+
hass, entry, api, device, coordinators_by_id, True
204+
)
205+
devices_data.sensors.append((device, coordinator))
206+
devices_data.binary_sensors.append((device, coordinator))
207+
if isinstance(device, Device) and device.device_type in ["Water Detector"]:
208+
coordinator = await coordinator_for_device(
209+
hass, entry, api, device, coordinators_by_id, True
210+
)
211+
devices_data.binary_sensors.append((device, coordinator))
212+
devices_data.sensors.append((device, coordinator))
192213

193214
if isinstance(device, Device) and device.device_type in [
194215
"Battery Circulator Fan",
@@ -377,7 +398,7 @@ async def _internal_handle_webhook(
377398
):
378399
_LOGGER.debug("Received invalid data from switchbot webhook %s", repr(data))
379400
return
380-
401+
_LOGGER.debug("Received data from switchbot webhook: %s", repr(data))
381402
deviceMac = data["context"]["deviceMac"]
382403

383404
if deviceMac not in coordinators_by_id:

homeassistant/components/switchbot_cloud/binary_sensor.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""Support for SwitchBot Cloud binary sensors."""
22

3+
from collections.abc import Callable
34
from dataclasses import dataclass
5+
from typing import Any
46

57
from switchbot_api import Device, SwitchBotAPI
68

@@ -26,6 +28,7 @@ class SwitchBotCloudBinarySensorEntityDescription(BinarySensorEntityDescription)
2628

2729
# Value or values to consider binary sensor to be "on"
2830
on_value: bool | str = True
31+
value_fn: Callable[[dict[str, Any]], bool | None] | None = None
2932

3033

3134
CALIBRATION_DESCRIPTION = SwitchBotCloudBinarySensorEntityDescription(
@@ -43,6 +46,34 @@ class SwitchBotCloudBinarySensorEntityDescription(BinarySensorEntityDescription)
4346
on_value="opened",
4447
)
4548

49+
MOVE_DETECTED_DESCRIPTION = SwitchBotCloudBinarySensorEntityDescription(
50+
key="moveDetected",
51+
device_class=BinarySensorDeviceClass.MOTION,
52+
value_fn=(
53+
lambda data: data.get("moveDetected") is True
54+
or data.get("detectionState") == "DETECTED"
55+
),
56+
)
57+
58+
IS_LIGHT_DESCRIPTION = SwitchBotCloudBinarySensorEntityDescription(
59+
key="brightness",
60+
device_class=BinarySensorDeviceClass.LIGHT,
61+
on_value="bright",
62+
)
63+
64+
LEAK_DESCRIPTION = SwitchBotCloudBinarySensorEntityDescription(
65+
key="status",
66+
device_class=BinarySensorDeviceClass.MOISTURE,
67+
value_fn=lambda data: any(data.get(key) for key in ("status", "detectionState")),
68+
)
69+
70+
OPEN_DESCRIPTION = SwitchBotCloudBinarySensorEntityDescription(
71+
key="openState",
72+
device_class=BinarySensorDeviceClass.OPENING,
73+
value_fn=lambda data: data.get("openState") in ("open", "timeOutNotClose"),
74+
)
75+
76+
4677
BINARY_SENSOR_DESCRIPTIONS_BY_DEVICE_TYPES = {
4778
"Smart Lock": (
4879
CALIBRATION_DESCRIPTION,
@@ -65,6 +96,14 @@ class SwitchBotCloudBinarySensorEntityDescription(BinarySensorEntityDescription)
6596
"Roller Shade": (CALIBRATION_DESCRIPTION,),
6697
"Blind Tilt": (CALIBRATION_DESCRIPTION,),
6798
"Garage Door Opener": (DOOR_OPEN_DESCRIPTION,),
99+
"Motion Sensor": (MOVE_DETECTED_DESCRIPTION,),
100+
"Contact Sensor": (
101+
MOVE_DETECTED_DESCRIPTION,
102+
IS_LIGHT_DESCRIPTION,
103+
OPEN_DESCRIPTION,
104+
),
105+
"Hub 3": (MOVE_DETECTED_DESCRIPTION,),
106+
"Water Detector": (LEAK_DESCRIPTION,),
68107
}
69108

70109

@@ -108,6 +147,9 @@ def is_on(self) -> bool | None:
108147
if not self.coordinator.data:
109148
return None
110149

150+
if self.entity_description.value_fn:
151+
return self.entity_description.value_fn(self.coordinator.data)
152+
111153
return (
112154
self.coordinator.data.get(self.entity_description.key)
113155
== self.entity_description.on_value

homeassistant/components/switchbot_cloud/icons.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,23 @@
1717
}
1818
}
1919
}
20+
},
21+
"sensor": {
22+
"light_level": {
23+
"default": "mdi:brightness-7",
24+
"state": {
25+
"1": "mdi:brightness-1",
26+
"2": "mdi:brightness-1",
27+
"3": "mdi:brightness-1",
28+
"4": "mdi:brightness-1",
29+
"5": "mdi:brightness-2",
30+
"6": "mdi:brightness-3",
31+
"7": "mdi:brightness-4",
32+
"8": "mdi:brightness-5",
33+
"9": "mdi:brightness-6",
34+
"10": "mdi:brightness-7"
35+
}
36+
}
2037
}
2138
}
2239
}

homeassistant/components/switchbot_cloud/sensor.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
SENSOR_TYPE_POWER = "power"
3333
SENSOR_TYPE_VOLTAGE = "voltage"
3434
SENSOR_TYPE_CURRENT = "electricCurrent"
35+
SENSOR_TYPE_LIGHTLEVEL = "lightLevel"
36+
3537

3638
TEMPERATURE_DESCRIPTION = SensorEntityDescription(
3739
key=SENSOR_TYPE_TEMPERATURE,
@@ -89,6 +91,13 @@
8991
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
9092
)
9193

94+
LIGHTLEVEL_DESCRIPTION = SensorEntityDescription(
95+
key="lightLevel",
96+
translation_key="light_level",
97+
state_class=SensorStateClass.MEASUREMENT,
98+
)
99+
100+
92101
SENSOR_DESCRIPTIONS_BY_DEVICE_TYPES = {
93102
"Bot": (BATTERY_DESCRIPTION,),
94103
"Battery Circulator Fan": (BATTERY_DESCRIPTION,),
@@ -143,6 +152,14 @@
143152
"Curtain3": (BATTERY_DESCRIPTION,),
144153
"Roller Shade": (BATTERY_DESCRIPTION,),
145154
"Blind Tilt": (BATTERY_DESCRIPTION,),
155+
"Hub 3": (
156+
TEMPERATURE_DESCRIPTION,
157+
HUMIDITY_DESCRIPTION,
158+
LIGHTLEVEL_DESCRIPTION,
159+
),
160+
"Motion Sensor": (BATTERY_DESCRIPTION,),
161+
"Contact Sensor": (BATTERY_DESCRIPTION,),
162+
"Water Detector": (BATTERY_DESCRIPTION,),
146163
}
147164

148165

homeassistant/components/switchbot_cloud/strings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131
}
3232
}
3333
}
34+
},
35+
"sensor": {
36+
"light_level": {
37+
"name": "Light level"
38+
}
3439
}
3540
}
3641
}

tests/components/switchbot_cloud/__init__.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,44 @@ async def configure_integration(hass: HomeAssistant) -> MockConfigEntry:
4040
deviceType="Battery Circulator Fan",
4141
hubDeviceId="test-hub-id",
4242
)
43+
44+
45+
METER_INFO = Device(
46+
version="V1.0",
47+
deviceId="meter-id-1",
48+
deviceName="meter-1",
49+
deviceType="Meter",
50+
hubDeviceId="test-hub-id",
51+
)
52+
53+
CONTACT_SENSOR_INFO = Device(
54+
version="V1.7",
55+
deviceId="contact-sensor-id",
56+
deviceName="contact-sensor-name",
57+
deviceType="Contact Sensor",
58+
hubDeviceId="test-hub-id",
59+
)
60+
61+
HUB3_INFO = Device(
62+
version="V1.3-0.8-0.1",
63+
deviceId="hub3-id",
64+
deviceName="Hub-3-name",
65+
deviceType="Hub 3",
66+
hubDeviceId="test-hub-id",
67+
)
68+
69+
MOTION_SENSOR_INFO = Device(
70+
version="V1.9",
71+
deviceId="motion-sensor-id",
72+
deviceName="motion-sensor-name",
73+
deviceType="Motion Sensor",
74+
hubDeviceId="test-hub-id",
75+
)
76+
77+
WATER_DETECTOR_INFO = Device(
78+
version="V1.7",
79+
deviceId="water-detector-id",
80+
deviceName="water-detector-name",
81+
deviceType="Water Detector",
82+
hubDeviceId="test-hub-id",
83+
)

tests/components/switchbot_cloud/fixtures/meter_status.json

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
[
2+
{},
3+
{
4+
"version": "V3.3",
5+
"temperature": 21.8,
6+
"battery": 100,
7+
"humidity": 32,
8+
"deviceId": "meter-id-1",
9+
"deviceType": "Meter",
10+
"hubDeviceId": "test-hub-id"
11+
},
12+
{
13+
"version": "V1.7",
14+
"battery": 60,
15+
"moveDetected": true,
16+
"brightness": "bright",
17+
"openState": "timeOutNotClose",
18+
"deviceId": "contact-sensor-id",
19+
"deviceType": "Contact Sensor",
20+
"hubDeviceId": "test-hub-id"
21+
},
22+
{
23+
"version": "V1.3-0.8-0.1",
24+
"temperature": 26.5,
25+
"lightLevel": 10,
26+
"humidity": 55,
27+
"moveDetected": false,
28+
"deviceId": "hub3-id",
29+
"deviceType": "Hub 3",
30+
"hubDeviceId": "test-hub-id"
31+
},
32+
{
33+
"version": "V1.9",
34+
"battery": 20,
35+
"moveDetected": false,
36+
"deviceId": "motion-sensor-id",
37+
"deviceType": "Motion Sensor",
38+
"hubDeviceId": "test-hub-id"
39+
},
40+
{
41+
"version": "V1.7",
42+
"battery": 90,
43+
"status": 1,
44+
"deviceId": "water-detector-id",
45+
"deviceType": "Water Detector",
46+
"hubDeviceId": "test-hub-id"
47+
}
48+
]

0 commit comments

Comments
 (0)