Skip to content

Commit bafd342

Browse files
authored
Add initial support for tuya cwjwq (home-assistant#148420)
1 parent fae6b37 commit bafd342

File tree

10 files changed

+321
-0
lines changed

10 files changed

+321
-0
lines changed

homeassistant/components/tuya/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,7 @@ class DPCode(StrEnum):
406406
WIRELESS_ELECTRICITY = "wireless_electricity"
407407
WORK_MODE = "work_mode" # Working mode
408408
WORK_POWER = "work_power"
409+
WORK_STATE_E = "work_state_e"
409410

410411

411412
@dataclass

homeassistant/components/tuya/select.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,15 @@
5555
entity_category=EntityCategory.CONFIG,
5656
),
5757
),
58+
# Smart Odor Eliminator-Pro
59+
# Undocumented, see https://github.com/orgs/home-assistant/discussions/79
60+
"cwjwq": (
61+
SelectEntityDescription(
62+
key=DPCode.WORK_MODE,
63+
entity_category=EntityCategory.CONFIG,
64+
translation_key="odor_elimination_mode",
65+
),
66+
),
5867
# Multi-functional Sensor
5968
# https://developer.tuya.com/en/docs/iot/categorydgnbj?id=Kaiuz3yorvzg3
6069
"dgnbj": (

homeassistant/components/tuya/sensor.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,15 @@ class TuyaSensorEntityDescription(SensorEntityDescription):
220220
state_class=SensorStateClass.MEASUREMENT,
221221
),
222222
),
223+
# Smart Odor Eliminator-Pro
224+
# Undocumented, see https://github.com/orgs/home-assistant/discussions/79
225+
"cwjwq": (
226+
TuyaSensorEntityDescription(
227+
key=DPCode.WORK_STATE_E,
228+
translation_key="odor_elimination_status",
229+
),
230+
*BATTERY_SENSORS,
231+
),
223232
# Smart Pet Feeder
224233
# https://developer.tuya.com/en/docs/iot/categorycwwsq?id=Kaiuz2b6vydld
225234
"cwwsq": (

homeassistant/components/tuya/strings.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,13 @@
485485
"level_9": "Level 9",
486486
"level_10": "High"
487487
}
488+
},
489+
"odor_elimination_mode": {
490+
"name": "Odor elimination mode",
491+
"state": {
492+
"smart": "Smart",
493+
"interim": "Interim"
494+
}
488495
}
489496
},
490497
"sensor": {
@@ -697,6 +704,15 @@
697704
},
698705
"water_time": {
699706
"name": "Water usage duration"
707+
},
708+
"odor_elimination_status": {
709+
"name": "Status",
710+
"state": {
711+
"work": "Working",
712+
"standby": "[%key:common::state::standby%]",
713+
"charging": "[%key:common::state::charging%]",
714+
"charge_done": "Charge done"
715+
}
700716
}
701717
},
702718
"switch": {

homeassistant/components/tuya/switch.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,14 @@
8585
entity_category=EntityCategory.CONFIG,
8686
),
8787
),
88+
# Smart Odor Eliminator-Pro
89+
# Undocumented, see https://github.com/orgs/home-assistant/discussions/79
90+
"cwjwq": (
91+
SwitchEntityDescription(
92+
key=DPCode.SWITCH,
93+
translation_key="switch",
94+
),
95+
),
8896
# Smart Pet Feeder
8997
# https://developer.tuya.com/en/docs/iot/categorycwwsq?id=Kaiuz2b6vydld
9098
"cwwsq": (

tests/components/tuya/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@
4545
Platform.FAN,
4646
Platform.HUMIDIFIER,
4747
],
48+
"cwjwq_smart_odor_eliminator": [
49+
# https://github.com/orgs/home-assistant/discussions/79
50+
Platform.SELECT,
51+
Platform.SENSOR,
52+
Platform.SWITCH,
53+
],
4854
"cwwsq_cleverio_pf100": [
4955
# https://github.com/home-assistant/core/issues/144745
5056
Platform.NUMBER,
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
{
2+
"endpoint": "https://apigw.tuyaeu.com",
3+
"terminal_id": "1750837476328i3TNXQ",
4+
"mqtt_connected": true,
5+
"disabled_by": null,
6+
"disabled_polling": false,
7+
"id": "bf6574iutyikgwkx",
8+
"name": "Smart Odor Eliminator-Pro",
9+
"category": "cwjwq",
10+
"product_id": "agwu93lr",
11+
"product_name": "Smart Odor Eliminator-Pro",
12+
"online": false,
13+
"sub": false,
14+
"time_zone": "+02:00",
15+
"active_time": "2025-06-25T07:43:07+00:00",
16+
"create_time": "2025-06-25T07:43:07+00:00",
17+
"update_time": "2025-06-25T07:43:07+00:00",
18+
"function": {
19+
"switch": {
20+
"type": "Boolean",
21+
"value": {}
22+
},
23+
"work_mode": {
24+
"type": "Enum",
25+
"value": {
26+
"range": ["smart", "interim"]
27+
}
28+
}
29+
},
30+
"status_range": {
31+
"switch": {
32+
"type": "Boolean",
33+
"value": {}
34+
},
35+
"work_mode": {
36+
"type": "Enum",
37+
"value": {
38+
"range": ["smart", "interim"]
39+
}
40+
},
41+
"work_state_e": {
42+
"type": "Enum",
43+
"value": {
44+
"range": ["work", "standby", "charging", "charge_done"]
45+
}
46+
},
47+
"battery_percentage": {
48+
"type": "Integer",
49+
"value": {
50+
"unit": "%",
51+
"min": 0,
52+
"max": 100,
53+
"scale": 0,
54+
"step": 1
55+
}
56+
}
57+
},
58+
"status": {
59+
"switch": false,
60+
"work_mode": "smart",
61+
"work_state_e": "work",
62+
"battery_percentage": 43
63+
},
64+
"set_up": false,
65+
"support_local": true
66+
}

tests/components/tuya/snapshots/test_select.ambr

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,63 @@
178178
'state': 'unavailable',
179179
})
180180
# ---
181+
# name: test_platform_setup_and_discovery[cwjwq_smart_odor_eliminator][select.smart_odor_eliminator_pro_odor_elimination_mode-entry]
182+
EntityRegistryEntrySnapshot({
183+
'aliases': set({
184+
}),
185+
'area_id': None,
186+
'capabilities': dict({
187+
'options': list([
188+
'smart',
189+
'interim',
190+
]),
191+
}),
192+
'config_entry_id': <ANY>,
193+
'config_subentry_id': <ANY>,
194+
'device_class': None,
195+
'device_id': <ANY>,
196+
'disabled_by': None,
197+
'domain': 'select',
198+
'entity_category': <EntityCategory.CONFIG: 'config'>,
199+
'entity_id': 'select.smart_odor_eliminator_pro_odor_elimination_mode',
200+
'has_entity_name': True,
201+
'hidden_by': None,
202+
'icon': None,
203+
'id': <ANY>,
204+
'labels': set({
205+
}),
206+
'name': None,
207+
'options': dict({
208+
}),
209+
'original_device_class': None,
210+
'original_icon': None,
211+
'original_name': 'Odor elimination mode',
212+
'platform': 'tuya',
213+
'previous_unique_id': None,
214+
'suggested_object_id': None,
215+
'supported_features': 0,
216+
'translation_key': 'odor_elimination_mode',
217+
'unique_id': 'tuya.bf6574iutyikgwkxwork_mode',
218+
'unit_of_measurement': None,
219+
})
220+
# ---
221+
# name: test_platform_setup_and_discovery[cwjwq_smart_odor_eliminator][select.smart_odor_eliminator_pro_odor_elimination_mode-state]
222+
StateSnapshot({
223+
'attributes': ReadOnlyDict({
224+
'friendly_name': 'Smart Odor Eliminator-Pro Odor elimination mode',
225+
'options': list([
226+
'smart',
227+
'interim',
228+
]),
229+
}),
230+
'context': <ANY>,
231+
'entity_id': 'select.smart_odor_eliminator_pro_odor_elimination_mode',
232+
'last_changed': <ANY>,
233+
'last_reported': <ANY>,
234+
'last_updated': <ANY>,
235+
'state': 'unavailable',
236+
})
237+
# ---
181238
# name: test_platform_setup_and_discovery[kj_bladeless_tower_fan][select.bree_countdown-entry]
182239
EntityRegistryEntrySnapshot({
183240
'aliases': set({

tests/components/tuya/snapshots/test_sensor.ambr

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,107 @@
105105
'state': 'unavailable',
106106
})
107107
# ---
108+
# name: test_platform_setup_and_discovery[cwjwq_smart_odor_eliminator][sensor.smart_odor_eliminator_pro_battery-entry]
109+
EntityRegistryEntrySnapshot({
110+
'aliases': set({
111+
}),
112+
'area_id': None,
113+
'capabilities': dict({
114+
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
115+
}),
116+
'config_entry_id': <ANY>,
117+
'config_subentry_id': <ANY>,
118+
'device_class': None,
119+
'device_id': <ANY>,
120+
'disabled_by': None,
121+
'domain': 'sensor',
122+
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
123+
'entity_id': 'sensor.smart_odor_eliminator_pro_battery',
124+
'has_entity_name': True,
125+
'hidden_by': None,
126+
'icon': None,
127+
'id': <ANY>,
128+
'labels': set({
129+
}),
130+
'name': None,
131+
'options': dict({
132+
}),
133+
'original_device_class': <SensorDeviceClass.BATTERY: 'battery'>,
134+
'original_icon': None,
135+
'original_name': 'Battery',
136+
'platform': 'tuya',
137+
'previous_unique_id': None,
138+
'suggested_object_id': None,
139+
'supported_features': 0,
140+
'translation_key': 'battery',
141+
'unique_id': 'tuya.bf6574iutyikgwkxbattery_percentage',
142+
'unit_of_measurement': '%',
143+
})
144+
# ---
145+
# name: test_platform_setup_and_discovery[cwjwq_smart_odor_eliminator][sensor.smart_odor_eliminator_pro_battery-state]
146+
StateSnapshot({
147+
'attributes': ReadOnlyDict({
148+
'device_class': 'battery',
149+
'friendly_name': 'Smart Odor Eliminator-Pro Battery',
150+
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
151+
'unit_of_measurement': '%',
152+
}),
153+
'context': <ANY>,
154+
'entity_id': 'sensor.smart_odor_eliminator_pro_battery',
155+
'last_changed': <ANY>,
156+
'last_reported': <ANY>,
157+
'last_updated': <ANY>,
158+
'state': 'unavailable',
159+
})
160+
# ---
161+
# name: test_platform_setup_and_discovery[cwjwq_smart_odor_eliminator][sensor.smart_odor_eliminator_pro_status-entry]
162+
EntityRegistryEntrySnapshot({
163+
'aliases': set({
164+
}),
165+
'area_id': None,
166+
'capabilities': None,
167+
'config_entry_id': <ANY>,
168+
'config_subentry_id': <ANY>,
169+
'device_class': None,
170+
'device_id': <ANY>,
171+
'disabled_by': None,
172+
'domain': 'sensor',
173+
'entity_category': None,
174+
'entity_id': 'sensor.smart_odor_eliminator_pro_status',
175+
'has_entity_name': True,
176+
'hidden_by': None,
177+
'icon': None,
178+
'id': <ANY>,
179+
'labels': set({
180+
}),
181+
'name': None,
182+
'options': dict({
183+
}),
184+
'original_device_class': None,
185+
'original_icon': None,
186+
'original_name': 'Status',
187+
'platform': 'tuya',
188+
'previous_unique_id': None,
189+
'suggested_object_id': None,
190+
'supported_features': 0,
191+
'translation_key': 'odor_elimination_status',
192+
'unique_id': 'tuya.bf6574iutyikgwkxwork_state_e',
193+
'unit_of_measurement': None,
194+
})
195+
# ---
196+
# name: test_platform_setup_and_discovery[cwjwq_smart_odor_eliminator][sensor.smart_odor_eliminator_pro_status-state]
197+
StateSnapshot({
198+
'attributes': ReadOnlyDict({
199+
'friendly_name': 'Smart Odor Eliminator-Pro Status',
200+
}),
201+
'context': <ANY>,
202+
'entity_id': 'sensor.smart_odor_eliminator_pro_status',
203+
'last_changed': <ANY>,
204+
'last_reported': <ANY>,
205+
'last_updated': <ANY>,
206+
'state': 'unavailable',
207+
})
208+
# ---
108209
# name: test_platform_setup_and_discovery[cwwsq_cleverio_pf100][sensor.cleverio_pf100_last_amount-entry]
109210
EntityRegistryEntrySnapshot({
110211
'aliases': set({

tests/components/tuya/snapshots/test_switch.ambr

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,54 @@
146146
'state': 'unavailable',
147147
})
148148
# ---
149+
# name: test_platform_setup_and_discovery[cwjwq_smart_odor_eliminator][switch.smart_odor_eliminator_pro_switch-entry]
150+
EntityRegistryEntrySnapshot({
151+
'aliases': set({
152+
}),
153+
'area_id': None,
154+
'capabilities': None,
155+
'config_entry_id': <ANY>,
156+
'config_subentry_id': <ANY>,
157+
'device_class': None,
158+
'device_id': <ANY>,
159+
'disabled_by': None,
160+
'domain': 'switch',
161+
'entity_category': None,
162+
'entity_id': 'switch.smart_odor_eliminator_pro_switch',
163+
'has_entity_name': True,
164+
'hidden_by': None,
165+
'icon': None,
166+
'id': <ANY>,
167+
'labels': set({
168+
}),
169+
'name': None,
170+
'options': dict({
171+
}),
172+
'original_device_class': None,
173+
'original_icon': None,
174+
'original_name': 'Switch',
175+
'platform': 'tuya',
176+
'previous_unique_id': None,
177+
'suggested_object_id': None,
178+
'supported_features': 0,
179+
'translation_key': 'switch',
180+
'unique_id': 'tuya.bf6574iutyikgwkxswitch',
181+
'unit_of_measurement': None,
182+
})
183+
# ---
184+
# name: test_platform_setup_and_discovery[cwjwq_smart_odor_eliminator][switch.smart_odor_eliminator_pro_switch-state]
185+
StateSnapshot({
186+
'attributes': ReadOnlyDict({
187+
'friendly_name': 'Smart Odor Eliminator-Pro Switch',
188+
}),
189+
'context': <ANY>,
190+
'entity_id': 'switch.smart_odor_eliminator_pro_switch',
191+
'last_changed': <ANY>,
192+
'last_reported': <ANY>,
193+
'last_updated': <ANY>,
194+
'state': 'unavailable',
195+
})
196+
# ---
149197
# name: test_platform_setup_and_discovery[cwysj_pixi_smart_drinking_fountain][switch.pixi_smart_drinking_fountain_filter_reset-entry]
150198
EntityRegistryEntrySnapshot({
151199
'aliases': set({

0 commit comments

Comments
 (0)