Просмотр исходного кода

Add support for Parkside Smart Charger

Issue #136
Jason Rumney 3 лет назад
Родитель
Сommit
fe185a21e4

+ 147 - 0
custom_components/tuya_local/devices/parkside_plgs2012a1_smart_charger.yaml

@@ -0,0 +1,147 @@
+name: Parkside PLGS2012A1 Charger
+product:
+  - id: h6pglenun37dzsgo
+primary_entity:
+  entity: switch
+  icon: "mdi:ev-station"
+  dps:
+    - id: 1
+      type: boolean
+      name: switch
+    - id: 11
+      type: string
+      name: unknown_11
+secondary_entities:
+  - entity: number
+    name: Charge Current
+    icon: "mdi:current-dc"
+    category: config
+    dps:
+      - id: 3
+        type: integer
+        name: value
+        range:
+          min: 0
+          max: 30000
+        mapping:
+          - step: 100
+        unit: mA
+  - entity: number
+    name: Charge Voltage
+    icon: "mdi:battery-charging"
+    category: config
+    dps:
+      - id: 4
+        type: integer
+        name: value
+        range:
+          min: 0
+          max: 25000
+        mapping:
+          - scale: 1000
+            step: 100
+        unit: V
+  - entity: switch
+    name: Storage
+    category: config
+    dps:
+      - id: 8
+        type: boolean
+        name: switch
+        mapping:
+          - dps_val: true
+            icon: "mdi:battery-60"
+          - dps_val: false
+            icon: "mdi:battery"
+  - entity: switch
+    name: Temperature Limiter
+    category: config
+    icon: "mdi:thermometer-alert"
+    dps:
+      - id: 9
+        type: boolean
+        name: switch
+  - entity: sensor
+    name: Battery
+    class: battery
+    dps:
+      - id: 5
+        type: integer
+        name: sensor
+        unit: "%"
+  - entity: sensor
+    name: Current Temperature
+    class: temperature
+    category: diagnostic
+    dps:
+      - id: 6
+        type: integer
+        name: sensor
+        unit: C
+        class: measurement
+  - entity: sensor
+    name: Max Temperature Count
+    icon: "mdi:thermometer-plus"
+    category: diagnostic
+    dps:
+      - id: 10
+        type: integer
+        name: sensor
+  - entity: sensor
+    name: Name
+    icon: "mdi:form-textbox"
+    category: diagnostic
+    dps:
+      - id: 2
+        type: string
+        name: sensor
+  - entity: select
+    name: Charge Type
+    icon: "mdi:battery-unknown"
+    category: config
+    dps:
+      - id: 7
+        type: string
+        name: option
+        mapping:
+          - dps_val: ECO
+            value: Eco
+          - dps_val: quick
+            value: Performance
+          - dps_val: standard
+            value: Balanced
+          - dps_val: individual
+            value: Expert
+  - entity: sensor
+    name: Max Current
+    class: current
+    category: diagnostic
+    dps:
+      - id: 101
+        type: integer
+        name: sensor
+        unit: mA
+  - entity: sensor
+    name: Time Remaining
+    icon: "mdi:battery-clock"
+    dps:
+      - id: 102
+        type: integer
+        name: sensor
+        unit: min
+  - entity: binary_sensor
+    name: Almost Charged
+    icon: "mdi:battery-charging-90"
+    category: diagnostic
+    dps:
+      - id: 103
+        type: boolean
+        name: sensor
+  - entity: binary_sensor
+    name: Fully Charged
+    icon: "mdi:battery-charging-100"
+    category: diagnostic
+    dps:
+      - id: 104
+        type: boolean
+        name: sensor

+ 3 - 1
custom_components/tuya_local/helpers/device_config.py

@@ -44,12 +44,14 @@ def _scale_range(r, s):
 _unsignedFmts = {
     1: "B",
     2: "H",
+    3: "3s",
     4: "I",
 }
 
 _signedFmts = {
     1: "b",
     2: "h",
+    3: "3s",
     4: "i",
 }
 
@@ -304,7 +306,7 @@ class TuyaDpsConfig:
                     max = range.get("max")
                 else:
                     min = 0
-                    max = 256**bytes - 1
+                    max = 256 ** bytes - 1
 
                 unpack_fmt = unpack_fmt + _bytesToFmt(bytes, min < 0)
                 ranges.append({"min": min, "max": max})

+ 22 - 0
custom_components/tuya_local/translations/en.json

@@ -33,6 +33,8 @@
                     "sensor": "Include a sensor entity",
                     "switch": "Include a switch entity",
 		    "vacuum": "Include a vacuum entity",
+		    "binary_sensor_almost_charged": "Include almost charged as a binary sensor",
+		    "binary_sensor_fully_charged": "Include fully charged as a binary sensor",
                     "binary_sensor_continuous_heat": "Include continuous heat alarm as a binary_sensor entity",
                     "binary_sensor_defrost": "Include defrost as a binary_sensor entity",
 		    "binary_sensor_door_open": "Include door open as a binary sensor",
@@ -74,6 +76,8 @@
                     "number_calibration_swing": "Include calibration swing as a number entity",
                     "number_calibration_swing_external": "Include calibration swing for external sensor as a number entity",
                     "number_calibration_swing_internal": "Include calibration swing for internal sensor as a number entity",
+		    "number_charge_current": "Include charge current as a number entity",
+		    "number_charge_voltage": "Include charge voltage as a number entity",
 		    "number_compressor_delay": "Include compressor delay as a number entity",
 		    "number_cooling_hysteresis": "Include cooling hysteresis as a number entity",
 		    "number_heating_hysteresis": "Include heating hysteresis as a number entity",
@@ -93,6 +97,7 @@
                     "number_timer_3": "Include timer 3 as a number entity",
                     "number_timer_4": "Include timer 4 as a number entity",
                     "number_usb_timer": "Include timer USB as a number entity",
+		    "select_charge_type": "Include charge type as a select entity",
                     "select_configuration": "Include configuration as a select entity",
                     "select_initial_state": "Include initial state as a select entity",
                     "select_installation": "Include installation as a select entity",
@@ -119,12 +124,16 @@
                     "sensor_external_temperature": "Include external temperature as a sensor entity",
                     "sensor_floor_temperature": "Include floor temperature as a sensor entity",
                     "sensor_hepa_filter_life": "Include HEPA filter life as a sensor entity",
+		    "sensor_max_current": "Include max current as a sensor entity",
+		    "sensor_max_temperature_count": "Include max temperature count as a sensor entity",
+		    "sensor_name": "Include name as a sensor entity",
                     "sensor_open": "Include open as a sensor entity",
                     "sensor_power": "Include power as a sensor entity",
                     "sensor_power_level": "Include power level as a sensor entity",
                     "sensor_pm2_5": "Include PM2.5 as a sensor entity",
                     "sensor_prefilter_life": "Include prefilter life as a sensor entity",
 		    "sensor_status": "Include status as a sensor entity",
+                    "sensor_time_remaining": "Include time remaining as a sensor entity",
                     "sensor_timer": "Include time remaining as a sensor entity",
                     "sensor_voltage": "Include voltage as a sensor entity",
                     "sensor_ambient_temperature": "Include ambient temperature as a sensor entity",
@@ -156,6 +165,8 @@
 		    "switch_prepay": "Include prepay as a switch entity",
                     "switch_sleep": "Include sleep mode as a switch entity",
                     "switch_sound": "Include sound mute as a switch entity",
+		    "switch_storage": "Include storage as a switch entity",
+		    "switch_temperature_limiter": "Include Temperature Limiter as a switch entity",
 		    "switch_time_sync": "Include time sync as a switch entity",
                     "switch_usb_switch": "Include USB as a switch entity",
                     "switch_uv_sterilization": "Include UV sterilization as a switch"
@@ -190,6 +201,8 @@
                     "sensor": "Include a sensor entity",
                     "switch": "Include a switch entity",
 		    "vacuum": "Include a vacuum entity",
+		    "binary_sensor_almost_charged": "Include almost charged as a binary sensor",
+		    "binary_sensor_fully_charged": "Include fully charged as a binary sensor",
                     "binary_sensor_continuous_heat": "Include continuous heat alarm as a binary_sensor entity",
                     "binary_sensor_defrost": "Include defrost as a binary_sensor entity",
 		    "binary_sensor_door_open": "Include door open as a binary sensor",
@@ -231,6 +244,8 @@
                     "number_calibration_swing": "Include calibration swing as a number entity",
                     "number_calibration_swing_external": "Include calibration swing for external sensor as a number entity",
                     "number_calibration_swing_internal": "Include calibration swing for internal sensor as a number entity",
+		    "number_charge_current": "Include charge current as a number entity",
+		    "number_charge_voltage": "Include charge voltage as a number entity",
 		    "number_compressor_delay": "Include compressor delay as a number entity",
 		    "number_cooling_hysteresis": "Include cooling hysteresis as a number entity",
 		    "number_heating_hysteresis": "Include heating hysteresis as a number entity",
@@ -250,6 +265,7 @@
                     "number_timer_3": "Include timer 3 as a number entity",
                     "number_timer_4": "Include timer 4 as a number entity",
                     "number_usb_timer": "Include timer USB as a number entity",
+		    "select_charge_type": "Include charge type as a select entity",
                     "select_configuration": "Include configuration as a select entity",
                     "select_initial_state": "Include initial state as a select entity",
                     "select_installation": "Include installation as a select entity",
@@ -276,12 +292,16 @@
                     "sensor_external_temperature": "Include external temperature as a sensor entity",
                     "sensor_floor_temperature": "Include floor temperature as a sensor entity",
                     "sensor_hepa_filter_life": "Include HEPA filter life as a sensor entity",
+		    "sensor_max_current": "Include max current as a sensor entity",
+		    "sensor_max_temperature_count": "Include max temperature count as a sensor entity",
+		    "sensor_name": "Include name as a sensor entity",
                     "sensor_open": "Include open as a sensor entity",
                     "sensor_power": "Include power as a sensor entity",
                     "sensor_power_level": "Include power level as a sensor entity",
                     "sensor_pm2_5": "Include PM2.5 as a sensor entity",
                     "sensor_prefilter_life": "Include prefilter life as a sensor entity",
 		    "sensor_status": "Include status as a sensor entity",
+                    "sensor_time_remaining": "Include time remaining as a sensor entity",
                     "sensor_timer": "Include time remaining as a sensor entity",
                     "sensor_voltage": "Include voltage as a sensor entity",
                     "sensor_ambient_temperature": "Include ambient temperature as a sensor entity",
@@ -313,6 +333,8 @@
 		    "switch_prepay": "Include prepay as a switch entity",
                     "switch_sleep": "Include sleep mode as a switch entity",
                     "switch_sound": "Include sound mute as a switch entity",
+		    "switch_storage": "Include storage as a switch entity",
+		    "switch_temperature_limiter": "Include Temperature Limiter as a switch entity",
 		    "switch_time_sync": "Include time sync as a switch entity",
                     "switch_usb_switch": "Include USB as a switch entity",
                     "switch_uv_sterilization": "Include UV sterilization as a switch"

+ 18 - 0
tests/const.py

@@ -1069,3 +1069,21 @@ LOGICOM_STRIPPY_PAYLOAD = {
     "12": 0,
     "13": 0,
 }
+
+PARKSIDE_PLGS2012A1_PAYLOAD = {
+    "1": True,
+    "2": "test",
+    "3": 1000,
+    "4": 1320,
+    "5": 80,
+    "6": 25,
+    "7": "standard",
+    "8": False,
+    "9": True,
+    "10": 5,
+    "11": "unknown",
+    "101": 2500,
+    "102": 11,
+    "103": False,
+    "104": False,
+}

+ 174 - 0
tests/devices/test_parkside_plgs2012a1_smart_charger.py

@@ -0,0 +1,174 @@
+"""Tests for Parkside PLGS 2012 A1 Smart Charger"""
+from homeassistant.const import (
+    ELECTRIC_CURRENT_MILLIAMPERE,
+    ELECTRIC_POTENTIAL_VOLT,
+    PERCENTAGE,
+    TEMP_CELSIUS,
+    TIME_MINUTES,
+)
+from homeassistant.components.sensor import (
+    DEVICE_CLASS_BATTERY,
+    DEVICE_CLASS_CURRENT,
+    DEVICE_CLASS_TEMPERATURE,
+    STATE_CLASS_MEASUREMENT,
+)
+from ..const import PARKSIDE_PLGS2012A1_PAYLOAD
+from ..mixins.binary_sensor import MultiBinarySensorTests
+from ..mixins.number import MultiNumberTests
+from ..mixins.select import BasicSelectTests
+from ..mixins.sensor import MultiSensorTests
+from ..mixins.switch import MultiSwitchTests
+from .base_device_tests import TuyaDeviceTestCase
+
+SWITCH_DPS = "1"
+NAME_DPS = "2"
+CURRENT_DPS = "3"
+VOLTAGE_DPS = "4"
+BATTERY_DPS = "5"
+TEMPERATURE_DPS = "6"
+MODE_DPS = "7"
+STORAGE_DPS = "8"
+LIMITER_DPS = "9"
+MAXTEMPCOUNT_DPS = "10"
+UNKNOWN11_DPS = "11"
+MAXCURRENT_DPS = "101"
+REMAIN_DPS = "102"
+ALMOSTCHARGED_DPS = "103"
+FULLYCHARGED_DPS = "104"
+
+
+class TestParksidePLGS2012A1Charger(
+    MultiBinarySensorTests,
+    MultiNumberTests,
+    BasicSelectTests,
+    MultiSensorTests,
+    MultiSwitchTests,
+    TuyaDeviceTestCase,
+):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig(
+            "parkside_plgs2012a1_smart_charger.yaml", PARKSIDE_PLGS2012A1_PAYLOAD
+        )
+        self.setUpMultiBinarySensors(
+            [
+                {
+                    "name": "binary_sensor_almost_charged",
+                    "dps": ALMOSTCHARGED_DPS,
+                },
+                {
+                    "name": "binary_sensor_fully_charged",
+                    "dps": FULLYCHARGED_DPS,
+                },
+            ],
+        )
+        self.setUpMultiNumber(
+            [
+                {
+                    "name": "number_charge_current",
+                    "dps": CURRENT_DPS,
+                    "max": 30000,
+                    "step": 100,
+                    "unit": ELECTRIC_CURRENT_MILLIAMPERE,
+                },
+                {
+                    "name": "number_charge_voltage",
+                    "dps": VOLTAGE_DPS,
+                    "max": 25.0,
+                    "scale": 1000,
+                    "step": 0.1,
+                    "unit": ELECTRIC_POTENTIAL_VOLT,
+                },
+            ],
+        )
+        self.setUpBasicSelect(
+            MODE_DPS,
+            self.entities.get("select_charge_type"),
+            {
+                "ECO": "Eco",
+                "quick": "Performance",
+                "standard": "Balanced",
+                "individual": "Expert",
+            },
+        )
+        self.setUpMultiSensors(
+            [
+                {
+                    "name": "sensor_battery",
+                    "dps": BATTERY_DPS,
+                    "unit": PERCENTAGE,
+                    "device_class": DEVICE_CLASS_BATTERY,
+                },
+                {
+                    "name": "sensor_time_remaining",
+                    "dps": REMAIN_DPS,
+                    "unit": TIME_MINUTES,
+                },
+                {
+                    "name": "sensor_current_temperature",
+                    "dps": TEMPERATURE_DPS,
+                    "unit": TEMP_CELSIUS,
+                    "device_class": DEVICE_CLASS_TEMPERATURE,
+                    "state_class": STATE_CLASS_MEASUREMENT,
+                },
+                {
+                    "name": "sensor_max_current",
+                    "dps": MAXCURRENT_DPS,
+                    "unit": ELECTRIC_CURRENT_MILLIAMPERE,
+                    "device_class": DEVICE_CLASS_CURRENT,
+                },
+                {
+                    "name": "sensor_max_temperature_count",
+                    "dps": MAXTEMPCOUNT_DPS,
+                },
+                {
+                    "name": "sensor_name",
+                    "dps": NAME_DPS,
+                    "testdata": ("test", "test"),
+                },
+            ],
+        )
+        self.setUpMultiSwitch(
+            [
+                {
+                    "name": "switch",
+                    "dps": SWITCH_DPS,
+                },
+                {
+                    "name": "switch_storage",
+                    "dps": STORAGE_DPS,
+                },
+                {
+                    "name": "switch_temperature_limiter",
+                    "dps": LIMITER_DPS,
+                },
+            ],
+        )
+
+        self.mark_secondary(
+            [
+                "number_charge_current",
+                "number_charge_voltage",
+                "switch_storage",
+                "switch_temperature_limiter",
+                "sensor_current_temperature",
+                "sensor_max_temperature_count",
+                "sensor_name",
+                "select_charge_type",
+                "sensor_max_current",
+                "binary_sensor_almost_charged",
+                "binary_sensor_fully_charged",
+            ]
+        )
+
+    def test_multi_switch_state_attributes(self):
+        switch = self.multiSwitch.get("switch")
+        storage = self.multiSwitch.get("switch_storage")
+        temp = self.multiSwitch.get("switch_temperature_limiter")
+        self.assertEqual(storage.extra_state_attributes, {})
+        self.assertEqual(temp.extra_state_attributes, {})
+        self.dps[UNKNOWN11_DPS] = "unknown_11"
+        self.assertDictEqual(
+            switch.extra_state_attributes, {"unknown_11": "unknown_11"}
+        )