Explorar o código

Add support for essentials air purifier.

Issue #214
Jason Rumney %!s(int64=3) %!d(string=hai) anos
pai
achega
e714dee8b9

+ 1 - 0
ACKNOWLEDGEMENTS.md

@@ -106,3 +106,4 @@ Further device support has been made with the assistance of users.  Please consi
 - [illuzn](https://github.com/illuzn) for contributing support for Kogan Tower Heaters.
 - [vnkorol](https://github.com/vnkorol) for assistance supporting 4-way power monitoring strip.
 - [OmegaKill](https://github.com/OmegaKill) for assistance supporting Be Cool heatpumps.
+- [djusHa](https://github.com/djusHa) for contributing support for essentials portable air purifier.

+ 18 - 11
README.md

@@ -7,16 +7,22 @@
 [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=make-all_tuya-local&metric=coverage)](https://sonarcloud.io/dashboard?id=make-all_tuya-local)
 
 This is a Home Assistant add-on to support Wi-fi devices running Tuya
-firmware without going via the Tuya cloud.  Using this integration
-does not stop your devices from sending status to the Tuya cloud, so
-this should not be seen as a security measure, rather it improves
-speed and reliability by using local connections, and may unlock some
-features of your device, or even unlock whole devices, that are not
-supported by the Tuya cloud API.  Currently the focus is mainly on
-more complex devices, which are not well supported by other similar
-integrations. Simpler devices like switches and lights can be covered
-by [rospogrigio/localtuya](https://github.com/rospogrigio/localtuya/),
-though some switches are now covered by this integration.
+firmware without going via the Tuya cloud.  Currently only WiFi
+devices are supported, Tuya also makes Zigbee, BLE and other devices
+that connect to WiFi using a gateway, such devices are not yet
+supported.
+
+Using this integration does not stop your devices from sending status
+to the Tuya cloud, so this should not be seen as a security measure,
+rather it improves speed and reliability by using local connections,
+and may unlock some features of your device, or even unlock whole
+devices, that are not supported by the Tuya cloud API. 
+
+A similar but unrelated integration is
+[rospogrigio/localtuya](https://github.com/rospogrigio/localtuya/), if
+your device is not supported by this integration, you may find it
+easier to set up using that as an alternative.
+
 
 ---
 
@@ -33,7 +39,7 @@ configuration for it in the following locations:
 
 2. If you have signed up for iot.tuya.com to get your local key, you should also have access to the API Explorer under "Cloud".  One of the functions under the "Device Control" section - the last "Get Device Specification Attribute" function listed, returns the dp_id in addition to range information that is needed for integer and enum data types.
 
-3. By following the method described at the link below, you can find information for all the data points supported by your device, including those not listed by the API explorer method above and those that are only returned under specific conditions.
+3. By following the method described at the link below, you can find information for all the data points supported by your device, including those not listed by the API explorer method above and those that are only returned under specific conditions. Ignore the requirement for a Tuya Zigbee gateway, that is for Zigbee devices, and this integration does not currently support devices connected via a gateway, but the non-Zigbee/gateway specific parts of the procedure apply also to WiFi devices.
 
 https://www.zigbee2mqtt.io/advanced/support-new-devices/03_find_tuya_data_points.html
 
@@ -129,6 +135,7 @@ If you submit a pull request, please understand that the config file naming and
 - Himox H05 and H06 air purifiers
 - Tesla Pro and Mini air purifiers
 - Vork VK6067AW air purifier
+- essentials portable air purifier
 
 ### Dehumidifiers
 - Goldair GPDH420 dehumidifier

+ 126 - 0
custom_components/tuya_local/devices/essentials_purifier.yaml

@@ -0,0 +1,126 @@
+name: essentials Air Purifier
+primary_entity:
+  entity: switch
+  icon: "mdi:air-purifier"
+  dps:
+    - id: 1
+      type: boolean
+      name: switch
+secondary_entities:
+  - entity: sensor
+    name: Active Filter Life
+    icon: "mdi:air-filter"
+    category: diagnostic
+    dps:
+      - id: 5
+        type: integer
+        name: sensor
+        readonly: true
+        unit: "%"
+  - entity: lock
+    name: Child Lock
+    category: config
+    dps:
+      - id: 7
+        type: boolean
+        name: lock
+        mapping:
+          - dps_val: true
+            icon: "mdi:hand-back-right-off"
+          - dps_val: false
+            icon: "mdi-hand-back-right"
+  - entity: select
+    name: Light
+    category: config
+    dps:
+      - id: 101
+        name: option
+        type: string
+        mapping:
+          - dps_val: Standard
+            value: "On"
+            icon: "mdi:lightbulb-on"
+          - dps_val: Soft
+            value: "Soft"
+            icon: "mdi:lightbulb-on-outline"
+          - dps_val: Close
+            value: "Off"
+            icon: "mdi:lightbulb-outline"
+  - entity: switch
+    name: UV Disinfection
+    category: config
+    dps:
+      - id: 9
+        type: boolean
+        name: switch
+        mapping:
+          - dps_val: true
+            icon: "mdi:lightbulb"
+          - dps_val: false
+            icon: "mdi:lightbulb-outline"
+  - entity: switch
+    name: Filter Reset
+    category: config
+    icon: "mdi:refresh"
+    dps:
+      - id: 11
+        type: boolean
+        name: switch
+  - entity: select
+    name: Timer
+    icon: "mdi:timer"
+    category: config
+    dps:
+      - id: 18
+        name: option
+        type: string
+        mapping:
+          - dps_val: cancel
+            value: "Off"
+          - dps_val: 2h
+            value: "2 hours"
+          - dps_val: 4h
+            value: "4 hours"
+          - dps_val: 8h
+            value: "8 hours"
+  - entity: sensor
+    name: Timer
+    icon: "mdi:timer"
+    category: diagnostic
+    dps:
+      - id: 19
+        type: integer
+        name: sensor
+        readonly: true
+        unit: "min"
+  - entity: sensor
+    name: PM2.5
+    class: pm25
+    dps:
+      - id: 2
+        type: integer
+        name: sensor
+        class: measurement
+        unit: ugm3
+  - entity: sensor
+    name: Air Quality
+    dps:
+      - id: 21
+        type: string
+        name: sensor
+        readonly: true
+  - entity: select
+    name: Mode
+    dps:
+      - id: 3
+        name: option
+        type: string
+        mapping:
+          - dps_val: auto
+            value: "Auto"
+          - dps_val: "M"
+            value: "Medium"
+          - dps_val: "H"
+            value: "High"
+          - dps_val: "sleep"
+            value: "Sleep"

+ 14 - 0
tests/const.py

@@ -1449,3 +1449,17 @@ BECOOL_HEATPUMP_PAYLOAD = {
     "17": False,
     "19": False,
 }
+
+ESSENTIALS_PURIFIER_PAYLOAD = {
+    "1": True,
+    "2": 12,
+    "3": "auto",
+    "5": 50,
+    "7": False,
+    "9": False,
+    "11": False,
+    "18": "cancel",
+    "19": 0,
+    "21": "good",
+    "101": "Standard",
+}

+ 125 - 0
tests/devices/test_essentials_purifier.py

@@ -0,0 +1,125 @@
+"""Tests for the essentials air purifier."""
+from homeassistant.components.sensor import SensorDeviceClass
+from homeassistant.const import (
+    CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
+    PERCENTAGE,
+    TIME_MINUTES,
+)
+
+from ..const import ESSENTIALS_PURIFIER_PAYLOAD
+from ..mixins.lock import BasicLockTests
+from ..mixins.select import MultiSelectTests
+from ..mixins.sensor import MultiSensorTests
+from ..mixins.switch import MultiSwitchTests
+from .base_device_tests import TuyaDeviceTestCase
+
+SWITCH_DP = "1"
+PM25_DP = "2"
+MODE_DP = "3"
+FILTER_DP = "5"
+LOCK_DP = "7"
+UV_DP = "9"
+RESET_DP = "11"
+TIMER_DP = "18"
+COUNTDOWN_DP = "19"
+QUALITY_DP = "21"
+LIGHT_DP = "101"
+
+
+class TestEssentialsPurifier(
+    BasicLockTests,
+    MultiSelectTests,
+    MultiSensorTests,
+    MultiSwitchTests,
+    TuyaDeviceTestCase,
+):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig("essentials_purifier.yaml", ESSENTIALS_PURIFIER_PAYLOAD)
+        self.setUpBasicLock(LOCK_DP, self.entities.get("lock_child_lock"))
+        self.setUpMultiSelect(
+            [
+                {
+                    "dps": LIGHT_DP,
+                    "name": "select_light",
+                    "options": {
+                        "Standard": "On",
+                        "Soft": "Soft",
+                        "Close": "Off",
+                    },
+                },
+                {
+                    "dps": TIMER_DP,
+                    "name": "select_timer",
+                    "options": {
+                        "cancel": "Off",
+                        "2h": "2 hours",
+                        "4h": "4 hours",
+                        "8h": "8 hours",
+                    },
+                },
+                {
+                    "dps": MODE_DP,
+                    "name": "select_mode",
+                    "options": {
+                        "auto": "Auto",
+                        "M": "Medium",
+                        "H": "High",
+                        "sleep": "Sleep",
+                    },
+                },
+            ]
+        )
+        self.setUpMultiSensors(
+            [
+                {
+                    "dps": FILTER_DP,
+                    "name": "sensor_active_filter_life",
+                    "unit": PERCENTAGE,
+                },
+                {
+                    "dps": COUNTDOWN_DP,
+                    "name": "sensor_timer",
+                    "unit": TIME_MINUTES,
+                },
+                {
+                    "dps": PM25_DP,
+                    "name": "sensor_pm2_5",
+                    "unit": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
+                    "device_class": SensorDeviceClass.PM25,
+                    "state_class": "measurement",
+                },
+                {
+                    "dps": QUALITY_DP,
+                    "name": "sensor_air_quality",
+                },
+            ]
+        )
+        self.setUpMultiSwitch(
+            [
+                {
+                    "dps": SWITCH_DP,
+                    "name": "switch",
+                },
+                {
+                    "dps": UV_DP,
+                    "name": "switch_uv_disinfection",
+                },
+                {
+                    "dps": RESET_DP,
+                    "name": "switch_filter_reset",
+                },
+            ]
+        )
+        self.mark_secondary(
+            [
+                "sensor_active_filter_life",
+                "lock_child_lock",
+                "select_light",
+                "switch_uv_disinfection",
+                "switch_filter_reset",
+                "select_timer",
+                "sensor_timer",
+            ]
+        )