Compare commits
	
		
			150 Commits
		
	
	
		
			v0.1.1
			...
			v0.9.0-bet
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b1448ddfd8 | |||
| dfa5735bc2 | |||
| 52c3a861de | |||
| d3503af158 | |||
| d81b1ae712 | |||
| eb5ba43707 | |||
| efcac321b8 | |||
| 79b43b8695 | |||
| 5bc3120000 | |||
| 0f9f0dee4c | |||
| 80b3741f2f | |||
| c433714a94 | |||
| 228cf3cf73 | |||
| 1a50e8112d | |||
| 57ecd7c3a5 | |||
| 2fe8ace9f5 | |||
| 6e9981c9ab | |||
| cb660fa9e0 | |||
| a8762367ed | |||
| 696dc136eb | |||
| e9d1bb2056 | |||
| 9518031f24 | |||
| bf1a6e8fe2 | |||
| 833c395c97 | |||
| d963086dbf | |||
| 29238d3d08 | |||
| a4ec3290ba | |||
| d39deba973 | |||
| fae4c4c879 | |||
| 617ea0f99a | |||
| 81676771c7 | |||
| 604cf1b3c6 | |||
| 9a65eaba77 | |||
| e777fe1ec9 | |||
| 845adc75c9 | |||
| 17d4d14ead | |||
| 593d3912af | |||
| aefe2cf88d | |||
| 146e710881 | |||
| 0afbfe997d | |||
| 6828f3e9a8 | |||
| a56d3e5f88 | |||
| 240dc85ff3 | |||
| 44794c35ca | |||
| a5c7b99569 | |||
| 6935f5f07f | |||
| 74f5887bb2 | |||
| 155b1ff91a | |||
| 7b80acb6b9 | |||
| 0e9bd97c7b | |||
| dae8b48075 | |||
| 7e40afae68 | |||
| c0fda4cd1b | |||
| 2802bcad25 | |||
| 8aa8563b9b | |||
| 8e4e491c33 | |||
| 28a8ad1672 | |||
| e56f2c99c0 | |||
| e35a6ce751 | |||
| 5bff5d2143 | |||
| f1e16312ff | |||
| 8c1bba2468 | |||
| 616f7babdb | |||
| 1143c47fd3 | |||
| c60d94a170 | |||
| c89521f169 | |||
| e49841608d | |||
| 90e02428e8 | |||
| 9370cf84b8 | |||
| e24b48d672 | |||
| 4c3f6604d3 | |||
| 13a23eb6e1 | |||
| 2c93b86dfe | |||
| 9c0b467d68 | |||
| d2cebfad67 | |||
| 7f439139d5 | |||
| aa7b40a454 | |||
| e0cba7379a | |||
| 873cc2d70f | |||
| 43b967cd41 | |||
| 2c6def8f57 | |||
| b723744948 | |||
| e0081bf75e | |||
| 554ce1d7ff | |||
| 256c691213 | |||
| 7fb68be033 | |||
| 72c83527d5 | |||
| 75622e18a2 | |||
| a2d0257410 | |||
| e2c7ca36db | |||
| b33b6a40b2 | |||
| 75859543aa | |||
| 891ae51832 | |||
| 102a05ffcd | |||
| 380cde5a71 | |||
| 5f9dbef4fc | |||
| 5dbf508519 | |||
| 7d3813b8fd | |||
| 2aa1d3df01 | |||
| e2f7f15a5f | |||
| d91b3edb40 | |||
| 83c5e3479e | |||
| b0cd020941 | |||
| 593842144a | |||
| 9a6e1155f9 | |||
| 365a3af171 | |||
| 6de6ff375c | |||
| 89d2fd4af1 | |||
| 92add01a59 | |||
| 4a685e67e0 | |||
| 6303843116 | |||
| 907bc44533 | |||
| 4901be4050 | |||
| c8189414b8 | |||
| 799ac67d94 | |||
| 7e9202ef38 | |||
| e1a2af70e9 | |||
| c78aeb1fbb | |||
| 67f280512d | |||
| 6093b57f76 | |||
| 287e895f4d | |||
| d3dc1b9f45 | |||
| 116f9d5470 | |||
| 05e9d835b1 | |||
| 135d6cafed | |||
| 077bded6dd | |||
| 0d575f65f9 | |||
| 34e888f6d6 | |||
| 26db07acdc | |||
| e698393841 | |||
| 28a0ae53e0 | |||
| 34e99230da | |||
| 5032811963 | |||
| 196309ef5f | |||
| ae6d28f520 | |||
| 1a53ee7e5e | |||
| fbee75108d | |||
| fb8306a4d9 | |||
| 7ec3ca4681 | |||
| 2a3bcfe033 | |||
| db49881b57 | |||
| 93b9989cf2 | |||
| 8eaf2d75e6 | |||
| 57473349c3 | |||
| dfd661cc7c | |||
| f89e2361df | |||
| 075d34b5e2 | |||
| 88c76b8056 | |||
| 03a1e40b6e | |||
| 9d8b17b2cf | 
							
								
								
									
										17
									
								
								.github/workflows/hacs_check.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								.github/workflows/hacs_check.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | name: HACS Action | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |   pull_request: | ||||||
|  |   schedule: | ||||||
|  |     - cron: "0 0 * * *" | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   hacs: | ||||||
|  |     name: HACS Action | ||||||
|  |     runs-on: "ubuntu-latest" | ||||||
|  |     steps: | ||||||
|  |       - name: HACS Action | ||||||
|  |         uses: "hacs/action@main" | ||||||
|  |         with: | ||||||
|  |           category: "integration" | ||||||
							
								
								
									
										38
									
								
								.github/workflows/python_check.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								.github/workflows/python_check.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | |||||||
|  | name: Python check | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     branches: [ "main" ] | ||||||
|  |   pull_request: | ||||||
|  |     branches: [ "main" ] | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   build: | ||||||
|  |  | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     strategy: | ||||||
|  |       fail-fast: false | ||||||
|  |       matrix: | ||||||
|  |         python-version: ["3.10", "3.11"] | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |     - uses: actions/checkout@v3 | ||||||
|  |     - name: Set up Python ${{ matrix.python-version }} | ||||||
|  |       uses: actions/setup-python@v3 | ||||||
|  |       with: | ||||||
|  |         python-version: ${{ matrix.python-version }} | ||||||
|  |     - name: Install dependencies | ||||||
|  |       run: | | ||||||
|  |         python -m pip install --upgrade pip | ||||||
|  |         python -m pip install flake8 pylint black | ||||||
|  |     - name: Lint with flake8 | ||||||
|  |       run: | | ||||||
|  |         # stop the build if there are Python syntax errors or undefined names | ||||||
|  |         flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics | ||||||
|  |         flake8 . --count --exit-zero --max-complexity=10 --max-line-length=88 --statistics | ||||||
|  |     # - name: Analysing the code with pylint | ||||||
|  |     #   run: | | ||||||
|  |     #     pylint --max-line-length 88 $(git ls-files '*.py') | ||||||
|  |     - name: Check black style | ||||||
|  |       run: | | ||||||
|  |         black . --check | ||||||
							
								
								
									
										25
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | name: Release | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   release: | ||||||
|  |     types: [published] | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   release-zip: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     steps: | ||||||
|  |       - uses: actions/checkout@v2 | ||||||
|  |  | ||||||
|  |       - name: ZIP Component Dir | ||||||
|  |         run: | | ||||||
|  |           cd ${{ github.workspace }}/custom_components/hon | ||||||
|  |           zip -r haier_hon.zip ./ | ||||||
|  |  | ||||||
|  |       - name: Upload zip to release | ||||||
|  |         uses: svenstaro/upload-release-action@v2 | ||||||
|  |         with: | ||||||
|  |           repo_token: ${{ secrets.GITHUB_TOKEN }} | ||||||
|  |           file: ${{ github.workspace }}/custom_components/hon/haier_hon.zip | ||||||
|  |           asset_name: haier_hon.zip | ||||||
|  |           tag: ${{ github.ref }} | ||||||
|  |           overwrite: true | ||||||
							
								
								
									
										14
									
								
								.github/workflows/validate.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/validate.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | |||||||
|  | name: Validate with hassfest | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |   pull_request: | ||||||
|  |   schedule: | ||||||
|  |     - cron:  '0 0 * * *' | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   validate: | ||||||
|  |     runs-on: "ubuntu-latest" | ||||||
|  |     steps: | ||||||
|  |         - uses: "actions/checkout@v3" | ||||||
|  |         - uses: "home-assistant/actions/hassfest@master" | ||||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,4 @@ | |||||||
| __pycache__/ | __pycache__/ | ||||||
| test.py |  | ||||||
| .idea/ | .idea/ | ||||||
|  | scripts/translations/ | ||||||
|  | scripts/test* | ||||||
|  | |||||||
							
								
								
									
										532
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										532
									
								
								README.md
									
									
									
									
									
								
							| @ -1,26 +1,516 @@ | |||||||
| # hOn | # Haier hOn | ||||||
| Home Assistant component supporting hOn cloud. | [](https://hacs.xyz) | ||||||
|  | [](https://github.com/Andre0512/hon/releases/latest) | ||||||
| ## Installation | [](https://github.com/Andre0512/pyhOn) | ||||||
| 1. Installing via HACS | [](https://github.com/Andre0512/hon/blob/main/LICENSE) | ||||||
| 2. Go to HACS->Integrations | [](https://tooomm.github.io/github-release-stats/?username=Andre0512&repository=hon)   | ||||||
| 3. Add this repo into your HACS custom repositories | Home Assistant integration for [Haier's mobile app hOn](https://hon-smarthome.com/) based on [pyhOn](https://github.com/Andre0512/pyhon). | ||||||
| 4. Search for Haier hOn and Download it |  | ||||||
| 5. Restart your HomeAssistant |  | ||||||
| 6. Go to Settings->Devices & Services |  | ||||||
| 7. Shift reload your browser |  | ||||||
| 8. Click Add Integration |  | ||||||
| 9. Search for Haier hOn  |  | ||||||
| 10. Type your username used in the hOn App and hit submit |  | ||||||
|  |  | ||||||
| ## Supported Appliances | ## Supported Appliances | ||||||
| - Washing Machine | - [Washing Machine](https://github.com/Andre0512/hon#washing-machine) | ||||||
|  | - [Tumble Dryer](https://github.com/Andre0512/hon#tumble-dryer) | ||||||
|  | - [Washer Dryer](https://github.com/Andre0512/hon#washer-dryer) | ||||||
|  | - [Oven](https://github.com/Andre0512/hon#oven) | ||||||
|  | - [Dish Washer](https://github.com/Andre0512/hon#dish-washer) | ||||||
|  | - [Air conditioner](https://github.com/Andre0512/hon#air-conditioner) | ||||||
|  | - [Fridge](https://github.com/Andre0512/hon#fridge) | ||||||
|  | - [Hob](https://github.com/Andre0512/hon#hob) [BETA] | ||||||
|  | - [Hood](https://github.com/Andre0512/hon#hood) [BETA] | ||||||
|  | - [Wine Cellar](https://github.com/Andre0512/hon#wine-cellar) [BETA] | ||||||
|  |  | ||||||
| ## Tested Devices | ## Installation | ||||||
| - Haier WD90 | **Method 1:** [](https://my.home-assistant.io/redirect/hacs_repository/?owner=Andre0512&repository=hon&category=integration) | ||||||
|  |  | ||||||
| ## About this Repo | **Method 2:** [HACS](https://hacs.xyz/) > Integrations > Add Integration > **Haier hOn** > Install   | ||||||
| The existing integrations missed some features from the app I liked to have in HomeAssistant. |  | ||||||
| I tried to create a pull request, but in the structures of these existing repos, I find it hard to fit in my needs, so I basically rewrote everything.  |  | ||||||
| I moved the api related stuff into the package [pyhOn](https://github.com/Andre0512/pyhOn). |  | ||||||
|  |  | ||||||
|  | **Method 3:** Manually copy `hon` folder from [latest release](https://github.com/Andre0512/hon/releases/latest) to `config/custom_components` folder. | ||||||
|  |  | ||||||
|  | _Restart Home Assistant_ | ||||||
|  |  | ||||||
|  | ## Configuration | ||||||
|  |  | ||||||
|  | **Method 1**: [](https://my.home-assistant.io/redirect/config_flow_start/?domain=hon) | ||||||
|  |  | ||||||
|  | **Method 2**: Settings > Devices & Services > Add Integration > **Haier hOn**   | ||||||
|  | _If the integration is not in the list, you need to clear the browser cache._ | ||||||
|  |  | ||||||
|  | ## Supported Models | ||||||
|  | Support has been confirmed for these models, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8). | ||||||
|  |  | ||||||
|  | |                     | **Haier**                                                                                                        | **Hoover**                                                                                                            | **Candy**                                                  | | ||||||
|  | |---------------------|------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------| | ||||||
|  | | **Washing Machine** | HW90-B14TEAM5 <br/> HW100-B14959U1                                                                               | H-WASH 500 <br/> H7W4 48MBC-S                                                                                         | RO441286DWMC4-07 <br/> HW 68AMC/1-80 <br/> HWPD 69AMBC/1-S | | ||||||
|  | | **Tumble Dryer**    | HD80-A3959                                                                                                       | H-DRY 500 <br/> H9A3TCBEXS-S <br/> HLE C10DCE-80 <br/> NDE H10A2TCE-80 <br/> NDE H9A2TSBEXS-S <br/> NDPHY10A2TCBEXSS  | BCTDH7A1TE <br/> CSOE C10DE-80 <br/> ROE H9A3TCEX-S        | | ||||||
|  | | **Washer Dryer**    | HWD100-B14979                                                                                                    | HWPS4954DAMR-11                                                                                                       | RPW41066BWMR/1-S                                           | | ||||||
|  | | **Oven**            | HWO60SM2F3XH                                                                                                     | HSOT3161WG                                                                                                            |                                                            | | ||||||
|  | | **Dish Washer**     | XIB 3B2SFS-80 <br/> XIB 6B2D3FB                                                                                  | HFB 6B2S3FX                                                                                                           |                                                            | | ||||||
|  | | **Air conditioner** | AD105S2SM3FA <br/> AS20HPL1HRA <br/> AS25PBAHRA <br/> AS25S2SF1FA-WH <br/> AS25TADHRA-2 <br/> AS35TADHRA-2 <br/> |                                                                                                                       |                                                            | | ||||||
|  | | **Fridge**          | HFW7720ENMB                                                                                                      |                                                                                                                       | CCE4T620EWU                                                | | ||||||
|  | | **Hob**             | HA2MTSJ68MC                                                                                                      |                                                                                                                       | CIS633SCTTWIFI                                             | | ||||||
|  | | **Hood**            | HADG6DS46BWIFI                                                                                                   |                                                                                                                       |                                                            | | ||||||
|  | | **Wine Cellar**     | HWS247FDU1                                                                                                       |                                                                                                                       |                                                            | | ||||||
|  |  | ||||||
|  | ## Supported Languages | ||||||
|  | Translation of internal names like programs are available for all languages which are official supported by the hOn app: | ||||||
|  | * 🇨🇳 Chinese | ||||||
|  | * 🇭🇷 Croatian | ||||||
|  | * 🇨🇿 Czech | ||||||
|  | * 🇳🇱 Dutch | ||||||
|  | * 🇬🇧 English | ||||||
|  | * 🇫🇷 French | ||||||
|  | * 🇩🇪 German | ||||||
|  | * 🇬🇷 Greek | ||||||
|  | * 🇮🇱 Hebrew | ||||||
|  | * 🇮🇹 Italian | ||||||
|  | * 🇵🇱 Polish | ||||||
|  | * 🇵🇹 Portuguese | ||||||
|  | * 🇷🇴 Romanian | ||||||
|  | * 🇷🇺 Russian | ||||||
|  | * 🇷🇸 Serbian | ||||||
|  | * 🇸🇰 Slovak | ||||||
|  | * 🇸🇮 Slovenian | ||||||
|  | * 🇪🇸 Spanish | ||||||
|  | * 🇹🇷 Turkish | ||||||
|  |  | ||||||
|  | ## Examples | ||||||
|  | ### Washing Machine | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## Contribute | ||||||
|  | Any kind of contribution is welcome! | ||||||
|  | ### Read out device data | ||||||
|  | If you want to make a request for adding new appliances or additional attributes and don't want to use the command line, here is how you can read out your device data. | ||||||
|  | For every device exists a hidden button which can be used to log all infos of your appliance. | ||||||
|  | 1. Enable the "Show Device Info" button   | ||||||
|  |    _This button can be found in the diagnostic section of your device or in the entity overview if "show disabled entities" is enabled._ | ||||||
|  | 2. Press the button to create a notification | ||||||
|  | 3. Open home assistant notifications and copy the message (Crtl+A, Ctrl+C) | ||||||
|  | ### Add appliances or additional attributes | ||||||
|  | 1. Install [pyhOn](https://github.com/Andre0512/pyhOn) | ||||||
|  |    ```commandline | ||||||
|  |     $ pip install pyhOn | ||||||
|  |     ``` | ||||||
|  | 2. Use the command line tool to read out all appliance data from your account | ||||||
|  |     ```commandline | ||||||
|  |     $ pyhOn | ||||||
|  |     User for hOn account: user.name@example.com | ||||||
|  |     Password for hOn account: ******** | ||||||
|  |     ========== WM - Washing Machine ========== | ||||||
|  |     commands: | ||||||
|  |       pauseProgram: pauseProgram command | ||||||
|  |       resumeProgram: resumeProgram command | ||||||
|  |       startProgram: startProgram command | ||||||
|  |       stopProgram: stopProgram command | ||||||
|  |     data: | ||||||
|  |       actualWeight: 0 | ||||||
|  |       airWashTempLevel: 0 | ||||||
|  |       airWashTime: 0 | ||||||
|  |       antiAllergyStatus: 0 | ||||||
|  |       ... | ||||||
|  |     ``` | ||||||
|  | 3. Fork this repository and clone it to your local machine | ||||||
|  | 4. Add the keys of the attributes you'd like to have as `EntityDescription` into this Repository   | ||||||
|  |    _Example: Add pause button_ | ||||||
|  |     ```python | ||||||
|  |     BUTTONS: dict[str, tuple[ButtonEntityDescription, ...]] = { | ||||||
|  |         "WM": (                        # WM is the applianceTypeName | ||||||
|  |             ButtonEntityDescription( | ||||||
|  |                 key="pauseProgram",    # key from pyhOn | ||||||
|  |                 name="Pause Program",  # name in home assistant | ||||||
|  |                 icon="mdi:pause",      # icon in home assistant | ||||||
|  |                 ... | ||||||
|  |             ), | ||||||
|  |         ... | ||||||
|  |     ``` | ||||||
|  | 5. Create a [pull request](https://github.com/Andre0512/hon/pulls) | ||||||
|  |  | ||||||
|  | #### Tips and Tricks | ||||||
|  | - If you want to have some states humanreadable, have a look at the `translation_key` parameter of the `EntityDescription`. | ||||||
|  | - If you need to implement some more logic, create a pull request to the underlying library. There we collect special requirements in the `appliances` directory. | ||||||
|  | - Use [pyhOn's translate command](https://github.com/Andre0512/pyhOn#translation) to read out the official translations | ||||||
|  |  | ||||||
|  | ## Special Thanks | ||||||
|  | - to [@alexandre-leites](https://github.com/alexandre-leites), [@MiguelAngelLV](https://github.com/MiguelAngelLV) and [@drudgebg](https://github.com/drudgebg) for contributing early to this project and adding new integrations. | ||||||
|  | - to [gvigroux/hon](https://github.com/gvigroux/hon), [signalize/hon-app-research](https://github.com/signalize/hon-app-research) and [slegars56/hon](https://github.com/slegars56/hon) for inspiring me to do this integration and for doing pioneer work on the hOn api. | ||||||
|  | - to everyone who contributed, created an issue, gave this repo a star, and used this integration. | ||||||
|  | - to the patience of my girlfriend as I work on this integration. | ||||||
|  |  | ||||||
|  | ## Appliance Features | ||||||
|  |  | ||||||
|  | ### Air conditioner | ||||||
|  | #### Controls | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | 10° Heating | `heat-wave` | `switch` | `10degreeHeatingStatus` | | ||||||
|  | | Air Conditioner | `air-conditioner` | `climate` | `settings` | | ||||||
|  | | Echo | `account-voice` | `switch` | `echoStatus` | | ||||||
|  | | Eco Mode |  | `switch` | `ecoMode` | | ||||||
|  | | Eco Pilot | `run` | `select` | `settings.humanSensingStatus` | | ||||||
|  | | Health Mode | `medication-outline` | `switch` | `healthMode` | | ||||||
|  | | Mute | `volume-off` | `switch` | `muteStatus` | | ||||||
|  | | Rapid Mode | `run-fast` | `switch` | `rapidMode` | | ||||||
|  | | Screen Display | `monitor-small` | `switch` | `screenDisplayStatus` | | ||||||
|  | | Self Cleaning | `air-filter` | `switch` | `selfCleaningStatus` | | ||||||
|  | | Self Cleaning 56 | `air-filter` | `switch` | `selfCleaning56Status` | | ||||||
|  | | Silent Sleep | `bed` | `switch` | `silentSleepStatus` | | ||||||
|  | | Target Temperature | `thermometer` | `number` | `settings.tempSel` | | ||||||
|  | #### Sensors | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Air Temperature Outdoor | `thermometer` | `sensor` | `tempAirOutdoor` | | ||||||
|  | | Ch2O Cleaning |  | `binary_sensor` | `ch2oCleaningStatus` | | ||||||
|  | | Coiler Temperature Indoor | `thermometer` | `sensor` | `tempCoilerIndoor` | | ||||||
|  | | Coiler Temperature Outside | `thermometer` | `sensor` | `tempCoilerOutdoor` | | ||||||
|  | | Defrost Temperature Outdoor | `thermometer` | `sensor` | `tempDefrostOutdoor` | | ||||||
|  | | Filter Replacement |  | `binary_sensor` | `filterChangeStatusLocal` | | ||||||
|  | | In Air Temperature Outdoor | `thermometer` | `sensor` | `tempInAirOutdoor` | | ||||||
|  | | Indoor Temperature | `thermometer` | `sensor` | `tempIndoor` | | ||||||
|  | | Machine Status | `information` | `sensor` | `machMode` | | ||||||
|  | | Outdoor Temperature | `thermometer` | `sensor` | `tempOutdoor` | | ||||||
|  | | Program |  | `select` | `startProgram.program` | | ||||||
|  | | Program | `play` | `sensor` | `programName` | | ||||||
|  | | Selected Temperature | `thermometer` | `sensor` | `tempSel` | | ||||||
|  |  | ||||||
|  | ### Dish washer | ||||||
|  | #### Controls | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Buzzer Disabled | `volume-off` | `switch` | `buzzerDisabled` | | ||||||
|  | | Dish Washer | `dishwasher` | `switch` | `startProgram` / `stopProgram` | | ||||||
|  | #### Configs | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Add Dish | `silverware-fork-knife` | `switch` | `startProgram.addDish` | | ||||||
|  | | Delay time | `timer-plus` | `number` | `startProgram.delayTime` | | ||||||
|  | | Eco Express | `sprout` | `switch` | `startProgram.ecoExpress` | | ||||||
|  | | Eco Index | `sprout` | `sensor` | `startProgram.ecoIndex` | | ||||||
|  | | Energy Label | `lightning-bolt-circle` | `sensor` | `startProgram.energyLabel` | | ||||||
|  | | Extra Dry | `hair-dryer` | `switch` | `startProgram.extraDry` | | ||||||
|  | | Half Load | `fraction-one-half` | `switch` | `startProgram.halfLoad` | | ||||||
|  | | Open Door | `door-open` | `switch` | `startProgram.openDoor` | | ||||||
|  | | Program |  | `select` | `startProgram.program` | | ||||||
|  | | Remaining Time | `timer` | `select` | `startProgram.remainingTime` | | ||||||
|  | | Temperature | `thermometer` | `select` | `startProgram.temp` | | ||||||
|  | | Temperature | `thermometer` | `sensor` | `startProgram.temp` | | ||||||
|  | | Three in One | `numeric-3-box-outline` | `switch` | `startProgram.threeInOne` | | ||||||
|  | | Time | `timer` | `sensor` | `startProgram.remainingTime` | | ||||||
|  | | Water Efficiency | `water` | `sensor` | `startProgram.waterEfficiency` | | ||||||
|  | | Water Saving | `water-percent` | `sensor` | `startProgram.waterSaving` | | ||||||
|  | | Water hard | `water` | `number` | `startProgram.waterHard` | | ||||||
|  | #### Sensors | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Connection |  | `binary_sensor` | `attributes.lastConnEvent.category` | | ||||||
|  | | Door |  | `binary_sensor` | `doorStatus` | | ||||||
|  | | Error | `math-log` | `sensor` | `errors` | | ||||||
|  | | Machine Status | `information` | `sensor` | `machMode` | | ||||||
|  | | Program | `play` | `sensor` | `programName` | | ||||||
|  | | Program Phase | `washing-machine` | `sensor` | `prPhase` | | ||||||
|  | | Remaining Time | `timer` | `sensor` | `remainingTimeMM` | | ||||||
|  | | Rinse Aid | `spray-bottle` | `binary_sensor` | `rinseAidStatus` | | ||||||
|  | | Salt | `shaker-outline` | `binary_sensor` | `saltStatus` | | ||||||
|  |  | ||||||
|  | ### Hood | ||||||
|  | #### Controls | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Start Program | `hvac` | `button` | `startProgram` | | ||||||
|  | | Stop Program | `hvac-off` | `button` | `stopProgram` | | ||||||
|  | | Wind Speed |  | `fan` | `settings.windSpeed` | | ||||||
|  | #### Configs | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Light status | `lightbulb` | `number` | `startProgram.lightStatus` | | ||||||
|  | #### Sensors | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Delay time | `clock-start` | `sensor` | `delayTime` | | ||||||
|  | | Delay time status | `clock-start` | `sensor` | `delayTimeStatus` | | ||||||
|  | | Errors | `alert-circle` | `sensor` | `errors` | | ||||||
|  | | Filter Cleaning Alarm Status |  | `sensor` | `filterCleaningAlarmStatus` | | ||||||
|  | | Filter Cleaning Status |  | `sensor` | `filterCleaningStatus` | | ||||||
|  | | Last Work Time | `clock-start` | `sensor` | `lastWorkTime` | | ||||||
|  | | Light Status | `lightbulb` | `sensor` | `lightStatus` | | ||||||
|  | | Mach Mode |  | `sensor` | `machMode` | | ||||||
|  | | On / Off Status | `lightbulb` | `sensor` | `onOffStatus` | | ||||||
|  | | Quick Delay Time Status |  | `sensor` | `quickDelayTimeStatus` | | ||||||
|  | | RGB Light Color | `lightbulb` | `sensor` | `rgbLightColors` | | ||||||
|  | | RGB Light Status | `lightbulb` | `sensor` | `rgbLightStatus` | | ||||||
|  |  | ||||||
|  | ### Hob | ||||||
|  | #### Controls | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Start Program | `pot-steam` | `button` | `startProgram` | | ||||||
|  | #### Configs | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Power Management | `timelapse` | `number` | `startProgram.powerManagement` | | ||||||
|  | | Program |  | `select` | `startProgram.program` | | ||||||
|  | | Temperature | `thermometer` | `number` | `startProgram.temp` | | ||||||
|  | #### Sensors | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Connection | `wifi` | `binary_sensor` | `attributes.lastConnEvent.category` | | ||||||
|  | | Error | `math-log` | `sensor` | `errors` | | ||||||
|  | | Hob Lock |  | `binary_sensor` | `hobLockStatus` | | ||||||
|  | | Hot Status |  | `binary_sensor` | `hotStatus` | | ||||||
|  | | On | `power-cycle` | `binary_sensor` | `attributes.parameters.onOffStatus` | | ||||||
|  | | Pan Status | `pot-mix` | `binary_sensor` | `panStatus` | | ||||||
|  | | Power | `lightning-bolt` | `sensor` | `power` | | ||||||
|  | | Program | `play` | `sensor` | `programName` | | ||||||
|  | | Remaining Time | `timer` | `sensor` | `remainingTimeMM` | | ||||||
|  | | Temperature | `thermometer` | `sensor` | `temp` | | ||||||
|  |  | ||||||
|  | ### Oven | ||||||
|  | #### Controls | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Oven | `toaster-oven` | `switch` | `startProgram` / `stopProgram` | | ||||||
|  | | Oven | `thermometer` | `climate` | `settings.tempSel` | | ||||||
|  | #### Configs | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Delay time | `timer-plus` | `number` | `startProgram.delayTime` | | ||||||
|  | | Preheat | `thermometer-chevron-up` | `switch` | `startProgram.preheatStatus` | | ||||||
|  | | Program |  | `select` | `startProgram.program` | | ||||||
|  | | Program Duration | `timelapse` | `number` | `startProgram.prTime` | | ||||||
|  | | Target Temperature | `thermometer` | `number` | `startProgram.tempSel` | | ||||||
|  | #### Sensors | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Connection | `wifi` | `binary_sensor` | `attributes.lastConnEvent.category` | | ||||||
|  | | On | `power-cycle` | `binary_sensor` | `attributes.parameters.onOffStatus` | | ||||||
|  | | Program | `play` | `sensor` | `programName` | | ||||||
|  | | Remaining Time | `timer` | `sensor` | `remainingTimeMM` | | ||||||
|  | | Start Time | `clock-start` | `sensor` | `delayTime` | | ||||||
|  | | Temperature | `thermometer` | `sensor` | `temp` | | ||||||
|  | | Temperature Selected | `thermometer` | `sensor` | `tempSel` | | ||||||
|  |  | ||||||
|  | ### Fridge | ||||||
|  | #### Controls | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Auto-Set Mode | `thermometer-auto` | `switch` | `intelligenceMode` | | ||||||
|  | | Freezer | `snowflake-thermometer` | `climate` | `settings.tempSelZ2` | | ||||||
|  | | Freezer Temperature | `thermometer` | `number` | `settings.tempSelZ2` | | ||||||
|  | | Fridge | `thermometer` | `climate` | `settings.tempSelZ1` | | ||||||
|  | | Fridge Temperature | `thermometer` | `number` | `settings.tempSelZ1` | | ||||||
|  | | Holiday Mode | `palm-tree` | `switch` | `holidayMode` | | ||||||
|  | | Program Start | `play` | `button` | `startProgram` | | ||||||
|  | | Program Stop | `stop` | `button` | `stopProgram` | | ||||||
|  | | Super Cool | `snowflake` | `switch` | `quickModeZ2` | | ||||||
|  | | Super Freeze | `snowflake-variant` | `switch` | `quickModeZ1` | | ||||||
|  | #### Configs | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Program |  | `select` | `startProgram.program` | | ||||||
|  | | Zone | `radiobox-marked` | `select` | `startProgram.zone` | | ||||||
|  | #### Sensors | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Auto-Set Mode | `thermometer-auto` | `binary_sensor` | `intelligenceMode` | | ||||||
|  | | Door Status Freezer | `fridge-top` | `binary_sensor` | `doorStatusZ1` | | ||||||
|  | | Door Status Fridge | `fridge-bottom` | `binary_sensor` | `door2StatusZ1` | | ||||||
|  | | Error | `math-log` | `sensor` | `errors` | | ||||||
|  | | Holiday Mode | `palm-tree` | `binary_sensor` | `holidayMode` | | ||||||
|  | | Room Humidity | `water-percent` | `sensor` | `humidityEnv` | | ||||||
|  | | Room Temperature | `home-thermometer-outline` | `sensor` | `tempEnv` | | ||||||
|  | | Super Cool | `snowflake` | `binary_sensor` | `quickModeZ2` | | ||||||
|  | | Super Freeze | `snowflake-variant` | `binary_sensor` | `quickModeZ1` | | ||||||
|  | | Temperature Freezer | `snowflake-thermometer` | `sensor` | `tempZ2` | | ||||||
|  | | Temperature Fridge | `thermometer` | `sensor` | `tempZ1` | | ||||||
|  |  | ||||||
|  | ### Tumble dryer | ||||||
|  | #### Controls | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Pause Tumble Dryer | `pause` | `switch` | `pauseProgram` / `resumeProgram` | | ||||||
|  | | Tumble Dryer | `tumble-dryer` | `switch` | `startProgram` / `stopProgram` | | ||||||
|  | #### Configs | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Anti-Crease | `timer` | `switch` | `startProgram.antiCreaseTime` | | ||||||
|  | | Anti-Crease | `timer` | `switch` | `startProgram.anticrease` | | ||||||
|  | | Delay time | `timer-plus` | `number` | `startProgram.delayTime` | | ||||||
|  | | Dry Time |  | `number` | `startProgram.dryTime` | | ||||||
|  | | Dry Time | `timer` | `select` | `startProgram.dryTimeMM` | | ||||||
|  | | Dry level | `hair-dryer` | `select` | `startProgram.dryLevel` | | ||||||
|  | | Energy Label | `lightning-bolt-circle` | `sensor` | `startProgram.energyLabel` | | ||||||
|  | | Program |  | `select` | `startProgram.program` | | ||||||
|  | | Steam Type | `weather-dust` | `sensor` | `steamType` | | ||||||
|  | | Steam level | `smoke` | `sensor` | `startProgram.steamLevel` | | ||||||
|  | | Sterilization | `clock-start` | `switch` | `startProgram.sterilizationStatus` | | ||||||
|  | | Suggested Load | `weight-kilogram` | `sensor` | `startProgram.suggestedLoadD` | | ||||||
|  | | Temperature level | `thermometer` | `number` | `startProgram.tempLevel` | | ||||||
|  | #### Sensors | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Anti-Crease |  | `binary_sensor` | `anticrease` | | ||||||
|  | | Connection |  | `binary_sensor` | `attributes.lastConnEvent.category` | | ||||||
|  | | Door |  | `binary_sensor` | `doorStatus` | | ||||||
|  | | Dry level | `hair-dryer` | `sensor` | `dryLevel` | | ||||||
|  | | Error | `math-log` | `sensor` | `errors` | | ||||||
|  | | Machine Status | `information` | `sensor` | `machMode` | | ||||||
|  | | Program | `play` | `sensor` | `programName` | | ||||||
|  | | Program Phase | `washing-machine` | `sensor` | `prPhase` | | ||||||
|  | | Remaining Time | `timer` | `sensor` | `remainingTimeMM` | | ||||||
|  | | Start Time | `clock-start` | `sensor` | `delayTime` | | ||||||
|  | | Steam level | `smoke` | `sensor` | `steamLevel` | | ||||||
|  | | Temperature level | `thermometer` | `sensor` | `tempLevel` | | ||||||
|  |  | ||||||
|  | ### Wine Cellar | ||||||
|  | #### Controls | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Light | `lightbulb` | `switch` | `lightStatus` | | ||||||
|  | | Sabbath Mode | `palm-tree` | `switch` | `sabbathStatus` | | ||||||
|  | | Wine Cellar | `thermometer` | `climate` | `settings.tempSel` | | ||||||
|  | | Wine Cellar | `thermometer` | `climate` | `settings.tempSelZ2` | | ||||||
|  | #### Sensors | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Error | `math-log` | `sensor` | `errors` | | ||||||
|  | | Humidity | `water-percent` | `sensor` | `humidityZ1` | | ||||||
|  | | Humidity 2 | `water-percent` | `sensor` | `humidityZ2` | | ||||||
|  | | Program | `play` | `sensor` | `programName` | | ||||||
|  | | Room Temperature | `home-thermometer-outline` | `sensor` | `tempEnv` | | ||||||
|  | | Selected Temperature | `thermometer` | `sensor` | `tempSel` | | ||||||
|  | | Selected Temperature 2 | `thermometer` | `sensor` | `tempSelZ2` | | ||||||
|  | | Temperature | `thermometer` | `sensor` | `temp` | | ||||||
|  | | Temperature 2 | `thermometer` | `sensor` | `tempZ2` | | ||||||
|  |  | ||||||
|  | ### Washer dryer | ||||||
|  | #### Controls | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Pause Washer Dryer | `pause` | `switch` | `pauseProgram` / `resumeProgram` | | ||||||
|  | | Washer Dryer | `washing-machine` | `switch` | `startProgram` / `stopProgram` | | ||||||
|  | #### Configs | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Acqua Plus | `water-plus` | `switch` | `startProgram.acquaplus` | | ||||||
|  | | Anti-Crease | `timer` | `switch` | `startProgram.antiCreaseTime` | | ||||||
|  | | Anti-Crease | `timer` | `switch` | `startProgram.anticrease` | | ||||||
|  | | Auto Dose Detergent | `cup` | `switch` | `startProgram.autoDetergentStatus` | | ||||||
|  | | Auto Dose Softener | `teddy-bear` | `switch` | `startProgram.autoSoftenerStatus` | | ||||||
|  | | Delay Status | `timer-check` | `switch` | `startProgram.delayStatus` | | ||||||
|  | | Delay Time | `timer-plus` | `number` | `startProgram.delayTime` | | ||||||
|  | | Dry Time |  | `number` | `startProgram.dryTime` | | ||||||
|  | | Dry Time | `timer` | `select` | `startProgram.dryTimeMM` | | ||||||
|  | | Dry level | `hair-dryer` | `select` | `startProgram.dryLevel` | | ||||||
|  | | Energy Label | `lightning-bolt-circle` | `sensor` | `startProgram.energyLabel` | | ||||||
|  | | Extra Rinse 1 | `numeric-1-box-multiple-outline` | `switch` | `startProgram.extraRinse1` | | ||||||
|  | | Extra Rinse 2 | `numeric-2-box-multiple-outline` | `switch` | `startProgram.extraRinse2` | | ||||||
|  | | Extra Rinse 3 | `numeric-3-box-multiple-outline` | `switch` | `startProgram.extraRinse3` | | ||||||
|  | | Good Night | `weather-night` | `switch` | `startProgram.goodNight` | | ||||||
|  | | Keep Fresh | `refresh-circle` | `switch` | `startProgram.permanentPressStatus` | | ||||||
|  | | Liquid Detergent Dose | `cup-water` | `sensor` | `startProgram.liquidDetergentDose` | | ||||||
|  | | Main Wash Time | `clock-start` | `number` | `startProgram.mainWashTime` | | ||||||
|  | | Powder Detergent Dose | `cup` | `sensor` | `startProgram.powderDetergentDose` | | ||||||
|  | | Program |  | `select` | `startProgram.program` | | ||||||
|  | | Remaining Time | `timer` | `sensor` | `startProgram.remainingTime` | | ||||||
|  | | Rinse Iterations | `rotate-right` | `number` | `startProgram.rinseIterations` | | ||||||
|  | | Soak Prewash Selection | `tshirt-crew` | `switch` | `startProgram.haier_SoakPrewashSelection` | | ||||||
|  | | Spin speed | `numeric` | `select` | `startProgram.spinSpeed` | | ||||||
|  | | Steam Level | `weather-dust` | `number` | `startProgram.steamLevel` | | ||||||
|  | | Steam Type | `weather-dust` | `sensor` | `steamType` | | ||||||
|  | | Steam level | `smoke` | `sensor` | `startProgram.steamLevel` | | ||||||
|  | | Sterilization | `clock-start` | `switch` | `startProgram.sterilizationStatus` | | ||||||
|  | | Suggested Load | `weight-kilogram` | `sensor` | `startProgram.suggestedLoadW` | | ||||||
|  | | Suggested Load | `weight-kilogram` | `sensor` | `startProgram.suggestedLoadD` | | ||||||
|  | | Suggested weight | `weight-kilogram` | `sensor` | `startProgram.weight` | | ||||||
|  | | Temperature | `thermometer` | `select` | `startProgram.temp` | | ||||||
|  | | Temperature level | `thermometer` | `number` | `startProgram.tempLevel` | | ||||||
|  | | Water hard | `water` | `number` | `startProgram.waterHard` | | ||||||
|  | | lang |  | `number` | `startProgram.lang` | | ||||||
|  | #### Sensors | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Acqua Plus |  | `binary_sensor` | `acquaplus` | | ||||||
|  | | Anti-Crease |  | `binary_sensor` | `anticrease` | | ||||||
|  | | Current Electricity Used | `lightning-bolt` | `sensor` | `currentElectricityUsed` | | ||||||
|  | | Current Temperature | `thermometer` | `sensor` | `temp` | | ||||||
|  | | Current Water Used | `water` | `sensor` | `currentWaterUsed` | | ||||||
|  | | Dirt level | `liquid-spot` | `sensor` | `dirtyLevel` | | ||||||
|  | | Door |  | `binary_sensor` | `doorStatus` | | ||||||
|  | | Door Lock |  | `binary_sensor` | `doorLockStatus` | | ||||||
|  | | Dry level | `hair-dryer` | `sensor` | `dryLevel` | | ||||||
|  | | Error | `math-log` | `sensor` | `errors` | | ||||||
|  | | Extra Rinse 1 |  | `binary_sensor` | `extraRinse1` | | ||||||
|  | | Extra Rinse 2 |  | `binary_sensor` | `extraRinse2` | | ||||||
|  | | Extra Rinse 3 |  | `binary_sensor` | `extraRinse3` | | ||||||
|  | | Good Night Mode |  | `binary_sensor` | `goodNight` | | ||||||
|  | | Machine Status | `information` | `sensor` | `machMode` | | ||||||
|  | | Pre Wash |  | `binary_sensor` | `startProgram.prewash` | | ||||||
|  | | Program | `play` | `sensor` | `programName` | | ||||||
|  | | Program Phase | `washing-machine` | `sensor` | `prPhase` | | ||||||
|  | | Remaining Time | `timer` | `sensor` | `remainingTimeMM` | | ||||||
|  | | Remote Control | `remote` | `binary_sensor` | `attributes.lastConnEvent.category` | | ||||||
|  | | Spin Speed | `speedometer` | `sensor` | `spinSpeed` | | ||||||
|  | | Start Time | `clock-start` | `sensor` | `delayTime` | | ||||||
|  | | Steam level | `smoke` | `sensor` | `steamLevel` | | ||||||
|  | | Temperature level | `thermometer` | `sensor` | `tempLevel` | | ||||||
|  | | Total Power |  | `sensor` | `totalElectricityUsed` | | ||||||
|  | | Total Wash Cycle | `counter` | `sensor` | `totalWashCycle` | | ||||||
|  | | Total Water |  | `sensor` | `totalWaterUsed` | | ||||||
|  |  | ||||||
|  | ### Washing machine | ||||||
|  | #### Controls | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Pause Washing Machine | `pause` | `switch` | `pauseProgram` / `resumeProgram` | | ||||||
|  | | Washing Machine | `washing-machine` | `switch` | `startProgram` / `stopProgram` | | ||||||
|  | #### Configs | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Acqua Plus | `water-plus` | `switch` | `startProgram.acquaplus` | | ||||||
|  | | Auto Dose Detergent | `cup` | `switch` | `startProgram.autoDetergentStatus` | | ||||||
|  | | Auto Dose Softener | `teddy-bear` | `switch` | `startProgram.autoSoftenerStatus` | | ||||||
|  | | Delay Status | `timer-check` | `switch` | `startProgram.delayStatus` | | ||||||
|  | | Delay Time | `timer-plus` | `number` | `startProgram.delayTime` | | ||||||
|  | | Energy Label | `lightning-bolt-circle` | `sensor` | `startProgram.energyLabel` | | ||||||
|  | | Extra Rinse 1 | `numeric-1-box-multiple-outline` | `switch` | `startProgram.extraRinse1` | | ||||||
|  | | Extra Rinse 2 | `numeric-2-box-multiple-outline` | `switch` | `startProgram.extraRinse2` | | ||||||
|  | | Extra Rinse 3 | `numeric-3-box-multiple-outline` | `switch` | `startProgram.extraRinse3` | | ||||||
|  | | Good Night | `weather-night` | `switch` | `startProgram.goodNight` | | ||||||
|  | | Keep Fresh | `refresh-circle` | `switch` | `startProgram.permanentPressStatus` | | ||||||
|  | | Liquid Detergent Dose | `cup-water` | `sensor` | `startProgram.liquidDetergentDose` | | ||||||
|  | | Main Wash Time | `clock-start` | `number` | `startProgram.mainWashTime` | | ||||||
|  | | Powder Detergent Dose | `cup` | `sensor` | `startProgram.powderDetergentDose` | | ||||||
|  | | Program |  | `select` | `startProgram.program` | | ||||||
|  | | Remaining Time | `timer` | `sensor` | `startProgram.remainingTime` | | ||||||
|  | | Rinse Iterations | `rotate-right` | `number` | `startProgram.rinseIterations` | | ||||||
|  | | Soak Prewash Selection | `tshirt-crew` | `switch` | `startProgram.haier_SoakPrewashSelection` | | ||||||
|  | | Spin speed | `numeric` | `select` | `startProgram.spinSpeed` | | ||||||
|  | | Steam Level | `weather-dust` | `number` | `startProgram.steamLevel` | | ||||||
|  | | Suggested Load | `weight-kilogram` | `sensor` | `startProgram.suggestedLoadW` | | ||||||
|  | | Suggested weight | `weight-kilogram` | `sensor` | `startProgram.weight` | | ||||||
|  | | Temperature | `thermometer` | `select` | `startProgram.temp` | | ||||||
|  | | Water hard | `water` | `number` | `startProgram.waterHard` | | ||||||
|  | | lang |  | `number` | `startProgram.lang` | | ||||||
|  | #### Sensors | ||||||
|  | | Name | Icon | Entity | Key | | ||||||
|  | | --- | --- | --- | --- | | ||||||
|  | | Acqua Plus |  | `binary_sensor` | `acquaplus` | | ||||||
|  | | Current Electricity Used | `lightning-bolt` | `sensor` | `currentElectricityUsed` | | ||||||
|  | | Current Temperature | `thermometer` | `sensor` | `temp` | | ||||||
|  | | Current Water Used | `water` | `sensor` | `currentWaterUsed` | | ||||||
|  | | Dirt level | `liquid-spot` | `sensor` | `dirtyLevel` | | ||||||
|  | | Door |  | `binary_sensor` | `doorStatus` | | ||||||
|  | | Door Lock |  | `binary_sensor` | `doorLockStatus` | | ||||||
|  | | Error | `math-log` | `sensor` | `errors` | | ||||||
|  | | Extra Rinse 1 |  | `binary_sensor` | `extraRinse1` | | ||||||
|  | | Extra Rinse 2 |  | `binary_sensor` | `extraRinse2` | | ||||||
|  | | Extra Rinse 3 |  | `binary_sensor` | `extraRinse3` | | ||||||
|  | | Good Night Mode |  | `binary_sensor` | `goodNight` | | ||||||
|  | | Machine Status | `information` | `sensor` | `machMode` | | ||||||
|  | | Pre Wash |  | `binary_sensor` | `startProgram.prewash` | | ||||||
|  | | Program | `play` | `sensor` | `programName` | | ||||||
|  | | Program Phase | `washing-machine` | `sensor` | `prPhase` | | ||||||
|  | | Remaining Time | `timer` | `sensor` | `remainingTimeMM` | | ||||||
|  | | Remote Control | `remote` | `binary_sensor` | `attributes.lastConnEvent.category` | | ||||||
|  | | Spin Speed | `speedometer` | `sensor` | `spinSpeed` | | ||||||
|  | | Total Power |  | `sensor` | `totalElectricityUsed` | | ||||||
|  | | Total Wash Cycle | `counter` | `sensor` | `totalWashCycle` | | ||||||
|  | | Total Water |  | `sensor` | `totalWaterUsed` | | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								assets/washing_machine.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/washing_machine.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 202 KiB | 
| @ -1,86 +0,0 @@ | |||||||
| import logging |  | ||||||
| from dataclasses import dataclass |  | ||||||
|  |  | ||||||
| from pyhon import HonConnection |  | ||||||
|  |  | ||||||
| from homeassistant.components.binary_sensor import BinarySensorEntityDescription, BinarySensorDeviceClass, \ |  | ||||||
|     BinarySensorEntity |  | ||||||
| from homeassistant.config_entries import ConfigEntry |  | ||||||
| from homeassistant.core import callback |  | ||||||
| from .const import DOMAIN |  | ||||||
| from .hon import HonCoordinator, HonEntity |  | ||||||
|  |  | ||||||
| _LOGGER = logging.getLogger(__name__) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass |  | ||||||
| class HonBinarySensorEntityDescriptionMixin: |  | ||||||
|     on_value: str = "" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass |  | ||||||
| class HonBinarySensorEntityDescription(HonBinarySensorEntityDescriptionMixin, BinarySensorEntityDescription): |  | ||||||
|     pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| BINARY_SENSORS: dict[str, tuple[HonBinarySensorEntityDescription, ...]] = { |  | ||||||
|     "WM": ( |  | ||||||
|         HonBinarySensorEntityDescription( |  | ||||||
|             key="lastConnEvent.category", |  | ||||||
|             name="Connection", |  | ||||||
|             device_class=BinarySensorDeviceClass.CONNECTIVITY, |  | ||||||
|             on_value="CONNECTED", |  | ||||||
|         ), |  | ||||||
|         HonBinarySensorEntityDescription( |  | ||||||
|             key="doorLockStatus", |  | ||||||
|             name="Door Locked", |  | ||||||
|             device_class=BinarySensorDeviceClass.DOOR, |  | ||||||
|             on_value="1", |  | ||||||
|         ), |  | ||||||
|     ) |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: |  | ||||||
|     hon: HonConnection = hass.data[DOMAIN][entry.unique_id] |  | ||||||
|     coordinators = hass.data[DOMAIN]["coordinators"] |  | ||||||
|     appliances = [] |  | ||||||
|     for device in hon.devices: |  | ||||||
|         if device.mac_address in coordinators: |  | ||||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] |  | ||||||
|         else: |  | ||||||
|             coordinator = HonCoordinator(hass, device) |  | ||||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator |  | ||||||
|         await coordinator.async_config_entry_first_refresh() |  | ||||||
|  |  | ||||||
|         if descriptions := BINARY_SENSORS.get(device.appliance_type_name): |  | ||||||
|             for description in descriptions: |  | ||||||
|                 if not device.data.get(description.key): |  | ||||||
|                     _LOGGER.info("Can't setup %s", description.key) |  | ||||||
|                     continue |  | ||||||
|                 appliances.extend([ |  | ||||||
|                     HonBinarySensorEntity(hass, coordinator, entry, device, description)] |  | ||||||
|                 ) |  | ||||||
|  |  | ||||||
|     async_add_entities(appliances) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HonBinarySensorEntity(HonEntity, BinarySensorEntity): |  | ||||||
|     entity_description: HonBinarySensorEntityDescription |  | ||||||
|  |  | ||||||
|     def __init__(self, hass, coordinator, entry, device, description) -> None: |  | ||||||
|         super().__init__(hass, entry, coordinator, device) |  | ||||||
|  |  | ||||||
|         self._coordinator = coordinator |  | ||||||
|  |  | ||||||
|         self.entity_description = description |  | ||||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def is_on(self) -> bool: |  | ||||||
|         return self._device.data.get(self.entity_description.key, "") == self.entity_description.on_value |  | ||||||
|  |  | ||||||
|     @callback |  | ||||||
|     def _handle_coordinator_update(self): |  | ||||||
|         self._attr_native_value = self._device.data.get(self.entity_description.key, "") |  | ||||||
|         self.async_write_ha_state() |  | ||||||
| @ -1,59 +0,0 @@ | |||||||
| from pyhon import HonConnection |  | ||||||
| from pyhon.device import HonDevice |  | ||||||
|  |  | ||||||
| from homeassistant.components.button import ButtonEntityDescription, ButtonEntity |  | ||||||
| from homeassistant.config_entries import ConfigEntry |  | ||||||
|  |  | ||||||
| from .const import DOMAIN |  | ||||||
| from .hon import HonCoordinator, HonEntity |  | ||||||
|  |  | ||||||
| BUTTONS: dict[str, tuple[ButtonEntityDescription, ...]] = { |  | ||||||
|     "WM": ( |  | ||||||
|         ButtonEntityDescription( |  | ||||||
|             key="pauseProgram", |  | ||||||
|             name="Pause Program", |  | ||||||
|             icon="mdi:pause", |  | ||||||
|         ), |  | ||||||
|         ButtonEntityDescription( |  | ||||||
|             key="resumeProgram", |  | ||||||
|             name="Resume Program", |  | ||||||
|             icon="mdi:play-pause", |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: |  | ||||||
|     hon: HonConnection = hass.data[DOMAIN][entry.unique_id] |  | ||||||
|     coordinators = hass.data[DOMAIN]["coordinators"] |  | ||||||
|     appliances = [] |  | ||||||
|     for device in hon.devices: |  | ||||||
|         if device.mac_address in coordinators: |  | ||||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] |  | ||||||
|         else: |  | ||||||
|             coordinator = HonCoordinator(hass, device) |  | ||||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator |  | ||||||
|         await coordinator.async_config_entry_first_refresh() |  | ||||||
|  |  | ||||||
|         if descriptions := BUTTONS.get(device.appliance_type_name): |  | ||||||
|             for description in descriptions: |  | ||||||
|                 if not device.commands.get(description.key): |  | ||||||
|                     continue |  | ||||||
|                 appliances.extend([ |  | ||||||
|                     HonButtonEntity(hass, coordinator, entry, device, description)] |  | ||||||
|                 ) |  | ||||||
|  |  | ||||||
|     async_add_entities(appliances) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HonButtonEntity(HonEntity, ButtonEntity): |  | ||||||
|     def __init__(self, hass, coordinator, entry, device: HonDevice, description) -> None: |  | ||||||
|         super().__init__(hass, entry, coordinator, device) |  | ||||||
|  |  | ||||||
|         self._coordinator = coordinator |  | ||||||
|         self._device = device |  | ||||||
|         self.entity_description = description |  | ||||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" |  | ||||||
|  |  | ||||||
|     async def async_press(self) -> None: |  | ||||||
|         await self._device.commands[self.entity_description.key].send() |  | ||||||
| @ -1,10 +0,0 @@ | |||||||
| DOMAIN = "hon" |  | ||||||
|  |  | ||||||
| PLATFORMS = [ |  | ||||||
|     "sensor", |  | ||||||
|     "select", |  | ||||||
|     "number", |  | ||||||
|     "switch", |  | ||||||
|     "button", |  | ||||||
|     "binary_sensor", |  | ||||||
| ] |  | ||||||
| @ -1,45 +0,0 @@ | |||||||
| import logging |  | ||||||
| from datetime import timedelta |  | ||||||
|  |  | ||||||
| from pyhon.device import HonDevice |  | ||||||
|  |  | ||||||
| from homeassistant.helpers.entity import DeviceInfo |  | ||||||
| from homeassistant.helpers.update_coordinator import CoordinatorEntity |  | ||||||
| from homeassistant.helpers.update_coordinator import DataUpdateCoordinator |  | ||||||
|  |  | ||||||
| from .const import DOMAIN |  | ||||||
|  |  | ||||||
| _LOGGER = logging.getLogger(__name__) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HonEntity(CoordinatorEntity): |  | ||||||
|     _attr_has_entity_name = True |  | ||||||
|  |  | ||||||
|     def __init__(self, hass, entry, coordinator, device: HonDevice) -> None: |  | ||||||
|         super().__init__(coordinator) |  | ||||||
|  |  | ||||||
|         self._hon = hass.data[DOMAIN][entry.unique_id] |  | ||||||
|         self._hass = hass |  | ||||||
|         self._device = device |  | ||||||
|  |  | ||||||
|         self._attr_unique_id = self._device.mac_address |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def device_info(self): |  | ||||||
|         return DeviceInfo( |  | ||||||
|             identifiers={(DOMAIN, self._device.mac_address)}, |  | ||||||
|             manufacturer=self._device.brand, |  | ||||||
|             name=self._device.nick_name if self._device.nick_name else self._device.model_name, |  | ||||||
|             model=self._device.model_name, |  | ||||||
|             sw_version=self._device.fw_version, |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HonCoordinator(DataUpdateCoordinator): |  | ||||||
|     def __init__(self, hass, device: HonDevice): |  | ||||||
|         """Initialize my coordinator.""" |  | ||||||
|         super().__init__(hass, _LOGGER, name=device.mac_address, update_interval=timedelta(seconds=30)) |  | ||||||
|         self._device = device |  | ||||||
|  |  | ||||||
|     async def _async_update_data(self): |  | ||||||
|         await self._device.update() |  | ||||||
| @ -1,10 +0,0 @@ | |||||||
| { |  | ||||||
|   "domain": "hon", |  | ||||||
|   "name": "hOn", |  | ||||||
|   "config_flow": true, |  | ||||||
|   "version": "0.1.0", |  | ||||||
|   "codeowners": ["@Andre0512"], |  | ||||||
|   "iot_class": "cloud_polling", |  | ||||||
|   "requirements": ["pyhOn==0.2.4"], |  | ||||||
|   "documentation": "https://github.com/Andre0512/hOn/" |  | ||||||
| } |  | ||||||
| @ -1,94 +0,0 @@ | |||||||
| from __future__ import annotations |  | ||||||
|  |  | ||||||
| from pyhon import HonConnection |  | ||||||
| from pyhon.parameter import HonParameterRange |  | ||||||
|  |  | ||||||
| from homeassistant.components.number import ( |  | ||||||
|     NumberEntity, |  | ||||||
|     NumberEntityDescription, |  | ||||||
| ) |  | ||||||
| from homeassistant.config_entries import ConfigEntry |  | ||||||
| from homeassistant.const import UnitOfTime |  | ||||||
| from homeassistant.core import callback |  | ||||||
| from homeassistant.helpers.entity import EntityCategory |  | ||||||
|  |  | ||||||
| from .const import DOMAIN |  | ||||||
| from .hon import HonEntity, HonCoordinator |  | ||||||
|  |  | ||||||
| NUMBERS: dict[str, tuple[NumberEntityDescription, ...]] = { |  | ||||||
|     "WM": ( |  | ||||||
|         NumberEntityDescription( |  | ||||||
|             key="startProgram.delayTime", |  | ||||||
|             name="Delay Time", |  | ||||||
|             icon="mdi:timer", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|             native_unit_of_measurement=UnitOfTime.MINUTES |  | ||||||
|         ), |  | ||||||
|         NumberEntityDescription( |  | ||||||
|             key="startProgram.rinseIterations", |  | ||||||
|             name="Rinse Iterations", |  | ||||||
|             entity_category=EntityCategory.CONFIG |  | ||||||
|         ), |  | ||||||
|         NumberEntityDescription( |  | ||||||
|             key="startProgram.mainWashTime", |  | ||||||
|             name="Main Wash Time", |  | ||||||
|             icon="mdi:timer", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|             native_unit_of_measurement=UnitOfTime.MINUTES |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: |  | ||||||
|     hon: HonConnection = hass.data[DOMAIN][entry.unique_id] |  | ||||||
|     coordinators = hass.data[DOMAIN]["coordinators"] |  | ||||||
|     appliances = [] |  | ||||||
|     for device in hon.devices: |  | ||||||
|         if device.mac_address in coordinators: |  | ||||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] |  | ||||||
|         else: |  | ||||||
|             coordinator = HonCoordinator(hass, device) |  | ||||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator |  | ||||||
|         await coordinator.async_config_entry_first_refresh() |  | ||||||
|  |  | ||||||
|         if descriptions := NUMBERS.get(device.appliance_type_name): |  | ||||||
|             for description in descriptions: |  | ||||||
|                 appliances.extend([ |  | ||||||
|                     HonNumberEntity(hass, coordinator, entry, device, description)] |  | ||||||
|                 ) |  | ||||||
|  |  | ||||||
|     async_add_entities(appliances) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HonNumberEntity(HonEntity, NumberEntity): |  | ||||||
|     def __init__(self, hass, coordinator, entry, device, description) -> None: |  | ||||||
|         super().__init__(hass, entry, coordinator, device) |  | ||||||
|  |  | ||||||
|         self._coordinator = coordinator |  | ||||||
|         self._data = device.settings[description.key] |  | ||||||
|         self.entity_description = description |  | ||||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" |  | ||||||
|  |  | ||||||
|         if isinstance(self._data, HonParameterRange): |  | ||||||
|             self._attr_native_max_value = self._data.max |  | ||||||
|             self._attr_native_min_value = self._data.min |  | ||||||
|             self._attr_native_step = self._data.step |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def native_value(self) -> float | None: |  | ||||||
|         return self._data.value |  | ||||||
|  |  | ||||||
|     async def async_set_native_value(self, value: float) -> None: |  | ||||||
|         self._data.value = value |  | ||||||
|         await self.coordinator.async_request_refresh() |  | ||||||
|  |  | ||||||
|     @callback |  | ||||||
|     def _handle_coordinator_update(self): |  | ||||||
|         self._data = self._device.settings[self.entity_description.key] |  | ||||||
|         if isinstance(self._data, HonParameterRange): |  | ||||||
|             self._attr_native_max_value = self._data.max |  | ||||||
|             self._attr_native_min_value = self._data.min |  | ||||||
|             self._attr_native_step = self._data.step |  | ||||||
|         self._attr_native_value = self._data.value |  | ||||||
|         self.async_write_ha_state() |  | ||||||
| @ -1,99 +0,0 @@ | |||||||
| """Support for Tuya select.""" |  | ||||||
| from __future__ import annotations |  | ||||||
|  |  | ||||||
| from pyhon import HonConnection |  | ||||||
| from pyhon.device import HonDevice |  | ||||||
| from pyhon.parameter import HonParameterFixed |  | ||||||
|  |  | ||||||
| from homeassistant.components.select import SelectEntity, SelectEntityDescription |  | ||||||
| from homeassistant.config_entries import ConfigEntry |  | ||||||
| from homeassistant.const import UnitOfTemperature, REVOLUTIONS_PER_MINUTE |  | ||||||
| from homeassistant.core import callback |  | ||||||
| from homeassistant.helpers.entity import EntityCategory |  | ||||||
|  |  | ||||||
| from .hon import HonEntity, HonCoordinator |  | ||||||
|  |  | ||||||
| DOMAIN = "hon" |  | ||||||
|  |  | ||||||
| SELECTS = { |  | ||||||
|     "WM": ( |  | ||||||
|         SelectEntityDescription( |  | ||||||
|             key="startProgram.spinSpeed", |  | ||||||
|             name="Spin speed", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|             icon="mdi:numeric", |  | ||||||
|             unit_of_measurement=REVOLUTIONS_PER_MINUTE |  | ||||||
|         ), |  | ||||||
|         SelectEntityDescription( |  | ||||||
|             key="startProgram.temp", |  | ||||||
|             name="Temperature", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|             icon="mdi:thermometer", |  | ||||||
|             unit_of_measurement=UnitOfTemperature.CELSIUS |  | ||||||
|         ), |  | ||||||
|         SelectEntityDescription( |  | ||||||
|             key="startProgram.program", |  | ||||||
|             name="Programme", |  | ||||||
|             entity_category=EntityCategory.CONFIG |  | ||||||
|         ), |  | ||||||
|     ) |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: |  | ||||||
|     hon: HonConnection = hass.data[DOMAIN][entry.unique_id] |  | ||||||
|     coordinators = hass.data[DOMAIN]["coordinators"] |  | ||||||
|     appliances = [] |  | ||||||
|     for device in hon.devices: |  | ||||||
|         if device.mac_address in coordinators: |  | ||||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] |  | ||||||
|         else: |  | ||||||
|             coordinator = HonCoordinator(hass, device) |  | ||||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator |  | ||||||
|         await coordinator.async_config_entry_first_refresh() |  | ||||||
|  |  | ||||||
|         if descriptions := SELECTS.get(device.appliance_type_name): |  | ||||||
|             for description in descriptions: |  | ||||||
|                 if not device.data.get(description.key): |  | ||||||
|                     continue |  | ||||||
|                 appliances.extend([ |  | ||||||
|                     HonSelectEntity(hass, coordinator, entry, device, description)] |  | ||||||
|                 ) |  | ||||||
|     async_add_entities(appliances) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HonSelectEntity(HonEntity, SelectEntity): |  | ||||||
|     def __init__(self, hass, coordinator, entry, device: HonDevice, description) -> None: |  | ||||||
|         super().__init__(hass, entry, coordinator, device) |  | ||||||
|  |  | ||||||
|         self._coordinator = coordinator |  | ||||||
|         self._device = device |  | ||||||
|         self._data = device.settings[description.key] |  | ||||||
|         self.entity_description = description |  | ||||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" |  | ||||||
|  |  | ||||||
|         if not isinstance(self._data, HonParameterFixed): |  | ||||||
|             self._attr_options: list[str] = self._data.values |  | ||||||
|         else: |  | ||||||
|             self._attr_options = [self._data.value] |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def current_option(self) -> str | None: |  | ||||||
|         value = self._data.value |  | ||||||
|         if value is None or value not in self._attr_options: |  | ||||||
|             return None |  | ||||||
|         return value |  | ||||||
|  |  | ||||||
|     async def async_select_option(self, option: str) -> None: |  | ||||||
|         self._data.value = option |  | ||||||
|         await self.coordinator.async_request_refresh() |  | ||||||
|  |  | ||||||
|     @callback |  | ||||||
|     def _handle_coordinator_update(self): |  | ||||||
|         self._data = self._device.settings[self.entity_description.key] |  | ||||||
|         if not isinstance(self._data, HonParameterFixed): |  | ||||||
|             self._attr_options: list[str] = self._data.values |  | ||||||
|         else: |  | ||||||
|             self._attr_options = [self._data.value] |  | ||||||
|         self._attr_native_value = self._data.value |  | ||||||
|         self.async_write_ha_state() |  | ||||||
| @ -1,122 +0,0 @@ | |||||||
| import logging |  | ||||||
|  |  | ||||||
| from pyhon import HonConnection |  | ||||||
|  |  | ||||||
| from homeassistant.components.sensor import ( |  | ||||||
|     SensorEntity, |  | ||||||
|     SensorDeviceClass, |  | ||||||
|     SensorStateClass, |  | ||||||
|     SensorEntityDescription, |  | ||||||
| ) |  | ||||||
| from homeassistant.config_entries import ConfigEntry |  | ||||||
| from homeassistant.const import UnitOfEnergy, UnitOfVolume, UnitOfMass, UnitOfPower |  | ||||||
| from homeassistant.core import callback |  | ||||||
| from homeassistant.helpers.entity import EntityCategory |  | ||||||
| from homeassistant.helpers.typing import StateType |  | ||||||
|  |  | ||||||
| from .const import DOMAIN |  | ||||||
| from .hon import HonCoordinator, HonEntity |  | ||||||
|  |  | ||||||
| _LOGGER = logging.getLogger(__name__) |  | ||||||
|  |  | ||||||
| SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { |  | ||||||
|     "WM": ( |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="totalElectricityUsed", |  | ||||||
|             name="Total Power", |  | ||||||
|             device_class=SensorDeviceClass.ENERGY, |  | ||||||
|             state_class=SensorStateClass.TOTAL_INCREASING, |  | ||||||
|             native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="totalWaterUsed", |  | ||||||
|             name="Total Water", |  | ||||||
|             device_class=SensorDeviceClass.WATER, |  | ||||||
|             state_class=SensorStateClass.TOTAL_INCREASING, |  | ||||||
|             native_unit_of_measurement=UnitOfVolume.LITERS |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="totalWashCycle", |  | ||||||
|             name="Total Wash Cycle", |  | ||||||
|             state_class=SensorStateClass.TOTAL_INCREASING, |  | ||||||
|             icon="mdi:counter" |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="currentElectricityUsed", |  | ||||||
|             name="Current Electricity Used", |  | ||||||
|             state_class=SensorStateClass.MEASUREMENT, |  | ||||||
|             device_class=SensorDeviceClass.POWER, |  | ||||||
|             native_unit_of_measurement=UnitOfPower.KILO_WATT, |  | ||||||
|             icon="mdi:lightning-bolt" |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="currentWaterUsed", |  | ||||||
|             name="Current Water Used", |  | ||||||
|             state_class=SensorStateClass.MEASUREMENT, |  | ||||||
|             icon="mdi:water" |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="startProgram.weight", |  | ||||||
|             name="Suggested weight", |  | ||||||
|             state_class=SensorStateClass.MEASUREMENT, |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|             native_unit_of_measurement=UnitOfMass.KILOGRAMS, |  | ||||||
|             icon="mdi:weight-kilogram" |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="machMode", |  | ||||||
|             name="Machine Last Status", |  | ||||||
|             icon="mdi:information", |  | ||||||
|             translation_key="mode" |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="errors", |  | ||||||
|             name="Last Error", |  | ||||||
|             icon="mdi:math-log", |  | ||||||
|             translation_key="errors" |  | ||||||
|         ), |  | ||||||
|  |  | ||||||
|     ) |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: |  | ||||||
|     hon: HonConnection = hass.data[DOMAIN][entry.unique_id] |  | ||||||
|     coordinators = hass.data[DOMAIN]["coordinators"] |  | ||||||
|     appliances = [] |  | ||||||
|     for device in hon.devices: |  | ||||||
|         if device.mac_address in coordinators: |  | ||||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] |  | ||||||
|         else: |  | ||||||
|             coordinator = HonCoordinator(hass, device) |  | ||||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator |  | ||||||
|         await coordinator.async_config_entry_first_refresh() |  | ||||||
|  |  | ||||||
|         if descriptions := SENSORS.get(device.appliance_type_name): |  | ||||||
|             for description in descriptions: |  | ||||||
|                 if not device.data.get(description.key): |  | ||||||
|                     continue |  | ||||||
|                 appliances.extend([ |  | ||||||
|                     HonSensorEntity(hass, coordinator, entry, device, description)] |  | ||||||
|                 ) |  | ||||||
|  |  | ||||||
|     async_add_entities(appliances) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HonSensorEntity(HonEntity, SensorEntity): |  | ||||||
|     def __init__(self, hass, coordinator, entry, device, description) -> None: |  | ||||||
|         super().__init__(hass, entry, coordinator, device) |  | ||||||
|  |  | ||||||
|         self._coordinator = coordinator |  | ||||||
|  |  | ||||||
|         self.entity_description = description |  | ||||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def native_value(self) -> StateType: |  | ||||||
|         return self._device.data.get(self.entity_description.key, "") |  | ||||||
|  |  | ||||||
|     @callback |  | ||||||
|     def _handle_coordinator_update(self): |  | ||||||
|         self._attr_native_value = self._device.data.get(self.entity_description.key, "") |  | ||||||
|         self.async_write_ha_state() |  | ||||||
| @ -1,113 +0,0 @@ | |||||||
| from collections.abc import Callable, Coroutine |  | ||||||
| from dataclasses import dataclass |  | ||||||
| from typing import Any |  | ||||||
|  |  | ||||||
| from pyhon import HonConnection |  | ||||||
| from pyhon.device import HonDevice |  | ||||||
|  |  | ||||||
| from homeassistant.components.switch import SwitchEntityDescription, SwitchEntity |  | ||||||
| from homeassistant.config_entries import ConfigEntry |  | ||||||
| from homeassistant.const import EntityCategory |  | ||||||
|  |  | ||||||
| from .const import DOMAIN |  | ||||||
| from .hon import HonCoordinator, HonEntity |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass |  | ||||||
| class HonSwitchEntityDescriptionMixin: |  | ||||||
|     turn_on_key: str = "" |  | ||||||
|     turn_off_key: str = "" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass |  | ||||||
| class HonSwitchEntityDescription(HonSwitchEntityDescriptionMixin, |  | ||||||
|     SwitchEntityDescription |  | ||||||
| ): |  | ||||||
|     pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { |  | ||||||
|     "WM": ( |  | ||||||
|         HonSwitchEntityDescription( |  | ||||||
|             key="startProgram", |  | ||||||
|             name="Start Program", |  | ||||||
|             icon="mdi:play", |  | ||||||
|             turn_on_key="startProgram", |  | ||||||
|             turn_off_key="stopProgram", |  | ||||||
|         ), |  | ||||||
|         HonSwitchEntityDescription( |  | ||||||
|             key="startProgram.delayStatus", |  | ||||||
|             name="Delay Status", |  | ||||||
|             entity_category=EntityCategory.CONFIG |  | ||||||
|         ), |  | ||||||
|         HonSwitchEntityDescription( |  | ||||||
|             key="startProgram.haier_SoakPrewashSelection", |  | ||||||
|             name="Soak Prewash Selection", |  | ||||||
|             entity_category=EntityCategory.CONFIG |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: |  | ||||||
|     hon: HonConnection = hass.data[DOMAIN][entry.unique_id] |  | ||||||
|     coordinators = hass.data[DOMAIN]["coordinators"] |  | ||||||
|     appliances = [] |  | ||||||
|     for device in hon.devices: |  | ||||||
|         if device.mac_address in coordinators: |  | ||||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] |  | ||||||
|         else: |  | ||||||
|             coordinator = HonCoordinator(hass, device) |  | ||||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator |  | ||||||
|         await coordinator.async_config_entry_first_refresh() |  | ||||||
|  |  | ||||||
|         if descriptions := SWITCHES.get(device.appliance_type_name): |  | ||||||
|             for description in descriptions: |  | ||||||
|                 if device.data.get(description.key) is not None or device.commands.get(description.key) is not None: |  | ||||||
|                     appliances.extend([ |  | ||||||
|                         HonSwitchEntity(hass, coordinator, entry, device, description)] |  | ||||||
|                     ) |  | ||||||
|  |  | ||||||
|     async_add_entities(appliances) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HonSwitchEntity(HonEntity, SwitchEntity): |  | ||||||
|     entity_description: HonSwitchEntityDescription |  | ||||||
|  |  | ||||||
|     def __init__(self, hass, coordinator, entry, device: HonDevice, description: HonSwitchEntityDescription) -> None: |  | ||||||
|         super().__init__(hass, entry, coordinator, device) |  | ||||||
|         self._coordinator = coordinator |  | ||||||
|         self._device = device |  | ||||||
|         self.entity_description = description |  | ||||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" |  | ||||||
|  |  | ||||||
|     def available(self) -> bool: |  | ||||||
|         if self.entity_category == EntityCategory.CONFIG: |  | ||||||
|             return self._device.settings[self.entity_description.key].typology == "fixed" |  | ||||||
|         return True |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def is_on(self) -> bool | None: |  | ||||||
|         """Return True if entity is on.""" |  | ||||||
|         if self.entity_category == EntityCategory.CONFIG: |  | ||||||
|             setting = self._device.settings[self.entity_description.key] |  | ||||||
|             return setting.value == "1" or hasattr(setting, "min") and setting.value != setting.min |  | ||||||
|         return self._device.data.get(self.entity_description.key, "") |  | ||||||
|  |  | ||||||
|     async def async_turn_on(self, **kwargs: Any) -> None: |  | ||||||
|         if self.entity_category == EntityCategory.CONFIG: |  | ||||||
|             setting = self._device.settings[self.entity_description.key] |  | ||||||
|             setting.value = setting.max |  | ||||||
|             self.async_write_ha_state() |  | ||||||
|         else: |  | ||||||
|             await self._device.commands[self.entity_description.turn_on_key].send() |  | ||||||
|  |  | ||||||
|     async def async_turn_off(self, **kwargs: Any) -> None: |  | ||||||
|         if self.entity_category == EntityCategory.CONFIG: |  | ||||||
|             setting = self._device.settings[self.entity_description.key] |  | ||||||
|             setting.value = setting.min |  | ||||||
|             self.async_write_ha_state() |  | ||||||
|         else: |  | ||||||
|             await self._device.commands[self.entity_description.turn_off_key].send() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -1,34 +0,0 @@ | |||||||
| { |  | ||||||
|   "config": { |  | ||||||
|     "step": { |  | ||||||
|       "user": { |  | ||||||
|         "title": "hOn", |  | ||||||
|         "description": "Please enters your hOn credentials", |  | ||||||
|         "data": { |  | ||||||
|           "email": "Email Address", |  | ||||||
|           "password": "Password" |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   "entity": { |  | ||||||
|     "sensor": { |  | ||||||
|       "mode": { |  | ||||||
|         "state": { |  | ||||||
|           "1": "Ready", |  | ||||||
|           "2": "Running", |  | ||||||
|           "5": "Scheduled", |  | ||||||
|           "6": "Error", |  | ||||||
|           "7": "Finished" |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|       "errors": { |  | ||||||
|         "state": { |  | ||||||
|           "00": "No error", |  | ||||||
|           "100000000000": "E2: Check if the door is closed", |  | ||||||
|           "8000000000000": "E4: Check the water supply" |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,7 +1,7 @@ | |||||||
| import logging | import logging | ||||||
| 
 | 
 | ||||||
| import voluptuous as vol | import voluptuous as vol | ||||||
| from pyhon import HonConnection | from pyhon import Hon | ||||||
| 
 | 
 | ||||||
| from homeassistant.config_entries import ConfigEntry | from homeassistant.config_entries import ConfigEntry | ||||||
| from homeassistant.const import CONF_EMAIL, CONF_PASSWORD | from homeassistant.const import CONF_EMAIL, CONF_PASSWORD | ||||||
| @ -28,8 +28,9 @@ CONFIG_SCHEMA = vol.Schema( | |||||||
| 
 | 
 | ||||||
| async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): | async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): | ||||||
|     session = aiohttp_client.async_get_clientsession(hass) |     session = aiohttp_client.async_get_clientsession(hass) | ||||||
|     hon = HonConnection(entry.data["email"], entry.data["password"], session) |     hon = await Hon( | ||||||
|     await hon.setup() |         entry.data["email"], entry.data["password"], session=session | ||||||
|  |     ).create() | ||||||
|     hass.data.setdefault(DOMAIN, {}) |     hass.data.setdefault(DOMAIN, {}) | ||||||
|     hass.data[DOMAIN][entry.unique_id] = hon |     hass.data[DOMAIN][entry.unique_id] = hon | ||||||
|     hass.data[DOMAIN]["coordinators"] = {} |     hass.data[DOMAIN]["coordinators"] = {} | ||||||
							
								
								
									
										280
									
								
								custom_components/hon/binary_sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								custom_components/hon/binary_sensor.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,280 @@ | |||||||
|  | import logging | ||||||
|  | from dataclasses import dataclass | ||||||
|  |  | ||||||
|  | from homeassistant.components.binary_sensor import ( | ||||||
|  |     BinarySensorEntityDescription, | ||||||
|  |     BinarySensorDeviceClass, | ||||||
|  |     BinarySensorEntity, | ||||||
|  | ) | ||||||
|  | from homeassistant.config_entries import ConfigEntry | ||||||
|  | from homeassistant.core import callback | ||||||
|  |  | ||||||
|  | from .const import DOMAIN | ||||||
|  | from .hon import HonEntity, unique_entities | ||||||
|  |  | ||||||
|  | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonBinarySensorEntityDescriptionMixin: | ||||||
|  |     on_value: str = "" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonBinarySensorEntityDescription( | ||||||
|  |     HonBinarySensorEntityDescriptionMixin, BinarySensorEntityDescription | ||||||
|  | ): | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | BINARY_SENSORS: dict[str, tuple[HonBinarySensorEntityDescription, ...]] = { | ||||||
|  |     "WM": ( | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="attributes.lastConnEvent.category", | ||||||
|  |             name="Remote Control", | ||||||
|  |             device_class=BinarySensorDeviceClass.CONNECTIVITY, | ||||||
|  |             on_value="CONNECTED", | ||||||
|  |             icon="mdi:remote", | ||||||
|  |             translation_key="remote_control", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="doorLockStatus", | ||||||
|  |             name="Door Lock", | ||||||
|  |             device_class=BinarySensorDeviceClass.LOCK, | ||||||
|  |             on_value="0", | ||||||
|  |             translation_key="door_lock", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="doorStatus", | ||||||
|  |             name="Door", | ||||||
|  |             device_class=BinarySensorDeviceClass.DOOR, | ||||||
|  |             on_value="1", | ||||||
|  |             translation_key="door_open", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="startProgram.prewash", name="Pre Wash", translation_key="prewash" | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="extraRinse1", name="Extra Rinse 1", translation_key="extra_rinse_1" | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="extraRinse2", name="Extra Rinse 2", translation_key="extra_rinse_2" | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="extraRinse3", name="Extra Rinse 3", translation_key="extra_rinse_3" | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="goodNight", name="Good Night Mode", translation_key="good_night" | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="acquaplus", name="Acqua Plus", translation_key="acqua_plus" | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "TD": ( | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="attributes.lastConnEvent.category", | ||||||
|  |             name="Connection", | ||||||
|  |             device_class=BinarySensorDeviceClass.CONNECTIVITY, | ||||||
|  |             on_value="CONNECTED", | ||||||
|  |             translation_key="connection", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="doorStatus", | ||||||
|  |             name="Door", | ||||||
|  |             device_class=BinarySensorDeviceClass.DOOR, | ||||||
|  |             on_value="1", | ||||||
|  |             translation_key="door_open", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="anticrease", name="Anti-Crease", translation_key="anti_crease" | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "OV": ( | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="attributes.lastConnEvent.category", | ||||||
|  |             name="Connection", | ||||||
|  |             device_class=BinarySensorDeviceClass.CONNECTIVITY, | ||||||
|  |             on_value="CONNECTED", | ||||||
|  |             icon="mdi:wifi", | ||||||
|  |             translation_key="connection", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="attributes.parameters.onOffStatus", | ||||||
|  |             name="On", | ||||||
|  |             device_class=BinarySensorDeviceClass.RUNNING, | ||||||
|  |             on_value="1", | ||||||
|  |             icon="mdi:power-cycle", | ||||||
|  |             translation_key="on", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "IH": ( | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="attributes.lastConnEvent.category", | ||||||
|  |             name="Connection", | ||||||
|  |             device_class=BinarySensorDeviceClass.CONNECTIVITY, | ||||||
|  |             on_value="CONNECTED", | ||||||
|  |             icon="mdi:wifi", | ||||||
|  |             translation_key="connection", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="attributes.parameters.onOffStatus", | ||||||
|  |             name="On", | ||||||
|  |             device_class=BinarySensorDeviceClass.RUNNING, | ||||||
|  |             on_value="1", | ||||||
|  |             icon="mdi:power-cycle", | ||||||
|  |             translation_key="on", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="hotStatus", | ||||||
|  |             name="Hot Status", | ||||||
|  |             device_class=BinarySensorDeviceClass.HEAT, | ||||||
|  |             on_value="1", | ||||||
|  |             translation_key="still_hot", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="panStatus", | ||||||
|  |             name="Pan Status", | ||||||
|  |             on_value="1", | ||||||
|  |             icon="mdi:pot-mix", | ||||||
|  |             translation_key="pan_status", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="hobLockStatus", | ||||||
|  |             name="Hob Lock", | ||||||
|  |             device_class=BinarySensorDeviceClass.LOCK, | ||||||
|  |             on_value="0", | ||||||
|  |             translation_key="child_lock", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "DW": ( | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="saltStatus", | ||||||
|  |             name="Salt", | ||||||
|  |             device_class=BinarySensorDeviceClass.PROBLEM, | ||||||
|  |             on_value="1", | ||||||
|  |             icon="mdi:shaker-outline", | ||||||
|  |             translation_key="salt_level", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="rinseAidStatus", | ||||||
|  |             name="Rinse Aid", | ||||||
|  |             device_class=BinarySensorDeviceClass.PROBLEM, | ||||||
|  |             on_value="1", | ||||||
|  |             icon="mdi:spray-bottle", | ||||||
|  |             translation_key="rinse_aid", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="attributes.lastConnEvent.category", | ||||||
|  |             name="Connection", | ||||||
|  |             device_class=BinarySensorDeviceClass.CONNECTIVITY, | ||||||
|  |             on_value="CONNECTED", | ||||||
|  |             translation_key="connection", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="doorStatus", | ||||||
|  |             name="Door", | ||||||
|  |             device_class=BinarySensorDeviceClass.DOOR, | ||||||
|  |             on_value="1", | ||||||
|  |             translation_key="door_open", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "AC": ( | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="filterChangeStatusLocal", | ||||||
|  |             name="Filter Replacement", | ||||||
|  |             device_class=BinarySensorDeviceClass.PROBLEM, | ||||||
|  |             on_value="1", | ||||||
|  |             translation_key="filter_replacement", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="ch2oCleaningStatus", | ||||||
|  |             name="Ch2O Cleaning", | ||||||
|  |             on_value="1", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "REF": ( | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="quickModeZ2", | ||||||
|  |             name="Super Cool", | ||||||
|  |             icon="mdi:snowflake", | ||||||
|  |             device_class=BinarySensorDeviceClass.RUNNING, | ||||||
|  |             on_value="1", | ||||||
|  |             translation_key="super_cool", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="quickModeZ1", | ||||||
|  |             name="Super Freeze", | ||||||
|  |             icon="mdi:snowflake-variant", | ||||||
|  |             device_class=BinarySensorDeviceClass.RUNNING, | ||||||
|  |             on_value="1", | ||||||
|  |             translation_key="super_freeze", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="doorStatusZ1", | ||||||
|  |             name="Door Status Freezer", | ||||||
|  |             device_class=BinarySensorDeviceClass.DOOR, | ||||||
|  |             icon="mdi:fridge-top", | ||||||
|  |             on_value="1", | ||||||
|  |             translation_key="freezer_door", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="door2StatusZ1", | ||||||
|  |             name="Door Status Fridge", | ||||||
|  |             icon="mdi:fridge-bottom", | ||||||
|  |             device_class=BinarySensorDeviceClass.DOOR, | ||||||
|  |             on_value="1", | ||||||
|  |             translation_key="fridge_door", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="intelligenceMode", | ||||||
|  |             name="Auto-Set Mode", | ||||||
|  |             icon="mdi:thermometer-auto", | ||||||
|  |             device_class=BinarySensorDeviceClass.RUNNING, | ||||||
|  |             on_value="1", | ||||||
|  |             translation_key="auto_set", | ||||||
|  |         ), | ||||||
|  |         HonBinarySensorEntityDescription( | ||||||
|  |             key="holidayMode", | ||||||
|  |             name="Holiday Mode", | ||||||
|  |             icon="mdi:palm-tree", | ||||||
|  |             device_class=BinarySensorDeviceClass.RUNNING, | ||||||
|  |             on_value="1", | ||||||
|  |             translation_key="holiday_mode", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | BINARY_SENSORS["WD"] = unique_entities(BINARY_SENSORS["WM"], BINARY_SENSORS["TD"]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||||
|  |     entities = [] | ||||||
|  |     for device in hass.data[DOMAIN][entry.unique_id].appliances: | ||||||
|  |         for description in BINARY_SENSORS.get(device.appliance_type, []): | ||||||
|  |             if not device.get(description.key): | ||||||
|  |                 continue | ||||||
|  |             entity = HonBinarySensorEntity(hass, entry, device, description) | ||||||
|  |             await entity.coordinator.async_config_entry_first_refresh() | ||||||
|  |             entities.append(entity) | ||||||
|  |     async_add_entities(entities) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonBinarySensorEntity(HonEntity, BinarySensorEntity): | ||||||
|  |     entity_description: HonBinarySensorEntityDescription | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def is_on(self) -> bool: | ||||||
|  |         return ( | ||||||
|  |             self._device.get(self.entity_description.key, "") | ||||||
|  |             == self.entity_description.on_value | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     @callback | ||||||
|  |     def _handle_coordinator_update(self, update=True) -> None: | ||||||
|  |         self._attr_native_value = ( | ||||||
|  |             self._device.get(self.entity_description.key, "") | ||||||
|  |             == self.entity_description.on_value | ||||||
|  |         ) | ||||||
|  |         if update: | ||||||
|  |             self.async_write_ha_state() | ||||||
							
								
								
									
										102
									
								
								custom_components/hon/button.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								custom_components/hon/button.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,102 @@ | |||||||
|  | import logging | ||||||
|  |  | ||||||
|  | import pkg_resources | ||||||
|  | from homeassistant.components import persistent_notification | ||||||
|  | from homeassistant.components.button import ButtonEntityDescription, ButtonEntity | ||||||
|  | from homeassistant.config_entries import ConfigEntry | ||||||
|  | from homeassistant.const import EntityCategory | ||||||
|  | from pyhon.appliance import HonAppliance | ||||||
|  |  | ||||||
|  | from .const import DOMAIN | ||||||
|  | from .hon import HonEntity | ||||||
|  |  | ||||||
|  | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  | BUTTONS: dict[str, tuple[ButtonEntityDescription, ...]] = { | ||||||
|  |     "IH": ( | ||||||
|  |         ButtonEntityDescription( | ||||||
|  |             key="startProgram", | ||||||
|  |             name="Start Program", | ||||||
|  |             icon="mdi:pot-steam", | ||||||
|  |             translation_key="induction_hob", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "REF": ( | ||||||
|  |         ButtonEntityDescription( | ||||||
|  |             key="startProgram", | ||||||
|  |             name="Program Start", | ||||||
|  |             icon="mdi:play", | ||||||
|  |             translation_key="start_program", | ||||||
|  |         ), | ||||||
|  |         ButtonEntityDescription( | ||||||
|  |             key="stopProgram", | ||||||
|  |             name="Program Stop", | ||||||
|  |             icon="mdi:stop", | ||||||
|  |             translation_key="stop_program", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "HO": ( | ||||||
|  |         ButtonEntityDescription( | ||||||
|  |             key="startProgram", | ||||||
|  |             name="Start Program", | ||||||
|  |             icon="mdi:hvac", | ||||||
|  |             translation_key="start_program", | ||||||
|  |         ), | ||||||
|  |         ButtonEntityDescription( | ||||||
|  |             key="stopProgram", | ||||||
|  |             name="Stop Program", | ||||||
|  |             icon="mdi:hvac-off", | ||||||
|  |             translation_key="stop_program", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||||
|  |     entities = [] | ||||||
|  |     for device in hass.data[DOMAIN][entry.unique_id].appliances: | ||||||
|  |         for description in BUTTONS.get(device.appliance_type, []): | ||||||
|  |             if not device.commands.get(description.key): | ||||||
|  |                 continue | ||||||
|  |             entity = HonButtonEntity(hass, entry, device, description) | ||||||
|  |             await entity.coordinator.async_config_entry_first_refresh() | ||||||
|  |             entities.append(entity) | ||||||
|  |         entities.append(HonFeatureRequestButton(hass, entry, device)) | ||||||
|  |         await entities[-1].coordinator.async_config_entry_first_refresh() | ||||||
|  |     async_add_entities(entities) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonButtonEntity(HonEntity, ButtonEntity): | ||||||
|  |     entity_description: ButtonEntityDescription | ||||||
|  |  | ||||||
|  |     async def async_press(self) -> None: | ||||||
|  |         await self._device.commands[self.entity_description.key].send() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def available(self) -> bool: | ||||||
|  |         """Return True if entity is available.""" | ||||||
|  |         return ( | ||||||
|  |             super().available | ||||||
|  |             and self._device.get("remoteCtrValid", "1") == "1" | ||||||
|  |             and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonFeatureRequestButton(HonEntity, ButtonEntity): | ||||||
|  |     def __init__(self, hass, entry, device: HonAppliance) -> None: | ||||||
|  |         super().__init__(hass, entry, device) | ||||||
|  |  | ||||||
|  |         self._attr_unique_id = f"{super().unique_id}_log_device_info" | ||||||
|  |         self._attr_icon = "mdi:information" | ||||||
|  |         self._attr_name = "Show Device Info" | ||||||
|  |         self._attr_entity_category = EntityCategory.DIAGNOSTIC | ||||||
|  |         self._attr_entity_registry_enabled_default = False | ||||||
|  |  | ||||||
|  |     async def async_press(self) -> None: | ||||||
|  |         pyhon_version = pkg_resources.get_distribution("pyhon").version | ||||||
|  |         info = f"{self._device.diagnose()}pyhOnVersion: {pyhon_version}" | ||||||
|  |         title = f"{self._device.nick_name} Device Info" | ||||||
|  |         persistent_notification.create( | ||||||
|  |             self._hass, f"````\n```\n{info}\n```\n````", title | ||||||
|  |         ) | ||||||
|  |         _LOGGER.info(info.replace(" ", "\u200B ")) | ||||||
							
								
								
									
										336
									
								
								custom_components/hon/climate.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								custom_components/hon/climate.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,336 @@ | |||||||
|  | import logging | ||||||
|  | from dataclasses import dataclass | ||||||
|  |  | ||||||
|  | from homeassistant.components.climate import ( | ||||||
|  |     ClimateEntity, | ||||||
|  |     ClimateEntityDescription, | ||||||
|  | ) | ||||||
|  | from homeassistant.components.climate.const import ( | ||||||
|  |     FAN_OFF, | ||||||
|  |     SWING_OFF, | ||||||
|  |     SWING_BOTH, | ||||||
|  |     SWING_VERTICAL, | ||||||
|  |     SWING_HORIZONTAL, | ||||||
|  |     ClimateEntityFeature, | ||||||
|  |     HVACMode, | ||||||
|  | ) | ||||||
|  | from homeassistant.config_entries import ConfigEntry | ||||||
|  | from homeassistant.const import ( | ||||||
|  |     ATTR_TEMPERATURE, | ||||||
|  |     TEMP_CELSIUS, | ||||||
|  | ) | ||||||
|  | from homeassistant.core import callback | ||||||
|  | from pyhon.appliance import HonAppliance | ||||||
|  |  | ||||||
|  | from .const import HON_HVAC_MODE, HON_FAN, HON_HVAC_PROGRAM, DOMAIN | ||||||
|  | from .hon import HonEntity | ||||||
|  |  | ||||||
|  | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonACClimateEntityDescription(ClimateEntityDescription): | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonClimateEntityDescription(ClimateEntityDescription): | ||||||
|  |     mode: HVACMode = "auto" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CLIMATES = { | ||||||
|  |     "AC": ( | ||||||
|  |         HonACClimateEntityDescription( | ||||||
|  |             key="settings", | ||||||
|  |             name="Air Conditioner", | ||||||
|  |             icon="mdi:air-conditioner", | ||||||
|  |             translation_key="air_conditioner", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "REF": ( | ||||||
|  |         HonClimateEntityDescription( | ||||||
|  |             key="settings.tempSelZ1", | ||||||
|  |             mode=HVACMode.COOL, | ||||||
|  |             name="Fridge", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             translation_key="fridge", | ||||||
|  |         ), | ||||||
|  |         HonClimateEntityDescription( | ||||||
|  |             key="settings.tempSelZ2", | ||||||
|  |             mode=HVACMode.COOL, | ||||||
|  |             name="Freezer", | ||||||
|  |             icon="mdi:snowflake-thermometer", | ||||||
|  |             translation_key="freezer", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "OV": ( | ||||||
|  |         HonClimateEntityDescription( | ||||||
|  |             key="settings.tempSel", | ||||||
|  |             mode=HVACMode.HEAT, | ||||||
|  |             name="Oven", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             translation_key="oven", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "WC": ( | ||||||
|  |         HonClimateEntityDescription( | ||||||
|  |             key="settings.tempSel", | ||||||
|  |             mode=HVACMode.COOL, | ||||||
|  |             name="Wine Cellar", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             translation_key="wine", | ||||||
|  |         ), | ||||||
|  |         HonClimateEntityDescription( | ||||||
|  |             key="settings.tempSelZ2", | ||||||
|  |             mode=HVACMode.COOL, | ||||||
|  |             name="Wine Cellar", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             translation_key="wine", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||||
|  |     entities = [] | ||||||
|  |     for device in hass.data[DOMAIN][entry.unique_id].appliances: | ||||||
|  |         for description in CLIMATES.get(device.appliance_type, []): | ||||||
|  |             if isinstance(description, HonACClimateEntityDescription): | ||||||
|  |                 if description.key not in list(device.commands): | ||||||
|  |                     continue | ||||||
|  |                 entity = HonACClimateEntity(hass, entry, device, description) | ||||||
|  |             elif isinstance(description, HonClimateEntityDescription): | ||||||
|  |                 if description.key not in device.available_settings: | ||||||
|  |                     continue | ||||||
|  |                 entity = HonClimateEntity(hass, entry, device, description) | ||||||
|  |             else: | ||||||
|  |                 continue | ||||||
|  |             await entity.coordinator.async_config_entry_first_refresh() | ||||||
|  |             entities.append(entity) | ||||||
|  |     async_add_entities(entities) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonACClimateEntity(HonEntity, ClimateEntity): | ||||||
|  |     def __init__(self, hass, entry, device: HonAppliance, description) -> None: | ||||||
|  |         super().__init__(hass, entry, device, description) | ||||||
|  |  | ||||||
|  |         self._attr_temperature_unit = TEMP_CELSIUS | ||||||
|  |         self._attr_target_temperature_step = device.settings["settings.tempSel"].step | ||||||
|  |         self._attr_max_temp = device.settings["settings.tempSel"].max | ||||||
|  |         self._attr_min_temp = device.settings["settings.tempSel"].min | ||||||
|  |  | ||||||
|  |         self._attr_hvac_modes = [HVACMode.OFF] | ||||||
|  |         for mode in device.settings["settings.machMode"].values: | ||||||
|  |             self._attr_hvac_modes.append(HON_HVAC_MODE[mode]) | ||||||
|  |         self._attr_fan_modes = [FAN_OFF] | ||||||
|  |         for mode in device.settings["settings.windSpeed"].values: | ||||||
|  |             self._attr_fan_modes.append(HON_FAN[mode]) | ||||||
|  |         self._attr_swing_modes = [ | ||||||
|  |             SWING_OFF, | ||||||
|  |             SWING_VERTICAL, | ||||||
|  |             SWING_HORIZONTAL, | ||||||
|  |             SWING_BOTH, | ||||||
|  |         ] | ||||||
|  |         self._attr_supported_features = ( | ||||||
|  |             ClimateEntityFeature.TARGET_TEMPERATURE | ||||||
|  |             | ClimateEntityFeature.FAN_MODE | ||||||
|  |             | ClimateEntityFeature.SWING_MODE | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         self._handle_coordinator_update(update=False) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def target_temperature(self) -> int | None: | ||||||
|  |         """Return the temperature we try to reach.""" | ||||||
|  |         return int(float(self._device.get("tempSel"))) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def current_temperature(self) -> float | None: | ||||||
|  |         """Return the current temperature.""" | ||||||
|  |         return float(self._device.get("tempIndoor")) | ||||||
|  |  | ||||||
|  |     async def async_set_temperature(self, **kwargs): | ||||||
|  |         if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None: | ||||||
|  |             return False | ||||||
|  |         self._device.settings["settings.tempSel"].value = str(int(temperature)) | ||||||
|  |         await self._device.commands["settings"].send() | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def hvac_mode(self) -> HVACMode | str | None: | ||||||
|  |         if self._device.get("onOffStatus") == "0": | ||||||
|  |             return HVACMode.OFF | ||||||
|  |         else: | ||||||
|  |             return HON_HVAC_MODE[self._device.get("machMode")] | ||||||
|  |  | ||||||
|  |     async def async_set_hvac_mode(self, hvac_mode): | ||||||
|  |         self._attr_hvac_mode = hvac_mode | ||||||
|  |         if hvac_mode == HVACMode.OFF: | ||||||
|  |             command = "stopProgram" | ||||||
|  |         else: | ||||||
|  |             mode = HON_HVAC_PROGRAM[hvac_mode] | ||||||
|  |             self._device.settings["startProgram.program"].value = mode | ||||||
|  |             command = "startProgram" | ||||||
|  |         await self._device.commands[command].send() | ||||||
|  |         self._device.sync_command(command, "settings") | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def fan_mode(self) -> str | None: | ||||||
|  |         """Return the fan setting.""" | ||||||
|  |         return HON_FAN[self._device.get("windSpeed")] | ||||||
|  |  | ||||||
|  |     async def async_set_fan_mode(self, fan_mode): | ||||||
|  |         mode_number = list(HON_FAN.values()).index(fan_mode) | ||||||
|  |         mode = list(HON_FAN.keys())[mode_number] | ||||||
|  |         self._device.settings["settings.windSpeed"].value = mode | ||||||
|  |         self._attr_fan_mode = fan_mode | ||||||
|  |         await self._device.commands["settings"].send() | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def swing_mode(self) -> str | None: | ||||||
|  |         """Return the swing setting.""" | ||||||
|  |         horizontal = self._device.get("windDirectionHorizontal") | ||||||
|  |         vertical = self._device.get("windDirectionVertical") | ||||||
|  |         if horizontal == "7" and vertical == "8": | ||||||
|  |             return SWING_BOTH | ||||||
|  |         elif horizontal == "7": | ||||||
|  |             return SWING_HORIZONTAL | ||||||
|  |         elif vertical == "8": | ||||||
|  |             return SWING_VERTICAL | ||||||
|  |         else: | ||||||
|  |             return SWING_OFF | ||||||
|  |  | ||||||
|  |     async def async_set_swing_mode(self, swing_mode): | ||||||
|  |         horizontal = self._device.settings["settings.windDirectionHorizontal"] | ||||||
|  |         vertical = self._device.settings["settings.windDirectionVertical"] | ||||||
|  |         if swing_mode in [SWING_BOTH, SWING_HORIZONTAL]: | ||||||
|  |             horizontal.value = "7" | ||||||
|  |         if swing_mode in [SWING_BOTH, SWING_VERTICAL]: | ||||||
|  |             vertical.value = "8" | ||||||
|  |         if swing_mode in [SWING_OFF, SWING_HORIZONTAL] and vertical.value == "8": | ||||||
|  |             vertical.value = "5" | ||||||
|  |         if swing_mode in [SWING_OFF, SWING_VERTICAL] and horizontal.value == "7": | ||||||
|  |             horizontal.value = "0" | ||||||
|  |         self._attr_swing_mode = swing_mode | ||||||
|  |         await self._device.commands["settings"].send() | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |     @callback | ||||||
|  |     def _handle_coordinator_update(self, update=True) -> None: | ||||||
|  |         self._attr_target_temperature = self.target_temperature | ||||||
|  |         self._attr_current_temperature = self.current_temperature | ||||||
|  |         self._attr_hvac_mode = self.hvac_mode | ||||||
|  |         self._attr_fan_mode = self.fan_mode | ||||||
|  |         self._attr_swing_mode = self.swing_mode | ||||||
|  |         if update: | ||||||
|  |             self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonClimateEntity(HonEntity, ClimateEntity): | ||||||
|  |     entity_description: HonClimateEntityDescription | ||||||
|  |  | ||||||
|  |     def __init__(self, hass, entry, device: HonAppliance, description) -> None: | ||||||
|  |         super().__init__(hass, entry, device, description) | ||||||
|  |  | ||||||
|  |         self._attr_temperature_unit = TEMP_CELSIUS | ||||||
|  |         self._set_temperature_bound() | ||||||
|  |  | ||||||
|  |         self._attr_supported_features = ( | ||||||
|  |             ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         self._attr_hvac_modes = [description.mode] | ||||||
|  |         if "stopProgram" in device.commands: | ||||||
|  |             self._attr_hvac_modes += [HVACMode.OFF] | ||||||
|  |             modes = [] | ||||||
|  |         else: | ||||||
|  |             modes = ["no_mode"] | ||||||
|  |  | ||||||
|  |         for mode, data in device.commands["startProgram"].categories.items(): | ||||||
|  |             if mode not in data.parameters["program"].values: | ||||||
|  |                 continue | ||||||
|  |             if zone := data.parameters.get("zone"): | ||||||
|  |                 if self.entity_description.name.lower() in zone.values: | ||||||
|  |                     modes.append(mode) | ||||||
|  |             else: | ||||||
|  |                 modes.append(mode) | ||||||
|  |         self._attr_preset_modes = modes | ||||||
|  |  | ||||||
|  |         self._handle_coordinator_update(update=False) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def target_temperature(self) -> float | None: | ||||||
|  |         """Return the temperature we try to reach.""" | ||||||
|  |         return float(self._device.get(self.entity_description.key)) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def current_temperature(self) -> float | None: | ||||||
|  |         """Return the current temperature.""" | ||||||
|  |         temp_key = self.entity_description.key.split(".")[-1].replace("Sel", "") | ||||||
|  |         return float(self._device.get(temp_key)) | ||||||
|  |  | ||||||
|  |     async def async_set_temperature(self, **kwargs): | ||||||
|  |         if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None: | ||||||
|  |             return False | ||||||
|  |         self._device.settings[self.entity_description.key].value = str(int(temperature)) | ||||||
|  |         await self._device.commands["settings"].send() | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def hvac_mode(self) -> HVACMode | str | None: | ||||||
|  |         if self._device.get("onOffStatus") == "0": | ||||||
|  |             return HVACMode.OFF | ||||||
|  |         else: | ||||||
|  |             return self.entity_description.mode | ||||||
|  |  | ||||||
|  |     async def async_set_hvac_mode(self, hvac_mode): | ||||||
|  |         if len(self.hvac_modes) <= 1: | ||||||
|  |             return | ||||||
|  |         if hvac_mode == HVACMode.OFF: | ||||||
|  |             await self._device.commands["stopProgram"].send() | ||||||
|  |         else: | ||||||
|  |             await self._device.commands["startProgram"].send() | ||||||
|  |         self._attr_hvac_mode = hvac_mode | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def preset_mode(self) -> str | None: | ||||||
|  |         """Return the current Preset for this channel.""" | ||||||
|  |         if self._device.get("onOffStatus") is not None: | ||||||
|  |             return self._device.get("programName", "") | ||||||
|  |         else: | ||||||
|  |             return self._device.get( | ||||||
|  |                 f"mode{self.entity_description.key[-2:]}", "no_mode" | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |     async def async_set_preset_mode(self, preset_mode: str) -> None: | ||||||
|  |         """Set the new preset mode.""" | ||||||
|  |         command = "stopProgram" if preset_mode == "no_mode" else "startProgram" | ||||||
|  |         if program := self._device.settings.get(f"{command}.program"): | ||||||
|  |             program.value = preset_mode | ||||||
|  |         if zone := self._device.settings.get(f"{command}.zone"): | ||||||
|  |             zone.value = self.entity_description.name.lower() | ||||||
|  |         self._device.sync_command(command, "settings") | ||||||
|  |         self._set_temperature_bound() | ||||||
|  |         await self.coordinator.async_refresh() | ||||||
|  |         await self._device.commands[command].send() | ||||||
|  |         self._attr_preset_mode = preset_mode | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |     def _set_temperature_bound(self): | ||||||
|  |         self._attr_target_temperature_step = self._device.settings[ | ||||||
|  |             self.entity_description.key | ||||||
|  |         ].step | ||||||
|  |         self._attr_max_temp = self._device.settings[self.entity_description.key].max | ||||||
|  |         self._attr_min_temp = self._device.settings[self.entity_description.key].min | ||||||
|  |  | ||||||
|  |     @callback | ||||||
|  |     def _handle_coordinator_update(self, update=True) -> None: | ||||||
|  |         self._attr_target_temperature = self.target_temperature | ||||||
|  |         self._attr_current_temperature = self.current_temperature | ||||||
|  |         self._attr_hvac_mode = self.hvac_mode | ||||||
|  |         self._attr_preset_mode = self.preset_mode | ||||||
|  |         if update: | ||||||
|  |             self.async_write_ha_state() | ||||||
							
								
								
									
										10
									
								
								custom_components/hOn/config_flow.py → custom_components/hon/config_flow.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										10
									
								
								custom_components/hOn/config_flow.py → custom_components/hon/config_flow.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -1,7 +1,6 @@ | |||||||
| import logging | import logging | ||||||
| 
 | 
 | ||||||
| import voluptuous as vol | import voluptuous as vol | ||||||
| 
 |  | ||||||
| from homeassistant import config_entries | from homeassistant import config_entries | ||||||
| from homeassistant.const import CONF_EMAIL, CONF_PASSWORD | from homeassistant.const import CONF_EMAIL, CONF_PASSWORD | ||||||
| 
 | 
 | ||||||
| @ -11,7 +10,6 @@ _LOGGER = logging.getLogger(__name__) | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class HonFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): | class HonFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): | ||||||
| 
 |  | ||||||
|     VERSION = 1 |     VERSION = 1 | ||||||
|     CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL |     CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL | ||||||
| 
 | 
 | ||||||
| @ -21,8 +19,12 @@ class HonFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): | |||||||
| 
 | 
 | ||||||
|     async def async_step_user(self, user_input=None): |     async def async_step_user(self, user_input=None): | ||||||
|         if user_input is None: |         if user_input is None: | ||||||
|             return self.async_show_form(step_id="user", data_schema=vol.Schema( |             return self.async_show_form( | ||||||
|                 {vol.Required(CONF_EMAIL): str, vol.Required(CONF_PASSWORD): str})) |                 step_id="user", | ||||||
|  |                 data_schema=vol.Schema( | ||||||
|  |                     {vol.Required(CONF_EMAIL): str, vol.Required(CONF_PASSWORD): str} | ||||||
|  |                 ), | ||||||
|  |             ) | ||||||
| 
 | 
 | ||||||
|         self._email = user_input[CONF_EMAIL] |         self._email = user_input[CONF_EMAIL] | ||||||
|         self._password = user_input[CONF_PASSWORD] |         self._password = user_input[CONF_PASSWORD] | ||||||
							
								
								
									
										190
									
								
								custom_components/hon/const.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								custom_components/hon/const.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,190 @@ | |||||||
|  | from homeassistant.components.climate import ( | ||||||
|  |     HVACMode, | ||||||
|  |     FAN_LOW, | ||||||
|  |     FAN_MEDIUM, | ||||||
|  |     FAN_HIGH, | ||||||
|  |     FAN_AUTO, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | DOMAIN = "hon" | ||||||
|  | UPDATE_INTERVAL = 10 | ||||||
|  |  | ||||||
|  | PLATFORMS = [ | ||||||
|  |     "sensor", | ||||||
|  |     "select", | ||||||
|  |     "number", | ||||||
|  |     "switch", | ||||||
|  |     "button", | ||||||
|  |     "binary_sensor", | ||||||
|  |     "climate", | ||||||
|  |     "fan", | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | HON_HVAC_MODE = { | ||||||
|  |     "0": HVACMode.AUTO, | ||||||
|  |     "1": HVACMode.COOL, | ||||||
|  |     "2": HVACMode.DRY, | ||||||
|  |     "3": HVACMode.DRY, | ||||||
|  |     "4": HVACMode.HEAT, | ||||||
|  |     "5": HVACMode.FAN_ONLY, | ||||||
|  |     "6": HVACMode.FAN_ONLY, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | HON_HVAC_PROGRAM = { | ||||||
|  |     HVACMode.AUTO: "iot_auto", | ||||||
|  |     HVACMode.COOL: "iot_cool", | ||||||
|  |     HVACMode.DRY: "iot_dry", | ||||||
|  |     HVACMode.HEAT: "iot_heat", | ||||||
|  |     HVACMode.FAN_ONLY: "iot_fan", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | HON_FAN = { | ||||||
|  |     "1": FAN_HIGH, | ||||||
|  |     "2": FAN_MEDIUM, | ||||||
|  |     "3": FAN_LOW, | ||||||
|  |     "4": FAN_AUTO, | ||||||
|  |     "5": FAN_AUTO, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # These languages are official supported by hOn | ||||||
|  | LANGUAGES = [ | ||||||
|  |     "cs",  # Czech | ||||||
|  |     "de",  # German | ||||||
|  |     "el",  # Greek | ||||||
|  |     "en",  # English | ||||||
|  |     "es",  # Spanish | ||||||
|  |     "fr",  # French | ||||||
|  |     "he",  # Hebrew | ||||||
|  |     "hr",  # Croatian | ||||||
|  |     "it",  # Italian | ||||||
|  |     "nl",  # Dutch | ||||||
|  |     "pl",  # Polish | ||||||
|  |     "pt",  # Portuguese | ||||||
|  |     "ro",  # Romanian | ||||||
|  |     "ru",  # Russian | ||||||
|  |     "sk",  # Slovak | ||||||
|  |     "sl",  # Slovenian | ||||||
|  |     "sr",  # Serbian | ||||||
|  |     "tr",  # Turkish | ||||||
|  |     "zh",  # Chinese | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | WASHING_PR_PHASE = { | ||||||
|  |     "0": "ready", | ||||||
|  |     "1": "washing", | ||||||
|  |     "2": "washing", | ||||||
|  |     "3": "spin", | ||||||
|  |     "4": "rinse", | ||||||
|  |     "5": "rinse", | ||||||
|  |     "6": "rinse", | ||||||
|  |     "7": "drying", | ||||||
|  |     "9": "steam", | ||||||
|  |     "10": "ready", | ||||||
|  |     "11": "spin", | ||||||
|  |     "12": "weighting", | ||||||
|  |     "13": "weighting", | ||||||
|  |     "14": "washing", | ||||||
|  |     "15": "washing", | ||||||
|  |     "16": "washing", | ||||||
|  |     "17": "rinse", | ||||||
|  |     "18": "rinse", | ||||||
|  |     "19": "scheduled", | ||||||
|  |     "20": "tumbling", | ||||||
|  |     "24": "refresh", | ||||||
|  |     "25": "washing", | ||||||
|  |     "26": "heating", | ||||||
|  |     "27": "washing", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MACH_MODE = { | ||||||
|  |     "0": "ready",  # NO_STATE | ||||||
|  |     "1": "ready",  # SELECTION_MODE | ||||||
|  |     "2": "running",  # EXECUTION_MODE | ||||||
|  |     "3": "pause",  # PAUSE_MODE | ||||||
|  |     "4": "scheduled",  # DELAY_START_SELECTION_MODE | ||||||
|  |     "5": "scheduled",  # DELAY_START_EXECUTION_MODE | ||||||
|  |     "6": "error",  # ERROR_MODE | ||||||
|  |     "7": "ready",  # END_MODE | ||||||
|  |     "8": "test",  # TEST_MODE | ||||||
|  |     "9": "ending",  # STOP_MODE | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TUMBLE_DRYER_PR_PHASE = { | ||||||
|  |     "0": "ready", | ||||||
|  |     "1": "heat_stroke", | ||||||
|  |     "2": "drying", | ||||||
|  |     "3": "cooldown", | ||||||
|  |     "8": "unknown", | ||||||
|  |     "11": "ready", | ||||||
|  |     "12": "unknown", | ||||||
|  |     "13": "cooldown", | ||||||
|  |     "14": "heat_stroke", | ||||||
|  |     "15": "heat_stroke", | ||||||
|  |     "16": "cooldown", | ||||||
|  |     "17": "unknown", | ||||||
|  |     "18": "tumbling", | ||||||
|  |     "19": "drying", | ||||||
|  |     "20": "drying", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | DIRTY_LEVEL = { | ||||||
|  |     "0": "unknown", | ||||||
|  |     "1": "little", | ||||||
|  |     "2": "normal", | ||||||
|  |     "3": "very", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | STEAM_LEVEL = { | ||||||
|  |     "0": "no_steam", | ||||||
|  |     "1": "cotton", | ||||||
|  |     "2": "delicate", | ||||||
|  |     "3": "synthetic", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | DISHWASHER_PR_PHASE = { | ||||||
|  |     "0": "ready", | ||||||
|  |     "1": "prewash", | ||||||
|  |     "2": "washing", | ||||||
|  |     "3": "rinse", | ||||||
|  |     "4": "drying", | ||||||
|  |     "5": "ready", | ||||||
|  |     "6": "hot_rinse", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TUMBLE_DRYER_DRY_LEVEL = { | ||||||
|  |     "0": "no_dry", | ||||||
|  |     "1": "iron_dry", | ||||||
|  |     "2": "no_dry_iron", | ||||||
|  |     "3": "cupboard_dry", | ||||||
|  |     "4": "extra_dry", | ||||||
|  |     "11": "no_dry", | ||||||
|  |     "12": "iron_dry", | ||||||
|  |     "13": "cupboard_dry", | ||||||
|  |     "14": "ready_to_wear", | ||||||
|  |     "15": "extra_dry", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | AC_MACH_MODE = { | ||||||
|  |     "0": "auto", | ||||||
|  |     "1": "cool", | ||||||
|  |     "2": "cool", | ||||||
|  |     "3": "dry", | ||||||
|  |     "4": "heat", | ||||||
|  |     "5": "fan", | ||||||
|  |     "6": "fan", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | AC_FAN_MODE = { | ||||||
|  |     "1": "high", | ||||||
|  |     "2": "mid", | ||||||
|  |     "3": "low", | ||||||
|  |     "4": "auto", | ||||||
|  |     "5": "auto", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | AC_HUMAN_SENSE = { | ||||||
|  |     "0": "touch_off", | ||||||
|  |     "1": "avoid_touch", | ||||||
|  |     "2": "follow_touch", | ||||||
|  |     "3": "unknown", | ||||||
|  | } | ||||||
							
								
								
									
										122
									
								
								custom_components/hon/fan.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								custom_components/hon/fan.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,122 @@ | |||||||
|  | import logging | ||||||
|  | import math | ||||||
|  | from dataclasses import dataclass | ||||||
|  | from typing import Any | ||||||
|  |  | ||||||
|  | from homeassistant.components.fan import ( | ||||||
|  |     FanEntityDescription, | ||||||
|  |     FanEntity, | ||||||
|  |     FanEntityFeature, | ||||||
|  | ) | ||||||
|  | from homeassistant.config_entries import ConfigEntry | ||||||
|  | from homeassistant.core import callback | ||||||
|  | from homeassistant.util.percentage import ( | ||||||
|  |     percentage_to_ranged_value, | ||||||
|  |     ranged_value_to_percentage, | ||||||
|  | ) | ||||||
|  | from pyhon.appliance import HonAppliance | ||||||
|  | from pyhon.parameter.range import HonParameterRange | ||||||
|  |  | ||||||
|  | from .const import DOMAIN | ||||||
|  | from .hon import HonEntity | ||||||
|  |  | ||||||
|  | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonFanEntityDescription(FanEntityDescription): | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FANS = { | ||||||
|  |     "HO": ( | ||||||
|  |         HonFanEntityDescription( | ||||||
|  |             key="settings.windSpeed", | ||||||
|  |             name="Wind Speed", | ||||||
|  |             translation_key="air_extraction", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||||
|  |     entities = [] | ||||||
|  |     for device in hass.data[DOMAIN][entry.unique_id].appliances: | ||||||
|  |         for description in FANS.get(device.appliance_type, []): | ||||||
|  |             if isinstance(description, HonFanEntityDescription): | ||||||
|  |                 if description.key not in device.available_settings or not device.get( | ||||||
|  |                     description.key.split(".")[-1] | ||||||
|  |                 ): | ||||||
|  |                     continue | ||||||
|  |                 entity = HonFanEntity(hass, entry, device, description) | ||||||
|  |             else: | ||||||
|  |                 continue | ||||||
|  |             await entity.coordinator.async_config_entry_first_refresh() | ||||||
|  |             entities.append(entity) | ||||||
|  |     async_add_entities(entities) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonFanEntity(HonEntity, FanEntity): | ||||||
|  |     entity_description: HonFanEntityDescription | ||||||
|  |  | ||||||
|  |     def __init__(self, hass, entry, device: HonAppliance, description) -> None: | ||||||
|  |         self._attr_supported_features = FanEntityFeature.SET_SPEED | ||||||
|  |         self._wind_speed: HonParameterRange = device.settings.get(description.key) | ||||||
|  |         self._speed_range = ( | ||||||
|  |             int(self._wind_speed.values[1]), | ||||||
|  |             int(self._wind_speed.values[-1]), | ||||||
|  |         ) | ||||||
|  |         self._command, self._parameter = description.key.split(".") | ||||||
|  |  | ||||||
|  |         super().__init__(hass, entry, device, description) | ||||||
|  |         self._handle_coordinator_update(update=False) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def percentage(self) -> int | None: | ||||||
|  |         """Return the current speed.""" | ||||||
|  |         value = int(self._device.get(self._parameter, "0")) | ||||||
|  |         return ranged_value_to_percentage(self._speed_range, value) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def speed_count(self) -> int: | ||||||
|  |         """Return the number of speeds the fan supports.""" | ||||||
|  |         return len(self._wind_speed.values[1:]) | ||||||
|  |  | ||||||
|  |     async def async_set_percentage(self, percentage: int) -> None: | ||||||
|  |         """Set the speed percentage of the fan.""" | ||||||
|  |         mode = math.ceil(percentage_to_ranged_value(self._speed_range, percentage)) | ||||||
|  |         self._device.settings[self.entity_description.key].value = mode | ||||||
|  |         await self._device.commands[self._command].send() | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def is_on(self) -> bool | None: | ||||||
|  |         """Return true if device is on.""" | ||||||
|  |         mode = math.ceil(percentage_to_ranged_value(self._speed_range, self.percentage)) | ||||||
|  |         return mode > self._wind_speed.min | ||||||
|  |  | ||||||
|  |     async def async_turn_on( | ||||||
|  |         self, | ||||||
|  |         percentage: int | None = None, | ||||||
|  |         preset_mode: str | None = None, | ||||||
|  |         **kwargs: Any, | ||||||
|  |     ) -> None: | ||||||
|  |         """Turn the entity on.""" | ||||||
|  |         if percentage is None: | ||||||
|  |             percentage = ranged_value_to_percentage( | ||||||
|  |                 self._speed_range, int(self._wind_speed.values[1]) | ||||||
|  |             ) | ||||||
|  |         await self.async_set_percentage(percentage) | ||||||
|  |  | ||||||
|  |     async def async_turn_off(self, **kwargs: Any) -> None: | ||||||
|  |         """Turn the entity off.""" | ||||||
|  |         self._device.settings[self.entity_description.key].value = 0 | ||||||
|  |         await self._device.commands[self._command].send() | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |     @callback | ||||||
|  |     def _handle_coordinator_update(self, update=True) -> None: | ||||||
|  |         self._wind_speed = self._device.settings.get(self.entity_description.key) | ||||||
|  |         self._attr_percentage = self.percentage | ||||||
|  |         if update: | ||||||
|  |             self.async_write_ha_state() | ||||||
							
								
								
									
										83
									
								
								custom_components/hon/hon.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								custom_components/hon/hon.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,83 @@ | |||||||
|  | import logging | ||||||
|  | from datetime import timedelta | ||||||
|  |  | ||||||
|  | from homeassistant.core import callback | ||||||
|  | from homeassistant.helpers.entity import DeviceInfo | ||||||
|  | from homeassistant.helpers.update_coordinator import CoordinatorEntity | ||||||
|  | from homeassistant.helpers.update_coordinator import DataUpdateCoordinator | ||||||
|  | from pyhon.appliance import HonAppliance | ||||||
|  |  | ||||||
|  | from .const import DOMAIN, UPDATE_INTERVAL | ||||||
|  |  | ||||||
|  | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonEntity(CoordinatorEntity): | ||||||
|  |     _attr_has_entity_name = True | ||||||
|  |  | ||||||
|  |     def __init__(self, hass, entry, device: HonAppliance, description=None) -> None: | ||||||
|  |         coordinator = get_coordinator(hass, device) | ||||||
|  |         super().__init__(coordinator) | ||||||
|  |  | ||||||
|  |         self._hon = hass.data[DOMAIN][entry.unique_id] | ||||||
|  |         self._hass = hass | ||||||
|  |         self._coordinator = coordinator | ||||||
|  |         self._device: HonAppliance = device | ||||||
|  |  | ||||||
|  |         if description is not None: | ||||||
|  |             self.entity_description = description | ||||||
|  |             self._attr_unique_id = f"{self._device.unique_id}{description.key}" | ||||||
|  |         else: | ||||||
|  |             self._attr_unique_id = self._device.unique_id | ||||||
|  |         self._handle_coordinator_update(update=False) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def device_info(self): | ||||||
|  |         return DeviceInfo( | ||||||
|  |             identifiers={(DOMAIN, self._device.unique_id)}, | ||||||
|  |             manufacturer=self._device.get("brand", ""), | ||||||
|  |             name=self._device.nick_name | ||||||
|  |             if self._device.nick_name | ||||||
|  |             else self._device.model_name, | ||||||
|  |             model=self._device.model_name, | ||||||
|  |             sw_version=self._device.get("fwVersion", ""), | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     @callback | ||||||
|  |     def _handle_coordinator_update(self, update: bool = True) -> None: | ||||||
|  |         if update: | ||||||
|  |             self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonCoordinator(DataUpdateCoordinator): | ||||||
|  |     def __init__(self, hass, device: HonAppliance): | ||||||
|  |         """Initialize my coordinator.""" | ||||||
|  |         super().__init__( | ||||||
|  |             hass, | ||||||
|  |             _LOGGER, | ||||||
|  |             name=device.unique_id, | ||||||
|  |             update_interval=timedelta(seconds=UPDATE_INTERVAL), | ||||||
|  |         ) | ||||||
|  |         self._device = device | ||||||
|  |  | ||||||
|  |     async def _async_update_data(self): | ||||||
|  |         await self._device.update() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def unique_entities(base_entities, new_entities): | ||||||
|  |     result = list(base_entities) | ||||||
|  |     existing_entities = [entity.key for entity in base_entities] | ||||||
|  |     for entity in new_entities: | ||||||
|  |         if entity.key not in existing_entities: | ||||||
|  |             result.append(entity) | ||||||
|  |     return tuple(result) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_coordinator(hass, appliance): | ||||||
|  |     coordinators = hass.data[DOMAIN]["coordinators"] | ||||||
|  |     if appliance.unique_id in coordinators: | ||||||
|  |         coordinator = hass.data[DOMAIN]["coordinators"][appliance.unique_id] | ||||||
|  |     else: | ||||||
|  |         coordinator = HonCoordinator(hass, appliance) | ||||||
|  |         hass.data[DOMAIN]["coordinators"][appliance.unique_id] = coordinator | ||||||
|  |     return coordinator | ||||||
							
								
								
									
										15
									
								
								custom_components/hon/manifest.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								custom_components/hon/manifest.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | { | ||||||
|  |   "domain": "hon", | ||||||
|  |   "name": "Haier hOn", | ||||||
|  |   "codeowners": [ | ||||||
|  |     "@Andre0512" | ||||||
|  |   ], | ||||||
|  |   "config_flow": true, | ||||||
|  |   "documentation": "https://github.com/Andre0512/hon/", | ||||||
|  |   "iot_class": "cloud_polling", | ||||||
|  |   "issue_tracker": "https://github.com/Andre0512/hon/issues", | ||||||
|  |   "requirements": [ | ||||||
|  |     "pyhOn==0.13.0" | ||||||
|  |   ], | ||||||
|  |   "version": "0.9.0-beta.2" | ||||||
|  | } | ||||||
							
								
								
									
										252
									
								
								custom_components/hon/number.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								custom_components/hon/number.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,252 @@ | |||||||
|  | from __future__ import annotations | ||||||
|  |  | ||||||
|  | from dataclasses import dataclass | ||||||
|  |  | ||||||
|  | from homeassistant.components.number import ( | ||||||
|  |     NumberEntity, | ||||||
|  |     NumberEntityDescription, | ||||||
|  | ) | ||||||
|  | from homeassistant.config_entries import ConfigEntry | ||||||
|  | from homeassistant.const import UnitOfTime, UnitOfTemperature | ||||||
|  | from homeassistant.core import callback | ||||||
|  | from homeassistant.helpers.entity import EntityCategory | ||||||
|  | from pyhon.parameter.range import HonParameterRange | ||||||
|  |  | ||||||
|  | from .const import DOMAIN | ||||||
|  | from .hon import HonEntity, unique_entities | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonConfigNumberEntityDescription(NumberEntityDescription): | ||||||
|  |     entity_category: EntityCategory = EntityCategory.CONFIG | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonNumberEntityDescription(NumberEntityDescription): | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | NUMBERS: dict[str, tuple[NumberEntityDescription, ...]] = { | ||||||
|  |     "WM": ( | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.delayTime", | ||||||
|  |             name="Delay Time", | ||||||
|  |             icon="mdi:timer-plus", | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="delay_time", | ||||||
|  |         ), | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.rinseIterations", | ||||||
|  |             name="Rinse Iterations", | ||||||
|  |             icon="mdi:rotate-right", | ||||||
|  |             translation_key="rinse_iterations", | ||||||
|  |         ), | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.mainWashTime", | ||||||
|  |             name="Main Wash Time", | ||||||
|  |             icon="mdi:clock-start", | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="wash_time", | ||||||
|  |         ), | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.steamLevel", | ||||||
|  |             name="Steam Level", | ||||||
|  |             icon="mdi:weather-dust", | ||||||
|  |             translation_key="steam_level", | ||||||
|  |         ), | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.waterHard", | ||||||
|  |             name="Water hard", | ||||||
|  |             icon="mdi:water", | ||||||
|  |             translation_key="water_hard", | ||||||
|  |         ), | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.lang", | ||||||
|  |             name="lang", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "TD": ( | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.delayTime", | ||||||
|  |             name="Delay time", | ||||||
|  |             icon="mdi:timer-plus", | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="delay_time", | ||||||
|  |         ), | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.tempLevel", | ||||||
|  |             name="Temperature level", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             translation_key="tumbledryertemplevel", | ||||||
|  |         ), | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.dryTime", | ||||||
|  |             name="Dry Time", | ||||||
|  |             translation_key="dry_time", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "OV": ( | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.delayTime", | ||||||
|  |             name="Delay time", | ||||||
|  |             icon="mdi:timer-plus", | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="delay_time", | ||||||
|  |         ), | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.tempSel", | ||||||
|  |             name="Target Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="target_temperature", | ||||||
|  |         ), | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.prTime", | ||||||
|  |             name="Program Duration", | ||||||
|  |             icon="mdi:timelapse", | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="program_duration", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "IH": ( | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.temp", | ||||||
|  |             name="Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             translation_key="temperature", | ||||||
|  |         ), | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.powerManagement", | ||||||
|  |             name="Power Management", | ||||||
|  |             icon="mdi:timelapse", | ||||||
|  |             translation_key="power_management", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "DW": ( | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.delayTime", | ||||||
|  |             name="Delay time", | ||||||
|  |             icon="mdi:timer-plus", | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="delay_time", | ||||||
|  |         ), | ||||||
|  |         HonConfigNumberEntityDescription( | ||||||
|  |             key="startProgram.waterHard", | ||||||
|  |             name="Water hard", | ||||||
|  |             icon="mdi:water", | ||||||
|  |             translation_key="water_hard", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "AC": ( | ||||||
|  |         HonNumberEntityDescription( | ||||||
|  |             key="settings.tempSel", | ||||||
|  |             name="Target Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="target_temperature", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "REF": ( | ||||||
|  |         HonNumberEntityDescription( | ||||||
|  |             key="settings.tempSelZ1", | ||||||
|  |             name="Fridge Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="fridge_temp_sel", | ||||||
|  |         ), | ||||||
|  |         HonNumberEntityDescription( | ||||||
|  |             key="settings.tempSelZ2", | ||||||
|  |             name="Freezer Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="freezer_temp_sel", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "HO": ( | ||||||
|  |         HonNumberEntityDescription( | ||||||
|  |             key="startProgram.lightStatus", | ||||||
|  |             name="Light status", | ||||||
|  |             icon="mdi:lightbulb", | ||||||
|  |             entity_category=EntityCategory.CONFIG, | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NUMBERS["WD"] = unique_entities(NUMBERS["WM"], NUMBERS["TD"]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||||
|  |     entities = [] | ||||||
|  |     for device in hass.data[DOMAIN][entry.unique_id].appliances: | ||||||
|  |         for description in NUMBERS.get(device.appliance_type, []): | ||||||
|  |             if description.key not in device.available_settings: | ||||||
|  |                 continue | ||||||
|  |             if isinstance(description, HonNumberEntityDescription): | ||||||
|  |                 entity = HonNumberEntity(hass, entry, device, description) | ||||||
|  |             elif isinstance(description, HonConfigNumberEntityDescription): | ||||||
|  |                 entity = HonConfigNumberEntity(hass, entry, device, description) | ||||||
|  |             else: | ||||||
|  |                 continue | ||||||
|  |             await entity.coordinator.async_config_entry_first_refresh() | ||||||
|  |             entities.append(entity) | ||||||
|  |     async_add_entities(entities) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonNumberEntity(HonEntity, NumberEntity): | ||||||
|  |     entity_description: HonNumberEntityDescription | ||||||
|  |  | ||||||
|  |     def __init__(self, hass, entry, device, description) -> None: | ||||||
|  |         super().__init__(hass, entry, device, description) | ||||||
|  |  | ||||||
|  |         self._data = device.settings[description.key] | ||||||
|  |         if isinstance(self._data, HonParameterRange): | ||||||
|  |             self._attr_native_max_value = self._data.max | ||||||
|  |             self._attr_native_min_value = self._data.min | ||||||
|  |             self._attr_native_step = self._data.step | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def native_value(self) -> float | None: | ||||||
|  |         return self._device.get(self.entity_description.key) | ||||||
|  |  | ||||||
|  |     async def async_set_native_value(self, value: float) -> None: | ||||||
|  |         setting = self._device.settings[self.entity_description.key] | ||||||
|  |         if isinstance(setting, HonParameterRange): | ||||||
|  |             setting.value = value | ||||||
|  |         command = self.entity_description.key.split(".")[0] | ||||||
|  |         await self._device.commands[command].send() | ||||||
|  |         await self.coordinator.async_refresh() | ||||||
|  |  | ||||||
|  |     @callback | ||||||
|  |     def _handle_coordinator_update(self, update=True) -> None: | ||||||
|  |         setting = self._device.settings[self.entity_description.key] | ||||||
|  |         if isinstance(setting, HonParameterRange): | ||||||
|  |             self._attr_native_max_value = setting.max | ||||||
|  |             self._attr_native_min_value = setting.min | ||||||
|  |             self._attr_native_step = setting.step | ||||||
|  |         self._attr_native_value = setting.value | ||||||
|  |         if update: | ||||||
|  |             self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def available(self) -> bool: | ||||||
|  |         """Return True if entity is available.""" | ||||||
|  |         return ( | ||||||
|  |             super().available | ||||||
|  |             and self._device.get("remoteCtrValid", "1") == "1" | ||||||
|  |             and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonConfigNumberEntity(HonNumberEntity): | ||||||
|  |     entity_description: HonConfigNumberEntityDescription | ||||||
|  |  | ||||||
|  |     async def async_set_native_value(self, value: str) -> None: | ||||||
|  |         setting = self._device.settings[self.entity_description.key] | ||||||
|  |         if isinstance(setting, HonParameterRange): | ||||||
|  |             setting.value = value | ||||||
|  |         await self.coordinator.async_refresh() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def available(self) -> bool: | ||||||
|  |         """Return True if entity is available.""" | ||||||
|  |         return super(NumberEntity, self).available | ||||||
							
								
								
									
										220
									
								
								custom_components/hon/select.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								custom_components/hon/select.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,220 @@ | |||||||
|  | from __future__ import annotations | ||||||
|  |  | ||||||
|  | import logging | ||||||
|  | from dataclasses import dataclass | ||||||
|  | from typing import Dict, List | ||||||
|  |  | ||||||
|  | from homeassistant.components.select import SelectEntity, SelectEntityDescription | ||||||
|  | from homeassistant.config_entries import ConfigEntry | ||||||
|  | from homeassistant.const import UnitOfTemperature, UnitOfTime, REVOLUTIONS_PER_MINUTE | ||||||
|  | from homeassistant.core import callback | ||||||
|  | from homeassistant.helpers.entity import EntityCategory | ||||||
|  | from pyhon.appliance import HonAppliance | ||||||
|  |  | ||||||
|  | from . import const | ||||||
|  | from .const import DOMAIN | ||||||
|  | from .hon import HonEntity, unique_entities | ||||||
|  |  | ||||||
|  | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonSelectEntityDescription(SelectEntityDescription): | ||||||
|  |     option_list: Dict[str, str] = None | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonConfigSelectEntityDescription(SelectEntityDescription): | ||||||
|  |     entity_category: EntityCategory = EntityCategory.CONFIG | ||||||
|  |     option_list: Dict[str, str] = None | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SELECTS = { | ||||||
|  |     "WM": ( | ||||||
|  |         HonConfigSelectEntityDescription( | ||||||
|  |             key="startProgram.spinSpeed", | ||||||
|  |             name="Spin speed", | ||||||
|  |             icon="mdi:numeric", | ||||||
|  |             unit_of_measurement=REVOLUTIONS_PER_MINUTE, | ||||||
|  |             translation_key="spin_speed", | ||||||
|  |         ), | ||||||
|  |         HonConfigSelectEntityDescription( | ||||||
|  |             key="startProgram.temp", | ||||||
|  |             name="Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="temperature", | ||||||
|  |         ), | ||||||
|  |         HonConfigSelectEntityDescription( | ||||||
|  |             key="startProgram.program", | ||||||
|  |             name="Program", | ||||||
|  |             translation_key="programs_wm", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "TD": ( | ||||||
|  |         HonConfigSelectEntityDescription( | ||||||
|  |             key="startProgram.program", | ||||||
|  |             name="Program", | ||||||
|  |             translation_key="programs_td", | ||||||
|  |         ), | ||||||
|  |         HonConfigSelectEntityDescription( | ||||||
|  |             key="startProgram.dryTimeMM", | ||||||
|  |             name="Dry Time", | ||||||
|  |             icon="mdi:timer", | ||||||
|  |             unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="dry_time", | ||||||
|  |         ), | ||||||
|  |         HonConfigSelectEntityDescription( | ||||||
|  |             key="startProgram.dryLevel", | ||||||
|  |             name="Dry level", | ||||||
|  |             icon="mdi:hair-dryer", | ||||||
|  |             translation_key="dry_levels", | ||||||
|  |             option_list=const.TUMBLE_DRYER_DRY_LEVEL, | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "OV": ( | ||||||
|  |         HonConfigSelectEntityDescription( | ||||||
|  |             key="startProgram.program", | ||||||
|  |             name="Program", | ||||||
|  |             translation_key="programs_ov", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "IH": ( | ||||||
|  |         HonConfigSelectEntityDescription( | ||||||
|  |             key="startProgram.program", | ||||||
|  |             name="Program", | ||||||
|  |             translation_key="programs_ih", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "DW": ( | ||||||
|  |         HonConfigSelectEntityDescription( | ||||||
|  |             key="startProgram.program", | ||||||
|  |             name="Program", | ||||||
|  |             translation_key="programs_dw", | ||||||
|  |         ), | ||||||
|  |         HonConfigSelectEntityDescription( | ||||||
|  |             key="startProgram.temp", | ||||||
|  |             name="Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="temperature", | ||||||
|  |         ), | ||||||
|  |         HonConfigSelectEntityDescription( | ||||||
|  |             key="startProgram.remainingTime", | ||||||
|  |             name="Remaining Time", | ||||||
|  |             icon="mdi:timer", | ||||||
|  |             unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="remaining_time", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "AC": ( | ||||||
|  |         HonSelectEntityDescription( | ||||||
|  |             key="startProgram.program", | ||||||
|  |             name="Program", | ||||||
|  |             translation_key="programs_ac", | ||||||
|  |         ), | ||||||
|  |         HonSelectEntityDescription( | ||||||
|  |             key="settings.humanSensingStatus", | ||||||
|  |             name="Eco Pilot", | ||||||
|  |             icon="mdi:run", | ||||||
|  |             translation_key="eco_pilot", | ||||||
|  |             option_list=const.AC_HUMAN_SENSE, | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "REF": ( | ||||||
|  |         HonConfigSelectEntityDescription( | ||||||
|  |             key="startProgram.program", | ||||||
|  |             name="Program", | ||||||
|  |             translation_key="programs_ref", | ||||||
|  |         ), | ||||||
|  |         HonConfigSelectEntityDescription( | ||||||
|  |             key="startProgram.zone", | ||||||
|  |             name="Zone", | ||||||
|  |             icon="mdi:radiobox-marked", | ||||||
|  |             translation_key="ref_zones", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SELECTS["WD"] = unique_entities(SELECTS["WM"], SELECTS["TD"]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||||
|  |     entities = [] | ||||||
|  |     for device in hass.data[DOMAIN][entry.unique_id].appliances: | ||||||
|  |         for description in SELECTS.get(device.appliance_type, []): | ||||||
|  |             if description.key not in device.available_settings: | ||||||
|  |                 continue | ||||||
|  |             if isinstance(description, HonSelectEntityDescription): | ||||||
|  |                 entity = HonSelectEntity(hass, entry, device, description) | ||||||
|  |             elif isinstance(description, HonConfigSelectEntityDescription): | ||||||
|  |                 entity = HonConfigSelectEntity(hass, entry, device, description) | ||||||
|  |             else: | ||||||
|  |                 continue | ||||||
|  |             await entity.coordinator.async_config_entry_first_refresh() | ||||||
|  |             entities.append(entity) | ||||||
|  |     async_add_entities(entities) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonSelectEntity(HonEntity, SelectEntity): | ||||||
|  |     entity_description: HonSelectEntityDescription | ||||||
|  |  | ||||||
|  |     def __init__(self, hass, entry, device: HonAppliance, description) -> None: | ||||||
|  |         super().__init__(hass, entry, device, description) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def current_option(self) -> str | None: | ||||||
|  |         value = self._device.settings.get(self.entity_description.key) | ||||||
|  |         if value is None or value.value not in self._attr_options: | ||||||
|  |             return None | ||||||
|  |         return value.value | ||||||
|  |  | ||||||
|  |     async def async_select_option(self, option: str) -> None: | ||||||
|  |         self._device.settings[self.entity_description.key].value = option | ||||||
|  |         command = self.entity_description.key.split(".")[0] | ||||||
|  |         await self._device.commands[command].send() | ||||||
|  |         await self.coordinator.async_refresh() | ||||||
|  |  | ||||||
|  |     @callback | ||||||
|  |     def _handle_coordinator_update(self, update=True) -> None: | ||||||
|  |         setting = self._device.settings.get(self.entity_description.key) | ||||||
|  |         if setting is None: | ||||||
|  |             self._attr_available = False | ||||||
|  |             self._attr_options: List[str] = [] | ||||||
|  |             value = None | ||||||
|  |         else: | ||||||
|  |             self._attr_available = True | ||||||
|  |             self._attr_options: List[str] = setting.values | ||||||
|  |             value = setting.value | ||||||
|  |         if self.entity_description.option_list is not None: | ||||||
|  |             self._attr_options = [ | ||||||
|  |                 self.entity_description.option_list.get(k, k) | ||||||
|  |                 for k in self._attr_options | ||||||
|  |             ] | ||||||
|  |             if value is not None: | ||||||
|  |                 value = self.entity_description.option_list.get(value, value) | ||||||
|  |         self._attr_native_value = value | ||||||
|  |         if update: | ||||||
|  |             self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def available(self) -> bool: | ||||||
|  |         """Return True if entity is available.""" | ||||||
|  |         return ( | ||||||
|  |             super().available | ||||||
|  |             and self._device.get("remoteCtrValid", "1") == "1" | ||||||
|  |             and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonConfigSelectEntity(HonSelectEntity): | ||||||
|  |     entity_description: HonConfigSelectEntityDescription | ||||||
|  |  | ||||||
|  |     async def async_select_option(self, option: str) -> None: | ||||||
|  |         self._device.settings[self.entity_description.key].value = option | ||||||
|  |         await self.coordinator.async_refresh() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def available(self) -> bool: | ||||||
|  |         """Return True if entity is available.""" | ||||||
|  |         return super(SelectEntity, self).available | ||||||
							
								
								
									
										750
									
								
								custom_components/hon/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										750
									
								
								custom_components/hon/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,750 @@ | |||||||
|  | import logging | ||||||
|  | from dataclasses import dataclass | ||||||
|  | from typing import Dict | ||||||
|  |  | ||||||
|  | from homeassistant.components.sensor import ( | ||||||
|  |     SensorEntity, | ||||||
|  |     SensorDeviceClass, | ||||||
|  |     SensorStateClass, | ||||||
|  |     SensorEntityDescription, | ||||||
|  | ) | ||||||
|  | from homeassistant.config_entries import ConfigEntry | ||||||
|  | from homeassistant.const import PERCENTAGE | ||||||
|  | from homeassistant.const import ( | ||||||
|  |     REVOLUTIONS_PER_MINUTE, | ||||||
|  |     UnitOfEnergy, | ||||||
|  |     UnitOfVolume, | ||||||
|  |     UnitOfMass, | ||||||
|  |     UnitOfPower, | ||||||
|  |     UnitOfTime, | ||||||
|  |     UnitOfTemperature, | ||||||
|  | ) | ||||||
|  | from homeassistant.core import callback | ||||||
|  | from homeassistant.helpers.entity import EntityCategory | ||||||
|  |  | ||||||
|  | from . import const | ||||||
|  | from .const import DOMAIN | ||||||
|  | from .hon import HonEntity, unique_entities | ||||||
|  |  | ||||||
|  | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonConfigSensorEntityDescription(SensorEntityDescription): | ||||||
|  |     entity_category: EntityCategory = EntityCategory.CONFIG | ||||||
|  |     option_list: Dict[str, str] = None | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonSensorEntityDescription(SensorEntityDescription): | ||||||
|  |     option_list: Dict[str, str] = None | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { | ||||||
|  |     "WM": ( | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="prPhase", | ||||||
|  |             name="Program Phase", | ||||||
|  |             icon="mdi:washing-machine", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="program_phases_wm", | ||||||
|  |             option_list=const.WASHING_PR_PHASE, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="totalElectricityUsed", | ||||||
|  |             name="Total Power", | ||||||
|  |             device_class=SensorDeviceClass.ENERGY, | ||||||
|  |             state_class=SensorStateClass.TOTAL_INCREASING, | ||||||
|  |             native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, | ||||||
|  |             translation_key="energy_total", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="totalWaterUsed", | ||||||
|  |             name="Total Water", | ||||||
|  |             device_class=SensorDeviceClass.WATER, | ||||||
|  |             state_class=SensorStateClass.TOTAL_INCREASING, | ||||||
|  |             native_unit_of_measurement=UnitOfVolume.LITERS, | ||||||
|  |             translation_key="water_total", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="totalWashCycle", | ||||||
|  |             name="Total Wash Cycle", | ||||||
|  |             state_class=SensorStateClass.TOTAL_INCREASING, | ||||||
|  |             icon="mdi:counter", | ||||||
|  |             translation_key="cycles_total", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="currentElectricityUsed", | ||||||
|  |             name="Current Electricity Used", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.POWER, | ||||||
|  |             native_unit_of_measurement=UnitOfPower.KILO_WATT, | ||||||
|  |             icon="mdi:lightning-bolt", | ||||||
|  |             translation_key="energy_current", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="currentWaterUsed", | ||||||
|  |             name="Current Water Used", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             icon="mdi:water", | ||||||
|  |             translation_key="water_current", | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.weight", | ||||||
|  |             name="Suggested weight", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfMass.KILOGRAMS, | ||||||
|  |             icon="mdi:weight-kilogram", | ||||||
|  |             translation_key="suggested_load", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="machMode", | ||||||
|  |             name="Machine Status", | ||||||
|  |             icon="mdi:information", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="washing_modes", | ||||||
|  |             option_list=const.MACH_MODE, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="errors", name="Error", icon="mdi:math-log", translation_key="errors" | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="remainingTimeMM", | ||||||
|  |             name="Remaining Time", | ||||||
|  |             icon="mdi:timer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="remaining_time", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="spinSpeed", | ||||||
|  |             name="Spin Speed", | ||||||
|  |             icon="mdi:speedometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=REVOLUTIONS_PER_MINUTE, | ||||||
|  |             translation_key="spin_speed", | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.energyLabel", | ||||||
|  |             name="Energy Label", | ||||||
|  |             icon="mdi:lightning-bolt-circle", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             translation_key="energy_label", | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.liquidDetergentDose", | ||||||
|  |             name="Liquid Detergent Dose", | ||||||
|  |             icon="mdi:cup-water", | ||||||
|  |             translation_key="det_liquid", | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.powderDetergentDose", | ||||||
|  |             name="Powder Detergent Dose", | ||||||
|  |             icon="mdi:cup", | ||||||
|  |             translation_key="det_dust", | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.remainingTime", | ||||||
|  |             name="Remaining Time", | ||||||
|  |             icon="mdi:timer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="remaining_time", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="dirtyLevel", | ||||||
|  |             name="Dirt level", | ||||||
|  |             icon="mdi:liquid-spot", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="dirt_level", | ||||||
|  |             option_list=const.DIRTY_LEVEL, | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.suggestedLoadW", | ||||||
|  |             name="Suggested Load", | ||||||
|  |             icon="mdi:weight-kilogram", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfMass.KILOGRAMS, | ||||||
|  |             translation_key="suggested_load", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="temp", | ||||||
|  |             name="Current Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="temperature", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="programName", | ||||||
|  |             name="Program", | ||||||
|  |             icon="mdi:play", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="programs_wm", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "TD": ( | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="machMode", | ||||||
|  |             name="Machine Status", | ||||||
|  |             icon="mdi:information", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="washing_modes", | ||||||
|  |             option_list=const.MACH_MODE, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="errors", name="Error", icon="mdi:math-log", translation_key="errors" | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="remainingTimeMM", | ||||||
|  |             name="Remaining Time", | ||||||
|  |             icon="mdi:timer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="remaining_time", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="delayTime", | ||||||
|  |             name="Start Time", | ||||||
|  |             icon="mdi:clock-start", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="delay_time", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="programName", | ||||||
|  |             name="Program", | ||||||
|  |             icon="mdi:play", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="programs_td", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="prPhase", | ||||||
|  |             name="Program Phase", | ||||||
|  |             icon="mdi:washing-machine", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="program_phases_td", | ||||||
|  |             option_list=const.TUMBLE_DRYER_PR_PHASE, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="dryLevel", | ||||||
|  |             name="Dry level", | ||||||
|  |             icon="mdi:hair-dryer", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="dry_levels", | ||||||
|  |             option_list=const.TUMBLE_DRYER_DRY_LEVEL, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempLevel", | ||||||
|  |             name="Temperature level", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             translation_key="tumbledryertemplevel", | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.suggestedLoadD", | ||||||
|  |             name="Suggested Load", | ||||||
|  |             icon="mdi:weight-kilogram", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfMass.KILOGRAMS, | ||||||
|  |             translation_key="suggested_load", | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.energyLabel", | ||||||
|  |             name="Energy Label", | ||||||
|  |             icon="mdi:lightning-bolt-circle", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             translation_key="energy_label", | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.steamLevel", | ||||||
|  |             name="Steam level", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             icon="mdi:smoke", | ||||||
|  |             translation_key="steam_level", | ||||||
|  |             option_list=const.STEAM_LEVEL, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="steamLevel", | ||||||
|  |             name="Steam level", | ||||||
|  |             icon="mdi:smoke", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="steam_level", | ||||||
|  |             option_list=const.STEAM_LEVEL, | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="steamType", | ||||||
|  |             name="Steam Type", | ||||||
|  |             icon="mdi:weather-dust", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "OV": ( | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="remainingTimeMM", | ||||||
|  |             name="Remaining Time", | ||||||
|  |             icon="mdi:timer", | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="remaining_time", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="delayTime", | ||||||
|  |             name="Start Time", | ||||||
|  |             icon="mdi:clock-start", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="delay_time", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="temp", | ||||||
|  |             name="Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             translation_key="temperature", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempSel", | ||||||
|  |             name="Temperature Selected", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             translation_key="target_temperature", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="programName", | ||||||
|  |             name="Program", | ||||||
|  |             icon="mdi:play", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="programs_ov", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "IH": ( | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="remainingTimeMM", | ||||||
|  |             name="Remaining Time", | ||||||
|  |             icon="mdi:timer", | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="remaining_time", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="temp", | ||||||
|  |             name="Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="temperature", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="errors", name="Error", icon="mdi:math-log", translation_key="errors" | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="power", | ||||||
|  |             name="Power", | ||||||
|  |             icon="mdi:lightning-bolt", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             translation_key="power", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="programName", | ||||||
|  |             name="Program", | ||||||
|  |             icon="mdi:play", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="programs_ih", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "DW": ( | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.ecoIndex", | ||||||
|  |             name="Eco Index", | ||||||
|  |             icon="mdi:sprout", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.waterEfficiency", | ||||||
|  |             name="Water Efficiency", | ||||||
|  |             icon="mdi:water", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             translation_key="water_efficiency", | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.waterSaving", | ||||||
|  |             name="Water Saving", | ||||||
|  |             icon="mdi:water-percent", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=PERCENTAGE, | ||||||
|  |             translation_key="water_saving", | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.temp", | ||||||
|  |             name="Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="temperature", | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.energyLabel", | ||||||
|  |             name="Energy Label", | ||||||
|  |             icon="mdi:lightning-bolt-circle", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             translation_key="energy_label", | ||||||
|  |         ), | ||||||
|  |         HonConfigSensorEntityDescription( | ||||||
|  |             key="startProgram.remainingTime", | ||||||
|  |             name="Time", | ||||||
|  |             icon="mdi:timer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="duration", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="machMode", | ||||||
|  |             name="Machine Status", | ||||||
|  |             icon="mdi:information", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="washing_modes", | ||||||
|  |             option_list=const.MACH_MODE, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="errors", name="Error", icon="mdi:math-log", translation_key="errors" | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="remainingTimeMM", | ||||||
|  |             name="Remaining Time", | ||||||
|  |             icon="mdi:timer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |             translation_key="remaining_time", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="prPhase", | ||||||
|  |             name="Program Phase", | ||||||
|  |             icon="mdi:washing-machine", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="program_phases_dw", | ||||||
|  |             option_list=const.DISHWASHER_PR_PHASE, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="programName", | ||||||
|  |             name="Program", | ||||||
|  |             icon="mdi:play", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="programs_dw", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "AC": ( | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempAirOutdoor", | ||||||
|  |             name="Air Temperature Outdoor", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempCoilerIndoor", | ||||||
|  |             name="Coiler Temperature Indoor", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempCoilerOutdoor", | ||||||
|  |             name="Coiler Temperature Outside", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempDefrostOutdoor", | ||||||
|  |             name="Defrost Temperature Outdoor", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempInAirOutdoor", | ||||||
|  |             name="In Air Temperature Outdoor", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempIndoor", | ||||||
|  |             name="Indoor Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempOutdoor", | ||||||
|  |             name="Outdoor Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempSel", | ||||||
|  |             name="Selected Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="target_temperature", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="programName", | ||||||
|  |             name="Program", | ||||||
|  |             icon="mdi:play", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="programs_ac", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="machMode", | ||||||
|  |             name="Machine Status", | ||||||
|  |             icon="mdi:information", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="mach_modes_ac", | ||||||
|  |             option_list=const.AC_MACH_MODE, | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "REF": ( | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="humidityEnv", | ||||||
|  |             name="Room Humidity", | ||||||
|  |             icon="mdi:water-percent", | ||||||
|  |             device_class=SensorDeviceClass.HUMIDITY, | ||||||
|  |             native_unit_of_measurement=PERCENTAGE, | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             translation_key="humidity", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempEnv", | ||||||
|  |             name="Room Temperature", | ||||||
|  |             icon="mdi:home-thermometer-outline", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="room_temperature", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempZ1", | ||||||
|  |             name="Temperature Fridge", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="fridge_temp", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempZ2", | ||||||
|  |             name="Temperature Freezer", | ||||||
|  |             icon="mdi:snowflake-thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="freezer_temp", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="errors", name="Error", icon="mdi:math-log", translation_key="errors" | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "HO": ( | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="delayTime", | ||||||
|  |             name="Delay time", | ||||||
|  |             icon="mdi:clock-start", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="delayTimeStatus", | ||||||
|  |             name="Delay time status", | ||||||
|  |             icon="mdi:clock-start", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="errors", | ||||||
|  |             name="Errors", | ||||||
|  |             icon="mdi:alert-circle", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="filterCleaningAlarmStatus", | ||||||
|  |             name="Filter Cleaning Alarm Status", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="filterCleaningStatus", | ||||||
|  |             name="Filter Cleaning Status", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="lastWorkTime", | ||||||
|  |             name="Last Work Time", | ||||||
|  |             icon="mdi:clock-start", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="lightStatus", | ||||||
|  |             name="Light Status", | ||||||
|  |             icon="mdi:lightbulb", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="machMode", | ||||||
|  |             name="Mach Mode", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="onOffStatus", | ||||||
|  |             name="On / Off Status", | ||||||
|  |             icon="mdi:lightbulb", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="quickDelayTimeStatus", | ||||||
|  |             name="Quick Delay Time Status", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="rgbLightColors", | ||||||
|  |             name="RGB Light Color", | ||||||
|  |             icon="mdi:lightbulb", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="rgbLightStatus", | ||||||
|  |             name="RGB Light Status", | ||||||
|  |             icon="mdi:lightbulb", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "WC": ( | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="errors", name="Error", icon="mdi:math-log", translation_key="errors" | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="humidityZ1", | ||||||
|  |             name="Humidity", | ||||||
|  |             icon="mdi:water-percent", | ||||||
|  |             device_class=SensorDeviceClass.HUMIDITY, | ||||||
|  |             native_unit_of_measurement=PERCENTAGE, | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             translation_key="humidity", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="humidityZ2", | ||||||
|  |             name="Humidity 2", | ||||||
|  |             icon="mdi:water-percent", | ||||||
|  |             device_class=SensorDeviceClass.HUMIDITY, | ||||||
|  |             native_unit_of_measurement=PERCENTAGE, | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             translation_key="humidity", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="temp", | ||||||
|  |             name="Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="temperature", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempEnv", | ||||||
|  |             name="Room Temperature", | ||||||
|  |             icon="mdi:home-thermometer-outline", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="room_temperature", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempSel", | ||||||
|  |             name="Selected Temperature", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="target_temperature", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempSelZ2", | ||||||
|  |             name="Selected Temperature 2", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             device_class=SensorDeviceClass.TEMPERATURE, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="target_temperature", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="tempZ2", | ||||||
|  |             name="Temperature 2", | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             state_class=SensorStateClass.MEASUREMENT, | ||||||
|  |             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||||
|  |             translation_key="temperature", | ||||||
|  |         ), | ||||||
|  |         HonSensorEntityDescription( | ||||||
|  |             key="programName", | ||||||
|  |             name="Program", | ||||||
|  |             icon="mdi:play", | ||||||
|  |             device_class=SensorDeviceClass.ENUM, | ||||||
|  |             translation_key="programs_wc", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | } | ||||||
|  | SENSORS["WD"] = unique_entities(SENSORS["WM"], SENSORS["TD"]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||||
|  |     entities = [] | ||||||
|  |     for device in hass.data[DOMAIN][entry.unique_id].appliances: | ||||||
|  |         for description in SENSORS.get(device.appliance_type, []): | ||||||
|  |             if isinstance(description, HonSensorEntityDescription): | ||||||
|  |                 if not device.get(description.key): | ||||||
|  |                     continue | ||||||
|  |                 entity = HonSensorEntity(hass, entry, device, description) | ||||||
|  |             elif isinstance(description, HonConfigSensorEntityDescription): | ||||||
|  |                 if description.key not in device.available_settings: | ||||||
|  |                     continue | ||||||
|  |                 entity = HonConfigSensorEntity(hass, entry, device, description) | ||||||
|  |             else: | ||||||
|  |                 continue | ||||||
|  |             await entity.coordinator.async_config_entry_first_refresh() | ||||||
|  |             entities.append(entity) | ||||||
|  |  | ||||||
|  |     async_add_entities(entities) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonSensorEntity(HonEntity, SensorEntity): | ||||||
|  |     entity_description: HonSensorEntityDescription | ||||||
|  |  | ||||||
|  |     @callback | ||||||
|  |     def _handle_coordinator_update(self, update=True) -> None: | ||||||
|  |         value = self._device.get(self.entity_description.key, "") | ||||||
|  |         if self.entity_description.key == "programName": | ||||||
|  |             self._attr_options = self._device.settings.get( | ||||||
|  |                 "startProgram.program" | ||||||
|  |             ).values + ["No Program"] | ||||||
|  |         elif self.entity_description.option_list is not None: | ||||||
|  |             self._attr_options = list(self.entity_description.option_list.values()) | ||||||
|  |             value = self.entity_description.option_list.get(value, value) | ||||||
|  |         if not value and self.entity_description.state_class is not None: | ||||||
|  |             self._attr_native_value = 0 | ||||||
|  |         self._attr_native_value = value | ||||||
|  |         if update: | ||||||
|  |             self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonConfigSensorEntity(HonEntity, SensorEntity): | ||||||
|  |     entity_description: HonConfigSensorEntityDescription | ||||||
|  |  | ||||||
|  |     @callback | ||||||
|  |     def _handle_coordinator_update(self, update=True) -> None: | ||||||
|  |         value = self._device.settings.get(self.entity_description.key, None) | ||||||
|  |         if self.entity_description.state_class is not None: | ||||||
|  |             if value and value.value: | ||||||
|  |                 value = ( | ||||||
|  |                     float(value.value) if "." in str(value.value) else int(value.value) | ||||||
|  |                 ) | ||||||
|  |             else: | ||||||
|  |                 value = 0 | ||||||
|  |         else: | ||||||
|  |             value = value.value | ||||||
|  |         if self.entity_description.option_list is not None and not value == 0: | ||||||
|  |             self._attr_options = list(self.entity_description.option_list.values()) | ||||||
|  |             value = self.entity_description.option_list.get(value, value) | ||||||
|  |         self._attr_native_value = value | ||||||
|  |         if update: | ||||||
|  |             self.async_write_ha_state() | ||||||
							
								
								
									
										490
									
								
								custom_components/hon/switch.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										490
									
								
								custom_components/hon/switch.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,490 @@ | |||||||
|  | import logging | ||||||
|  | from dataclasses import dataclass | ||||||
|  | from datetime import datetime, timedelta | ||||||
|  | from typing import Any | ||||||
|  |  | ||||||
|  | from homeassistant.components.switch import SwitchEntityDescription, SwitchEntity | ||||||
|  | from homeassistant.config_entries import ConfigEntry | ||||||
|  | from homeassistant.const import EntityCategory | ||||||
|  | from homeassistant.core import callback | ||||||
|  | from pyhon.parameter.base import HonParameter | ||||||
|  | from pyhon.parameter.range import HonParameterRange | ||||||
|  |  | ||||||
|  | from .const import DOMAIN | ||||||
|  | from .hon import HonEntity, unique_entities | ||||||
|  |  | ||||||
|  | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonSwitchEntityDescriptionMixin: | ||||||
|  |     turn_on_key: str = "" | ||||||
|  |     turn_off_key: str = "" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonControlSwitchEntityDescription( | ||||||
|  |     HonSwitchEntityDescriptionMixin, SwitchEntityDescription | ||||||
|  | ): | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonSwitchEntityDescription(SwitchEntityDescription): | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonConfigSwitchEntityDescription(SwitchEntityDescription): | ||||||
|  |     entity_category: EntityCategory = EntityCategory.CONFIG | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { | ||||||
|  |     "WM": ( | ||||||
|  |         HonControlSwitchEntityDescription( | ||||||
|  |             key="active", | ||||||
|  |             name="Washing Machine", | ||||||
|  |             icon="mdi:washing-machine", | ||||||
|  |             turn_on_key="startProgram", | ||||||
|  |             turn_off_key="stopProgram", | ||||||
|  |             translation_key="washing_machine", | ||||||
|  |         ), | ||||||
|  |         HonControlSwitchEntityDescription( | ||||||
|  |             key="pause", | ||||||
|  |             name="Pause Washing Machine", | ||||||
|  |             icon="mdi:pause", | ||||||
|  |             turn_on_key="pauseProgram", | ||||||
|  |             turn_off_key="resumeProgram", | ||||||
|  |             translation_key="pause", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.delayStatus", | ||||||
|  |             name="Delay Status", | ||||||
|  |             icon="mdi:timer-check", | ||||||
|  |             translation_key="delay_time", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.haier_SoakPrewashSelection", | ||||||
|  |             name="Soak Prewash Selection", | ||||||
|  |             icon="mdi:tshirt-crew", | ||||||
|  |             translation_key="prewash", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.permanentPressStatus", | ||||||
|  |             name="Keep Fresh", | ||||||
|  |             icon="mdi:refresh-circle", | ||||||
|  |             translation_key="keep_fresh", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.autoSoftenerStatus", | ||||||
|  |             name="Auto Dose Softener", | ||||||
|  |             icon="mdi:teddy-bear", | ||||||
|  |             translation_key="auto_dose_softener", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.autoDetergentStatus", | ||||||
|  |             name="Auto Dose Detergent", | ||||||
|  |             icon="mdi:cup", | ||||||
|  |             translation_key="auto_dose_detergent", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.acquaplus", | ||||||
|  |             name="Acqua Plus", | ||||||
|  |             icon="mdi:water-plus", | ||||||
|  |             translation_key="acqua_plus", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.extraRinse1", | ||||||
|  |             name="Extra Rinse 1", | ||||||
|  |             icon="mdi:numeric-1-box-multiple-outline", | ||||||
|  |             translation_key="extra_rinse_1", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.extraRinse2", | ||||||
|  |             name="Extra Rinse 2", | ||||||
|  |             icon="mdi:numeric-2-box-multiple-outline", | ||||||
|  |             translation_key="extra_rinse_2", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.extraRinse3", | ||||||
|  |             name="Extra Rinse 3", | ||||||
|  |             icon="mdi:numeric-3-box-multiple-outline", | ||||||
|  |             translation_key="extra_rinse_3", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.goodNight", | ||||||
|  |             name="Good Night", | ||||||
|  |             icon="mdi:weather-night", | ||||||
|  |             translation_key="good_night", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "TD": ( | ||||||
|  |         HonControlSwitchEntityDescription( | ||||||
|  |             key="active", | ||||||
|  |             name="Tumble Dryer", | ||||||
|  |             icon="mdi:tumble-dryer", | ||||||
|  |             turn_on_key="startProgram", | ||||||
|  |             turn_off_key="stopProgram", | ||||||
|  |             translation_key="tumble_dryer", | ||||||
|  |         ), | ||||||
|  |         HonControlSwitchEntityDescription( | ||||||
|  |             key="pause", | ||||||
|  |             name="Pause Tumble Dryer", | ||||||
|  |             icon="mdi:pause", | ||||||
|  |             turn_on_key="pauseProgram", | ||||||
|  |             turn_off_key="resumeProgram", | ||||||
|  |             translation_key="pause", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.sterilizationStatus", | ||||||
|  |             name="Sterilization", | ||||||
|  |             icon="mdi:clock-start", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.antiCreaseTime", | ||||||
|  |             name="Anti-Crease", | ||||||
|  |             icon="mdi:timer", | ||||||
|  |             translation_key="anti_crease", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.anticrease", | ||||||
|  |             name="Anti-Crease", | ||||||
|  |             icon="mdi:timer", | ||||||
|  |             translation_key="anti_crease", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "OV": ( | ||||||
|  |         HonControlSwitchEntityDescription( | ||||||
|  |             key="active", | ||||||
|  |             name="Oven", | ||||||
|  |             icon="mdi:toaster-oven", | ||||||
|  |             turn_on_key="startProgram", | ||||||
|  |             turn_off_key="stopProgram", | ||||||
|  |             translation_key="oven", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.preheatStatus", | ||||||
|  |             name="Preheat", | ||||||
|  |             icon="mdi:thermometer-chevron-up", | ||||||
|  |             translation_key="preheat", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "WD": ( | ||||||
|  |         HonControlSwitchEntityDescription( | ||||||
|  |             key="active", | ||||||
|  |             name="Washer Dryer", | ||||||
|  |             icon="mdi:washing-machine", | ||||||
|  |             turn_on_key="startProgram", | ||||||
|  |             turn_off_key="stopProgram", | ||||||
|  |             translation_key="washer_dryer", | ||||||
|  |         ), | ||||||
|  |         HonControlSwitchEntityDescription( | ||||||
|  |             key="pause", | ||||||
|  |             name="Pause Washer Dryer", | ||||||
|  |             icon="mdi:pause", | ||||||
|  |             turn_on_key="pauseProgram", | ||||||
|  |             turn_off_key="resumeProgram", | ||||||
|  |             translation_key="pause", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "DW": ( | ||||||
|  |         HonControlSwitchEntityDescription( | ||||||
|  |             key="active", | ||||||
|  |             name="Dish Washer", | ||||||
|  |             icon="mdi:dishwasher", | ||||||
|  |             turn_on_key="startProgram", | ||||||
|  |             turn_off_key="stopProgram", | ||||||
|  |             translation_key="dish_washer", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.extraDry", | ||||||
|  |             name="Extra Dry", | ||||||
|  |             icon="mdi:hair-dryer", | ||||||
|  |             translation_key="extra_dry", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.halfLoad", | ||||||
|  |             name="Half Load", | ||||||
|  |             icon="mdi:fraction-one-half", | ||||||
|  |             translation_key="half_load", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.openDoor", | ||||||
|  |             name="Open Door", | ||||||
|  |             icon="mdi:door-open", | ||||||
|  |             translation_key="open_door", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.threeInOne", | ||||||
|  |             name="Three in One", | ||||||
|  |             icon="mdi:numeric-3-box-outline", | ||||||
|  |             translation_key="three_in_one", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.ecoExpress", | ||||||
|  |             name="Eco Express", | ||||||
|  |             icon="mdi:sprout", | ||||||
|  |             translation_key="eco", | ||||||
|  |         ), | ||||||
|  |         HonConfigSwitchEntityDescription( | ||||||
|  |             key="startProgram.addDish", | ||||||
|  |             name="Add Dish", | ||||||
|  |             icon="mdi:silverware-fork-knife", | ||||||
|  |             translation_key="add_dish", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="buzzerDisabled", | ||||||
|  |             name="Buzzer Disabled", | ||||||
|  |             icon="mdi:volume-off", | ||||||
|  |             translation_key="buzzer", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "AC": ( | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="10degreeHeatingStatus", | ||||||
|  |             name="10° Heating", | ||||||
|  |             icon="mdi:heat-wave", | ||||||
|  |             translation_key="10_degree_heating", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="echoStatus", | ||||||
|  |             name="Echo", | ||||||
|  |             icon="mdi:account-voice", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="ecoMode", | ||||||
|  |             name="Eco Mode", | ||||||
|  |             translation_key="eco_mode", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="healthMode", | ||||||
|  |             name="Health Mode", | ||||||
|  |             icon="mdi:medication-outline", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="muteStatus", | ||||||
|  |             name="Mute", | ||||||
|  |             icon="mdi:volume-off", | ||||||
|  |             translation_key="mute_mode", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="rapidMode", | ||||||
|  |             name="Rapid Mode", | ||||||
|  |             icon="mdi:run-fast", | ||||||
|  |             translation_key="rapid_mode", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="screenDisplayStatus", | ||||||
|  |             name="Screen Display", | ||||||
|  |             icon="mdi:monitor-small", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="selfCleaning56Status", | ||||||
|  |             name="Self Cleaning 56", | ||||||
|  |             icon="mdi:air-filter", | ||||||
|  |             translation_key="self_clean_56", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="selfCleaningStatus", | ||||||
|  |             name="Self Cleaning", | ||||||
|  |             icon="mdi:air-filter", | ||||||
|  |             translation_key="self_clean", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="silentSleepStatus", | ||||||
|  |             name="Silent Sleep", | ||||||
|  |             icon="mdi:bed", | ||||||
|  |             translation_key="silent_mode", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "REF": ( | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="intelligenceMode", | ||||||
|  |             name="Auto-Set Mode", | ||||||
|  |             icon="mdi:thermometer-auto", | ||||||
|  |             translation_key="auto_set", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="quickModeZ1", | ||||||
|  |             name="Super Freeze", | ||||||
|  |             icon="mdi:snowflake-variant", | ||||||
|  |             translation_key="super_freeze", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="quickModeZ2", | ||||||
|  |             name="Super Cool", | ||||||
|  |             icon="mdi:snowflake", | ||||||
|  |             translation_key="super_cool", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="holidayMode", | ||||||
|  |             name="Holiday Mode", | ||||||
|  |             icon="mdi:palm-tree", | ||||||
|  |             translation_key="holiday_mode", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  |     "WC": ( | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="sabbathStatus", | ||||||
|  |             name="Sabbath Mode", | ||||||
|  |             icon="mdi:palm-tree", | ||||||
|  |             translation_key="holiday_mode", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="lightStatus", name="Light", icon="mdi:lightbulb" | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SWITCHES["WD"] = unique_entities(SWITCHES["WD"], SWITCHES["WM"]) | ||||||
|  | SWITCHES["WD"] = unique_entities(SWITCHES["WD"], SWITCHES["TD"]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||||
|  |     entities = [] | ||||||
|  |     for device in hass.data[DOMAIN][entry.unique_id].appliances: | ||||||
|  |         for description in SWITCHES.get(device.appliance_type, []): | ||||||
|  |             if isinstance(description, HonConfigSwitchEntityDescription): | ||||||
|  |                 if description.key not in device.available_settings: | ||||||
|  |                     continue | ||||||
|  |                 entity = HonConfigSwitchEntity(hass, entry, device, description) | ||||||
|  |             elif isinstance(description, HonControlSwitchEntityDescription): | ||||||
|  |                 if not ( | ||||||
|  |                     device.get(description.key) is not None | ||||||
|  |                     or description.turn_on_key in list(device.commands) | ||||||
|  |                     or description.turn_off_key in list(device.commands) | ||||||
|  |                 ): | ||||||
|  |                     continue | ||||||
|  |                 entity = HonControlSwitchEntity(hass, entry, device, description) | ||||||
|  |             elif isinstance(description, HonSwitchEntityDescription): | ||||||
|  |                 if ( | ||||||
|  |                     f"settings.{description.key}" not in device.available_settings | ||||||
|  |                     or not device.get(description.key) | ||||||
|  |                 ): | ||||||
|  |                     continue | ||||||
|  |                 entity = HonSwitchEntity(hass, entry, device, description) | ||||||
|  |             else: | ||||||
|  |                 continue | ||||||
|  |             await entity.coordinator.async_config_entry_first_refresh() | ||||||
|  |             entities.append(entity) | ||||||
|  |  | ||||||
|  |     async_add_entities(entities) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonSwitchEntity(HonEntity, SwitchEntity): | ||||||
|  |     entity_description: HonSwitchEntityDescription | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def is_on(self) -> bool | None: | ||||||
|  |         """Return True if entity is on.""" | ||||||
|  |         return self._device.get(self.entity_description.key, "0") == "1" | ||||||
|  |  | ||||||
|  |     async def async_turn_on(self, **kwargs: Any) -> None: | ||||||
|  |         setting = self._device.settings[f"settings.{self.entity_description.key}"] | ||||||
|  |         if type(setting) == HonParameter: | ||||||
|  |             return | ||||||
|  |         setting.value = setting.max if isinstance(setting, HonParameterRange) else "1" | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |         await self._device.commands["settings"].send() | ||||||
|  |         await self.coordinator.async_refresh() | ||||||
|  |  | ||||||
|  |     async def async_turn_off(self, **kwargs: Any) -> None: | ||||||
|  |         setting = self._device.settings[f"settings.{self.entity_description.key}"] | ||||||
|  |         if type(setting) == HonParameter: | ||||||
|  |             return | ||||||
|  |         setting.value = setting.min if isinstance(setting, HonParameterRange) else "0" | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |         await self._device.commands["settings"].send() | ||||||
|  |         await self.coordinator.async_refresh() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def available(self) -> bool: | ||||||
|  |         """Return True if entity is available.""" | ||||||
|  |         return ( | ||||||
|  |             super().available | ||||||
|  |             and self._device.get("remoteCtrValid", "1") == "1" | ||||||
|  |             and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     @callback | ||||||
|  |     def _handle_coordinator_update(self, update=True) -> None: | ||||||
|  |         value = self._device.get(self.entity_description.key, "0") | ||||||
|  |         self._attr_state = value == "1" | ||||||
|  |         if update: | ||||||
|  |             self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonControlSwitchEntity(HonEntity, SwitchEntity): | ||||||
|  |     entity_description: HonControlSwitchEntityDescription | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def is_on(self) -> bool | None: | ||||||
|  |         """Return True if entity is on.""" | ||||||
|  |         return self._device.get(self.entity_description.key, False) | ||||||
|  |  | ||||||
|  |     async def async_turn_on(self, **kwargs: Any) -> None: | ||||||
|  |         await self._device.commands[self.entity_description.turn_on_key].send() | ||||||
|  |         self._device.attributes[self.entity_description.key] = True | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |     async def async_turn_off(self, **kwargs: Any) -> None: | ||||||
|  |         await self._device.commands[self.entity_description.turn_off_key].send() | ||||||
|  |         self._device.attributes[self.entity_description.key] = False | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def available(self) -> bool: | ||||||
|  |         """Return True if entity is available.""" | ||||||
|  |         return ( | ||||||
|  |             super().available | ||||||
|  |             and self._device.get("remoteCtrValid", "1") == "1" | ||||||
|  |             and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def extra_state_attributes(self) -> dict[str, Any]: | ||||||
|  |         """Return the optional state attributes.""" | ||||||
|  |         result = {} | ||||||
|  |         if remaining_time := int(self._device.get("remainingTimeMM", 0)): | ||||||
|  |             delay_time = int(self._device.get("delayTime", 0)) | ||||||
|  |             result["start_time"] = datetime.now() + timedelta(minutes=delay_time) | ||||||
|  |             result["end_time"] = datetime.now() + timedelta( | ||||||
|  |                 minutes=delay_time + remaining_time | ||||||
|  |             ) | ||||||
|  |         return result | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonConfigSwitchEntity(HonEntity, SwitchEntity): | ||||||
|  |     entity_description: HonConfigSwitchEntityDescription | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def is_on(self) -> bool | None: | ||||||
|  |         """Return True if entity is on.""" | ||||||
|  |         setting = self._device.settings[self.entity_description.key] | ||||||
|  |         return ( | ||||||
|  |             setting.value != setting.min | ||||||
|  |             if hasattr(setting, "min") | ||||||
|  |             else setting.value == "1" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     async def async_turn_on(self, **kwargs: Any) -> None: | ||||||
|  |         setting = self._device.settings[self.entity_description.key] | ||||||
|  |         if type(setting) == HonParameter: | ||||||
|  |             return | ||||||
|  |         setting.value = setting.max if isinstance(setting, HonParameterRange) else "1" | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |         await self.coordinator.async_refresh() | ||||||
|  |  | ||||||
|  |     async def async_turn_off(self, **kwargs: Any) -> None: | ||||||
|  |         setting = self._device.settings[self.entity_description.key] | ||||||
|  |         if type(setting) == HonParameter: | ||||||
|  |             return | ||||||
|  |         setting.value = setting.min if isinstance(setting, HonParameterRange) else "0" | ||||||
|  |         self.async_write_ha_state() | ||||||
|  |         await self.coordinator.async_refresh() | ||||||
|  |  | ||||||
|  |     @callback | ||||||
|  |     def _handle_coordinator_update(self, update=True) -> None: | ||||||
|  |         value = self._device.settings.get(self.entity_description.key, "0") | ||||||
|  |         self._attr_state = value == "1" | ||||||
|  |         if update: | ||||||
|  |             self.async_write_ha_state() | ||||||
							
								
								
									
										88
									
								
								custom_components/hon/translations/bg.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								custom_components/hon/translations/bg.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | |||||||
|  | { | ||||||
|  |   "config": { | ||||||
|  |     "step": { | ||||||
|  |       "user": { | ||||||
|  |         "description": "Моля, въведете вашите данни за достъп до hOn", | ||||||
|  |         "data": { | ||||||
|  |           "email": "Email Адрес", | ||||||
|  |           "password": "Парола" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "entity": { | ||||||
|  |     "sensor": { | ||||||
|  |       "mode": { | ||||||
|  |         "state": { | ||||||
|  |           "0": "Изключен", | ||||||
|  |           "1": "Готов", | ||||||
|  |           "2": "Работи", | ||||||
|  |           "3": "На пауза", | ||||||
|  |           "5": "Scheduled", | ||||||
|  |           "6": "Грешка", | ||||||
|  |           "7": "Завършен" | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "errors": { | ||||||
|  |         "state": { | ||||||
|  |           "00": "Няма грешки", | ||||||
|  |           "100000000000": "E2: Провери дали вратата е затворена", | ||||||
|  |           "8000000000000": "E4: Провери подаването на вода" | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "programs": { | ||||||
|  |         "state": { | ||||||
|  |           "0": "Стандартна", | ||||||
|  |           "62": "Памук", | ||||||
|  |           "63": "Синтетика", | ||||||
|  |           "64": "Смесен тип", | ||||||
|  |           "66": "Чаршафи", | ||||||
|  |           "71": "Пердета", | ||||||
|  |           "72": "Спорт", | ||||||
|  |           "74": "i-time", | ||||||
|  |           "75": "Олекотени завивки", | ||||||
|  |           "76": "Вълна", | ||||||
|  |           "78": "i-Refresh", | ||||||
|  |           "83": "Хавлиена кърпа", | ||||||
|  |           "85": "Бързо Сушене", | ||||||
|  |           "92": "Деликатно пране", | ||||||
|  |           "103": "Отдалечен" | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "program_phases_td": { | ||||||
|  |         "state": { | ||||||
|  |           "0": "Изчаване", | ||||||
|  |           "2": "Сушене", | ||||||
|  |           "3": "Охлажане", | ||||||
|  |           "11": "11" | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "tumbledryertemplevel": { | ||||||
|  |         "state": { | ||||||
|  |           "1": "Хладен въздух", | ||||||
|  |           "2": "Ниска температура L-1", | ||||||
|  |           "3": "Средна температура L-2", | ||||||
|  |           "4": "Висока температура L-3" | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "dry_levels": { | ||||||
|  |         "state": { | ||||||
|  |           "3": "Готови за съхранение", | ||||||
|  |           "12": "Готови за гладене H-1", | ||||||
|  |           "13": "Готови за съхранение H-2", | ||||||
|  |           "14": "Екстра сухо H-3" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "select": { | ||||||
|  |       "dry_levels": { | ||||||
|  |         "state": { | ||||||
|  |           "3": "Готови за съхранение", | ||||||
|  |           "12": "Готови за гладене H-1", | ||||||
|  |           "13": "Готови за съхранение H-2", | ||||||
|  |           "14": "Екстра сухо H-3" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										1967
									
								
								custom_components/hon/translations/cs.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/cs.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/de.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/de.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/el.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/el.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1998
									
								
								custom_components/hon/translations/en.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1998
									
								
								custom_components/hon/translations/en.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/es.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/es.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/fr.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/fr.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1035
									
								
								custom_components/hon/translations/he.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1035
									
								
								custom_components/hon/translations/he.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/hr.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/hr.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1972
									
								
								custom_components/hon/translations/it.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1972
									
								
								custom_components/hon/translations/it.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/nl.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/nl.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/pl.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/pl.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/pt.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/pt.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/ro.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/ro.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/ru.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/ru.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/sk.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/sk.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/sl.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/sl.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/sr.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/sr.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/tr.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/tr.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1967
									
								
								custom_components/hon/translations/zh.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1967
									
								
								custom_components/hon/translations/zh.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,5 +1,6 @@ | |||||||
| { | { | ||||||
|     "name": "hOn", |     "name": "Haier hOn", | ||||||
|     "render_readme": false, |     "homeassistant": "2023.2.0", | ||||||
|     "homeassistant": "2023.2.0" |     "zip_release": true, | ||||||
| } |     "filename": "haier_hon.zip" | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										77
									
								
								info.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								info.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,77 @@ | |||||||
|  | # Haier hOn | ||||||
|  | [](https://github.com/Andre0512/hon/releases/latest) | ||||||
|  | [](https://github.com/Andre0512/hon/blob/main/LICENSE) | ||||||
|  | [](https://tooomm.github.io/github-release-stats/?username=Andre0512&repository=hon)   | ||||||
|  | Support for home appliances of [Haier's mobile app hOn](https://hon-smarthome.com/) based on [pyhOn](https://github.com/Andre0512/pyhon). | ||||||
|  |  | ||||||
|  | ## Supported Appliances | ||||||
|  | - [Washing Machine](https://github.com/Andre0512/hon#washing-machine) | ||||||
|  | - [Tumble Dryer](https://github.com/Andre0512/hon#tumble-dryer) | ||||||
|  | - [Washer Dryer](https://github.com/Andre0512/hon#washer-dryer) | ||||||
|  | - [Oven](https://github.com/Andre0512/hon#oven) | ||||||
|  | - [Dish Washer](https://github.com/Andre0512/hon#dish-washer) | ||||||
|  | - [Air conditioner](https://github.com/Andre0512/hon#air-conditioner) | ||||||
|  | - [Fridge](https://github.com/Andre0512/hon#fridge) | ||||||
|  | - [Hob](https://github.com/Andre0512/hon#hob) [BETA] | ||||||
|  | - [Hood](https://github.com/Andre0512/hon#hood) [BETA] | ||||||
|  | - [Wine Cellar](https://github.com/Andre0512/hon#wine-cellar) [BETA] | ||||||
|  |  | ||||||
|  | ## Configuration | ||||||
|  |  | ||||||
|  | **Method 1**: [](https://my.home-assistant.io/redirect/config_flow_start/?domain=hon) | ||||||
|  |  | ||||||
|  | **Method 2**: Settings > Devices & Services > Add Integration > **Haier hOn**   | ||||||
|  | _If the integration is not in the list, you need to clear the browser cache._ | ||||||
|  |  | ||||||
|  | ## Supported Models | ||||||
|  | Support has been confirmed for these models, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8). | ||||||
|  |  | ||||||
|  | |                     | **Haier**                                                                                                        | **Hoover**                                                                                                            | **Candy**                                                  | | ||||||
|  | |---------------------|------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------| | ||||||
|  | | **Washing Machine** | HW90-B14TEAM5 <br/> HW100-B14959U1                                                                               | H-WASH 500 <br/> H7W4 48MBC-S                                                                                         | RO441286DWMC4-07 <br/> HW 68AMC/1-80 <br/> HWPD 69AMBC/1-S | | ||||||
|  | | **Tumble Dryer**    | HD80-A3959                                                                                                       | H-DRY 500 <br/> H9A3TCBEXS-S <br/> HLE C10DCE-80 <br/> NDE H10A2TCE-80 <br/> NDE H9A2TSBEXS-S <br/> NDPHY10A2TCBEXSS  | BCTDH7A1TE <br/> CSOE C10DE-80 <br/> ROE H9A3TCEX-S        | | ||||||
|  | | **Washer Dryer**    | HWD100-B14979                                                                                                    | HWPS4954DAMR-11                                                                                                       | RPW41066BWMR/1-S                                           | | ||||||
|  | | **Oven**            | HWO60SM2F3XH                                                                                                     | HSOT3161WG                                                                                                            |                                                            | | ||||||
|  | | **Dish Washer**     | XIB 3B2SFS-80 <br/> XIB 6B2D3FB                                                                                  | HFB 6B2S3FX                                                                                                           |                                                            | | ||||||
|  | | **Air conditioner** | AD105S2SM3FA <br/> AS20HPL1HRA <br/> AS25PBAHRA <br/> AS25S2SF1FA-WH <br/> AS25TADHRA-2 <br/> AS35TADHRA-2 <br/> |                                                                                                                       |                                                            | | ||||||
|  | | **Fridge**          | HFW7720ENMB                                                                                                      |                                                                                                                       | CCE4T620EWU                                                | | ||||||
|  | | **Hob**             | HA2MTSJ68MC                                                                                                      |                                                                                                                       | CIS633SCTTWIFI                                             | | ||||||
|  | | **Hood**            | HADG6DS46BWIFI                                                                                                   |                                                                                                                       |                                                            | | ||||||
|  | | **Wine Cellar**     | HWS247FDU1                                                                                                       |                                                                                                                       |                                                            | | ||||||
|  |  | ||||||
|  | ## Supported Languages | ||||||
|  | Translation of internal names like programs are available for all languages which are official supported by the hOn app: | ||||||
|  | * 🇨🇳 Chinese | ||||||
|  | * 🇭🇷 Croatian | ||||||
|  | * 🇨🇿 Czech | ||||||
|  | * 🇳🇱 Dutch | ||||||
|  | * 🇬🇧 English | ||||||
|  | * 🇫🇷 French | ||||||
|  | * 🇩🇪 German | ||||||
|  | * 🇬🇷 Greek | ||||||
|  | * 🇮🇱 Hebrew | ||||||
|  | * 🇮🇹 Italian | ||||||
|  | * 🇵🇱 Polish | ||||||
|  | * 🇵🇹 Portuguese | ||||||
|  | * 🇷🇴 Romanian | ||||||
|  | * 🇷🇺 Russian | ||||||
|  | * 🇷🇸 Serbian | ||||||
|  | * 🇸🇰 Slovak | ||||||
|  | * 🇸🇮 Slovenian | ||||||
|  | * 🇪🇸 Spanish | ||||||
|  | * 🇹🇷 Turkish | ||||||
|  |  | ||||||
|  | ## Examples | ||||||
|  | ### Washing Machine | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## Contribute | ||||||
|  | Want to help us to support more appliances? Or add more sensors? Or help with translating? Or beautify some icons or captions?  | ||||||
|  | Check out the [project on GitHub](https://github.com/Andre0512/hon), every contribution is welcome! | ||||||
|  |  | ||||||
|  | ## Useful Links | ||||||
|  | * [GitHub repository](https://github.com/Andre0512/hon) (please add a star if you like this integration!) | ||||||
|  | * [pyhOn library](https://github.com/Andre0512/pyhOn) | ||||||
|  | * [Release notes](https://github.com/Andre0512/hon/releases) | ||||||
|  | * [Discussion and help](https://github.com/Andre0512/hon/discussions) | ||||||
|  | * [Issues](https://github.com/Andre0512/hon/issues) | ||||||
							
								
								
									
										3
									
								
								requirements_dev.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								requirements_dev.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | pyhOn | ||||||
|  | black | ||||||
|  | homeassistant | ||||||
							
								
								
									
										134
									
								
								scripts/generate_translation.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										134
									
								
								scripts/generate_translation.py
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,134 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | import asyncio | ||||||
|  | import json | ||||||
|  | import re | ||||||
|  | import sys | ||||||
|  | from pathlib import Path | ||||||
|  |  | ||||||
|  | from pyhon import HonAPI | ||||||
|  |  | ||||||
|  |  | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     sys.path.insert(0, str(Path(__file__).parent.parent)) | ||||||
|  |  | ||||||
|  | from scripts.translation_keys import SENSOR, SELECT, PROGRAMS, NAMES, CLIMATE | ||||||
|  | from custom_components.hon import const | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def check_translation_files(translations): | ||||||
|  |     for language in const.LANGUAGES: | ||||||
|  |         path = translations / f"{language}.json" | ||||||
|  |         if not path.is_file(): | ||||||
|  |             async with HonAPI(anonymous=True) as hon: | ||||||
|  |                 keys = await hon.translation_keys(language) | ||||||
|  |                 save_json(path, keys) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def load_hon_translations(): | ||||||
|  |     translations = Path(__file__).parent / "translations" | ||||||
|  |     translations.mkdir(exist_ok=True) | ||||||
|  |     asyncio.run(check_translation_files(translations)) | ||||||
|  |     return {f.stem: f for f in translations.glob("*.json")} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def load_hass_translations(): | ||||||
|  |     translations = ( | ||||||
|  |         Path(__file__).parent.parent / "custom_components" / "hon" / "translations" | ||||||
|  |     ) | ||||||
|  |     return {f.stem: f for f in translations.glob("*.json")} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def load_json(path): | ||||||
|  |     if path: | ||||||
|  |         with open(path, "r") as file: | ||||||
|  |             return json.loads(file.read()) | ||||||
|  |     return {} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def save_json(path, keys): | ||||||
|  |     with open(path, "w") as json_file: | ||||||
|  |         json_file.write(json.dumps(keys, indent=4, ensure_ascii=False)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def load_key(full_key, json_data, fallback=None): | ||||||
|  |     if isinstance(full_key, list): | ||||||
|  |         return " ".join( | ||||||
|  |             [load_key(item, json_data, fallback).strip() for item in full_key] | ||||||
|  |         ) | ||||||
|  |     result = json_data.copy() | ||||||
|  |     for key in full_key.split("."): | ||||||
|  |         result = result.get(key, {}) | ||||||
|  |     if not result and fallback: | ||||||
|  |         return load_key(full_key, fallback) | ||||||
|  |     return result or full_key | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def load_keys(full_key, json_data): | ||||||
|  |     blacklist = ["description", "desctiption", "_recipe_", "_guided_"] | ||||||
|  |     first, last = full_key.split(".") | ||||||
|  |     data = json_data.get(first, {}).get(last, {}) | ||||||
|  |     return { | ||||||
|  |         key.lower(): value | ||||||
|  |         for key, value in data.items() | ||||||
|  |         if not any(b in key.lower() for b in blacklist) | ||||||
|  |         and re.findall("^[a-z0-9-_]+$", key.lower()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def add_data(old, original, fallback, data, name, entity="sensor"): | ||||||
|  |     sensor = old.setdefault("entity", {}).setdefault(entity, {}) | ||||||
|  |     for number, phase in data.items(): | ||||||
|  |         state = sensor.setdefault(name, {}).setdefault("state", {}) | ||||||
|  |         if key := load_key(phase, original, fallback): | ||||||
|  |             state[str(number)] = key | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def translate_login(old, *args): | ||||||
|  |     login = old.setdefault("config", {}).setdefault("step", {}).setdefault("user", {}) | ||||||
|  |     login["description"] = load_key("CUBE90_ALEXA.HAIER_SMART_SKILLS.STEP_2", *args) | ||||||
|  |     login.setdefault("data", {})["email"] = load_key( | ||||||
|  |         "PET.EDIT_PET_PROFESSIONALS.EMAIL", *args | ||||||
|  |     ) | ||||||
|  |     login["data"]["password"] = load_key("CUBE90_GLOBAL.GENERAL.PASSWORD", *args) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def main(): | ||||||
|  |     hass = load_hass_translations() | ||||||
|  |     hon = load_hon_translations() | ||||||
|  |     base_path = Path(__file__).parent.parent / "custom_components/hon/translations" | ||||||
|  |     fallback = load_json(hon.get("en", "")) | ||||||
|  |     for language in const.LANGUAGES: | ||||||
|  |         original = load_json(hon.get(language, "")) | ||||||
|  |         old = load_json(hass.get(language, "")) | ||||||
|  |         for name, data in SENSOR.items(): | ||||||
|  |             add_data(old, original, fallback, data, name) | ||||||
|  |         for name, data in SELECT.items(): | ||||||
|  |             add_data(old, original, fallback, data, name, "select") | ||||||
|  |         for entity, data in PROGRAMS.items(): | ||||||
|  |             for name, program in data.items(): | ||||||
|  |                 select = old.setdefault("entity", {}).setdefault(entity, {}) | ||||||
|  |                 select.setdefault(name, {})["state"] = load_keys(program, original) | ||||||
|  |         for entity, data in NAMES.items(): | ||||||
|  |             for name, key in data.items(): | ||||||
|  |                 select = old.setdefault("entity", {}).setdefault(entity, {}) | ||||||
|  |                 select.setdefault(name, {})["name"] = load_key(key, original, fallback) | ||||||
|  |         for name, modes in CLIMATE.items(): | ||||||
|  |             climate = old.setdefault("entity", {}).setdefault("climate", {}) | ||||||
|  |             attr = climate.setdefault(name, {}).setdefault("state_attributes", {}) | ||||||
|  |             for mode, data in modes.items(): | ||||||
|  |                 mode_name = load_key(data["name"], original, fallback) | ||||||
|  |                 attr.setdefault(mode, {})["name"] = mode_name | ||||||
|  |                 if isinstance(data["state"], dict): | ||||||
|  |                     for state, key in data["state"].items(): | ||||||
|  |                         mode_state = load_key(key, original, fallback) | ||||||
|  |                         attr[mode].setdefault("state", {})[state] = mode_state | ||||||
|  |                 else: | ||||||
|  |                     attr[mode]["state"] = load_keys(data["state"], original) | ||||||
|  |  | ||||||
|  |         translate_login(old, original, fallback) | ||||||
|  |         save_json(base_path / f"{language}.json", old) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     main() | ||||||
							
								
								
									
										96
									
								
								scripts/sensor_docs.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										96
									
								
								scripts/sensor_docs.py
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,96 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  |  | ||||||
|  | import re | ||||||
|  | import sys | ||||||
|  | from pathlib import Path | ||||||
|  |  | ||||||
|  |  | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     sys.path.insert(0, str(Path(__file__).parent.parent)) | ||||||
|  |  | ||||||
|  | from custom_components.hon.binary_sensor import BINARY_SENSORS | ||||||
|  | from custom_components.hon.button import BUTTONS | ||||||
|  | from custom_components.hon.climate import CLIMATES | ||||||
|  | from custom_components.hon.number import NUMBERS | ||||||
|  | from custom_components.hon.select import SELECTS | ||||||
|  | from custom_components.hon.sensor import SENSORS | ||||||
|  | from custom_components.hon.fan import FANS | ||||||
|  | from custom_components.hon.switch import ( | ||||||
|  |     SWITCHES, | ||||||
|  |     HonControlSwitchEntityDescription, | ||||||
|  |     HonSwitchEntityDescription, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | APPLIANCES = { | ||||||
|  |     "AC": "Air conditioner", | ||||||
|  |     "AP": "Air purifier", | ||||||
|  |     "AS": "Air scanner", | ||||||
|  |     "DW": "Dish washer", | ||||||
|  |     "HO": "Hood", | ||||||
|  |     "IH": "Hob", | ||||||
|  |     "MW": "Microwave", | ||||||
|  |     "OV": "Oven", | ||||||
|  |     "REF": "Fridge", | ||||||
|  |     "RVC": "Robot vacuum cleaner", | ||||||
|  |     "TD": "Tumble dryer", | ||||||
|  |     "WC": "Wine Cellar", | ||||||
|  |     "WD": "Washer dryer", | ||||||
|  |     "WH": "Water Heater", | ||||||
|  |     "WM": "Washing machine", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ENTITY_CATEGORY_SORT = ["control", "config", "sensor"] | ||||||
|  |  | ||||||
|  | entities = { | ||||||
|  |     "binary_sensor": BINARY_SENSORS, | ||||||
|  |     "button": BUTTONS, | ||||||
|  |     "number": NUMBERS, | ||||||
|  |     "select": SELECTS, | ||||||
|  |     "sensor": SENSORS, | ||||||
|  |     "switch": SWITCHES, | ||||||
|  |     "climate": CLIMATES, | ||||||
|  |     "fan": FANS, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | result = {} | ||||||
|  | for entity_type, appliances in entities.items(): | ||||||
|  |     for appliance, data in appliances.items(): | ||||||
|  |         for entity in data: | ||||||
|  |             if isinstance(entity, HonControlSwitchEntityDescription): | ||||||
|  |                 key = f"{entity.turn_on_key}` / `{entity.turn_off_key}" | ||||||
|  |             else: | ||||||
|  |                 key = entity.key | ||||||
|  |             attributes = (key, entity.name, entity.icon, entity_type) | ||||||
|  |             category = ( | ||||||
|  |                 "control" | ||||||
|  |                 if entity.key.startswith("settings") | ||||||
|  |                 or isinstance(entity, HonSwitchEntityDescription) | ||||||
|  |                 or isinstance(entity, HonControlSwitchEntityDescription) | ||||||
|  |                 or entity_type in ["button", "climate"] | ||||||
|  |                 else "sensor" | ||||||
|  |             ) | ||||||
|  |             result.setdefault(appliance, {}).setdefault( | ||||||
|  |                 entity.entity_category or category, [] | ||||||
|  |             ).append(attributes) | ||||||
|  | text = "" | ||||||
|  | for appliance, categories in sorted(result.items()): | ||||||
|  |     text += f"\n### {APPLIANCES[appliance]}\n" | ||||||
|  |     categories = {k: categories[k] for k in ENTITY_CATEGORY_SORT if k in categories} | ||||||
|  |     for category, data in categories.items(): | ||||||
|  |         text += f"#### {str(category).capitalize()}s\n" | ||||||
|  |         text += "| Name | Icon | Entity | Key |\n" | ||||||
|  |         text += "| --- | --- | --- | --- |\n" | ||||||
|  |         for key, name, icon, entity_type in sorted(data, key=lambda d: d[1]): | ||||||
|  |             icon = f"`{icon.replace('mdi:', '')}`" if icon else "" | ||||||
|  |             text += f"| {name} | {icon} | `{entity_type}` | `{key}` |\n" | ||||||
|  |  | ||||||
|  | with open(Path(__file__).parent.parent / "README.md", "r") as file: | ||||||
|  |     readme = file.read() | ||||||
|  | readme = re.sub( | ||||||
|  |     "(## Appliance Features\n)(?:.|\\s)+?([^#]## |\\Z)", | ||||||
|  |     f"\\1{text}\\2", | ||||||
|  |     readme, | ||||||
|  |     re.DOTALL, | ||||||
|  | ) | ||||||
|  | with open(Path(__file__).parent.parent / "README.md", "w") as file: | ||||||
|  |     file.write(readme) | ||||||
							
								
								
									
										339
									
								
								scripts/translation_keys.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								scripts/translation_keys.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,339 @@ | |||||||
|  | WASHING_PR_PHASE = { | ||||||
|  |     "ready": "WASHING_CMD&CTRL.PHASE_READY.TITLE", | ||||||
|  |     "spin": "WASHING_CMD&CTRL.PHASE_SPIN.TITLE", | ||||||
|  |     "rinse": "WASHING_CMD&CTRL.PHASE_RINSE.TITLE", | ||||||
|  |     "drying": "WASHING_CMD&CTRL.PHASE_DRYING.TITLE", | ||||||
|  |     "steam": "WASHING_CMD&CTRL.PHASE_STEAM.TITLE", | ||||||
|  |     "weighting": "WASHING_CMD&CTRL.PHASE_WEIGHTING.TITLE", | ||||||
|  |     "scheduled": "WASHING_CMD&CTRL.PHASE_SCHEDULED.TITLE", | ||||||
|  |     "tumbling": "WASHING_CMD&CTRL.PHASE_TUMBLING.TITLE", | ||||||
|  |     "refresh": "WASHING_CMD&CTRL.PHASE_REFRESH.TITLE", | ||||||
|  |     "heating": "WASHING_CMD&CTRL.PHASE_HEATING.TITLE", | ||||||
|  |     "washing": "WASHING_CMD&CTRL.PHASE_WASHING.TITLE", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MACH_MODE = { | ||||||
|  |     "ready": "WASHING_CMD&CTRL.PHASE_READY.TITLE", | ||||||
|  |     "running": "WASHING_CMD&CTRL.PHASE_RUNNING.TITLE", | ||||||
|  |     "pause": "WASHING_CMD&CTRL.PHASE_PAUSE.TITLE", | ||||||
|  |     "scheduled": "WASHING_CMD&CTRL.PHASE_SCHEDULED.TITLE", | ||||||
|  |     "error": "WASHING_CMD&CTRL.PHASE_ERROR.TITLE", | ||||||
|  |     "test": "Test", | ||||||
|  |     "ending": "GLOBALS.APPLIANCE_STATUS.ENDING_PROGRAM", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TUMBLE_DRYER_PR_PHASE = { | ||||||
|  |     "ready": "WASHING_CMD&CTRL.PHASE_READY.TITLE", | ||||||
|  |     "heat_stroke": "TD_CMD&CTRL.STATUS_PHASE.PHASE_HEAT_STROKE", | ||||||
|  |     "drying": "WASHING_CMD&CTRL.PHASE_DRYING.TITLE", | ||||||
|  |     "cooldown": "TD_CMD&CTRL.STATUS_PHASE.PHASE_COOLDOWN", | ||||||
|  |     "unknown": "unknown", | ||||||
|  |     "tumbling": "WASHING_CMD&CTRL.PHASE_TUMBLING.DASHBOARD_TITLE", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | DIRTY_LEVEL = { | ||||||
|  |     "little": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OPTIONS_VALUES_DESCRIPTION.LITTLE", | ||||||
|  |     "normal": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OPTIONS_VALUES_DESCRIPTION.NORMAL", | ||||||
|  |     "very": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OPTIONS_VALUES_DESCRIPTION.VERY", | ||||||
|  |     "unknown": "unknown", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | STEAM_LEVEL = { | ||||||
|  |     "no_steam": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OPTIONS_VALUES_DESCRIPTION.NO_STEAM", | ||||||
|  |     "cotton": "WASHING_CMD&CTRL.GUIDED_WASHING_SYMBOLS_FABRICS.COTTON_TITLE", | ||||||
|  |     "delicate": "WASHING_CMD&CTRL.GUIDED_WASHING_SYMBOLS_FABRICS.DELICATE_TITLE", | ||||||
|  |     "synthetic": "WASHING_CMD&CTRL.GUIDED_WASHING_SYMBOLS_FABRICS.SYNTHETIC_TITLE", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | DISHWASHER_PR_PHASE = { | ||||||
|  |     "ready": "WASHING_CMD&CTRL.PHASE_READY.TITLE", | ||||||
|  |     "prewash": "WASHING_CMD&CTRL.PHASE_PREWASH.TITLE", | ||||||
|  |     "washing": "WASHING_CMD&CTRL.PHASE_WASHING.TITLE", | ||||||
|  |     "rinse": "WASHING_CMD&CTRL.PHASE_RINSE.TITLE", | ||||||
|  |     "drying": "WASHING_CMD&CTRL.PHASE_DRYING.TITLE", | ||||||
|  |     "hot_rinse": "WASHING_CMD&CTRL.PHASE_HOT_RINSE.TITLE", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TUMBLE_DRYER_DRY_LEVEL = { | ||||||
|  |     "no_dry": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_MAIN_OPTIONS.NO_DRY", | ||||||
|  |     "iron_dry": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OPTIONS_VALUES_DESCRIPTION.IRON_DRY", | ||||||
|  |     "no_dry_iron": "WASHING_CMD&CTRL.GUIDED_WASHING_SYMBOLS_DRYING.NO_DRY_IRON_TITLE", | ||||||
|  |     "cupboard_dry": "WASHING_CMD&CTRL.GUIDED_WASHING_SYMBOLS_DRYING.CUPBOARD_DRY_TITLE", | ||||||
|  |     "extra_dry": "WASHING_CMD&CTRL.GUIDED_WASHING_SYMBOLS_DRYING.EXTRA_DRY_TITLE", | ||||||
|  |     "ready_to_wear": "WASHING_CMD&CTRL.GUIDED_WASHING_SYMBOLS_DRYING.READY_TO_WEAR_TITLE", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | AC_MACH_MODE = { | ||||||
|  |     "auto": "PROGRAMS.AC.IOT_AUTO", | ||||||
|  |     "cool": "PROGRAMS.AC.IOT_COOL", | ||||||
|  |     "dry": "PROGRAMS.AC.IOT_DRY", | ||||||
|  |     "heat": "PROGRAMS.AC.IOT_HEAT", | ||||||
|  |     "fan": "PROGRAMS.AC.IOT_FAN", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | AC_FAN_MODE = { | ||||||
|  |     "high": "AC.PROGRAM_CARD.WIND_SPEED_HIGH", | ||||||
|  |     "mid": "AC.PROGRAM_CARD.WIND_SPEED_MID", | ||||||
|  |     "low": "AC.PROGRAM_CARD.WIND_SPEED_LOW", | ||||||
|  |     "auto": "AC.PROGRAM_CARD.WIND_SPEED_AUTO", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | AC_HUMAN_SENSE = { | ||||||
|  |     "touch_off": "AC.PROGRAM_DETAIL.TOUCH_OFF", | ||||||
|  |     "avoid_touch": "AC.PROGRAM_DETAIL.AVOID_TOUCH", | ||||||
|  |     "follow_touch": "AC.PROGRAM_DETAIL.FOLLOW_TOUCH", | ||||||
|  |     "unknown": "unknown", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | REF_ZONES = { | ||||||
|  |     "fridge": "REF.ZONES.FRIDGE", | ||||||
|  |     "freezer": "REF.ZONES.FREEZER", | ||||||
|  |     "vtroom1": "REF.ZONES.MY_ZONE_1", | ||||||
|  |     "fridge_freezer": ["REF.ZONES.FRIDGE", " & ", "REF.ZONES.FREEZER"], | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SENSOR = { | ||||||
|  |     "washing_modes": MACH_MODE, | ||||||
|  |     "mach_modes_ac": AC_MACH_MODE, | ||||||
|  |     "program_phases_wm": WASHING_PR_PHASE, | ||||||
|  |     "program_phases_td": TUMBLE_DRYER_PR_PHASE, | ||||||
|  |     "program_phases_dw": DISHWASHER_PR_PHASE, | ||||||
|  |     "dry_levels": TUMBLE_DRYER_DRY_LEVEL, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SELECT = { | ||||||
|  |     "dry_levels": TUMBLE_DRYER_DRY_LEVEL, | ||||||
|  |     "eco_pilot": AC_HUMAN_SENSE, | ||||||
|  |     "fan_mode": AC_FAN_MODE, | ||||||
|  |     "ref_zones": REF_ZONES, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | PROGRAMS = { | ||||||
|  |     "select": { | ||||||
|  |         "programs_ac": "PROGRAMS.AC", | ||||||
|  |         "programs_dw": "PROGRAMS.DW", | ||||||
|  |         "programs_ih": "PROGRAMS.IH", | ||||||
|  |         "programs_ov": "PROGRAMS.OV", | ||||||
|  |         "programs_td": "PROGRAMS.TD", | ||||||
|  |         "programs_wm": "PROGRAMS.WM_WD", | ||||||
|  |         "programs_ref": "PROGRAMS.REF", | ||||||
|  |     }, | ||||||
|  |     "sensor": { | ||||||
|  |         "programs_ac": "PROGRAMS.AC", | ||||||
|  |         "programs_dw": "PROGRAMS.DW", | ||||||
|  |         "programs_ih": "PROGRAMS.IH", | ||||||
|  |         "programs_ov": "PROGRAMS.OV", | ||||||
|  |         "programs_td": "PROGRAMS.TD", | ||||||
|  |         "programs_wm": "PROGRAMS.WM_WD", | ||||||
|  |         "programs_ref": "PROGRAMS.REF", | ||||||
|  |         "programs_wc": "PROGRAMS.WC", | ||||||
|  |     }, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CLIMATE = { | ||||||
|  |     "fridge": { | ||||||
|  |         "preset_mode": { | ||||||
|  |             "name": "REF_CMD&CTRL.MODE_SELECTION_DRAWER_FRIDGE.FRIDGE_MODE_TITLE", | ||||||
|  |             "state": { | ||||||
|  |                 "auto_set": "REF_CMD&CTRL.MODALITIES.ECO", | ||||||
|  |                 "super_cool": "REF_CMD&CTRL.MODALITIES.SUPER_COOL", | ||||||
|  |                 "holiday": "REF_CMD&CTRL.MODALITIES.BACK_FROM_HOLIDAY", | ||||||
|  |                 "no_mode": "REF_CMD&CTRL.MODALITIES.NO_MODE_SELECTED", | ||||||
|  |             }, | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     "freezer": { | ||||||
|  |         "preset_mode": { | ||||||
|  |             "name": "REF_CMD&CTRL.MODE_SELECTION_DRAWER_FREEZER.FREEZER_MODE_TITLE", | ||||||
|  |             "state": { | ||||||
|  |                 "auto_set": "REF_CMD&CTRL.MODALITIES.ECO", | ||||||
|  |                 "super_freeze": "REF_CMD&CTRL.MODALITIES.SHOCK_FREEZE", | ||||||
|  |                 "no_mode": "REF_CMD&CTRL.MODALITIES.NO_MODE_SELECTED", | ||||||
|  |             }, | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     "oven": { | ||||||
|  |         "preset_mode": { | ||||||
|  |             "name": "OV.TABS.PROGRAMS_TITLE", | ||||||
|  |             "state": "PROGRAMS.OV", | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     "wine": { | ||||||
|  |         "preset_mode": { | ||||||
|  |             "name": "WC.NAME", | ||||||
|  |             "state": "PROGRAMS.WC", | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | NAMES = { | ||||||
|  |     "switch": { | ||||||
|  |         "anti_crease": "HDRY_CMD&CTRL.PROGRAM_CYCLE_DETAIL.ANTICREASE_TITLE", | ||||||
|  |         "add_dish": "DW.ADD_DISH", | ||||||
|  |         "eco_express": "DW_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.ECO", | ||||||
|  |         "extra_dry": "DW_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.EXTRA_DRY", | ||||||
|  |         "half_load": "DW_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.HALF_LOAD", | ||||||
|  |         "open_door": "DW_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.OPEN_DOOR", | ||||||
|  |         "three_in_one": "DW_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.THREE_IN_ONE", | ||||||
|  |         "preheat": "OV.PROGRAM_DETAIL.PREHEAT", | ||||||
|  |         "dish_washer": "GLOBALS.APPLIANCES_NAME.DW", | ||||||
|  |         "tumble_dryer": "GLOBALS.APPLIANCES_NAME.TD", | ||||||
|  |         "washing_machine": "GLOBALS.APPLIANCES_NAME.WM", | ||||||
|  |         "washer_dryer": "GLOBALS.APPLIANCES_NAME.WD", | ||||||
|  |         "oven": "GLOBALS.APPLIANCES_NAME.OV", | ||||||
|  |         "prewash": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.PREWASH", | ||||||
|  |         "pause": "GENERAL.PAUSE_PROGRAM", | ||||||
|  |         "keep_fresh": "GLOBALS.APPLIANCE_STATUS.TUMBLING", | ||||||
|  |         "delay_time": "HINTS.TIPS_TIME_ENERGY_SAVING.TIPS_USE_AT_NIGHT_TITLE", | ||||||
|  |         "rapid_mode": "AC.PROGRAM_CARD.RAPID", | ||||||
|  |         "eco_mode": "AC.PROGRAM_CARD.ECO_MODE", | ||||||
|  |         "10_degree_heating": "PROGRAMS.AC.IOT_10_HEATING", | ||||||
|  |         "self_clean": "PROGRAMS.AC.IOT_SELF_CLEAN", | ||||||
|  |         "self_clean_56": "PROGRAMS.AC.IOT_SELF_CLEAN_56", | ||||||
|  |         "silent_mode": "AC.PROGRAM_DETAIL.SILENT_MODE", | ||||||
|  |         "mute_mode": "AC.PROGRAM_DETAIL.MUTE_MODE", | ||||||
|  |         "extra_rinse_1": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.EXTRARINSE1", | ||||||
|  |         "extra_rinse_2": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.EXTRARINSE2", | ||||||
|  |         "extra_rinse_3": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.EXTRARINSE3", | ||||||
|  |         "acqua_plus": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.ACQUAPLUS", | ||||||
|  |         "auto_dose_softener": [ | ||||||
|  |             "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.AUTODOSE", | ||||||
|  |             "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.SOFTENER", | ||||||
|  |         ], | ||||||
|  |         "auto_dose_detergent": [ | ||||||
|  |             "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.AUTODOSE", | ||||||
|  |             "WASHING_CMD&CTRL.DASHBOARD_MENU_MORE_SETTINGS_WATER.DETERGENT", | ||||||
|  |         ], | ||||||
|  |         "good_night": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.GOODNIGHT", | ||||||
|  |         "auto_set": "REF_CMD&CTRL.MODALITIES.ECO", | ||||||
|  |         "super_cool": "REF_CMD&CTRL.MODALITIES.SUPER_COOL", | ||||||
|  |         "super_freeze": "REF_CMD&CTRL.MODALITIES.SUPER_FREEZE", | ||||||
|  |         "refrigerator": "REF.NAME", | ||||||
|  |     }, | ||||||
|  |     "binary_sensor": { | ||||||
|  |         "door_lock": "WASHING_CMD&CTRL.CHECK_UP_RESULTS.DOOR_LOCK", | ||||||
|  |         "extra_rinse_1": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.EXTRARINSE1", | ||||||
|  |         "extra_rinse_2": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.EXTRARINSE2", | ||||||
|  |         "extra_rinse_3": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.EXTRARINSE3", | ||||||
|  |         "good_night": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.GOODNIGHT", | ||||||
|  |         "anti_crease": "HDRY_CMD&CTRL.PROGRAM_CYCLE_DETAIL.ANTICREASE_TITLE", | ||||||
|  |         "acqua_plus": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.ACQUAPLUS", | ||||||
|  |         "spin_speed": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_MAIN_OPTIONS.SPINSPEED", | ||||||
|  |         "still_hot": "IH.COILS_STATUS.STILL_HOT", | ||||||
|  |         "pan_status": "IH.COILS_STATUS.PAN", | ||||||
|  |         "remote_control": "OV.SUPPORT.REMOTE_CONTROL", | ||||||
|  |         "rinse_aid": "DW_CMD&CTRL.MAINTENANCE.CONSUMABLE_LEVELS_ICON_RINSE_AID", | ||||||
|  |         "salt_level": "DW_CMD&CTRL.MAINTENANCE.CONSUMABLE_LEVELS_ICON_SALT", | ||||||
|  |         "door_open": "GLOBALS.APPLIANCE_STATUS.DOOR_OPEN", | ||||||
|  |         "connection": "ENROLLMENT_COMMON.HEADER_NAME.STEP_APPLIANCE_CONNECTION", | ||||||
|  |         "child_lock": "AP.FOOTER_MENU_MORE.SECURITY_LOCK_TITLE", | ||||||
|  |         "on": "GLOBALS.GENERAL.ON", | ||||||
|  |         "prewash": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_OTHER_OPTIONS.PREWASH", | ||||||
|  |         "buzzer": "DW_CMD&CTRL.SETTINGS.END_CYCLE_BUZZER", | ||||||
|  |         "holiday_mode": "REF.DASHBOARD_MENU_MORE_NOTIFICATIONS.HOLIDAY_MODE", | ||||||
|  |         "auto_set": "REF_CMD&CTRL.MODALITIES.ECO", | ||||||
|  |         "super_cool": "REF_CMD&CTRL.MODALITIES.SUPER_COOL", | ||||||
|  |         "super_freeze": "REF_CMD&CTRL.MODALITIES.SUPER_FREEZE", | ||||||
|  |         "freezer_door": ["GLOBALS.APPLIANCE_STATUS.DOOR_OPEN", "REF.ZONES.FREEZER"], | ||||||
|  |         "fridge_door": ["GLOBALS.APPLIANCE_STATUS.DOOR_OPEN", "REF.ZONES.FRIDGE"], | ||||||
|  |         "filter_replacement": "AP.MAINTENANCE.FILTER_REPLACEMENT", | ||||||
|  |     }, | ||||||
|  |     "button": { | ||||||
|  |         "induction_hob": "GLOBALS.APPLIANCES_NAME.IH", | ||||||
|  |         "start_program": ["WC.SET_PROGRAM.PROGRAM", "GLOBALS.GENERAL.START_ON"], | ||||||
|  |         "stop_program": ["WC.SET_PROGRAM.PROGRAM", "GLOBALS.GENERAL.STOP"], | ||||||
|  |     }, | ||||||
|  |     "select": { | ||||||
|  |         "dry_levels": "WASHING_CMD&CTRL.DRAWER_CYCLE_DRYING.TAB_LEVEL", | ||||||
|  |         "dry_time": "WASHING_CMD&CTRL.DRAWER_CYCLE_DRYING.TAB_TIME", | ||||||
|  |         "spin_speed": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_MAIN_OPTIONS.SPINSPEED", | ||||||
|  |         "temperature": "IH.COMMON.TEMPERATURE", | ||||||
|  |         "programs_dw": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |         "programs_ih": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |         "programs_ov": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |         "programs_td": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |         "programs_wm": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |         "programs_ac": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |         "programs_ref": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |         "eco_pilot": "AC.PROGRAM_DETAIL.ECO_PILOT", | ||||||
|  |         "remaining_time": "ENROLLMENT_COMMON.GENERAL.REMAINING_TIME", | ||||||
|  |         "ref_zones": "IH.COMMON.COIL", | ||||||
|  |     }, | ||||||
|  |     "sensor": { | ||||||
|  |         "dry_levels": "WASHING_CMD&CTRL.DRAWER_CYCLE_DRYING.TAB_LEVEL", | ||||||
|  |         "dry_time": "WASHING_CMD&CTRL.DRAWER_CYCLE_DRYING.TAB_TIME", | ||||||
|  |         "power": "OV.RECIPE_DETAIL.POWER_LEVEL", | ||||||
|  |         "remaining_time": "ENROLLMENT_COMMON.GENERAL.REMAINING_TIME", | ||||||
|  |         "temperature": "IH.COMMON.TEMPERATURE", | ||||||
|  |         "water_efficiency": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_RESULT.WATER_EFFICIENCY", | ||||||
|  |         "water_saving": "STATISTICS.SMART_AI_CYCLE.WATER_SAVING", | ||||||
|  |         "duration": "WASHING_CMD&CTRL.DRAWER_PROGRAM_FILTERS.DURATION", | ||||||
|  |         "target_temperature": "IH.COOKING_DETAIL.TEMPERATURE_TARGETING", | ||||||
|  |         "spin_speed": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_MAIN_OPTIONS.SPINSPEED", | ||||||
|  |         "steam_leve": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_MAIN_OPTIONS.STEAM_LEVEL", | ||||||
|  |         "dirt_level": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_MAIN_OPTIONS.DIRTY_LEVEL", | ||||||
|  |         "program_phases_wm": "WASHING_CMD&CTRL.STATISTICS_GRAPHIC_INSTANT_CONSUMPTION.PHASE", | ||||||
|  |         "program_phases_td": "WASHING_CMD&CTRL.STATISTICS_GRAPHIC_INSTANT_CONSUMPTION.PHASE", | ||||||
|  |         "program_phases_dw": "WASHING_CMD&CTRL.STATISTICS_GRAPHIC_INSTANT_CONSUMPTION.PHASE", | ||||||
|  |         "delay_time": "HINTS.TIPS_TIME_ENERGY_SAVING.TIPS_USE_AT_NIGHT_TITLE", | ||||||
|  |         "suggested_load": "WASHING_CMD&CTRL.DRAWER_PROGRAM_FILTERS.LOAD_CAPACITY", | ||||||
|  |         "energy_label": "WASHING_CMD&CTRL.DRAWER_PROGRAM_FILTERS.ENERGY_EFFICIENCY", | ||||||
|  |         "det_dust": "HUBS.WIDGET.STAINS_WIDGET.STAINS.SUGGESTED_DET_DUST", | ||||||
|  |         "det_liquid": "HUBS.WIDGET.STAINS_WIDGET.STAINS.SUGGESTED_DET_LIQUID", | ||||||
|  |         "errors": "ROBOT_CMD&CTRL.PHASE_ERROR.TITLE", | ||||||
|  |         "programs": "OV.TABS.CURRENT_PROGRAM", | ||||||
|  |         "room_temperature": "REF.SMART_DRINK_ASSISTANT.AMBIENT", | ||||||
|  |         "humidity": "AP.TITLES.HUMIDITY", | ||||||
|  |         "cycles_total": [ | ||||||
|  |             "WASHING_CMD&CTRL.GENERAL.CYCLES", | ||||||
|  |             "WC.VIRTUAL_WINE_STATS_COUNTRY.TOTAL", | ||||||
|  |         ], | ||||||
|  |         "energy_total": [ | ||||||
|  |             "MISE.ENERGY_CONSUMPTION.TITLE", | ||||||
|  |             "WC.VIRTUAL_WINE_STATS_COUNTRY.TOTAL", | ||||||
|  |         ], | ||||||
|  |         "water_total": [ | ||||||
|  |             "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_RESULT.WATER_EFFICIENCY", | ||||||
|  |             "WC.VIRTUAL_WINE_STATS_COUNTRY.TOTAL", | ||||||
|  |         ], | ||||||
|  |         "energy_current": [ | ||||||
|  |             "MISE.ENERGY_CONSUMPTION.TITLE", | ||||||
|  |             "CUBE90_GLOBAL.GENERAL.CURRENT", | ||||||
|  |         ], | ||||||
|  |         "water_current": [ | ||||||
|  |             "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_RESULT.WATER_EFFICIENCY", | ||||||
|  |             "CUBE90_GLOBAL.GENERAL.CURRENT", | ||||||
|  |         ], | ||||||
|  |         "freezer_temp": "REF_CMD&CTRL.TEMPERATURE_DRAWER_FREEZER.FREEZER_TEMPERATURE_TITLE", | ||||||
|  |         "fridge_temp": "REF_CMD&CTRL.TEMPERATURE_DRAWER_FRIDGE.FRIDGE_TEMPERATURE_TITLE", | ||||||
|  |         "programs_dw": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |         "programs_ih": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |         "programs_ov": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |         "programs_td": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |         "programs_wm": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |         "programs_ac": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |         "programs_ref": "WC.SET_PROGRAM.PROGRAM", | ||||||
|  |     }, | ||||||
|  |     "number": { | ||||||
|  |         "power_management": "HINTS.COOKING_WITH_INDUCTION.POWER_MANAGEMENT", | ||||||
|  |         "temperature": "IH.COMMON.TEMPERATURE", | ||||||
|  |         "delay_time": "HINTS.TIPS_TIME_ENERGY_SAVING.TIPS_USE_AT_NIGHT_TITLE", | ||||||
|  |         "water_hard": "WASHING_CMD&CTRL.DASHBOARD_MENU_MORE_SETTINGS_WATER.TITLE", | ||||||
|  |         "program_duration": "OV.PROGRAM_DETAIL.PROGRAM_DURATION", | ||||||
|  |         "target_temperature": "IH.COOKING_DETAIL.TEMPERATURE_TARGETING", | ||||||
|  |         "rinse_iterations": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL.DRAWER_HEADER_RINSE", | ||||||
|  |         "wash_time": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL.WASHING_TIME", | ||||||
|  |         "dry_time": "WASHING_CMD&CTRL.DRAWER_CYCLE_DRYING.TAB_TIME", | ||||||
|  |         "steam_level": "WASHING_CMD&CTRL.PROGRAM_CYCLE_DETAIL_MAIN_OPTIONS.STEAM_LEVEL", | ||||||
|  |         "freezer_temp_sel": ["OV.COMMON.GOAL_TEMPERATURE", "REF.ZONES.FREEZER"], | ||||||
|  |         "fridge_temp_sel": ["OV.COMMON.GOAL_TEMPERATURE", "REF.ZONES.FRIDGE"], | ||||||
|  |     }, | ||||||
|  |     "climate": { | ||||||
|  |         "air_conditioner": "GLOBALS.APPLIANCES_NAME.AC", | ||||||
|  |         "fridge": "REF.ZONES.FRIDGE", | ||||||
|  |         "freezer": "REF.ZONES.FREEZER", | ||||||
|  |         "oven": "GLOBALS.APPLIANCES_NAME.OV", | ||||||
|  |     }, | ||||||
|  |     "fan": {"air_extraction": "HO.DASHBOARD.AIR_EXTRACTION_TITLE"}, | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	