Parcourir la source

Add support for Nashone MTS-700-WB Thermostat smartplugs.

Issue #101
Jason Rumney il y a 4 ans
Parent
commit
9c23dd7bc5

+ 2 - 1
ACKNOWLEDGEMENTS.md

@@ -69,4 +69,5 @@ Further device support has been made with the assistance of users.  Please consi
  - [edwinyoo44](https://github.com/edwinyoo44) for contributing support for JJPro JPD01 dehumidifiers and assistance with Poiema One purifiers.
  - [mpetcuRO](https://github.com/mpetcuRO) for assistance with Hysen HT08WE-2 thermometers.
  - [Paul-C-S](https://github.com/Paul-C-S) for assistance with Ecostrad Accent iQ heaters.
- 
+ - [WildeRNS](https://github.com/WildeRNS) for assistance with Nashone MTS-700-WB thermostat smartplugs.
+

+ 376 - 375
README.md

@@ -1,375 +1,376 @@
-# Home Assistant Tuya Local component
-
-[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=make-all_tuya-local&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=make-all_tuya-local)
-[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=make-all_tuya-local&metric=security_rating)](https://sonarcloud.io/dashboard?id=make-all_tuya-local)
-[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=make-all_tuya-local&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=make-all_tuya-local)
-[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=make-all_tuya-local&metric=ncloc)](https://sonarcloud.io/dashboard?id=make-all_tuya-local)
-[![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.
-
----
-
-## Device support
-
-Please note, this component is actively tested with the Goldair GPPH
-(inverter), GPDH420 (dehumidifier), Kogan SmarterHome 1500W Smart
-Panel Heater and Kogan SmarterHome Energy Monitoring SmartPlug. Other
-devices have been added at user request, and may or may not still be
-actively in use by others.
-
-Note that devices sometimes get firmware upgrades, or incompatible
-versions are sold under the same model name, so it is possible that
-the device will not work despite being listed below.
-
-### Heaters
-
-- Goldair heater models beginning with the code GPPH, GCPV, GECO
-- Kogan Wi-Fi Convection Panel heaters - KAHTP and KAWFHTP models
-- Andersson GSH heater
-- Eurom Mon Soleil 300,600,800, 350,601,720 and 300,450,720 Verre heaters
-- Eurom Wall Designheat 2000 heater
-- Purline Hoti M100 heater
-- Wetair WCH-750 heater
-- Kogan Flame effect heater - KAWHMFP20BA model
-- Nedis convection heater - WIFIHTPL20F models
-- Ecostrad Accent iQ heating panels
-
-### Air Conditioners / Heatpumps
-
-- ElectriQ 12WMINV
-- Tadiran Wind 65/3P
-- Fersk Vind 2
-- Carson CB PA280
-- Kogan 2.6kW portable air conditioner
-- Eberg Qubo Q40HD
-
-### Pool heaters / heatpumps
-
-- Garden PAC pool heatpump
-- Madimack Elite V3 pool heatpump
-- Madimack(model unknown) pool heatpump
-- Remora pool heatpump
-- BWT FI 45 heatpump
-- Poolex Silverline and Vertigo heatpump
-- these seem to use two common controllers, and many other Pool heatpumps
-  will work using the above configurations.
-  Report issues if there are any differences in presets or other features,
-  or if any of the "unknown" values that are returned as attributes can
-  be figured out.
-
-### Thermostats
-- Inkbird ITC306A thermostat smartplug (not fully functional)
-- Beca BHP-6000 Room Heat Pump control thermostat
-- Beca BHT-6000/8000 Floor Heating thermostat
-- Beca BHT-002/3000 Floor Heating thermostat (with external temp sensor)
-- Moes BHT-002 thermostat (without external temp sensor)
-- Beca BAC-002 thermostat
-- Awow/Mi-heat TH213 thermostat
-- Siswell T29UTW thermostat
-- Siswell C16 thermostat (rebadged as Warmme, Klima and others)
-- Minco MH-1823D thermostat
-- Owon PCT513 thermostat
-- Beok TR9B thermostat (rebadged as Vancoo and perhaps others)
-- Hysen HY08WE-2 thermostat
-
-### Kettles
-- Kogan Glass 1.7L Smart Kettle (not reliably detected)
-
-### Fans
-- Goldair GCPF315 fan
-- Anko HEGSM40 fan
-- Lexy F501 fan
-- Deta fan controller
-- Arlec Grid Connect Smart Ceiling Fan (without light)
-- Stirling FS1-40DC Pedestal fan
-- Aspen ASP 200 fan
-- TMWF02 fan controller
-
-### Air Purifiers
-- Renpho RP-AP001S air purifier
-- Poiema One air purifier
-
-### Dehumidifiers
-- Goldair GPDH420 dehumidifier
-- ElectriQ CD12PW dehmidifier
-- ElectriQ CD20PRO-LE-V2 dehumidifier
-- ElectriQ CD25PRO-LE-V2 dehumidifier
-- ElectriQ DESD9LW dehumidifier
-- Kogan SmarterHome 7L Desiccant dehumidifier
-- JJPro JPD01 dehumidifer
-
-### Humidifiers
-- Eanons QT-JS2014 Purifying humidifier
-- Wetair WAW-H1210LW humidifier
-
-### SmartPlugs/Wall sockets
-- Generic Smartplug with Energy monitoring (older models)
-  confirmed as working with Kogan Single Smartplugs
-- Generic Smartplug with Energy monitoring (newer models)
-  confirmed working with Kogan single smartplug with USB and Rillpac smartplugs
-- Generic Smartplug with more advanced energy monitoring
-  confirmed working with CBE smartplugs
-- Mirabella Genio Smart plug with USB
-- Grid Connect double outlet with Energy Monitoring, Master and Individual switches and Child Lock.
-- DIGOO DG-SP202 dual smartplug with energy monitoring and timers.
-- Grid Connect double outlet wall socket
-- Woox R4028/DIGOO DG-PS01 3 outlet + USB powerstrip with individual timers.
-Other brands may work with the above configurations
-
-- Simple Switch - a switch only, can be a fallback for many other unsupported devices, to allow just power to be switched on/off.
-- Simple Switch with Timer - a single switch and timer, will probably work for a lot of smart switches that are not covered by the more advanced configs above.
-
-### Covers
-- Simple Garage Door
-
-### Miscellaneous
-- Qoto 03 Smart Water Valve / Sprinkler Controller
-
----
-
-## Installation
-
-[![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge)](https://github.com/custom-components/hacs)
-
-Installation is via the [Home Assistant Community Store
-(HACS)](https://hacs.xyz/), which is the best place to get third-party
-integrations for Home Assistant. Once you have HACS set up, simply
-follow the [instructions for adding a custom
-repository](https://hacs.xyz/docs/faq/custom_repositories) and then
-the integration will be available to install like any other.
-
-## Configuration
-
-You can easily configure your devices using the Integrations configuration UI.
-
-[![Add Integration to your Home Assistant
-instance.](https://my.home-assistant.io/badges/config_flow_start.svg)](https://my.home-assistant.io/redirect/config_flow_start/?domain=tuya_local)
-
-### Stage One
-
-The first stage of configuration is to provide the information needed to
-connect to the device.
-
-You will need to provide your device's IP address or hostname, device
-ID and local key; the last two can be found using [the instructions
-below](#finding-your-device-id-and-local-key).
-
-#### host
-
-    _(string) (Required)_ IP or hostname of the device.
-
-#### device_id
-
-    _(string) (Required)_ Device ID retrieved
-[as per the instructions below](#finding-your-device-id-and-local-key).
-
-#### local_key
-
-    _(string) (Required)_ Local key retrieved
-[as per the instructions below](#finding-your-device-id-and-local-key).
-
-At the end of this step, an attempt is made to connect to the device and see if
-it returns any data. For tuya protocol version 3.3 devices, success
-at this point indicates that all settings you have supplied are correct, but
-for protocol version 3.1 devices, the local key is only used for sending
-commands to the device, so if your local key is incorrect the setup will
-appear to work, and you will not see any problems until you try to control
-your device.  Note that each time you pair the device, the local key changes,
-so if you obtained the local key using the instructions linked above, then
-repaired with your manufacturer's app, then the key will have changed already.
-
-### Stage Two
-
-The second stage of configuration is to select which device you are connecting.
-The list of devices offered will be limited to devices which appear to be
-at least a partial match to the data returned by the device.
-
-#### type
-
-    _(string) (Optional)_ The type of Tuya device.
-Select from the available options.
-
-If you pick the wrong type, you will need to delete the device and set
-it up again.
-
-### Stage Three
-
-The final stage is to choose a name for the device in Home Assistant,
-and select which entities you want to enable.  The options availble
-will depend on the capabilities of the device you selected in the
-previous step.
-
-Usually you will want to accept the defaults at this step.  Entities
-are selected by default, unless they are a deprecated alternative way
-of controlling the device (such as a climate entity for dehumidifiers
-as an alternative to humidifier and fan entities).  If you have
-multiple devices of the same type, you may want to change the name to
-make it easier to distinguish them.
-
-#### name
-
-    _(string) (Required)_ Any unique name for the
-device.  This will be used as the base for the entitiy names in Home
-Assistant.  Although Home Assistant allows you to change the name
-later, it will only change the name used in the UI, not the name of
-the entities.
-
-#### (entities)
-
-    _(boolean) (Optional)_ A number of options
-will be available for each of the entities exposed by the device.
-They will be named for the platform type and an optional name for
-the entity as a suffix (eg `climate`, `humidifier`, `lock_child_lock`)
-Setting them to True will expose the entity in Home Assistant.
-
-## Offline operation gotchas
-
-Many Tuya devices will stop responding if unable to connect to the Tuya servers for an extended period.  Reportedly, some devices act better offline if DNS as well as TCP connections is blocked.
-
-
-## Heater gotchas
-
-Goldair GPPH heaters have individual target temperatures for their
-Comfort and Eco modes, whereas Home Assistant only supports a single
-target temperature. Therefore, when you're in Comfort mode you will
-set the Comfort temperature (`5`-`35`), and when you're in Eco mode
-you will set the Eco temperature (`5`-`21`), just like you were using
-the heater's own control panel. Bear this in mind when writing
-automations that change the operation mode and set a temperature at
-the same time: you must change the operation mode _before_ setting the
-new target temperature, otherwise you will set the current thermostat
-rather than the new one.
-
-When switching to Anti-freeze mode, the heater will set the current
-power level to `1` as if you had manually chosen it. When you switch
-back to other modes, you will no longer be in `Auto` and will have to
-set it again if this is what you wanted. This could be worked around
-in code however it would require storing state that may be cleared if
-HA is restarted and due to this unreliability it's probably best that
-you just factor it into your automations.
-
-When child lock is enabled, the heater's display will flash with the
-child lock symbol (`[]`) whenever you change something in HA. This can
-be confusing because it's the same behaviour as when you try to change
-something via the heater's own control panel and the change is
-rejected due to being locked, however rest assured that the changes
-_are_ taking effect.
-
-When setting the target temperature, different heaters have different
-behaviour, which you may need to compensate for.  From observation,
-GPPH heaters allow the temperature to reach 3 degrees higher than the
-set temperature before turning off, and 1 degree lower before turning
-on again.  Kogan Heaters on the other hand turn off when the
-temperature reaches 1 degree over the targetin LOW mode, and turn on
-again 3 degrees below the target.  To make these heaters act the same
-in LOW power mode, you need to set the Kogan thermostat 2 degrees
-higher than the GPPH thermostat.  In HIGH power mode however, they
-seem to act the same as the GPPH heaters.
-
-The Inkbird thermostat switch does not seem to work for setting
-anything.  If you can figure out how to make setting temperatures and
-presets work, please leave feedback in Issue #19.
-
-## Fan gotchas
-
-Fans should be configured as `fan` entities, with any auxilary
-functions such as panel lighting control, child locks or additional
-switches configured as `light`, `lock` or `switch` entities.
-Configuration of Goldair fans as `climate` entities is supported for
-backward compatibility but is deprecated, and may be removed in
-future.
-
-Reportedly, Goldair fans can be a bit flaky. If they become
-unresponsive, give them about 60 seconds to wake up again.
-
-Anko fans mostly work, except setting the speed does not seem to
-work. If you can figure out how to set the speed through the Tuya
-protocol for these devices, please leave feedback on Issue #22.
-
-
-## Smart Switch gotchas
-
-It has been observed after a while that the current and
-power readings from the switch were returning 0 when there was clearly
-a load on the switch.  After unplugging and replugging, the switch
-started returning only dps 1 and 2 (switch status and timer). If
-HomeAssistant is restarted in that state, the switch detection would
-fail, however as Home Assistant was left running, it continued to work
-with no readings for the current, power and voltage.  I unplugged the
-switch overnight, and in the morning it was working correctly.
-
-Cumulative Energy readings seem to be reset whenever the reading is
-successfully sent to the server.  This leads to the energy usage never moving
-from the minimum reporting level of 0.1kWh, which isn't very useful.
-It may be possible to get useful readings by blocking the switch from accessing
-the internet, otherwise an integration sensor based on the Power sensor
-will need to be set up on the Home Assistant side, and the Energy sensor
-ignored.
-
-## Kogan Kettle gotchas
-
-Although these look like simple devices, their behaviour is not
-consistant so they are difficult to detect.  Sometimes they are
-misdetected as a simple switch, other times they only output the
-temperature sensor so are not detected at all.
-
-## Beca thermostat gotchas
-
-These devices support switching between Celcius and Fahrenheit on the control
-panel, but do not provide any information over the Tuya local protocol about
-which units are selected.  Two configurations for this device are provided,
-`beca_bhp6000_thermostat_c` and `beca_bhp6000_thermostat_f`, please select
-the appropriate one for the temperature units you use.  If you change the
-units on the device control panel, you will need to delete the device from
-Home Assistant and set it up again.
-
-## Siswell C19 thermostat gotchas
-
-These support configuration as either heating or cooling controllers, but
-only have one output.  The HVAC mode is provided as an indicator of which
-mode they are in, but are set to readonly so that you cannot accidentally
-switch the thermostat to the wrong mode from HA.
-
-## Humidifiers and dehumidifiers
-
-Humidifiers and Dehumidifiers should be configuured as `humidifier`
-entities, probably with `fan` entities as well if the fan speed can
-also be controlled, and any other auxilary features such as panel
-lighting, child locks or additional switches configured as `light`,
-`lock` or `switch` entities.  Configration of Goldair Dehumidifiers
-and Eanons Humidifiers as `climate` entities is also supported for
-backwards compatibility, but is deprecated and may be removed in
-future.  In particular, when humidifiers are represented as `climate`
-entities, the running mode will show as `Dry`, as the climate entity
-only supports functions commonly found on air conditioners/heatpumps.
-
-
-## Finding your device ID and local key
-
-You can find these keys the same way as you would for any Tuya local integration. You'll need the Goldair app or the Tuya Tuya Smart app (the Goldair app is just a rebranded Tuya app), then follow these instructions.
-
-- [Instructions for iOS](https://github.com/codetheweb/tuyapi/blob/master/docs/SETUP.md)
-- [Instructions for Android](https://github.com/codetheweb/tuyapi/blob/cdb4289/docs/SETUP_DEPRECATED.md#capture-https-traffic)
-
-## Next steps
-
-1. This component is mosty unit-tested thanks to the upstream project, but there are a few more to complete. Feel free to use existing specs as inspiration and the Sonar Cloud analysis to see where the gaps are.
-2. Once unit tests are complete, the next task is to complete the Home Assistant quality checklist before considering submission to the HA team for inclusion in standard installations.
-3. Discovery seems possible with the new tinytuya library, though the steps to get a local key will most likely remain manual.  Discovery also returns a productKey, which might help make the device detection more reliable where different devices use the same dps mapping but different names for the presets for example.
-
-Please report any issues and feel free to raise pull requests.
-[Many others](https://github.com/make-all/tuya-local/blob/main/ACKNOWLEDGEMENTS.md) have contributed their help already.
-
-
-[![BuyMeCoffee](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/jasonrumney)
+# Home Assistant Tuya Local component
+
+[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=make-all_tuya-local&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=make-all_tuya-local)
+[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=make-all_tuya-local&metric=security_rating)](https://sonarcloud.io/dashboard?id=make-all_tuya-local)
+[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=make-all_tuya-local&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=make-all_tuya-local)
+[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=make-all_tuya-local&metric=ncloc)](https://sonarcloud.io/dashboard?id=make-all_tuya-local)
+[![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.
+
+---
+
+## Device support
+
+Please note, this component is actively tested with the Goldair GPPH
+(inverter), GPDH420 (dehumidifier), Kogan SmarterHome 1500W Smart
+Panel Heater and Kogan SmarterHome Energy Monitoring SmartPlug. Other
+devices have been added at user request, and may or may not still be
+actively in use by others.
+
+Note that devices sometimes get firmware upgrades, or incompatible
+versions are sold under the same model name, so it is possible that
+the device will not work despite being listed below.
+
+### Heaters
+
+- Goldair heater models beginning with the code GPPH, GCPV, GECO
+- Kogan Wi-Fi Convection Panel heaters - KAHTP and KAWFHTP models
+- Andersson GSH heater
+- Eurom Mon Soleil 300,600,800, 350,601,720 and 300,450,720 Verre heaters
+- Eurom Wall Designheat 2000 heater
+- Purline Hoti M100 heater
+- Wetair WCH-750 heater
+- Kogan Flame effect heater - KAWHMFP20BA model
+- Nedis convection heater - WIFIHTPL20F models
+- Ecostrad Accent iQ heating panels
+
+### Air Conditioners / Heatpumps
+
+- ElectriQ 12WMINV
+- Tadiran Wind 65/3P
+- Fersk Vind 2
+- Carson CB PA280
+- Kogan 2.6kW portable air conditioner
+- Eberg Qubo Q40HD
+
+### Pool heaters / heatpumps
+
+- Garden PAC pool heatpump
+- Madimack Elite V3 pool heatpump
+- Madimack(model unknown) pool heatpump
+- Remora pool heatpump
+- BWT FI 45 heatpump
+- Poolex Silverline and Vertigo heatpump
+- these seem to use two common controllers, and many other Pool heatpumps
+  will work using the above configurations.
+  Report issues if there are any differences in presets or other features,
+  or if any of the "unknown" values that are returned as attributes can
+  be figured out.
+
+### Thermostats
+- Inkbird ITC306A thermostat smartplug (not fully functional)
+- Beca BHP-6000 Room Heat Pump control thermostat
+- Beca BHT-6000/8000 Floor Heating thermostat
+- Beca BHT-002/3000 Floor Heating thermostat (with external temp sensor)
+- Moes BHT-002 thermostat (without external temp sensor)
+- Beca BAC-002 thermostat
+- Awow/Mi-heat TH213 thermostat
+- Siswell T29UTW thermostat
+- Siswell C16 thermostat (rebadged as Warmme, Klima and others)
+- Minco MH-1823D thermostat
+- Owon PCT513 thermostat
+- Beok TR9B thermostat (rebadged as Vancoo and perhaps others)
+- Hysen HY08WE-2 thermostat
+- Nashone MTS-700-WB thermostat smartplug
+
+### Kettles
+- Kogan Glass 1.7L Smart Kettle (not reliably detected)
+
+### Fans
+- Goldair GCPF315 fan
+- Anko HEGSM40 fan
+- Lexy F501 fan
+- Deta fan controller
+- Arlec Grid Connect Smart Ceiling Fan (without light)
+- Stirling FS1-40DC Pedestal fan
+- Aspen ASP 200 fan
+- TMWF02 fan controller
+
+### Air Purifiers
+- Renpho RP-AP001S air purifier
+- Poiema One air purifier
+
+### Dehumidifiers
+- Goldair GPDH420 dehumidifier
+- ElectriQ CD12PW dehmidifier
+- ElectriQ CD20PRO-LE-V2 dehumidifier
+- ElectriQ CD25PRO-LE-V2 dehumidifier
+- ElectriQ DESD9LW dehumidifier
+- Kogan SmarterHome 7L Desiccant dehumidifier
+- JJPro JPD01 dehumidifer
+
+### Humidifiers
+- Eanons QT-JS2014 Purifying humidifier
+- Wetair WAW-H1210LW humidifier
+
+### SmartPlugs/Wall sockets
+- Generic Smartplug with Energy monitoring (older models)
+  confirmed as working with Kogan Single Smartplugs
+- Generic Smartplug with Energy monitoring (newer models)
+  confirmed working with Kogan single smartplug with USB and Rillpac smartplugs
+- Generic Smartplug with more advanced energy monitoring
+  confirmed working with CBE smartplugs
+- Mirabella Genio Smart plug with USB
+- Grid Connect double outlet with Energy Monitoring, Master and Individual switches and Child Lock.
+- DIGOO DG-SP202 dual smartplug with energy monitoring and timers.
+- Grid Connect double outlet wall socket
+- Woox R4028/DIGOO DG-PS01 3 outlet + USB powerstrip with individual timers.
+Other brands may work with the above configurations
+
+- Simple Switch - a switch only, can be a fallback for many other unsupported devices, to allow just power to be switched on/off.
+- Simple Switch with Timer - a single switch and timer, will probably work for a lot of smart switches that are not covered by the more advanced configs above.
+
+### Covers
+- Simple Garage Door
+
+### Miscellaneous
+- Qoto 03 Smart Water Valve / Sprinkler Controller
+
+---
+
+## Installation
+
+[![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge)](https://github.com/custom-components/hacs)
+
+Installation is via the [Home Assistant Community Store
+(HACS)](https://hacs.xyz/), which is the best place to get third-party
+integrations for Home Assistant. Once you have HACS set up, simply
+follow the [instructions for adding a custom
+repository](https://hacs.xyz/docs/faq/custom_repositories) and then
+the integration will be available to install like any other.
+
+## Configuration
+
+You can easily configure your devices using the Integrations configuration UI.
+
+[![Add Integration to your Home Assistant
+instance.](https://my.home-assistant.io/badges/config_flow_start.svg)](https://my.home-assistant.io/redirect/config_flow_start/?domain=tuya_local)
+
+### Stage One
+
+The first stage of configuration is to provide the information needed to
+connect to the device.
+
+You will need to provide your device's IP address or hostname, device
+ID and local key; the last two can be found using [the instructions
+below](#finding-your-device-id-and-local-key).
+
+#### host
+
+    _(string) (Required)_ IP or hostname of the device.
+
+#### device_id
+
+    _(string) (Required)_ Device ID retrieved
+[as per the instructions below](#finding-your-device-id-and-local-key).
+
+#### local_key
+
+    _(string) (Required)_ Local key retrieved
+[as per the instructions below](#finding-your-device-id-and-local-key).
+
+At the end of this step, an attempt is made to connect to the device and see if
+it returns any data. For tuya protocol version 3.3 devices, success
+at this point indicates that all settings you have supplied are correct, but
+for protocol version 3.1 devices, the local key is only used for sending
+commands to the device, so if your local key is incorrect the setup will
+appear to work, and you will not see any problems until you try to control
+your device.  Note that each time you pair the device, the local key changes,
+so if you obtained the local key using the instructions linked above, then
+repaired with your manufacturer's app, then the key will have changed already.
+
+### Stage Two
+
+The second stage of configuration is to select which device you are connecting.
+The list of devices offered will be limited to devices which appear to be
+at least a partial match to the data returned by the device.
+
+#### type
+
+    _(string) (Optional)_ The type of Tuya device.
+Select from the available options.
+
+If you pick the wrong type, you will need to delete the device and set
+it up again.
+
+### Stage Three
+
+The final stage is to choose a name for the device in Home Assistant,
+and select which entities you want to enable.  The options availble
+will depend on the capabilities of the device you selected in the
+previous step.
+
+Usually you will want to accept the defaults at this step.  Entities
+are selected by default, unless they are a deprecated alternative way
+of controlling the device (such as a climate entity for dehumidifiers
+as an alternative to humidifier and fan entities).  If you have
+multiple devices of the same type, you may want to change the name to
+make it easier to distinguish them.
+
+#### name
+
+    _(string) (Required)_ Any unique name for the
+device.  This will be used as the base for the entitiy names in Home
+Assistant.  Although Home Assistant allows you to change the name
+later, it will only change the name used in the UI, not the name of
+the entities.
+
+#### (entities)
+
+    _(boolean) (Optional)_ A number of options
+will be available for each of the entities exposed by the device.
+They will be named for the platform type and an optional name for
+the entity as a suffix (eg `climate`, `humidifier`, `lock_child_lock`)
+Setting them to True will expose the entity in Home Assistant.
+
+## Offline operation gotchas
+
+Many Tuya devices will stop responding if unable to connect to the Tuya servers for an extended period.  Reportedly, some devices act better offline if DNS as well as TCP connections is blocked.
+
+
+## Heater gotchas
+
+Goldair GPPH heaters have individual target temperatures for their
+Comfort and Eco modes, whereas Home Assistant only supports a single
+target temperature. Therefore, when you're in Comfort mode you will
+set the Comfort temperature (`5`-`35`), and when you're in Eco mode
+you will set the Eco temperature (`5`-`21`), just like you were using
+the heater's own control panel. Bear this in mind when writing
+automations that change the operation mode and set a temperature at
+the same time: you must change the operation mode _before_ setting the
+new target temperature, otherwise you will set the current thermostat
+rather than the new one.
+
+When switching to Anti-freeze mode, the heater will set the current
+power level to `1` as if you had manually chosen it. When you switch
+back to other modes, you will no longer be in `Auto` and will have to
+set it again if this is what you wanted. This could be worked around
+in code however it would require storing state that may be cleared if
+HA is restarted and due to this unreliability it's probably best that
+you just factor it into your automations.
+
+When child lock is enabled, the heater's display will flash with the
+child lock symbol (`[]`) whenever you change something in HA. This can
+be confusing because it's the same behaviour as when you try to change
+something via the heater's own control panel and the change is
+rejected due to being locked, however rest assured that the changes
+_are_ taking effect.
+
+When setting the target temperature, different heaters have different
+behaviour, which you may need to compensate for.  From observation,
+GPPH heaters allow the temperature to reach 3 degrees higher than the
+set temperature before turning off, and 1 degree lower before turning
+on again.  Kogan Heaters on the other hand turn off when the
+temperature reaches 1 degree over the targetin LOW mode, and turn on
+again 3 degrees below the target.  To make these heaters act the same
+in LOW power mode, you need to set the Kogan thermostat 2 degrees
+higher than the GPPH thermostat.  In HIGH power mode however, they
+seem to act the same as the GPPH heaters.
+
+The Inkbird thermostat switch does not seem to work for setting
+anything.  If you can figure out how to make setting temperatures and
+presets work, please leave feedback in Issue #19.
+
+## Fan gotchas
+
+Fans should be configured as `fan` entities, with any auxilary
+functions such as panel lighting control, child locks or additional
+switches configured as `light`, `lock` or `switch` entities.
+Configuration of Goldair fans as `climate` entities is supported for
+backward compatibility but is deprecated, and may be removed in
+future.
+
+Reportedly, Goldair fans can be a bit flaky. If they become
+unresponsive, give them about 60 seconds to wake up again.
+
+Anko fans mostly work, except setting the speed does not seem to
+work. If you can figure out how to set the speed through the Tuya
+protocol for these devices, please leave feedback on Issue #22.
+
+
+## Smart Switch gotchas
+
+It has been observed after a while that the current and
+power readings from the switch were returning 0 when there was clearly
+a load on the switch.  After unplugging and replugging, the switch
+started returning only dps 1 and 2 (switch status and timer). If
+HomeAssistant is restarted in that state, the switch detection would
+fail, however as Home Assistant was left running, it continued to work
+with no readings for the current, power and voltage.  I unplugged the
+switch overnight, and in the morning it was working correctly.
+
+Cumulative Energy readings seem to be reset whenever the reading is
+successfully sent to the server.  This leads to the energy usage never moving
+from the minimum reporting level of 0.1kWh, which isn't very useful.
+It may be possible to get useful readings by blocking the switch from accessing
+the internet, otherwise an integration sensor based on the Power sensor
+will need to be set up on the Home Assistant side, and the Energy sensor
+ignored.
+
+## Kogan Kettle gotchas
+
+Although these look like simple devices, their behaviour is not
+consistant so they are difficult to detect.  Sometimes they are
+misdetected as a simple switch, other times they only output the
+temperature sensor so are not detected at all.
+
+## Beca thermostat gotchas
+
+These devices support switching between Celcius and Fahrenheit on the control
+panel, but do not provide any information over the Tuya local protocol about
+which units are selected.  Two configurations for this device are provided,
+`beca_bhp6000_thermostat_c` and `beca_bhp6000_thermostat_f`, please select
+the appropriate one for the temperature units you use.  If you change the
+units on the device control panel, you will need to delete the device from
+Home Assistant and set it up again.
+
+## Siswell C19 thermostat gotchas
+
+These support configuration as either heating or cooling controllers, but
+only have one output.  The HVAC mode is provided as an indicator of which
+mode they are in, but are set to readonly so that you cannot accidentally
+switch the thermostat to the wrong mode from HA.
+
+## Humidifiers and dehumidifiers
+
+Humidifiers and Dehumidifiers should be configuured as `humidifier`
+entities, probably with `fan` entities as well if the fan speed can
+also be controlled, and any other auxilary features such as panel
+lighting, child locks or additional switches configured as `light`,
+`lock` or `switch` entities.  Configration of Goldair Dehumidifiers
+and Eanons Humidifiers as `climate` entities is also supported for
+backwards compatibility, but is deprecated and may be removed in
+future.  In particular, when humidifiers are represented as `climate`
+entities, the running mode will show as `Dry`, as the climate entity
+only supports functions commonly found on air conditioners/heatpumps.
+
+
+## Finding your device ID and local key
+
+You can find these keys the same way as you would for any Tuya local integration. You'll need the Goldair app or the Tuya Tuya Smart app (the Goldair app is just a rebranded Tuya app), then follow these instructions.
+
+- [Instructions for iOS](https://github.com/codetheweb/tuyapi/blob/master/docs/SETUP.md)
+- [Instructions for Android](https://github.com/codetheweb/tuyapi/blob/cdb4289/docs/SETUP_DEPRECATED.md#capture-https-traffic)
+
+## Next steps
+
+1. This component is mosty unit-tested thanks to the upstream project, but there are a few more to complete. Feel free to use existing specs as inspiration and the Sonar Cloud analysis to see where the gaps are.
+2. Once unit tests are complete, the next task is to complete the Home Assistant quality checklist before considering submission to the HA team for inclusion in standard installations.
+3. Discovery seems possible with the new tinytuya library, though the steps to get a local key will most likely remain manual.  Discovery also returns a productKey, which might help make the device detection more reliable where different devices use the same dps mapping but different names for the presets for example.
+
+Please report any issues and feel free to raise pull requests.
+[Many others](https://github.com/make-all/tuya-local/blob/main/ACKNOWLEDGEMENTS.md) have contributed their help already.
+
+
+[![BuyMeCoffee](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/jasonrumney)

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

@@ -0,0 +1,126 @@
+name: Nashone MTS-700-WB Thermostat
+primary_entity:
+  entity: climate
+  dps:
+    - id: 1
+      type: boolean
+      name: power
+      hidden: true
+      mapping:
+        - dps_val: False
+          value: "off"
+    - id: 2
+      type: string
+      name: hvac_mode
+      mapping:
+        - dps_val: cold
+          constraint: power
+          conditions:
+            - dps_val: true
+              value: cool
+            - dps_val: false
+              value_redirect: power
+              value: "off"
+        - dps_val: hot
+          constraint: power
+          conditions:
+            - dps_val: true
+              value: heat
+            - dps_val: false
+              value_redirect: power
+    - id: 3
+      type: string
+      name: hvac_action
+      mapping:
+        - dps_val: manual
+          constraint: hvac_mode
+          conditions:
+            - dps_val: cold
+              value: cooling
+            - dps_val: hot
+              value: heating
+    - id: 16
+      type: integer
+      name: temperature
+      range:
+        min: -20
+        max: 105
+      mapping:
+        - constraint: temperature_unit
+          conditions:
+            - dps_val: f
+              value_redirect: temp_f
+              range:
+                min: -4
+                max: 221
+    - id: 17
+      type: integer
+      name: temp_f
+      range:
+        min: -4
+        max: 221
+      hidden: true
+    - id: 23
+      type: string
+      name: temperature_unit
+      mapping:
+        - dps_val: c
+          value: C
+        - dps_val: f
+          value: F
+    - id: 24
+      type: integer
+      name: current_temperature
+      mapping:
+        - constraint: temperature_unit
+          conditions:
+            - dps_val: f
+              value_redirect: temp_current_f
+    - id: 29
+      type: integer
+      name: temp_current_f
+      hidden: true
+secondary_entities:
+  - entity: number
+    category: config
+    name: Calibration Offset
+    icon: "mdi:arrow-collapse-up"
+    dps:
+      - id: 27
+        type: integer
+        name: value
+        range:
+          min: -5
+          max: 5
+  - entity: switch
+    category: config
+    name: Factory Reset
+    icon: "mdi:cog-refresh"
+    dps:
+      - id: 39
+        type: boolean
+        name: switch
+  - entity: select
+    name: Timer
+    category: config
+    icon: "mdi:timer"
+    dps:
+      - id: 41
+        type: string
+        name: option
+        mapping:
+          - dps_val: "cancel"
+            value: "off"
+          - dps_val: "1h"
+            value: "1 hour"
+  - entity: sensor
+    category: diagnostic
+    name: Timer
+    icon: "mdi:timer"
+    dps:
+      - id: 42
+        type: integer
+        unit: min
+        name: sensor
+        mapping:
+          - scale: 60

+ 12 - 12
custom_components/tuya_local/manifest.json

@@ -1,12 +1,12 @@
-{
-    "domain": "tuya_local",
-    "iot_class": "local_polling",
-    "name": "Tuya Local",
-    "version": "0.14.2",
-    "documentation": "https://github.com/make-all/tuya-local",
-    "issue_tracker": "https://github.com/make-all/tuya-local/issues",
-    "dependencies": [],
-    "codeowners": ["@make-all"],
-    "requirements": ["pycryptodome==3.11.0","tinytuya==1.2.11"],
-    "config_flow": true
-}
+{
+    "domain": "tuya_local",
+    "iot_class": "local_polling",
+    "name": "Tuya Local",
+    "version": "0.14.3",
+    "documentation": "https://github.com/make-all/tuya-local",
+    "issue_tracker": "https://github.com/make-all/tuya-local/issues",
+    "dependencies": [],
+    "codeowners": ["@make-all"],
+    "requirements": ["pycryptodome==3.11.0","tinytuya==1.2.11"],
+    "config_flow": true
+}

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

@@ -105,6 +105,7 @@
                     "switch_adaptive": "Include adaptive as a switch entity",
                     "switch_air_clean": "Include air clean as a switch entity",
                     "switch_anti_frost": "Include anti-frost as a switch entity",
+		    "switch_factory_reset": "Include factory reset as a switch entity",
                     "switch_filter_reset": "Include filter reset as a switch entity",
                     "switch_ionizer": "Include ionizer as a switch entity",
                     "switch_master": "Include master switch as a switch entity",
@@ -221,6 +222,7 @@
                     "switch_adaptive": "Include adaptive as a switch entity",
                     "switch_air_clean": "Include air clean as a switch entity",
                     "switch_anti_frost": "Include anti-frost as a switch entity",
+		    "switch_factory_reset": "Include factory reset as a switch entity",
                     "switch_filter_reset": "Include filter reset as a switch entity",
                     "switch_ionizer": "Include ionizer as a switch entity",
                     "switch_master": "Include master switch as a switch entity",

+ 851 - 836
tests/const.py

@@ -1,836 +1,851 @@
-GPPH_HEATER_PAYLOAD = {
-    "1": False,
-    "2": 25,
-    "3": 17,
-    "4": "C",
-    "6": True,
-    "12": 0,
-    "101": "5",
-    "102": 0,
-    "103": False,
-    "104": True,
-    "105": "auto",
-    "106": 20,
-}
-
-GPCV_HEATER_PAYLOAD = {
-    "1": True,
-    "2": True,
-    "3": 30,
-    "4": 25,
-    "5": 0,
-    "6": 0,
-    "7": "Low",
-}
-
-EUROM_600_HEATER_PAYLOAD = {"1": True, "2": 15, "5": 18, "6": 0}
-EUROM_600v2_HEATER_PAYLOAD = {"1": True, "2": 15, "5": 18, "7": 0}
-
-EUROM_601_HEATER_PAYLOAD = {"1": True, "2": 21, "3": 20, "6": False, "13": 0}
-
-EUROM_WALLDESIGNHEAT2000_HEATER_PAYLOAD = {
-    "1": True,
-    "2": 21,
-    "3": 19,
-    "4": "off",
-    "7": False,
-}
-
-GECO_HEATER_PAYLOAD = {"1": True, "2": True, "3": 30, "4": 25, "5": 0, "6": 0}
-
-JJPRO_JPD01_PAYLOAD = {
-    "1": True,
-    "2": "0",
-    "4": 50,
-    "5": True,
-    "6": "1",
-    "11": 0,
-    "12": 0,
-    "101": False,
-    "102": False,
-    "103": 20,
-    "104": 62,
-    "105": False,
-}
-
-KOGAN_HEATER_PAYLOAD = {"2": 30, "3": 25, "4": "Low", "6": True, "7": True, "8": 0}
-
-KOGAN_KAWFHTP_HEATER_PAYLOAD = {
-    "1": True,
-    "2": True,
-    "3": 30,
-    "4": 25,
-    "5": 0,
-    "7": "Low",
-}
-
-KOGAN_KASHMFP20BA_HEATER_PAYLOAD = {
-    "1": True,
-    "2": "high",
-    "3": 27,
-    "4": 26,
-    "5": "orange",
-    "6": "white",
-}
-
-DEHUMIDIFIER_PAYLOAD = {
-    "1": False,
-    "2": "0",
-    "4": 30,
-    "5": False,
-    "6": "1",
-    "7": False,
-    "11": 0,
-    "12": "0",
-    "101": False,
-    "102": False,
-    "103": 20,
-    "104": 78,
-    "105": False,
-}
-
-FAN_PAYLOAD = {"1": False, "2": "12", "3": "normal", "8": True, "11": "0", "101": False}
-
-KOGAN_SOCKET_PAYLOAD = {
-    "1": True,
-    "2": 0,
-    "4": 200,
-    "5": 460,
-    "6": 2300,
-}
-
-KOGAN_SOCKET_PAYLOAD2 = {
-    "1": True,
-    "9": 0,
-    "18": 200,
-    "19": 460,
-    "20": 2300,
-}
-
-SMARTSWITCH_ENERGY_PAYLOAD = {
-    "1": True,
-    "9": 0,
-    "17": 100,
-    "18": 2368,
-    "19": 4866,
-    "20": 2148,
-    "21": 1,
-    "22": 628,
-    "23": 30636,
-    "24": 17426,
-    "25": 2400,
-    "26": 0,
-    "38": "memory",
-    "41": "",
-    "42": "",
-    "46": False,
-}
-
-KOGAN_SOCKET_CLEAR_PAYLOAD = {
-    "2": None,
-    "4": None,
-    "5": None,
-    "6": None,
-    "9": None,
-    "18": None,
-    "19": None,
-    "20": None,
-}
-
-GSH_HEATER_PAYLOAD = {
-    "1": True,
-    "2": 22,
-    "3": 24,
-    "4": "low",
-    "12": 0,
-}
-
-GARDENPAC_HEATPUMP_PAYLOAD = {
-    "1": True,
-    "102": 28,
-    "103": True,
-    "104": 100,
-    "105": "warm",
-    "106": 30,
-    "107": 18,
-    "108": 40,
-    "115": 0,
-    "116": 0,
-    "117": True,
-}
-
-MADIMACK_HEATPUMP_PAYLOAD = {
-    "1": True,
-    "102": 9,
-    "103": True,
-    "104": 0,
-    "105": "warm",
-    "106": 30,
-    "107": 18,
-    "108": 40,
-    "115": 4,
-    "116": 0,
-    "117": True,
-    "118": False,
-    "120": 8,
-    "122": 11,
-    "124": 9,
-    "125": 0,
-    "126": 0,
-    "127": 17,
-    "128": 480,
-    "129": 0,
-    "130": False,
-    "134": False,
-    "135": False,
-    "136": False,
-    "139": False,
-    "140": "LowSpeed",
-}
-
-MADIMACK_ELITEV3_HEATPUMP_PAYLOAD = {
-    "1": True,
-    "2": "heating",
-    "4": 28,
-    "5": "power",
-    "6": "c",
-    "15": 0,
-    "20": 50,
-    "21": 40,
-    "22": 18,
-    "23": 45,
-    "24": 40,
-    "25": 33,
-    "26": 18,
-    "101": 0,
-    "102": 21,
-    "103": 23,
-    "104": 18,
-    "105": 18,
-    "106": 480,
-    "107": False,
-}
-
-PURLINE_M100_HEATER_PAYLOAD = {
-    "1": True,
-    "2": 23,
-    "3": 23,
-    "5": "off",
-    "10": True,
-    "11": 0,
-    "12": 0,
-    "101": False,
-    "102": False,
-}
-
-REMORA_HEATPUMP_PAYLOAD = {"1": True, "2": 30, "3": 28, "4": "heat", "9": 0}
-BWT_HEATPUMP_PAYLOAD = {"1": True, "2": 30, "3": 28, "4": "auto", "9": 0}
-
-EANONS_HUMIDIFIER_PAYLOAD = {
-    "2": "middle",
-    "3": "cancel",
-    "4": 0,
-    "9": 0,
-    "10": True,
-    "12": "humidity",
-    "15": 65,
-    "16": 65,
-    "22": True,
-}
-
-INKBIRD_THERMOSTAT_PAYLOAD = {
-    "12": 0,
-    "101": "C",
-    "102": 0,
-    "103": "on",
-    "104": 257,
-    "106": 252,
-    "108": 6,
-    "109": 1000,
-    "110": 0,
-    "111": False,
-    "112": False,
-    "113": False,
-    "114": 260,
-    "115": True,
-    "116": 783,
-    "117": False,
-    "118": False,
-    "119": False,
-    "120": False,
-}
-
-ANKO_FAN_PAYLOAD = {
-    "1": True,
-    "2": "normal",
-    "3": "1",
-    "4": "off",
-    "6": "0",
-}
-
-DETA_FAN_PAYLOAD = {
-    "1": True,
-    "3": "1",
-    "9": False,
-    "101": True,
-    "102": "0",
-    "103": "0",
-}
-
-ELECTRIQ_DEHUMIDIFIER_PAYLOAD = {
-    "1": True,
-    "2": "auto",
-    "3": 60,
-    "4": 45,
-    "7": False,
-    "10": False,
-    "102": "90",
-    "103": 20,
-    "104": False,
-}
-
-ELECTRIQ_CD20PRO_DEHUMIDIFIER_PAYLOAD = {
-    "1": True,
-    "2": "high",
-    "3": 39,
-    "4": 45,
-    "5": False,
-    "10": False,
-    "101": False,
-    "102": "0_90",
-    "103": 30,
-}
-
-ELECTRIQ_CD12PW_DEHUMIDIFIER_PAYLOAD = {
-    "1": True,
-    "2": "high",
-    "3": 39,
-    "4": 45,
-    "101": False,
-    "103": 30,
-}
-
-ELECTRIQ_DESD9LW_DEHUMIDIFIER_PAYLOAD = {
-    "1": True,
-    "2": 50,
-    "4": "Low",
-    "5": "Dehumidity",
-    "6": 55,
-    "7": 18,
-    "10": False,
-    "12": False,
-    "15": False,
-    "101": 20,
-}
-
-POOLEX_SILVERLINE_HEATPUMP_PAYLOAD = {"1": True, "2": 30, "3": 28, "4": "Heat", "13": 0}
-POOLEX_VERTIGO_HEATPUMP_PAYLOAD = {"1": True, "2": 30, "3": 28, "4": "heat", "9": 0}
-
-ELECTRIQ_12WMINV_HEATPUMP_PAYLOAD = {
-    "1": True,
-    "2": 20,
-    "3": 18,
-    "4": "auto",
-    "5": "1",
-    "8": False,
-    "12": False,
-    "101": True,
-    "102": False,
-    "103": False,
-    "104": True,
-    "106": False,
-    "107": False,
-    "108": 0,
-    "109": 0,
-    "110": 0,
-}
-
-KOGAN_DEHUMIDIFIER_PAYLOAD = {
-    "1": True,
-    "2": "low",
-    "3": 70,
-    "8": False,
-    "11": 0,
-    "12": 0,
-    "13": 0,
-    "101": 50,
-}
-
-HELLNAR_HEATPUMP_PAYLOAD = {
-    "1": False,
-    "2": 260,
-    "3": 26,
-    "4": "cold",
-    "5": "low",
-    "18": 0,
-    "20": 0,
-    "105": "off",
-    "110": 131644,
-    "113": "0",
-    "114": "0",
-    "119": "0",
-    "120": "off",
-    "123": "0010",
-    "126": "0",
-    "127": "0",
-    "128": "0",
-    "129": "1",
-    "130": 26,
-    "131": False,
-    "132": False,
-    "133": "0",
-    "134": '{"t":1624086077,"s":false,"clr"true}',
-}
-
-TADIRAN_HEATPUMP_PAYLOAD = {
-    "1": True,
-    "2": 25,
-    "3": 250,
-    "4": "cooling",
-    "5": "low",
-    "101": 0,
-    "102": 260,
-    "103": 225,
-    "104": "low",
-    "105": "stop",
-    "106": -300,
-    "107": False,
-    "108": False,
-}
-
-BECA_BHP6000_PAYLOAD = {
-    "1": True,
-    "2": 77,
-    "3": 87,
-    "4": "3",
-    "5": "3",
-    "6": False,
-    "7": False,
-}
-
-BECA_BHT6000_PAYLOAD = {
-    "1": False,
-    "2": 40,
-    "3": 42,
-    "4": "0",
-    "5": False,
-    "6": False,
-    "102": 0,
-    "103": "1",
-    "104": True,
-}
-
-BECA_BHT002_PAYLOAD = {
-    "1": False,
-    "2": 40,
-    "3": 42,
-    "4": "0",
-    "5": False,
-    "6": False,
-    "102": 0,
-    "104": True,
-}
-
-MOES_BHT002_PAYLOAD = {
-    "1": False,
-    "2": 40,
-    "3": 42,
-    "4": "0",
-    "5": False,
-    "6": False,
-    "104": True,
-}
-
-BEOK_TR9B_PAYLOAD = {
-    "1": True,
-    "2": "manual",
-    "10": True,
-    "16": 590,
-    "19": 990,
-    "23": "f",
-    "24": 666,
-    "26": 410,
-    "31": "5_2",
-    "36": "close",
-    "40": False,
-    "45": 0,
-    "101": 1313,
-    "102": 10,
-}
-
-BECA_BAC002_PAYLOAD = {
-    "1": True,
-    "2": 39,
-    "3": 45,
-    "4": "1",
-    "5": False,
-    "6": False,
-    "102": "1",
-    "103": "2",
-}
-
-LEXY_F501_PAYLOAD = {
-    "1": True,
-    "2": "forestwindhigh",
-    "4": "off",
-    "6": 0,
-    "9": False,
-    "16": False,
-    "17": False,
-    "102": 8,
-}
-
-TH213_THERMOSTAT_PAYLOAD = {
-    "1": True,
-    "2": 18,
-    "3": 20,
-    "4": 1,
-    "6": False,
-    "12": 0,
-    "101": 16,
-    "102": 2,
-    "103": 0,
-    "104": 2,
-    "105": True,
-    "107": False,
-    "108": False,
-    "110": 0,
-}
-
-WETAIR_WCH750_HEATER_PAYLOAD = {
-    "1": False,
-    "2": 17,
-    "4": "mod_free",
-    "11": "heating",
-    "19": "0h",
-    "20": 0,
-    "21": 0,
-    "101": "level1",
-}
-
-WETAIR_WAWH1210_HUMIDIFIER_PAYLOAD = {
-    "1": True,
-    "5": True,
-    "8": True,
-    "13": 50,
-    "14": 57,
-    "22": 0,
-    "24": "AUTO",
-    "25": True,
-    "29": False,
-    "101": "Have_water",
-}
-
-SASWELL_T29UTK_THERMOSTAT_PAYLOAD = {
-    "1": True,
-    "2": 240,
-    "3": 241,
-    "4": "cold",
-    "5": "auto",
-    "19": "C",
-    "101": False,
-    "102": False,
-    "103": "cold",
-    "112": "3",
-    "113": 0,
-    "114": 24,
-    "115": 24,
-    "116": 75,
-    "117": 81,
-}
-
-SASWELL_C16_THERMOSTAT_PAYLOAD = {
-    "2": 220,
-    "3": "Smart",
-    "4": 0,
-    "5": 217,
-    "6": 350,
-    "7": False,
-    "8": 241,
-    "9": False,
-    "10": True,
-    "11": False,
-    "12": "7",
-    "14": 0,
-    "15": 0,
-    "17": 0,
-    "21": False,
-    "22": 1500,
-    "23": 12,
-    "24": "Standby",
-    "26": 50,
-}
-
-FERSK_VIND2_PAYLOAD = {
-    "1": True,
-    "2": 22,
-    "3": 23,
-    "4": "COOL",
-    "5": 1,
-    "19": "C",
-    "101": False,
-    "102": False,
-    "103": 0,
-    "104": False,
-    "105": 0,
-    "106": 0,
-    "109": False,
-    "110": 0,
-}
-
-KOGAN_GLASS_1_7L_KETTLE_PAYLOAD = {
-    "1": False,
-    "5": 99,
-    "102": "90",
-}
-
-RENPHO_PURIFIER_PAYLOAD = {
-    "1": True,
-    "4": "low",
-    "7": False,
-    "8": False,
-    "19": "0",
-    "22": "0",
-    "101": False,
-    "102": 0,
-    "103": 0,
-    "104": 0,
-    "105": 0,
-}
-
-ARLEC_FAN_PAYLOAD = {
-    "1": True,
-    "3": 1,
-    "4": "forward",
-    "102": "normal",
-    "103": "off",
-}
-
-CARSON_CB_PAYLOAD = {
-    "1": True,
-    "2": 20,
-    "3": 23,
-    "4": "COOL",
-    "5": 1,
-    "19": "C",
-    "102": False,
-    "103": 0,
-    "104": False,
-    "105": 0,
-    "106": 0,
-    "110": 0,
-}
-
-KOGAN_KAWFPAC09YA_AIRCON_PAYLOAD = {
-    "1": True,
-    "2": 19,
-    "3": 18,
-    "4": "COOL",
-    "5": "1",
-    "19": "C",
-    "105": 0,
-    "106": 0,
-    "107": False,
-}
-
-GRIDCONNECT_2SOCKET_PAYLOAD = {
-    "1": True,
-    "2": True,
-    "9": 0,
-    "10": 0,
-    "17": 0,
-    "18": 500,
-    "19": 1200,
-    "20": 240,
-    "21": 0,
-    "22": 0,
-    "23": 0,
-    "24": 0,
-    "25": 0,
-    "38": "0",
-    "40": False,
-    "101": True,
-}
-
-EBERG_QUBO_Q40HD_PAYLOAD = {
-    "1": True,
-    "2": 22,
-    "3": 20,
-    "4": "hot",
-    "5": "middle",
-    "19": "c",
-    "22": 0,
-    "25": False,
-    "30": False,
-    "101": "heat_s",
-}
-
-STIRLING_FS1_FAN_PAYLOAD = {
-    "1": True,
-    "2": "normal",
-    "3": 9,
-    "5": False,
-    "22": "cancel",
-}
-
-QOTO_SPRINKLER_PAYLOAD = {
-    "102": 100,
-    "103": 100,
-    "104": 10036,
-    "105": 10800,
-    "108": 0,
-}
-
-MINCO_MH1823D_THERMOSTAT_PAYLOAD = {
-    "1": True,
-    "2": "program",
-    "3": "stop",
-    "5": False,
-    "9": True,
-    "12": False,
-    "18": "out",
-    "19": "c",
-    "22": 18,
-    "23": 64,
-    "32": 1,
-    "33": 205,
-    "35": 0,
-    "37": 689,
-    "39": "7",
-    "45": 0,
-    "101": 200,
-    "102": 680,
-    "103": 0,
-    "104": 2,
-    "105": "no_power",
-    "106": 35,
-    "107": 95,
-}
-
-SIMPLE_GARAGE_DOOR_PAYLOAD = {
-    "1": True,
-    "101": False,
-}
-
-NEDIS_HTPL20F_PAYLOAD = {
-    "1": True,
-    "2": 25,
-    "3": 25,
-    "4": "1",
-    "7": False,
-    "11": "0",
-    "13": 0,
-    "101": False,
-}
-
-ASPEN_ASP200_FAN_PAYLOAD = {
-    "1": True,
-    "2": "in",
-    "3": 1,
-    "8": 0,
-    "18": 20,
-    "19": 25,
-    "101": True,
-    "102": 3,
-}
-
-TMWF02_FAN_PAYLOAD = {
-    "1": True,
-    "2": 0,
-    "3": "level_2",
-    "4": 40,
-}
-
-TIMED_SOCKET_PAYLOAD = {
-    "1": True,
-    "11": 0,
-}
-
-DIGOO_DGSP202_SOCKET_PAYLOAD = {
-    "1": True,
-    "2": True,
-    "9": 0,
-    "10": 0,
-    "18": 500,
-    "19": 1200,
-    "20": 240,
-}
-
-WOOX_R4028_SOCKET_PAYLOAD = {
-    "1": True,
-    "2": True,
-    "3": True,
-    "7": True,
-    "101": 0,
-    "102": 0,
-    "103": 0,
-    "105": 0,
-}
-
-OWON_PCT513_THERMOSTAT_PAYLOAD = {
-    "2": "cool",
-    "16": 2150,
-    "17": 71,
-    "23": "c",
-    "24": 2950,
-    "29": 85,
-    "34": 52,
-    "45": 0,
-    "107": "0",
-    "108": 2150,
-    "109": 1650,
-    "110": 71,
-    "111": 62,
-    "115": "auto",
-    "116": "1",
-    "119": True,
-    "120": "permhold",
-    "123": 25,
-    "129": "coolfanon",
-}
-
-HYSEN_HY08WE2_THERMOSTAT_PAYLOAD = {
-    "1": True,
-    "2": 50,
-    "3": 170,
-    "4": "Manual",
-    "6": False,
-    "12": 0,
-    "101": False,
-    "102": False,
-    "103": 170,
-    "104": 4,
-    "105": 15,
-    "106": True,
-    "107": True,
-    "108": True,
-    "109": -10,
-    "110": 10,
-    "111": 2,
-    "112": 35,
-    "113": 5,
-    "114": 30,
-    "115": 5,
-    "116": "all",
-    "117": "keep",
-    "118": "2days",
-}
-
-POIEMA_ONE_PURIFIER_PAYLOAD = {
-    "1": True,
-    "2": 12,
-    "3": "manual",
-    "4": "mid",
-    "7": False,
-    "11": False,
-    "18": "cancel",
-    "19": 0,
-}
-
-ECOSTRAD_ACCENTIQ_HEATER_PAYLOAD = {
-    "1": True,
-    "2": 200,
-    "3": 195,
-    "10": 0,
-    "101": True,
-}
+GPPH_HEATER_PAYLOAD = {
+    "1": False,
+    "2": 25,
+    "3": 17,
+    "4": "C",
+    "6": True,
+    "12": 0,
+    "101": "5",
+    "102": 0,
+    "103": False,
+    "104": True,
+    "105": "auto",
+    "106": 20,
+}
+
+GPCV_HEATER_PAYLOAD = {
+    "1": True,
+    "2": True,
+    "3": 30,
+    "4": 25,
+    "5": 0,
+    "6": 0,
+    "7": "Low",
+}
+
+EUROM_600_HEATER_PAYLOAD = {"1": True, "2": 15, "5": 18, "6": 0}
+EUROM_600v2_HEATER_PAYLOAD = {"1": True, "2": 15, "5": 18, "7": 0}
+
+EUROM_601_HEATER_PAYLOAD = {"1": True, "2": 21, "3": 20, "6": False, "13": 0}
+
+EUROM_WALLDESIGNHEAT2000_HEATER_PAYLOAD = {
+    "1": True,
+    "2": 21,
+    "3": 19,
+    "4": "off",
+    "7": False,
+}
+
+GECO_HEATER_PAYLOAD = {"1": True, "2": True, "3": 30, "4": 25, "5": 0, "6": 0}
+
+JJPRO_JPD01_PAYLOAD = {
+    "1": True,
+    "2": "0",
+    "4": 50,
+    "5": True,
+    "6": "1",
+    "11": 0,
+    "12": 0,
+    "101": False,
+    "102": False,
+    "103": 20,
+    "104": 62,
+    "105": False,
+}
+
+KOGAN_HEATER_PAYLOAD = {"2": 30, "3": 25, "4": "Low", "6": True, "7": True, "8": 0}
+
+KOGAN_KAWFHTP_HEATER_PAYLOAD = {
+    "1": True,
+    "2": True,
+    "3": 30,
+    "4": 25,
+    "5": 0,
+    "7": "Low",
+}
+
+KOGAN_KASHMFP20BA_HEATER_PAYLOAD = {
+    "1": True,
+    "2": "high",
+    "3": 27,
+    "4": 26,
+    "5": "orange",
+    "6": "white",
+}
+
+DEHUMIDIFIER_PAYLOAD = {
+    "1": False,
+    "2": "0",
+    "4": 30,
+    "5": False,
+    "6": "1",
+    "7": False,
+    "11": 0,
+    "12": "0",
+    "101": False,
+    "102": False,
+    "103": 20,
+    "104": 78,
+    "105": False,
+}
+
+FAN_PAYLOAD = {"1": False, "2": "12", "3": "normal", "8": True, "11": "0", "101": False}
+
+KOGAN_SOCKET_PAYLOAD = {
+    "1": True,
+    "2": 0,
+    "4": 200,
+    "5": 460,
+    "6": 2300,
+}
+
+KOGAN_SOCKET_PAYLOAD2 = {
+    "1": True,
+    "9": 0,
+    "18": 200,
+    "19": 460,
+    "20": 2300,
+}
+
+SMARTSWITCH_ENERGY_PAYLOAD = {
+    "1": True,
+    "9": 0,
+    "17": 100,
+    "18": 2368,
+    "19": 4866,
+    "20": 2148,
+    "21": 1,
+    "22": 628,
+    "23": 30636,
+    "24": 17426,
+    "25": 2400,
+    "26": 0,
+    "38": "memory",
+    "41": "",
+    "42": "",
+    "46": False,
+}
+
+KOGAN_SOCKET_CLEAR_PAYLOAD = {
+    "2": None,
+    "4": None,
+    "5": None,
+    "6": None,
+    "9": None,
+    "18": None,
+    "19": None,
+    "20": None,
+}
+
+GSH_HEATER_PAYLOAD = {
+    "1": True,
+    "2": 22,
+    "3": 24,
+    "4": "low",
+    "12": 0,
+}
+
+GARDENPAC_HEATPUMP_PAYLOAD = {
+    "1": True,
+    "102": 28,
+    "103": True,
+    "104": 100,
+    "105": "warm",
+    "106": 30,
+    "107": 18,
+    "108": 40,
+    "115": 0,
+    "116": 0,
+    "117": True,
+}
+
+MADIMACK_HEATPUMP_PAYLOAD = {
+    "1": True,
+    "102": 9,
+    "103": True,
+    "104": 0,
+    "105": "warm",
+    "106": 30,
+    "107": 18,
+    "108": 40,
+    "115": 4,
+    "116": 0,
+    "117": True,
+    "118": False,
+    "120": 8,
+    "122": 11,
+    "124": 9,
+    "125": 0,
+    "126": 0,
+    "127": 17,
+    "128": 480,
+    "129": 0,
+    "130": False,
+    "134": False,
+    "135": False,
+    "136": False,
+    "139": False,
+    "140": "LowSpeed",
+}
+
+MADIMACK_ELITEV3_HEATPUMP_PAYLOAD = {
+    "1": True,
+    "2": "heating",
+    "4": 28,
+    "5": "power",
+    "6": "c",
+    "15": 0,
+    "20": 50,
+    "21": 40,
+    "22": 18,
+    "23": 45,
+    "24": 40,
+    "25": 33,
+    "26": 18,
+    "101": 0,
+    "102": 21,
+    "103": 23,
+    "104": 18,
+    "105": 18,
+    "106": 480,
+    "107": False,
+}
+
+PURLINE_M100_HEATER_PAYLOAD = {
+    "1": True,
+    "2": 23,
+    "3": 23,
+    "5": "off",
+    "10": True,
+    "11": 0,
+    "12": 0,
+    "101": False,
+    "102": False,
+}
+
+REMORA_HEATPUMP_PAYLOAD = {"1": True, "2": 30, "3": 28, "4": "heat", "9": 0}
+BWT_HEATPUMP_PAYLOAD = {"1": True, "2": 30, "3": 28, "4": "auto", "9": 0}
+
+EANONS_HUMIDIFIER_PAYLOAD = {
+    "2": "middle",
+    "3": "cancel",
+    "4": 0,
+    "9": 0,
+    "10": True,
+    "12": "humidity",
+    "15": 65,
+    "16": 65,
+    "22": True,
+}
+
+INKBIRD_THERMOSTAT_PAYLOAD = {
+    "12": 0,
+    "101": "C",
+    "102": 0,
+    "103": "on",
+    "104": 257,
+    "106": 252,
+    "108": 6,
+    "109": 1000,
+    "110": 0,
+    "111": False,
+    "112": False,
+    "113": False,
+    "114": 260,
+    "115": True,
+    "116": 783,
+    "117": False,
+    "118": False,
+    "119": False,
+    "120": False,
+}
+
+ANKO_FAN_PAYLOAD = {
+    "1": True,
+    "2": "normal",
+    "3": "1",
+    "4": "off",
+    "6": "0",
+}
+
+DETA_FAN_PAYLOAD = {
+    "1": True,
+    "3": "1",
+    "9": False,
+    "101": True,
+    "102": "0",
+    "103": "0",
+}
+
+ELECTRIQ_DEHUMIDIFIER_PAYLOAD = {
+    "1": True,
+    "2": "auto",
+    "3": 60,
+    "4": 45,
+    "7": False,
+    "10": False,
+    "102": "90",
+    "103": 20,
+    "104": False,
+}
+
+ELECTRIQ_CD20PRO_DEHUMIDIFIER_PAYLOAD = {
+    "1": True,
+    "2": "high",
+    "3": 39,
+    "4": 45,
+    "5": False,
+    "10": False,
+    "101": False,
+    "102": "0_90",
+    "103": 30,
+}
+
+ELECTRIQ_CD12PW_DEHUMIDIFIER_PAYLOAD = {
+    "1": True,
+    "2": "high",
+    "3": 39,
+    "4": 45,
+    "101": False,
+    "103": 30,
+}
+
+ELECTRIQ_DESD9LW_DEHUMIDIFIER_PAYLOAD = {
+    "1": True,
+    "2": 50,
+    "4": "Low",
+    "5": "Dehumidity",
+    "6": 55,
+    "7": 18,
+    "10": False,
+    "12": False,
+    "15": False,
+    "101": 20,
+}
+
+POOLEX_SILVERLINE_HEATPUMP_PAYLOAD = {"1": True, "2": 30, "3": 28, "4": "Heat", "13": 0}
+POOLEX_VERTIGO_HEATPUMP_PAYLOAD = {"1": True, "2": 30, "3": 28, "4": "heat", "9": 0}
+
+ELECTRIQ_12WMINV_HEATPUMP_PAYLOAD = {
+    "1": True,
+    "2": 20,
+    "3": 18,
+    "4": "auto",
+    "5": "1",
+    "8": False,
+    "12": False,
+    "101": True,
+    "102": False,
+    "103": False,
+    "104": True,
+    "106": False,
+    "107": False,
+    "108": 0,
+    "109": 0,
+    "110": 0,
+}
+
+KOGAN_DEHUMIDIFIER_PAYLOAD = {
+    "1": True,
+    "2": "low",
+    "3": 70,
+    "8": False,
+    "11": 0,
+    "12": 0,
+    "13": 0,
+    "101": 50,
+}
+
+HELLNAR_HEATPUMP_PAYLOAD = {
+    "1": False,
+    "2": 260,
+    "3": 26,
+    "4": "cold",
+    "5": "low",
+    "18": 0,
+    "20": 0,
+    "105": "off",
+    "110": 131644,
+    "113": "0",
+    "114": "0",
+    "119": "0",
+    "120": "off",
+    "123": "0010",
+    "126": "0",
+    "127": "0",
+    "128": "0",
+    "129": "1",
+    "130": 26,
+    "131": False,
+    "132": False,
+    "133": "0",
+    "134": '{"t":1624086077,"s":false,"clr"true}',
+}
+
+TADIRAN_HEATPUMP_PAYLOAD = {
+    "1": True,
+    "2": 25,
+    "3": 250,
+    "4": "cooling",
+    "5": "low",
+    "101": 0,
+    "102": 260,
+    "103": 225,
+    "104": "low",
+    "105": "stop",
+    "106": -300,
+    "107": False,
+    "108": False,
+}
+
+BECA_BHP6000_PAYLOAD = {
+    "1": True,
+    "2": 77,
+    "3": 87,
+    "4": "3",
+    "5": "3",
+    "6": False,
+    "7": False,
+}
+
+BECA_BHT6000_PAYLOAD = {
+    "1": False,
+    "2": 40,
+    "3": 42,
+    "4": "0",
+    "5": False,
+    "6": False,
+    "102": 0,
+    "103": "1",
+    "104": True,
+}
+
+BECA_BHT002_PAYLOAD = {
+    "1": False,
+    "2": 40,
+    "3": 42,
+    "4": "0",
+    "5": False,
+    "6": False,
+    "102": 0,
+    "104": True,
+}
+
+MOES_BHT002_PAYLOAD = {
+    "1": False,
+    "2": 40,
+    "3": 42,
+    "4": "0",
+    "5": False,
+    "6": False,
+    "104": True,
+}
+
+BEOK_TR9B_PAYLOAD = {
+    "1": True,
+    "2": "manual",
+    "10": True,
+    "16": 590,
+    "19": 990,
+    "23": "f",
+    "24": 666,
+    "26": 410,
+    "31": "5_2",
+    "36": "close",
+    "40": False,
+    "45": 0,
+    "101": 1313,
+    "102": 10,
+}
+
+BECA_BAC002_PAYLOAD = {
+    "1": True,
+    "2": 39,
+    "3": 45,
+    "4": "1",
+    "5": False,
+    "6": False,
+    "102": "1",
+    "103": "2",
+}
+
+LEXY_F501_PAYLOAD = {
+    "1": True,
+    "2": "forestwindhigh",
+    "4": "off",
+    "6": 0,
+    "9": False,
+    "16": False,
+    "17": False,
+    "102": 8,
+}
+
+TH213_THERMOSTAT_PAYLOAD = {
+    "1": True,
+    "2": 18,
+    "3": 20,
+    "4": 1,
+    "6": False,
+    "12": 0,
+    "101": 16,
+    "102": 2,
+    "103": 0,
+    "104": 2,
+    "105": True,
+    "107": False,
+    "108": False,
+    "110": 0,
+}
+
+WETAIR_WCH750_HEATER_PAYLOAD = {
+    "1": False,
+    "2": 17,
+    "4": "mod_free",
+    "11": "heating",
+    "19": "0h",
+    "20": 0,
+    "21": 0,
+    "101": "level1",
+}
+
+WETAIR_WAWH1210_HUMIDIFIER_PAYLOAD = {
+    "1": True,
+    "5": True,
+    "8": True,
+    "13": 50,
+    "14": 57,
+    "22": 0,
+    "24": "AUTO",
+    "25": True,
+    "29": False,
+    "101": "Have_water",
+}
+
+SASWELL_T29UTK_THERMOSTAT_PAYLOAD = {
+    "1": True,
+    "2": 240,
+    "3": 241,
+    "4": "cold",
+    "5": "auto",
+    "19": "C",
+    "101": False,
+    "102": False,
+    "103": "cold",
+    "112": "3",
+    "113": 0,
+    "114": 24,
+    "115": 24,
+    "116": 75,
+    "117": 81,
+}
+
+SASWELL_C16_THERMOSTAT_PAYLOAD = {
+    "2": 220,
+    "3": "Smart",
+    "4": 0,
+    "5": 217,
+    "6": 350,
+    "7": False,
+    "8": 241,
+    "9": False,
+    "10": True,
+    "11": False,
+    "12": "7",
+    "14": 0,
+    "15": 0,
+    "17": 0,
+    "21": False,
+    "22": 1500,
+    "23": 12,
+    "24": "Standby",
+    "26": 50,
+}
+
+FERSK_VIND2_PAYLOAD = {
+    "1": True,
+    "2": 22,
+    "3": 23,
+    "4": "COOL",
+    "5": 1,
+    "19": "C",
+    "101": False,
+    "102": False,
+    "103": 0,
+    "104": False,
+    "105": 0,
+    "106": 0,
+    "109": False,
+    "110": 0,
+}
+
+KOGAN_GLASS_1_7L_KETTLE_PAYLOAD = {
+    "1": False,
+    "5": 99,
+    "102": "90",
+}
+
+RENPHO_PURIFIER_PAYLOAD = {
+    "1": True,
+    "4": "low",
+    "7": False,
+    "8": False,
+    "19": "0",
+    "22": "0",
+    "101": False,
+    "102": 0,
+    "103": 0,
+    "104": 0,
+    "105": 0,
+}
+
+ARLEC_FAN_PAYLOAD = {
+    "1": True,
+    "3": 1,
+    "4": "forward",
+    "102": "normal",
+    "103": "off",
+}
+
+CARSON_CB_PAYLOAD = {
+    "1": True,
+    "2": 20,
+    "3": 23,
+    "4": "COOL",
+    "5": 1,
+    "19": "C",
+    "102": False,
+    "103": 0,
+    "104": False,
+    "105": 0,
+    "106": 0,
+    "110": 0,
+}
+
+KOGAN_KAWFPAC09YA_AIRCON_PAYLOAD = {
+    "1": True,
+    "2": 19,
+    "3": 18,
+    "4": "COOL",
+    "5": "1",
+    "19": "C",
+    "105": 0,
+    "106": 0,
+    "107": False,
+}
+
+GRIDCONNECT_2SOCKET_PAYLOAD = {
+    "1": True,
+    "2": True,
+    "9": 0,
+    "10": 0,
+    "17": 0,
+    "18": 500,
+    "19": 1200,
+    "20": 240,
+    "21": 0,
+    "22": 0,
+    "23": 0,
+    "24": 0,
+    "25": 0,
+    "38": "0",
+    "40": False,
+    "101": True,
+}
+
+EBERG_QUBO_Q40HD_PAYLOAD = {
+    "1": True,
+    "2": 22,
+    "3": 20,
+    "4": "hot",
+    "5": "middle",
+    "19": "c",
+    "22": 0,
+    "25": False,
+    "30": False,
+    "101": "heat_s",
+}
+
+STIRLING_FS1_FAN_PAYLOAD = {
+    "1": True,
+    "2": "normal",
+    "3": 9,
+    "5": False,
+    "22": "cancel",
+}
+
+QOTO_SPRINKLER_PAYLOAD = {
+    "102": 100,
+    "103": 100,
+    "104": 10036,
+    "105": 10800,
+    "108": 0,
+}
+
+MINCO_MH1823D_THERMOSTAT_PAYLOAD = {
+    "1": True,
+    "2": "program",
+    "3": "stop",
+    "5": False,
+    "9": True,
+    "12": False,
+    "18": "out",
+    "19": "c",
+    "22": 18,
+    "23": 64,
+    "32": 1,
+    "33": 205,
+    "35": 0,
+    "37": 689,
+    "39": "7",
+    "45": 0,
+    "101": 200,
+    "102": 680,
+    "103": 0,
+    "104": 2,
+    "105": "no_power",
+    "106": 35,
+    "107": 95,
+}
+
+SIMPLE_GARAGE_DOOR_PAYLOAD = {
+    "1": True,
+    "101": False,
+}
+
+NEDIS_HTPL20F_PAYLOAD = {
+    "1": True,
+    "2": 25,
+    "3": 25,
+    "4": "1",
+    "7": False,
+    "11": "0",
+    "13": 0,
+    "101": False,
+}
+
+ASPEN_ASP200_FAN_PAYLOAD = {
+    "1": True,
+    "2": "in",
+    "3": 1,
+    "8": 0,
+    "18": 20,
+    "19": 25,
+    "101": True,
+    "102": 3,
+}
+
+TMWF02_FAN_PAYLOAD = {
+    "1": True,
+    "2": 0,
+    "3": "level_2",
+    "4": 40,
+}
+
+TIMED_SOCKET_PAYLOAD = {
+    "1": True,
+    "11": 0,
+}
+
+DIGOO_DGSP202_SOCKET_PAYLOAD = {
+    "1": True,
+    "2": True,
+    "9": 0,
+    "10": 0,
+    "18": 500,
+    "19": 1200,
+    "20": 240,
+}
+
+WOOX_R4028_SOCKET_PAYLOAD = {
+    "1": True,
+    "2": True,
+    "3": True,
+    "7": True,
+    "101": 0,
+    "102": 0,
+    "103": 0,
+    "105": 0,
+}
+
+OWON_PCT513_THERMOSTAT_PAYLOAD = {
+    "2": "cool",
+    "16": 2150,
+    "17": 71,
+    "23": "c",
+    "24": 2950,
+    "29": 85,
+    "34": 52,
+    "45": 0,
+    "107": "0",
+    "108": 2150,
+    "109": 1650,
+    "110": 71,
+    "111": 62,
+    "115": "auto",
+    "116": "1",
+    "119": True,
+    "120": "permhold",
+    "123": 25,
+    "129": "coolfanon",
+}
+
+HYSEN_HY08WE2_THERMOSTAT_PAYLOAD = {
+    "1": True,
+    "2": 50,
+    "3": 170,
+    "4": "Manual",
+    "6": False,
+    "12": 0,
+    "101": False,
+    "102": False,
+    "103": 170,
+    "104": 4,
+    "105": 15,
+    "106": True,
+    "107": True,
+    "108": True,
+    "109": -10,
+    "110": 10,
+    "111": 2,
+    "112": 35,
+    "113": 5,
+    "114": 30,
+    "115": 5,
+    "116": "all",
+    "117": "keep",
+    "118": "2days",
+}
+
+POIEMA_ONE_PURIFIER_PAYLOAD = {
+    "1": True,
+    "2": 12,
+    "3": "manual",
+    "4": "mid",
+    "7": False,
+    "11": False,
+    "18": "cancel",
+    "19": 0,
+}
+
+ECOSTRAD_ACCENTIQ_HEATER_PAYLOAD = {
+    "1": True,
+    "2": 200,
+    "3": 195,
+    "10": 0,
+    "101": True,
+}
+
+NASHONE_MTS700WB_THERMOSTAT_PAYLOAD = {
+    "1": True,
+    "2": "hot",
+    "3": "manual",
+    "16": 20,
+    "17": 68,
+    "23": "c",
+    "24": 19,
+    "27": 0,
+    "29": 66,
+    "39": False,
+    "41": "cancel",
+    "42": 0,
+}

+ 163 - 0
tests/devices/test_nashone_mts700wb_thermostat.py

@@ -0,0 +1,163 @@
+from homeassistant.components.climate.const import (
+    CURRENT_HVAC_COOL,
+    CURRENT_HVAC_HEAT,
+    HVAC_MODE_COOL,
+    HVAC_MODE_HEAT,
+    HVAC_MODE_OFF,
+    SUPPORT_TARGET_TEMPERATURE,
+)
+from homeassistant.const import (
+    STATE_UNAVAILABLE,
+    TEMP_CELSIUS,
+    TEMP_FAHRENHEIT,
+    TIME_MINUTES,
+)
+
+from ..const import NASHONE_MTS700WB_THERMOSTAT_PAYLOAD
+from ..helpers import assert_device_properties_set
+from ..mixins.climate import TargetTemperatureTests
+from ..mixins.number import BasicNumberTests
+from ..mixins.select import BasicSelectTests
+from ..mixins.sensor import BasicSensorTests
+from ..mixins.switch import BasicSwitchTests
+from .base_device_tests import TuyaDeviceTestCase
+
+POWER_DPS = "1"
+HVACMODE_DPS = "2"
+HVACACTION_DPS = "3"
+TEMPERATURE_DPS = "16"
+TEMPF_DPS = "17"
+UNIT_DPS = "23"
+CURRENTTEMP_DPS = "24"
+CALIBOFFSET_DPS = "27"
+CURRTEMPF_DPS = "29"
+RESET_DPS = "39"
+TIMER_DPS = "41"
+COUNTDOWN_DPS = "42"
+
+
+class TestNashoneMTS700WBThermostat(
+    BasicNumberTests,
+    BasicSelectTests,
+    BasicSensorTests,
+    BasicSwitchTests,
+    TargetTemperatureTests,
+    TuyaDeviceTestCase,
+):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig(
+            "nashone_mts700wb_thermostat.yaml",
+            NASHONE_MTS700WB_THERMOSTAT_PAYLOAD,
+        )
+        self.subject = self.entities.get("climate")
+        self.setUpTargetTemperature(
+            TEMPERATURE_DPS,
+            self.subject,
+            min=-20,
+            max=105,
+        )
+        self.setUpBasicNumber(
+            CALIBOFFSET_DPS,
+            self.entities.get("number_calibration_offset"),
+            min=-5,
+            max=5,
+        )
+        self.setUpBasicSelect(
+            TIMER_DPS,
+            self.entities.get("select_timer"),
+            {
+                "cancel": "off",
+                "1h": "1 hour",
+            },
+        )
+        self.setUpBasicSensor(
+            COUNTDOWN_DPS,
+            self.entities.get("sensor_timer"),
+            unit=TIME_MINUTES,
+            testdata=(600, 10.0),
+        )
+        self.setUpBasicSwitch(
+            RESET_DPS,
+            self.entities.get("switch_factory_reset"),
+        )
+        self.mark_secondary(
+            [
+                "number_calibration_offset",
+                "select_timer",
+                "sensor_timer",
+                "switch_factory_reset",
+            ],
+        )
+
+    def test_supported_features(self):
+        self.assertEqual(
+            self.subject.supported_features,
+            SUPPORT_TARGET_TEMPERATURE,
+        )
+
+    def test_current_temperature(self):
+        self.dps[CURRENTTEMP_DPS] = 24
+        self.assertEqual(self.subject.current_temperature, 24)
+
+    def test_hvac_mode(self):
+        self.dps[POWER_DPS] = False
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_OFF)
+
+        self.dps[POWER_DPS] = True
+        self.dps[HVACMODE_DPS] = "hot"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_HEAT)
+
+        self.dps[HVACMODE_DPS] = "cold"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_COOL)
+
+        self.dps[HVACMODE_DPS] = None
+        self.assertEqual(self.subject.hvac_mode, STATE_UNAVAILABLE)
+
+    def test_hvac_modes(self):
+        self.assertCountEqual(
+            self.subject.hvac_modes,
+            [
+                HVAC_MODE_COOL,
+                HVAC_MODE_HEAT,
+                HVAC_MODE_OFF,
+            ],
+        )
+
+    async def test_set_hvac_mode_cool(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {POWER_DPS: True, HVACMODE_DPS: "cold"},
+        ):
+            await self.subject.async_set_hvac_mode(HVAC_MODE_COOL)
+
+    async def test_set_hvac_mode_heat(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {POWER_DPS: True, HVACMODE_DPS: "hot"},
+        ):
+            await self.subject.async_set_hvac_mode(HVAC_MODE_HEAT)
+
+    async def test_set_hvac_mode_off(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {POWER_DPS: False},
+        ):
+            await self.subject.async_set_hvac_mode(HVAC_MODE_OFF)
+
+    def test_hvac_action(self):
+        self.dps[HVACMODE_DPS] = "hot"
+        self.dps[HVACACTION_DPS] = "manual"
+        self.assertEqual(self.subject.hvac_action, CURRENT_HVAC_HEAT)
+        self.dps[HVACMODE_DPS] = "cold"
+        self.assertEqual(self.subject.hvac_action, CURRENT_HVAC_COOL)
+
+    def test_extra_state_attributes(self):
+        self.assertEqual(self.subject.extra_state_attributes, {})
+
+    def test_icons(self):
+        self.assertEqual(self.basicNumber.icon, "mdi:arrow-collapse-up")
+        self.assertEqual(self.basicSelect.icon, "mdi:timer")
+        self.assertEqual(self.basicSensor.icon, "mdi:timer")
+        self.assertEqual(self.basicSwitch.icon, "mdi:cog-refresh")