├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .travis.yml ├── .travis └── push.sh ├── LICENSE ├── README.md ├── custom_components └── midea │ ├── __init__.py │ ├── climate.py │ └── manifest.json └── info.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://paypal.me/andersonshatch', 'https://monzo.me/joshanderson'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Something is not working right 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots / Logs** 24 | If applicable, add screenshots or your home-assistant log file to help explain your problem. 25 | 26 | **Versions** 27 | - Home Assistant version: 28 | - Midea integration version (commit hash): 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - '3.6' 4 | install: 5 | - pip install -r requirements.txt 6 | script: 7 | - python setup.py sdist bdist_wheel 8 | deploy: 9 | provider: pypi 10 | user: NeoAcheron 11 | skip_cleanup: true 12 | password: 13 | secure: Znp6wiYWcfjmIWl3Gsq+dqGLLNp3aUVDu2QTVqX5gJ9zc1MVPZE5mpw0Wfl9AUdCmO/xj7ZZ7lbhKh66xYbuvKNwStJUrSKdUL5JsNFGRxSsfaM++1wtiwNBzsATaVjBLsXhUomWfet78qsqvwLlBAT0prthoT3FP/5N8tP0TMauh2pdc+DoFyYe/D1eiTffZjiYj44Dycb965Ys5Voqu55hSE8Tiy1vKwT6wxiBvDjBSeNafpcyoLK0kDLEQomX57u7Z4T4OWPvcmIpS/U60iJ7WT4U+HxjwgvGsROPZ5vlD9sh+SZk+6GMb5nxo8jlp9RZz6C840TR7PGLskO+MvoFQuSdLEBcnnZOu9SxdYKO04LfqKBskM0n8TCDuGhLSTupS7ReaGOn5CeJmmE5qBpUm+K8Juz38zh7x0bF7rzmonUuNvSN/nY5lyg7yl457P2eeQCN/fhDEhetgp7jC6BiNJblq28DpUKRuRGgu1XOrTGk8Mdw8KXwO2Z3tE7Xi4Xz1vLv8zYs1NURJeLR3bDqfeyK5ALQbPxLhq+wIyGWzw4wuziNcaneJN6A3EUzBAu2I+jcKX/b/eW1PdBPtAxWs3r06axpCIa3Je1cnpLskqJsUar+Jw2zI82i1pM813z3/LoXdeHc10z7sJ4tLpWn49rIf/LnetYs23D3qJc= 14 | -------------------------------------------------------------------------------- /.travis/push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo Currently on branch `git branch` 4 | 5 | bumpversion patch --no-tag --allow-dirty --no-commit --list > .temp 6 | CURRENT_VERSION=`cat .temp | grep current_version | sed -r s,"^.*=",,` 7 | NEW_VERSION=`cat .temp | grep new_version | sed -r s,"^.*=",,` 8 | 9 | git add .bumpversion.cfg 10 | git add custom_components.json 11 | git add midea.py 12 | git add setup.py 13 | git add midea/*.py 14 | 15 | git commit -m "Version Changed from ${CURRENT_VERSION} -> ${NEW_VERSION}" 16 | git tag "v${NEW_VERSION}" 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 NeoAcheron 4 | Copyright (c) 2019 Josh Anderson (@andersonshatch) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Updated home-assistant component for hass version 0.96 and the "climate-1.0" changes. 2 | 3 | Last tested with hass version 0.110.x 4 | 5 | ## Installation 6 | 7 | ### HACS [![hacs_badge](https://img.shields.io/badge/HACS-Default-orange.svg)](https://github.com/custom-components/hacs) 8 | 1. Search the HACS Store for Midea 9 | 2. Install the Midea Aircon component 10 | 3. Add configuration to your yaml, as shown here: https://github.com/NeoAcheron/midea-ac-py/wiki/Installing-to-Home-Assistant 11 | 12 | ### Manual 13 | 1. Clone this repo 14 | 1. Place the `custom_components/midea` folder into your `custom_components` folder 15 | 1. Add configuration to your yaml, as shown here: https://github.com/NeoAcheron/midea-ac-py/wiki/Installing-to-Home-Assistant 16 | 17 | ## Fan Only Workaround 18 | There is an optional workaround to avoid reading the device's state on initial connection, since for some reason the update method causes my device to turn on and be set to fan only mode. (This is a bug to be fixed in [andersonshatch/midea-ac-lib](https://github.com/andersonshatch/midea-ac-lib)... if only I knew how.) 19 | 20 | With this workaround enabled, it restores state from home-assistant's previous state. 21 | This should work okay as long as you only alter the state of your device using home-assisant. 22 | 23 | If you find this component turns your device on and to fan_only every time home-assistant updates it (once a minute by default), you probably want to turn on the workaround with this config property: 24 | ``` 25 | use_fan_only_workaround: true 26 | ``` 27 | 28 | Original Readme: 29 | ```# midea-ac-py 30 | 31 | This is a library to allow communicating to a Midea AC via the Midea Cloud. 32 | 33 | This is a very early release, and comes without any guarantees. This is still an early work in progress and simply serves as a proof of concept. 34 | 35 | This library would not have been possible if it wasn't for the amazing work done by @yitsushi and his Ruby based command line tool. 36 | You can find his work here: https://github.com/yitsushi/midea-air-condition 37 | The reasons for me converting this to Python is that this library also serves as a platform component for Home Assistant. 38 | 39 | ## Wiki 40 | Please visit the Wiki for device support and instruction on how to use this component: https://github.com/NeoAcheron/midea-ac-py/wiki 41 | ``` 42 | -------------------------------------------------------------------------------- /custom_components/midea/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersonshatch/midea-ac-py/f779f3bcd25407f8f9069f33f4250031244a8aef/custom_components/midea/__init__.py -------------------------------------------------------------------------------- /custom_components/midea/climate.py: -------------------------------------------------------------------------------- 1 | """ 2 | A climate platform that adds support for Midea air conditioning units. 3 | 4 | For more details about this platform, please refer to the documentation 5 | https://github.com/andersonshatch/midea-ac-py 6 | 7 | This is still early work in progress 8 | """ 9 | import logging 10 | 11 | import voluptuous as vol 12 | 13 | import homeassistant.helpers.config_validation as cv 14 | try: 15 | from homeassistant.components.climate import ClimateEntity 16 | except ImportError: 17 | from homeassistant.components.climate import ClimateDevice as ClimateEntity 18 | from homeassistant.components.climate import PLATFORM_SCHEMA 19 | from homeassistant.components.climate.const import ( 20 | SUPPORT_TARGET_TEMPERATURE, SUPPORT_FAN_MODE, SUPPORT_SWING_MODE, 21 | SUPPORT_PRESET_MODE, PRESET_NONE, PRESET_ECO, PRESET_BOOST) 22 | from homeassistant.const import CONF_USERNAME, CONF_PASSWORD, TEMP_CELSIUS, \ 23 | ATTR_TEMPERATURE 24 | from homeassistant.exceptions import PlatformNotReady 25 | 26 | from homeassistant.helpers.restore_state import RestoreEntity 27 | 28 | _LOGGER = logging.getLogger(__name__) 29 | 30 | CONF_APP_KEY = 'app_key' 31 | CONF_TEMP_STEP = 'temp_step' 32 | CONF_INCLUDE_OFF_AS_STATE = 'include_off_as_state' 33 | CONF_USE_FAN_ONLY_WORKAROUND = 'use_fan_only_workaround' 34 | 35 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ 36 | vol.Required(CONF_APP_KEY): cv.string, 37 | vol.Required(CONF_USERNAME): cv.string, 38 | vol.Required(CONF_PASSWORD): cv.string, 39 | vol.Optional(CONF_TEMP_STEP, default=1.0): vol.Coerce(float), 40 | vol.Optional(CONF_INCLUDE_OFF_AS_STATE, default=True): vol.Coerce(bool), 41 | vol.Optional(CONF_USE_FAN_ONLY_WORKAROUND, default=False): vol.Coerce(bool) 42 | }) 43 | 44 | SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE \ 45 | | SUPPORT_SWING_MODE | SUPPORT_PRESET_MODE 46 | 47 | 48 | async def async_setup_platform(hass, config, async_add_entities, 49 | discovery_info=None): 50 | """Set up the Midea cloud service and query appliances.""" 51 | 52 | from midea.client import client as midea_client 53 | 54 | app_key = config.get(CONF_APP_KEY) 55 | username = config.get(CONF_USERNAME) 56 | password = config.get(CONF_PASSWORD) 57 | temp_step = config.get(CONF_TEMP_STEP) 58 | include_off_as_state = config.get(CONF_INCLUDE_OFF_AS_STATE) 59 | use_fan_only_workaround = config.get(CONF_USE_FAN_ONLY_WORKAROUND) 60 | 61 | try: 62 | client = midea_client(app_key, username, password) 63 | devices = await hass.async_add_executor_job(client.devices) 64 | except: 65 | raise PlatformNotReady 66 | entities = [] 67 | for device in devices: 68 | if device.type == 0xAC: 69 | entities.append(MideaClimateACDevice( 70 | hass, device, temp_step, include_off_as_state, 71 | use_fan_only_workaround)) 72 | else: 73 | _LOGGER.error( 74 | "Unsupported device type: 0x{:02x}".format(device.type)) 75 | 76 | async_add_entities(entities) 77 | 78 | 79 | class MideaClimateACDevice(ClimateEntity, RestoreEntity): 80 | """Representation of a Midea climate AC device.""" 81 | 82 | def __init__(self, hass, device, temp_step: float, 83 | include_off_as_state: bool, use_fan_only_workaround: bool): 84 | """Initialize the climate device.""" 85 | from midea.device import air_conditioning_device as ac 86 | 87 | self._operation_list = ac.operational_mode_enum.list() 88 | self._fan_list = ac.fan_speed_enum.list() 89 | self._swing_list = ac.swing_mode_enum.list() 90 | if include_off_as_state: 91 | self._operation_list.append("off") 92 | self._support_flags = SUPPORT_FLAGS 93 | self._device = device 94 | self._unit_of_measurement = TEMP_CELSIUS 95 | self._target_temperature_step = temp_step 96 | self._include_off_as_state = include_off_as_state 97 | self._use_fan_only_workaround = use_fan_only_workaround 98 | 99 | self.hass = hass 100 | self._old_state = None 101 | self._changed = False 102 | 103 | async def apply_changes(self): 104 | if not self._changed: 105 | return 106 | await self.hass.async_add_executor_job(self._device.apply) 107 | self._old_state = None 108 | await self.async_update_ha_state() 109 | self._changed = False 110 | 111 | async def async_update(self): 112 | """Retrieve latest state from the appliance if no changes made, 113 | otherwise update the remote device state.""" 114 | if self._changed: 115 | await self.hass.async_add_executor_job(self._device.apply) 116 | self._changed = False 117 | elif not self._use_fan_only_workaround: 118 | self._old_state = None 119 | await self.hass.async_add_executor_job(self._device.refresh) 120 | 121 | async def async_added_to_hass(self): 122 | """Run when entity about to be added.""" 123 | await super().async_added_to_hass() 124 | self._old_state = await self.async_get_last_state() 125 | 126 | @property 127 | def state_attributes(self): 128 | attrs = super().state_attributes 129 | attrs["outdoor_temperature"] = self._device.outdoor_temperature 130 | 131 | return attrs 132 | 133 | @property 134 | def available(self): 135 | """Checks if the appliance is available for commands.""" 136 | return self._device.online 137 | 138 | @property 139 | def supported_features(self): 140 | """Return the list of supported features.""" 141 | return self._support_flags 142 | 143 | @property 144 | def target_temperature_step(self): 145 | """Return the supported step of target temperature.""" 146 | return self._target_temperature_step 147 | 148 | @property 149 | def hvac_modes(self): 150 | """Return the list of available operation modes.""" 151 | return self._operation_list 152 | 153 | @property 154 | def fan_modes(self): 155 | """Return the list of available fan modes.""" 156 | return self._fan_list 157 | 158 | @property 159 | def swing_modes(self): 160 | """List of available swing modes.""" 161 | return self._swing_list 162 | 163 | @property 164 | def assumed_state(self): 165 | """Assume state rather than refresh to workaround fan_only bug.""" 166 | return self._use_fan_only_workaround 167 | 168 | @property 169 | def should_poll(self): 170 | """Poll the appliance for changes, there is no notification capability in the Midea API""" 171 | return not self._use_fan_only_workaround 172 | 173 | @property 174 | def unique_id(self): 175 | return self._device.id 176 | 177 | @property 178 | def name(self): 179 | """Return the name of the climate device.""" 180 | return "midea_{}".format(self._device.id) 181 | 182 | @property 183 | def temperature_unit(self): 184 | """Return the unit of measurement.""" 185 | return self._unit_of_measurement 186 | 187 | @property 188 | def current_temperature(self): 189 | """Return the current temperature.""" 190 | if self._old_state is not None: 191 | return self._old_state.attributes.get('current_temperature') 192 | 193 | return self._device.indoor_temperature 194 | 195 | @property 196 | def target_temperature(self): 197 | """Return the temperature we try to reach.""" 198 | if self._old_state is not None and 'temperature' in self._old_state.attributes: 199 | self._device.target_temperature = self._old_state.attributes['temperature'] 200 | return self._old_state.attributes['temperature'] 201 | 202 | return self._device.target_temperature 203 | 204 | @property 205 | def hvac_mode(self): 206 | """Return current operation ie. heat, cool, idle.""" 207 | if self._old_state is not None: 208 | from midea.device import air_conditioning_device as ac 209 | self._device.power_state = self._include_off_as_state and self._old_state.state != 'off' 210 | if self._old_state.state in ac.operational_mode_enum.list(): 211 | self._device.operational_mode = ac.operational_mode_enum[self._old_state.state] 212 | return self._old_state.state 213 | 214 | if self._include_off_as_state and not self._device.power_state: 215 | return "off" 216 | return self._device.operational_mode.name 217 | 218 | @property 219 | def fan_mode(self): 220 | """Return the fan setting.""" 221 | if self._old_state is not None and 'fan_mode' in self._old_state.attributes: 222 | from midea.device import air_conditioning_device as ac 223 | self._device.fan_speed = ac.fan_speed_enum[self._old_state.attributes['fan_mode']] 224 | return self._old_state.attributes['fan_mode'] 225 | 226 | return self._device.fan_speed.name 227 | 228 | @property 229 | def swing_mode(self): 230 | """Return the swing setting.""" 231 | if self._old_state is not None and 'swing_mode' in self._old_state.attributes: 232 | from midea.device import air_conditioning_device as ac 233 | self._device.swing_mode = ac.swing_mode_enum[self._old_state.attributes['swing_mode']] 234 | return self._old_state.attributes['swing_mode'] 235 | 236 | return self._device.swing_mode.name 237 | 238 | @property 239 | def is_on(self): 240 | """Return true if the device is on.""" 241 | return self._device.power_state 242 | 243 | async def async_set_temperature(self, **kwargs): 244 | """Set new target temperatures.""" 245 | if kwargs.get(ATTR_TEMPERATURE) is not None: 246 | self._device.target_temperature = int(kwargs.get(ATTR_TEMPERATURE)) 247 | self._changed = True 248 | await self.apply_changes() 249 | 250 | async def async_set_swing_mode(self, swing_mode): 251 | """Set new target temperature.""" 252 | from midea.device import air_conditioning_device as ac 253 | self._device.swing_mode = ac.swing_mode_enum[swing_mode] 254 | self._changed = True 255 | await self.apply_changes() 256 | 257 | async def async_set_fan_mode(self, fan_mode): 258 | """Set new target temperature.""" 259 | from midea.device import air_conditioning_device as ac 260 | self._device.fan_speed = ac.fan_speed_enum[fan_mode] 261 | self._changed = True 262 | await self.apply_changes() 263 | 264 | async def async_set_hvac_mode(self, hvac_mode): 265 | """Set new target temperature.""" 266 | from midea.device import air_conditioning_device as ac 267 | if self._include_off_as_state and hvac_mode == "off": 268 | self._device.power_state = False 269 | else: 270 | if self._include_off_as_state: 271 | self._device.power_state = True 272 | self._device.operational_mode = ac.operational_mode_enum[hvac_mode] 273 | self._changed = True 274 | await self.apply_changes() 275 | 276 | async def async_set_preset_mode(self, preset_mode: str): 277 | if preset_mode == PRESET_NONE: 278 | self._device.eco_mode = False 279 | self._device.turbo_mode = False 280 | elif preset_mode == PRESET_BOOST: 281 | self._device.eco_mode = False 282 | self._device.turbo_mode = True 283 | elif preset_mode == PRESET_ECO: 284 | self._device.turbo_mode = False 285 | self._device.eco_mode = True 286 | 287 | self._changed = True 288 | await self.apply_changes() 289 | 290 | @property 291 | def preset_modes(self): 292 | return [PRESET_NONE, PRESET_ECO, PRESET_BOOST] 293 | 294 | @property 295 | def preset_mode(self): 296 | if self._old_state is not None and 'preset_mode' in self._old_state.attributes: 297 | preset_mode = self._old_state.attributes['preset_mode'] 298 | if preset_mode == PRESET_ECO: 299 | self._device.eco_mode = True 300 | self._device.turbo_mode = False 301 | elif preset_mode == PRESET_BOOST: 302 | self._device.turbo_mode = True 303 | self._device.eco_mode = False 304 | 305 | return preset_mode 306 | 307 | if self._device.eco_mode: 308 | return PRESET_ECO 309 | elif self._device.turbo_mode: 310 | return PRESET_BOOST 311 | else: 312 | return PRESET_NONE 313 | 314 | async def async_turn_on(self): 315 | """Turn on.""" 316 | self._device.power_state = True 317 | self._changed = True 318 | await self.apply_changes() 319 | 320 | async def async_turn_off(self): 321 | """Turn off.""" 322 | self._device.power_state = False 323 | self._changed = True 324 | await self.apply_changes() 325 | 326 | @property 327 | def min_temp(self): 328 | """Return the minimum temperature.""" 329 | return 17 330 | 331 | @property 332 | def max_temp(self): 333 | """Return the maximum temperature.""" 334 | return 30 335 | -------------------------------------------------------------------------------- /custom_components/midea/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "domain": "midea", 3 | "name": "Midea Aircon", 4 | "documentation": "", 5 | "requirements": ["midea-andersonshatch==0.1.13", "pycryptodome"], 6 | "dependencies": [], 7 | "codeowners": ["@andersonshatch"], 8 | "homeassistant": "0.96.0", 9 | "version": "2021.1" 10 | } 11 | -------------------------------------------------------------------------------- /info.md: -------------------------------------------------------------------------------- 1 | **Example configuration.yaml:** 2 | 3 | ```yaml 4 | climate: 5 | platform: midea 6 | app_key: midea_app_api_key 7 | username: 'foo@bar.com' 8 | password: !secret midea_password 9 | ``` 10 | 11 | **Configuration variables:** 12 | 13 | key | description 14 | :--- | :--- 15 | **platform (Required)** | The platform name. 16 | **app_key (Required)** | Midea app API key. 17 | **username (Required)** | Username for Midea cloud. 18 | **password (Required)** | Password for Midea cloud. 19 | **use_fan_only_workaround (Optional)** | Set this to true if you need to turn off device updates because they turn device on and to fan_only 20 | --------------------------------------------------------------------------------