├── .gitignore ├── LICENSE.md ├── README-EN.md ├── README.md ├── components └── aux_ac │ ├── __init__.py │ ├── automation.h │ ├── aux_ac.h │ └── climate.py ├── docs ├── AC_TESTED.md ├── HARDWARE-EN.md ├── HARDWARE.md ├── HOW_TO_FEATURE_REQUEST-EN.md └── HOW_TO_FEATURE_REQUEST.md ├── enclosure ├── JST SM connector │ ├── pin-cap.stl │ ├── pin-cover.stl │ └── pin-main.stl └── case │ ├── aircon_cap.stl │ └── aircon_case.stl ├── examples ├── advanced │ ├── .gitignore │ ├── ac_common.yaml │ ├── ac_kitchen.yaml │ └── ac_livingroom.yaml └── simple │ ├── .gitignore │ └── aux_ac_simple.yaml ├── images ├── DD4012SA.jpg ├── USB-pinout.png ├── assembled.JPG ├── connections.png ├── connector.JPG ├── esp-12e.jpg ├── real-1.JPG ├── real-2.JPG ├── real-3.JPG └── scheme.png └── tests ├── .gitignore ├── ac_send_packet_for_engineer.py ├── test-ext-esp32.yaml ├── test-ext-for-engineer.yaml ├── test-ext-power-limit.yaml ├── test-local-airflow-dir.yaml ├── test-local-power-limit.yaml ├── test-local.yaml └── test-minimal.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | # Gitignore settings for ESPHome 2 | # This is an example and may include too much for your use-case. 3 | # You can modify this file to suit your needs. 4 | **/.vscode/ 5 | **/.esphome/ 6 | **/.pioenvs/ 7 | **/.piolibdeps/ 8 | **/lib/ 9 | **/src/ 10 | **/platformio.ini 11 | **/secrets.yaml 12 | **/livingroom_ac/ 13 | **/kitchen_ac/ 14 | /examples/*/*.h 15 | **/tests/test_* 16 | **/__pycache__ 17 | **/private/ -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # AUX AC component License 2 | 3 | Copyright (c) 2021 GrKoR
4 | https://github.com/GrKoR/ 5 | 6 | AUX_AC is published under the GPLv3 license ([EN](https://www.gnu.org/licenses/gpl-3.0.en.html), [RU](https://www.gnu.org/licenses/gpl-3.0.ru.html)). 7 | -------------------------------------------------------------------------------- /README-EN.md: -------------------------------------------------------------------------------- 1 | # ESPHome AUX air conditioner custom component (aux_ac) # 2 | For communication about this project [please join this telegram chat](https://t.me/aux_ac). 3 | 4 | For issues or feature requests, please go to [the issue section](https://github.com/GrKoR/esphome_aux_ac_component/issues). It will be perfect if you attach log to your issue. Log you can collect with [this python script](https://github.com/GrKoR/ac_python_logger). It helps you to save all data frames from the UART bus to a csv-file. This log combined with the detailed situation description will significantly speed up bug correction. 5 | There is also a [detailed instruction describing how to properly request a feature](docs/HOW_TO_FEATURE_REQUEST-EN.md). 6 | 7 | ## DISCLAIMER ## 8 | 1. All data of this project (software, firmware, schemes, 3d-models etc.) are provided **'AS IS'**. Everything you do with your devices, you are doing at your own risk. If you don't strongly understand what you are doing, just buy Wi-Fi module from your air conditioner manufacturer. 9 | 2. I am not a programmer. So source code is certainly not optimal and badly decorated (but there are a lot of comments in it; sorry, a significant part of it is in Russian). Also, code may be written unsafe. I tried to test all parts of the code, but I'm sure I missed a lot of things. So treat it with suspicion, expect a trick from it, and if you discover something wrong write an issue here. 10 | 3. Russian and English readme files are substantially identical in meaning. But in case of differences, the [Russian](https://github.com/GrKoR/esphome_aux_ac_component#readme) version is more significant. 11 | 12 | ## Short description ## 13 | This custom component allows you to control your air conditioner through Wi-Fi if it is made in the AUX factory.
14 | Component tested with ESPHome 1.18.0 and Rovex ALS1 air conditioner. It looks like many other air conditioners can be controlled by `aux_ac`, but this possibility isn't tested. See list of tested ACs below for more details. 15 | 16 | 17 | ## Supported air conditioners ## 18 | AUX is one of the OEM air conditioner manufacturers. AUX produce ACs for many brands. 19 | There is the following list of AUX-based air conditioner on the internet: AUX, Abion, AC ELECTRIC, Almacom, Ballu, Centek, Climer, DAX, Energolux, ERISSON, Green Energy, Hyundai, IGC, Kentatsu (some series only), Klimaire, KOMANCHI, LANZKRAFT, LEBERG, LGen, Monroe, Neoclima, NEOLINE, One Air, Pioneer (until 2016), Roda, Rovex, Royal Clima, SAKATA, Samurai, SATURN, Scarlett, SmartWay, Soling, Subtropic, SUBTROPIC, Supra, Timberk, Vertex, Zanussi. There are doubts about its completeness and reliability, but nothing better could be found. 20 | 21 | ### List of compatible ACs (tested) ### 22 | [The list of tested ACs](docs/AC_TESTED.md) is placed in a separate file and includes tested by the author or by users ACs. This list is permanently updated, mainly based on feedback from users in [Telegram chat](https://t.me/aux_ac).
23 | 24 | ### If your AC is not in the list ### 25 | 1. If your AC is listed above, you should take a closer look at `aux_ac`.
26 | 2. If something about AUX is written on the nameplate of the air conditioner in the manufacturer line.
27 | 3. If the User Manual of your HVAC describes connection to Wi-Fi with mobile app ACFreedom it seems you may go deeper with `aux_ac`. But try all soft and hardware for your own risk. You must clearly understand what you are doing.
28 | 4. If the manufacturer of your AC offers a CTTM-40X24-WIFI-AKS Wi-Fi module (left) or the one in the photo on the right for control. Moreover, the right module can be either with a USB connector or with a 5-pin connector.
29 | 30 | 31 | If you are unsure, it is better to wait while other users will test your model of AC (maybe never). Or please [go to telegram-chat](https://t.me/aux_ac) with your questions. Maybe you will get help there.
32 | If you have tested your air conditioner and `aux_ac` works with it, please let me know about it. I'll add this info to the list of tested ACs above.
33 | The best way to report about your test results is writing a message in the [telegram](https://t.me/aux_ac) or [in the issue section](https://github.com/GrKoR/esphome_aux_ac_component/issues).
34 | 35 | ## How to use it ## 36 | For correct component operation, you need hardware and firmware. The hardware description is located [in a separate file](docs/HARDWARE-EN.md). 37 | 38 | ### Firmware: Integration aux_ac to your configuration ### 39 | You need [ESPHome](https://esphome.io) v.1.18.0 or above. `External_components` have appeared in this version. But it is better to use ESPHome v.1.20.4 or above, cause there were a lot of `external_components` errors corrected before this version. 40 | 41 | ## Installing ## 42 | 1. Declare external component. Read [the manual](https://esphome.io/components/external_components.html?highlight=external) for details. 43 | ```yaml 44 | external_components: 45 | - source: 46 | type: git 47 | url: https://github.com/GrKoR/esphome_aux_ac_component 48 | ``` 49 | In case you need a specific version of the component, you can use the component declaration from the example below. The example uses version 0.2.14 of the component. You can find a list of available versions [on the GitHub tags page](https://github.com/GrKoR/esphome_aux_ac_component/tags). 50 | ```yaml 51 | external_components: 52 | - source: 53 | type: git 54 | url: https://github.com/GrKoR/esphome_aux_ac_component 55 | ref: v.0.2.14 56 | ``` 57 | 2. Configure UART to communicate with air conditioner: 58 | ```yaml 59 | uart: 60 | id: ac_uart_bus 61 | # ATTENTION! For TX and RX use GPIO4 (D2) and GPIO5 (D1) for NodeMCU-like boards! 62 | # See docs for details: https://github.com/GrKoR/esphome_aux_ac_component/blob/master/docs/HARDWARE-EN.md 63 | tx_pin: GPIO1 64 | rx_pin: GPIO3 65 | baud_rate: 4800 66 | data_bits: 8 67 | parity: EVEN 68 | stop_bits: 1 69 | ``` 70 | 3. **ATTENTION!** You need to disable the ESPHome logger so that it does not send its data to the air conditioner. Disabling the logger from the UART bus will not affect the logger output to the console or web server in any way. 71 | ```yaml 72 | logger: 73 | baud_rate: 0 74 | ``` 75 | If for some reason you need the logger output to the UART, you can switch it to another UART. ESP8266 has two hardware UARTs: UART0 and UART1. Only UART0 suits for `aux_ac` cause only it has both TX and RX. UART1 has TX only, and it can be used by logger for output: 76 | ```yaml 77 | logger: 78 | level: DEBUG 79 | hardware_uart: UART1 80 | ``` 81 | 82 | ## AUX_AC Configuration ## 83 | Minimal configuration: 84 | ```yaml 85 | climate: 86 | - platform: aux_ac 87 | name: "AC Name" 88 | ``` 89 | 90 | Full configuration: 91 | ```yaml 92 | climate: 93 | - platform: aux_ac 94 | name: "AC Name" 95 | id: aux_id 96 | uart_id: ac_uart_bus 97 | period: 7s 98 | show_action: true 99 | display_inverted: false 100 | timeout: 150 101 | optimistic: true 102 | indoor_temperature: 103 | name: AC Indoor Temperature 104 | id: ac_indoor_temp 105 | accuracy_decimals: 1 106 | internal: false 107 | outdoor_temperature: 108 | name: AC Outdoor Temperature 109 | id: ac_outdoor_temp 110 | internal: false 111 | outbound_temperature: 112 | name: AC Coolant Outbound Temperature 113 | id: ac_outbound_temp 114 | internal: false 115 | inbound_temperature: 116 | name: AC Coolant Inbound Temperature 117 | id: ac_inbound_temp 118 | internal: false 119 | compressor_temperature: 120 | name: AC Compressor Temperature 121 | id: ac_strange_temp 122 | internal: false 123 | display_state: 124 | name: AC Display State 125 | id: ac_display_state 126 | internal: false 127 | defrost_state: 128 | name: AC Defrost State 129 | id: ac_defrost_state 130 | internal: false 131 | inverter_power: 132 | name: AC Inverter Power 133 | id: ac_inverter_power 134 | internal: false 135 | inverter_power_limit_value: 136 | name: AC Inverter Power Limit Value 137 | id: ac_inverter_power_limit_value 138 | internal: false 139 | inverter_power_limit_state: 140 | name: AC Inverter Power Limit State 141 | id: ac_inverter_power_limit_state 142 | internal: false 143 | preset_reporter: 144 | name: AC Preset Reporter 145 | id: ac_preset_reporter 146 | internal: false 147 | vlouver_state: 148 | name: AC Vertical Louvers State 149 | id: ac_vlouver_state 150 | internal: false 151 | visual: 152 | min_temperature: 16 153 | max_temperature: 32 154 | temperature_step: 1 155 | supported_modes: 156 | - HEAT_COOL 157 | - COOL 158 | - HEAT 159 | - DRY 160 | - FAN_ONLY 161 | custom_fan_modes: 162 | - MUTE 163 | - TURBO 164 | supported_presets: 165 | - SLEEP 166 | custom_presets: 167 | - CLEAN 168 | - HEALTH 169 | - ANTIFUNGUS 170 | supported_swing_modes: 171 | - VERTICAL 172 | - HORIZONTAL 173 | - BOTH 174 | ``` 175 | 176 | ## Configuration variables: ## 177 | 178 | - **name** (**Required**, string): The name of the climate device. At least one of `id` or `name` is required! 179 | 180 | - **id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Manually specify the ID used for code generation. At least one of `id` or `name` is required! 181 | 182 | - **uart_id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Manually specify the ID of the [UART Bus](https://esphome.io/components/uart.html) if you want to use multiple UART buses. 183 | 184 | - **period** (*Optional*, [time](https://esphome.io/guides/configuration-types.html#config-time), default ``7s``): Period between status requests to the AC. `Aux_ac` will receive the new air conditioner status only after a regular request, even if you change the settings of AC using IR-remote. 185 | 186 | - **show_action** (*Optional*, boolean, default ``true``): Whether to show current action of the device (experimental). For example, in the HEAT_COOL mode, AC hardware may be in one of the following actions: 187 | - HEATING: AC is heating the air in the room; 188 | - IDLE: AC is working in the FAN mode, cause the target temperature is reached; 189 | - COOLING: AC is cooling the air. 190 | The same thing will be in HEAT or COOL modes, with the only difference of the list of actions (IDLE + HEATING or IDLE + COOLING). 191 | 192 | - **display_inverted** (*Optional*, boolean, default ``false``): It configures display driver logic level. As it turned out in the issue [#31](https://github.com/GrKoR/esphome_aux_ac_component/issues/31), different models of conditioners manage display different way. Rovex ACs powers off display by bit `1` in command packet and power it on by bit `0`. Many other conditioners do this vice versa. 193 | 194 | - **timeout** (*Optional*, unsigned integer, default ``150``): Packet timeout for `aux_ac` data receiver. 195 | In the most common use of `aux_ac`, it isn't necessary to change this value. This keyword is optional, so you may omit it. 196 | The only situation when you can play with timeout is heavily loaded ESP. When you are using your ESP for many hard tasks, it is possible that `aux_ac` does not have enough time to receive AC responses. In this case, you can slightly raise the timeout value. But the best solution would be to remove some of the tasks from the ESP. 197 | The timeout is limited to a range from `150` to `600` milliseconds. Other values are possible only with source code modification. But I don't recommend that. 198 | 199 | - **optimistic** (*Optional*, boolean, default ``true``): Whether entity states should be updated immediately after receiving a command from Home Assistant/ESPHome. 200 | 201 | - **indoor_temperature** (*Optional*): Parameters of the room air temperature sensor. 202 | - **name** (**Required**, string): The name for the temperature sensor. 203 | - **id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Set the ID of this sensor for use in lambdas. 204 | - **internal** (*Optional*, boolean): Mark this component as internal. Internal components will not be exposed to the frontend (like Home Assistant). As opposed to default [Sensor](https://esphome.io/components/sensor/index.html#base-sensor-configuration) behaviour, this variable is **always true** except in cases where the user has set it directly. 205 | - All other options from [Sensor](https://esphome.io/components/sensor/index.html#base-sensor-configuration). 206 | 207 | - **outdoor_temperature** (*Optional*): Parameters of the outdoor temperature sensor. They are the same as the **indoor_temperature** (see description above). 208 | > **Attention!** When the air conditioner is turned off, the outdoor temperature is updated rarely (every 6-7 hours). This isn't a bug of the component, but a feature of the air conditioner hardware. The only way to get changes more often is to create a template sensor, the temperature of which can be changed manually. When the air conditioner is working, the value of this sensor can be copied from the **outdoor_temperature**. When the air conditioner is turned off, the temperature value should be recalculated according to the dynamics of the **outbound_temperature** sensor (it changes frequently and shows values close to the air temperature when the air conditioner is turned off). You can't copy the value of **outbound_temperature** without changes to the template sensor in AC off mode, because these temperatures are not identical. 209 | 210 | - **inbound_temperature** (*Optional*): Parameters of the coolant inbound temperature sensor. They are the same as the **indoor_temperature** (see description above). 211 | 212 | - **outbound_temperature** (*Optional*): Parameters of the coolant outbound temperature sensor. They are the same as the **indoor_temperature** (see description above). 213 | 214 | - **compressor_temperature** (*Optional*): Parameters of the compressor temperature sensor. They are the same as the **indoor_temperature** (see description above). 215 | 216 | - **display_state** (*Optional*): The information for the HVAC display state sensor (is display ON or OFF) 217 | - **name** (**Required**, string): The name for the display state sensor. 218 | - **id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Set the ID of this sensor for use in lambdas. 219 | - **internal** (*Optional*, boolean): Mark this component as internal. Internal components will not be exposed to the frontend (like Home Assistant). As opposed to default [Binary Sensor](https://esphome.io/components/binary_sensor/index.html#base-binary-sensor-configuration) behavior, this variable is **always true** except in cases where the user has set it directly. 220 | - All other options from [Binary Sensor](https://esphome.io/components/binary_sensor/index.html#base-binary-sensor-configuration). 221 | 222 | - **defrost_state** (*Optional*): The information for the HVAC defrost function state sensor (is it ON or OFF). All settings are the same as for the **display_state** (see description above). 223 | 224 | - **inverter_power** (*Optional*): The information for the inverter power sensor. All settings are the same as for the **indoor_temperature** (see description above). 225 | > **ATTENTION!** The parameter name was changed in v.0.2.9 due to incorrect spelling. 226 | 227 | - **inverter_power_limit_state** (*Optional*): Configuration of the power limit state sensor. It displays the state of the power limitation function for the inverter HVAC (is it ON or OFF). All settings are the same as for the **display_state** (see description above). 228 | 229 | - **inverter_power_limit_value** (*Optional*): Configuration of the power limit value sensor. All settings are the same as for the **indoor_temperature** (see description above). 230 | It reports the current value of the power limitation function for the inverter HVAC. This sensor represents the value only after the HVAC confirms the power limitation. The value is always in the range from 30% to 100%. This is the hardware limitation. 231 | 232 | - **preset_reporter** (*Optional*): Parameters of text sensor with current preset. All settings are the same as for the **display_state** (see description above). 233 | ESPHome Climate devices are not reporting their active presets (from **supported_presets** and **custom_presets** lists) to MQTT. This behavior has been noticed at least in version 1.20.0. In case you are using MQTT and want to receive information about active preset, you should declare this sensor in your yaml. 234 | 235 | - **vlouver_state** (*Optional*): Parameters of vertical louvers state sensor. All settings are the same as for the **display_state** (see description above). The state of the vertical louvers is encoded by the integer value (see [aux_ac.vlouver_set action](#aux_ac_._vlouver_set) below). 236 | 237 | - **supported_modes** (*Optional*, list): List of supported modes. Possible values are: ``HEAT_COOL``, ``COOL``, ``HEAT``, ``DRY``, ``FAN_ONLY``. Please note: some manufacturers call AUTO mode instead of HEAT_COOL. Defaults to ``FAN_ONLY``. 238 | 239 | - **custom_fan_modes** (*Optional*, list): List of supported custom fan modes. Possible values are: ``MUTE``, ``TURBO``. No custom fan modes by default. 240 | 241 | - **supported_presets** (*Optional*, list): List of supported presets. Possible values are: ``SLEEP``. No presets by default. 242 | 243 | - **custom_presets** (*Optional*, list): List of supported custom presets. Possible values are: ``CLEAN``, ``HEALTH``, ``ANTIFUNGUS``. No custom presets by default. 244 | 245 | - **supported_swing_modes** (*Optional*, list): List of supported swing modes. Possible values are: ``VERTICAL``, ``HORIZONTAL``, ``BOTH``. No swing modes by default. 246 | 247 | - All other options from [Climate](https://esphome.io/components/climate/index.html#base-climate-configuration). 248 | 249 | 250 | ## Actions: ## 251 | ### ``aux_ac.display_on`` ### 252 | This action turns a HVAC temperature display on when executed. 253 | 254 | ```yaml 255 | on_...: 256 | then: 257 | - aux_ac.display_on: aux_id 258 | ``` 259 | - **aux_id** (**Requared**, string): ID of `aux_ac` component. 260 | 261 | ### ``aux_ac.display_off`` ### 262 | This action turns a HVAC temperature display off when executed. 263 | 264 | ```yaml 265 | on_...: 266 | then: 267 | - aux_ac.display_off: aux_id 268 | ``` 269 | - **aux_id** (**Requared**, string): ID of `aux_ac` component. 270 | 271 | ### ``aux_ac.vlouver_set`` ### 272 | This action moves HVAC vertical louvers to the specified position. 273 | 274 | The position is encoded by the following values: 275 | - `0`: the vertical louvers are in `SWING` mode (they are moving up and down); 276 | - `1`: the louvers are stopped in a user position; 277 | - `2`: the louvers are in the topmost position; 278 | - `3`: the louvers are in one step above middle position; 279 | - `4`: the louvers are in the middle position; 280 | - `5`: the louvers are in one step below middle position; 281 | - `6`: the louvers are in the lowest position. 282 | 283 | ```yaml 284 | on_...: 285 | then: 286 | - aux_ac.vlouver_set: 287 | id: aux_id 288 | position: 3 # moves the louvers to the middle position 289 | ``` 290 | - **aux_id** (**Required**, string): ID of `aux_ac` component. 291 | - **position** (**Required**, integer): position of the vertical louvers. 292 | 293 | ### ``aux_ac.vlouver_stop`` ### 294 | This action stops vertical swing of louvers. 295 | 296 | ```yaml 297 | on_...: 298 | then: 299 | - aux_ac.vlouver_stop: aux_id 300 | ``` 301 | - **aux_id** (**Required**, string): ID of `aux_ac` component. 302 | 303 | ### ``aux_ac.vlouver_swing`` ### 304 | This action starts the vertical swing of louvers. 305 | 306 | ```yaml 307 | on_...: 308 | then: 309 | - aux_ac.vlouver_swing: aux_id 310 | ``` 311 | - **aux_id** (**Required**, string): ID of `aux_ac` component. 312 | 313 | ### ``aux_ac.vlouver_top`` ### 314 | This action moves HVAC louvers to the topmost position. 315 | 316 | ```yaml 317 | on_...: 318 | then: 319 | - aux_ac.vlouver_top: aux_id 320 | ``` 321 | - **aux_id** (**Required**, string): ID of `aux_ac` component. 322 | 323 | ### ``aux_ac.vlouver_middle_above`` ### 324 | This action moves HVAC louvers to the position one step under the topmost. 325 | 326 | ```yaml 327 | on_...: 328 | then: 329 | - aux_ac.vlouver_middle_above: aux_id 330 | ``` 331 | - **aux_id** (**Required**, string): ID of `aux_ac` component. 332 | 333 | ### ``aux_ac.vlouver_middle`` ### 334 | This action moves HVAC louvers to the middle position. 335 | 336 | ```yaml 337 | on_...: 338 | then: 339 | - aux_ac.vlouver_middle: aux_id 340 | ``` 341 | - **aux_id** (**Required**, string): ID of `aux_ac` component. 342 | 343 | ### ``aux_ac.vlouver_middle_below`` ### 344 | This action moves HVAC louvers to the position one step under the middle position. 345 | 346 | ```yaml 347 | on_...: 348 | then: 349 | - aux_ac.vlouver_middle_below: aux_id 350 | ``` 351 | - **aux_id** (**Required**, string): ID of `aux_ac` component. 352 | 353 | ### ``aux_ac.vlouver_bottom`` ### 354 | This action moves HVAC louvers to the lowest position. 355 | 356 | ```yaml 357 | on_...: 358 | then: 359 | - aux_ac.vlouver_bottom: aux_id 360 | ``` 361 | - **aux_id** (**Required**, string): ID of `aux_ac` component. 362 | 363 | ### ``aux_ac.aux_ac.power_limit_off`` ### 364 | This action disables inverter HVAC power limitation. 365 | 366 | ```yaml 367 | on_...: 368 | then: 369 | - aux_ac.power_limit_off: aux_id 370 | ``` 371 | - **aux_id** (**Required**, string): ID of `aux_ac` component. 372 | 373 | ### ``aux_ac.power_limit_on`` ### 374 | This action enables inverter HVAC power limitation and sets this limit value. 375 | 376 | ```yaml 377 | on_...: 378 | then: 379 | - aux_ac.power_limit_on: 380 | id: aux_id 381 | limit: 46 # limits the maximum power of the inverter HVAC at 46% 382 | ``` 383 | - **aux_id** (**Required**, string): ID of `aux_ac` component. 384 | - **limit** (**Optional**, integer): the maximum power of the inverter HVAC. If the power limitation is enabled, the inverter HVAC will limits its power. 385 | > **Notice**, that power limitation will affect the efficiency of your HVAC. For example, a low power limit may block the possibility of the conditioner to reach user-specified room temperature, because HVAC will not have enough power for it. Keep this in mind when you are using this function. 386 | 387 | Due to hardware limitation this value should be in the range from `30%` to `100%`. The default value for `limit` is `30%` (it will be used if `limit` is omitted in configuration). 388 | 389 | 390 | 391 | ## Simple example ## 392 | The source code of this example is located in the [aux_ac_simple.yaml](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/examples/simple/aux_ac_simple.yaml) file. 393 | 394 | All settings in it is trivial. Just copy the file to your local folder, specify your Wi-Fi settings and compile YAML with ESPHome. 395 | 396 | 397 | ## Advanced example ## 398 | All sources are located [in advanced example folder](https://github.com/GrKoR/esphome_aux_ac_component/tree/master/examples/advanced). 399 | 400 | This time we'll configure two relative identical air conditioners with `aux_ac` custom component.
401 | Let's imagine we have ACs in a kitchen and in a living room. Air conditioners can be of the same brand or different brands - the main thing is that they are compatible with `aux_ac` and can be controlled using `aux_ac`.
402 | Because we are lazy, we'll define all common configuration parts for two air conditioners in one `ac_common.yaml` file.
403 | All specific parts of configuration are located in the `ac_kitchen.yaml` and `ac_livingroom.yaml`. Here we set `devicename` and `upper_devicename` for correct sensors and component naming. And here we specify the correct IP address of the device from `secrets.yaml`.
404 | **Don't forget** to specify `wifi_ip_kitchen`, `wifi_ota_ip_kitchen`, `wifi_ip_livingroom` and `wifi_ota_ip_livingroom` in the `secrets.yaml` along with the other sensitive information, such as passwords, tokens etc. 405 | 406 | If you try to compile `ac_common.yaml` it will raise errors. You need to compile `ac_kitchen.yaml` or `ac_livingroom.yaml` instead. 407 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Кастомный компонент для ESPHome для управления кондиционером по Wi-Fi 2 | 3 | English readme [is here](README-EN.md#esphome-aux-air-conditioner-custom-component-aux_ac). 4 | 5 | Управляет кондиционерами на базе AUX по Wi-Fi.
6 | По тексту ниже для компонента используется сокращение `aux_ac`. 7 | 8 | Обсудить проект можно [в чате Телеграм](https://t.me/aux_ac).
9 | Отзывы о багах и ошибках, а так же запросы на дополнительный функционал оставляйте [в соответствующем разделе](https://github.com/GrKoR/esphome_aux_ac_component/issues). 10 | Будет просто отлично, если к своему сообщению вы добавите лог и подробное описание. Для сбора логов есть [специальный скрипт на Python](https://github.com/GrKoR/ac_python_logger). С его помощью вы сможете сохранить в csv-файл все пакеты, которыми обменивается Wi-Fi модуль и сплит-система. Если такой лог дополнить описанием, в какое время и что именно вы пытались включить, то это сильно ускорит исправление багов. 11 | Также есть [подробная инструкция, описывающая как правильно запросить фичу](docs/HOW_TO_FEATURE_REQUEST.md). 12 | 13 | 14 | ## ДИСКЛЭЙМЕР (ОТМАЗКИ) ## 15 | 1. Все материалы этого проекта (программы, прошивки, схемы, 3D модели и т.п.) предоставляются "КАК ЕСТЬ". Всё, что вы делаете с вашим оборудованием, вы делаете на свой страх и риск. Автор не несет ответственности за результат и ничего не гарантирует. Если вы с абсолютной четкостью не понимаете, что именно вы делаете и для чего, лучше просто купите Wi-Fi модуль у производителя вашего кондиционера. 16 | 2. Я ~~не настоящий сварщик~~ не программер. Поэтому код наверняка не оптимален и плохо оформлен (зато комментариев по коду я разместил от души), местами может быть написан небезопасно. И хоть я и старался протестировать всё, но уверен, что какие-то моменты упустил. Так что отнеситесь к коду с подозрением, ожидайте от него подвоха и если что-то увидели - [пишите в багрепорт](https://github.com/GrKoR/esphome_aux_ac_component/issues). 17 | 18 | 19 | ## Поддерживаемые кондиционеры ## 20 | AUX - это один из нескольких OEM-производителей кондиционеров. AUX производят кондиционеры как под собственным брендом, так и для внешних заказчиков. Поэтому есть шанс, что произведенный на их фабрике кондиционер неизвестного бренда с `aux_ac` так же заработает. 21 | В интернете есть такой перечень производившихся на фабриках AUX брендов: AUX, Abion, AC ELECTRIC, Almacom, Ballu , Centek, Climer, DAX, Energolux, ERISSON, Green Energy, Hyundai, IGC, Kentatsu (некоторые серии), Klimaire, KOMANCHI, LANZKRAFT, LEBERG, LGen, Monroe, Neoclima, NEOLINE, One Air, Pioneer (до 2016 года), Roda, Rovex, Royal Clima, SAKATA, Samurai, SATURN, Scarlett, SmartWay, Soling, Subtropic, SUBTROPIC, Supra, Timberk, Vertex, Zanussi. В его полноте и достоверности есть сомнения, но ничего лучше найти не удалось. 22 | 23 | 24 | ### Список совместимых (протестированных) кондиционеров ### 25 | [Список протестированных кондиционеров](docs/AC_TESTED.md) размещен в отдельном файле и включает те модели, на которых `aux_ac` был запущен автором компонента или пользователями. Этот список постоянно пополняется, преимущественно по обратной связи от пользователей [в чате Телеграм](https://t.me/aux_ac).
26 | 27 | ### Если кондиционер в списке отсутствует ### 28 | Если ваш кондиционер отсутствует в списке протестированных, то это еще не значит, что его не получится подключить к Wi-Fi. Вот основные "звоночки", которые могут говорить о высоких шансах на успех: 29 | 1. Если производитель вашего кондиционера есть в списке протестированных выше, но модели нет. 30 | 2. Если на шильдике кондиционера в строке производитель написано что-то про AUX или Аукс. 31 | 3. Если в инструкции пользователя вашего кондиционера что-то написано про возможность управления по Wi-Fi с помощью мобильного приложения ACFreedom. 32 | 4. Если производитель вашего кондиционера предлагает для управления Wi-Fi модуль CTTM-40X24-WIFI-AKS (слева) или такой, как на фото справа. Причем правый модуль может быть как с USB-разъемом, так и с 5-контактным разъемом. 33 | 34 | 35 | 36 | Но будьте осмотрительны: ваш кондиционер никем не тестировался и важно четко понимать, что вы делаете. Иначе можете наломать дров. 37 | Если вы не уверены в своих силах, лучше дождитесь, пока другие более опытные пользователи протестируют вашу модель кондиционера (правда, это может не случиться никогда). Или приходите с вопросами [в телеграм-чат](https://t.me/aux_ac). Возможно, там вам помогут. 38 | 39 | Если вы протестировали ваш кондиционер и он работает, напишите мне, пожалуйста. Я внесу вашу модель в список протестированных. Возможно, это упростит кому-то жизнь =)
40 | Лучший способ сообщить о протестированном кондиционере - написать [в телеграм](https://t.me/aux_ac) или [в разделе багрепортов и заказа фич](https://github.com/GrKoR/esphome_aux_ac_component/issues). 41 | 42 | ## Как использовать компонент ## 43 | Для работы с кондиционером понадобится "железо" и прошивка. Описание электроники вынесено [в отдельный файл](docs/HARDWARE.md). 44 | 45 | ### Прошивка: интеграция aux_ac в вашу конфигурацию ESPHome ### 46 | Для использования требуется [ESPHome](https://esphome.io) версией не ниже 1.18.0. Именно в этой версии появились `external_components`. Но лучше использовать версию 1.20.4 или старше, так как до этой версии массированно исправлялись ошибки в механизме подключения внешних компонентов.
47 | 48 | ## Установка ## 49 | 1. Подключите компонент. 50 | За подробностями можно заглянуть в [официальную документацию ESPHome](https://esphome.io/components/external_components.html?highlight=external). 51 | ```yaml 52 | external_components: 53 | - source: 54 | type: git 55 | url: https://github.com/GrKoR/esphome_aux_ac_component 56 | ``` 57 | Если требуется прошить определенную версию компонента, используйте синтаксис из примера ниже. Здесь прошивается версия 0.2.14. Список версий смотрите [в тегах на гитхаб](https://github.com/GrKoR/esphome_aux_ac_component/tags). 58 | ```yaml 59 | external_components: 60 | - source: 61 | type: git 62 | url: https://github.com/GrKoR/esphome_aux_ac_component 63 | ref: v.0.2.14 64 | ``` 65 | 2. Настройте UART для коммуникации с вашим кондиционером: 66 | ```yaml 67 | uart: 68 | id: ac_uart_bus 69 | # ВНИМАНИЕ! Для TX и RX на платах типа NodeMCU используйте GPIO4 (D2) и GPIO5 (D1)! 70 | # подробнее см. в документации: https://github.com/GrKoR/esphome_aux_ac_component/blob/master/docs/HARDWARE.md 71 | tx_pin: GPIO1 72 | rx_pin: GPIO3 73 | baud_rate: 4800 74 | data_bits: 8 75 | parity: EVEN 76 | stop_bits: 1 77 | ``` 78 | 3. **ВАЖНО!** Нужно отключить логгер ESPHome, чтобы он не отправлял в кондиционер свои данные. 79 | Отключение логгера от UART никак не затронет вывод в лог консоли или web-сервера. 80 | ```yaml 81 | logger: 82 | baud_rate: 0 83 | ``` 84 | Если по каким-то причинам вам нужен вывод логгера в UART, можно переключить его на другой UART чипа. Например, у ESP8266 два аппаратных UART: UART0 и UART1. `Aux_ac` подходит только UART0, поскольку только он у esp8266 имеет и TX и RX. Логгеру достаточно только TX. Такой функционал в чипе esp8266 у UART1: 85 | ```yaml 86 | logger: 87 | level: DEBUG 88 | hardware_uart: UART1 89 | ``` 90 | 91 | ## Настройка компонента ## 92 | Минимальная конфигурация: 93 | ```yaml 94 | climate: 95 | - platform: aux_ac 96 | name: "AC Name" 97 | ``` 98 | 99 | Полная конфигурация: 100 | ```yaml 101 | climate: 102 | - platform: aux_ac 103 | name: "AC Name" 104 | id: aux_id 105 | uart_id: ac_uart_bus 106 | period: 7s 107 | show_action: true 108 | display_inverted: false 109 | timeout: 150 110 | indoor_temperature: 111 | name: AC Indoor Temperature 112 | id: ac_indoor_temp 113 | accuracy_decimals: 1 114 | internal: false 115 | outdoor_temperature: 116 | name: AC Outdoor Temperature 117 | id: ac_outdoor_temp 118 | internal: false 119 | outbound_temperature: 120 | name: AC Coolant Outbound Temperature 121 | id: ac_outbound_temp 122 | internal: false 123 | inbound_temperature: 124 | name: AC Coolant Inbound Temperature 125 | id: ac_inbound_temp 126 | internal: false 127 | compressor_temperature: 128 | name: AC Compressor Temperature 129 | id: ac_strange_temp 130 | internal: false 131 | display_state: 132 | name: AC Display State 133 | id: ac_display_state 134 | internal: false 135 | defrost_state: 136 | name: AC Defrost State 137 | id: ac_defrost_state 138 | internal: false 139 | inverter_power: 140 | name: AC Inverter Power 141 | id: ac_inverter_power 142 | internal: false 143 | inverter_power_limit_value: 144 | name: AC Inverter Power Limit Value 145 | id: ac_inverter_power_limit_value 146 | internal: false 147 | inverter_power_limit_state: 148 | name: AC Inverter Power Limit State 149 | id: ac_inverter_power_limit_state 150 | internal: false 151 | preset_reporter: 152 | name: AC Preset Reporter 153 | id: ac_preset_reporter 154 | internal: false 155 | vlouver_state: 156 | name: AC Vertical Louvers State 157 | id: ac_vlouver_state 158 | internal: false 159 | visual: 160 | min_temperature: 16 161 | max_temperature: 32 162 | temperature_step: 1 163 | supported_modes: 164 | - HEAT_COOL 165 | - COOL 166 | - HEAT 167 | - DRY 168 | - FAN_ONLY 169 | custom_fan_modes: 170 | - MUTE 171 | - TURBO 172 | supported_presets: 173 | - SLEEP 174 | custom_presets: 175 | - CLEAN 176 | - HEALTH 177 | - ANTIFUNGUS 178 | supported_swing_modes: 179 | - VERTICAL 180 | - HORIZONTAL 181 | - BOTH 182 | ``` 183 | 184 | ## Параметры компонента: ## 185 | 186 | - **name** (**Обязательный**, строка): Имя кондиционера. Как минимум один из параметров `id` или `name` должен быть указан! 187 | 188 | - **id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Укажите идентификатор кондиционера чтобы обращаться к нему из кода. Как минимум один из параметров `id` или `name` должен быть указан! 189 | 190 | - **uart_id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Укажите ID [шины UART](https://esphome.io/components/uart.html), к которой подключен кондиционер. Если сконфигурирована одна шина, то компонент подключит её автоматически. Если шин несколько, то лучше указать вручную. 191 | 192 | - **period** (*Опциональный*, [время](https://esphome.io/guides/configuration-types.html#config-time), по умолчанию ``7s``): Период между запросами статуса кондиционера. `Aux_ac` получает новое состояние кондиционера только после регулярного запроса, потому что сам кондиционер об изменении параметров своей работы не уведомляет. Поэтому нужно запрашивать его, вдруг пользователь установил иной режим работы с помощью ИК-пульта. 193 | 194 | - **show_action** (*Опциональный*, логическое, по умолчанию ``true``): Показывать ли текущую задачу кондиционера (экспериментальная функция). Например, в режиме HEAT_COOL кондиционер может выполнять одну из следующих задач: 195 | - НАГРЕВ: нагревает воздух в комнате; 196 | - ПРОСТОЙ: кондиционер работает в режиме вентилятора для перемешивания воздуха в комнате, поскольку целевая температура уже достигнута; 197 | - ОХЛАЖДЕНИЕ: кондиционер охлаждает воздух в комнате. 198 | Аналогично будут отображаться действия кондиционера и для режимов ОТОПЛЕНИЕ и ОХЛАЖДЕНИЕ. Единственная разница будет в количестве действий: ПРОСТОЙ+НАГРЕВ для режима отопления и ПРОСТОЙ+ОХЛАЖДЕНИЕ для режима охлаждения комнаты. 199 | 200 | - **display_inverted** (*Опциональный*, логическое, по умолчанию ``false``): Настраивает способ управления дисплеем. Как выяснилось (issue [#31](https://github.com/GrKoR/esphome_aux_ac_component/issues/31)), включение-выключение дисплея обрабатывается кондиционерами по разному. Кондиционеры Rovex включают дисплей по `0` в соответствующем бите команды и выключают по биту `1`. Многие другие модели кондиционеров поступают наоборот. 201 | 202 | - **timeout** (*Опциональный*, неотрицательное целое, по умолчанию ``150``): Таймаут получения пакета для ресивера данных `aux_ac`. 203 | Чаще всего вам это значение никогда не понадобится. Поскольку этот параметр опционален, то его можно смело пропустить, если нет необходимости менять таймауты. 204 | Единственная ситуация, когда вам может пригодиться этот параметр, - это сильно загруженная ESP. Если по какой-то неподдающейся логике причине вы кроме `aux_ac` нагрузили свою ESP кучей дополнительных ресурсоемких задач, то у компонента может просто не хватать времени для оперативного приёма ответов от кондиционера. В этом в логе будут сообщения о том, что последовательность команд была прервана по таймауту. Чтобы это исправить, лучше, конечно, немного разгрузить ESP. Если это вам не подходит, тогда можно увеличить таймаут. 205 | Значение таймаута в прошивке ограничено диапазоном от `150` до `600` миллисекунд. Устанавливать значения выше можно только отредактировав исходные коды компонента. Но сильно задирать таймаут не стоит. Кондиционер периодически рассылает пакеты без запроса со стороны `aux_ac` и это приводит к сбою в отправке команды. 206 | 207 | - **optimistic** (*Опциональный*, логическое, по умолчанию ``true``) В «оптимистичном» режиме компонент не ждёт от кондиционера изменения параметров работы, а сразу после отправки команды в кондиционер сообщает в Home Assistant о новом состоянии. Если кондиционер команду не принял, то спустя несколько секунд eps получит текущее состояние всех систем и отправит в умный дом реальное состояние кондиционера. В итоге, если подавать в кондиционер неподдерживаемые команды, они будут записываться в историю Home Assistant и спустя время сбрасываться сбрасываться. 208 | В «пессимистичном» режиме esp отправляет команду в кондиционер, но об изменении состояний не сообщает до тех пор, пока не получит информацию о фактическом режиме работы кондиционера. 209 | В большинстве случаев разница между этими режимами будет практически незаметна. 210 | 211 | - **indoor_temperature** (*Опциональный*): Параметры создаваемого датчика температуры воздуха, если такой датчик нужен 212 | - **name** (**Обязательный**, строка): Имя датчика температуры. 213 | - **id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Можно указать свой ID для датчика для использования в лямбдах. 214 | - **internal** (*Опциональный*, логическое): Пометить данный датчик как внутренний. Внутренний датчик не будет передаваться во фронтэнд (такой как Home Assistant). В противоположность стандартному поведению [сенсоров](https://esphome.io/components/sensor/index.html#base-sensor-configuration) этот параметр для датчика в кондиционере **всегда выставлен в true** за исключением случаев, когда пользователь не установил его в `false`. То есть по умолчанию значение сенсора не будет передаваться во фронтенд даже если указано `name` для сенсора. 215 | - Все остальные параметры [сенсора](https://esphome.io/components/sensor/index.html#base-sensor-configuration) ESPHome. 216 | 217 | - **outdoor_temperature** (*Опциональный*): Параметры создаваемого датчика уличной температуры воздуха, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше). 218 | > **ВНИМАНИЕ!** Когда кондиционер выключен, температура наружного воздуха обновляется редко (раз в 6-7 часов). Это не баг компонента, а особенность работы железа кондиционера. Единственный способ получать изменения чаще - создать шаблонный сенсор, температуру которого изменять вручную. Когда кондиционер работает, значение такого сенсора можно копировать из **outdoor_temperature**. Когда кондиционер выключен, значение температуры пересчитывать по динамике сенсора **outbound_temperature** (он изменяется часто и при выключенном кондее показывает значения близкие к температуре воздуха). Заморочки с пересчетом нужны потому, что показания сенсоров не идентичны и на графике значений шаблонного сенсора могут быть ступеньки при переходе с **outdoor_temperature** на **outbound_temperature** и обратно. 219 | 220 | - **inbound_temperature** (*Опциональный*): Параметры создаваемого датчика температуры на подаче теплоносителя, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше). 221 | 222 | - **outbound_temperature** (*Опциональный*): Параметры создаваемого датчика температуры на обратке теплоносителя, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше). 223 | 224 | - **compressor_temperature** (*Опциональный*): Параметры создаваемого датчика температуры компрессора, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше). 225 | 226 | - **display_state** (*Опциональный*): Параметры создаваемого датчика дисплея (включен или выключен), если такой датчик нужен. 227 | - **name** (**Обязательный**, строка): Имя датчика дисплея. 228 | - **id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Можно указать свой ID для датчика для использования в лямбдах. 229 | - **internal** (*Опциональный*, логическое): Пометить данный датчик как внутренний. Внутренний датчик не будет передаваться во фронтэнд (такой как Home Assistant). В противоположность стандартному поведению [бинарных сенсоров](https://esphome.io/components/binary_sensor/index.html#base-binary-sensor-configuration) этот параметр для датчика в кондиционере **всегда выставлен в true** за исключением случаев, когда пользователь не установил его в `false`. То есть по умолчанию значение сенсора не будет передаваться во фронтенд даже если указано `name` для сенсора. 230 | - Все остальные параметры [бинарного сенсора](https://esphome.io/components/binary_sensor/index.html#base-binary-sensor-configuration) ESPHome. 231 | 232 | - **defrost_state** (*Опциональный*): Параметры создаваемого датчика состояния разморозки (включена или выключена), если такой датчик нужен. Параметры аналогичны датчику дисплея **display_state**. 233 | 234 | - **inverter_power** (*Опциональный*): Параметры создаваемого датчика мощности инвертора, если такой датчик нужен. Параметры аналогичны датчику дисплея **indoor_temperature**. 235 | > **ВНИМАНИЕ!** Название параметра было изменено в версии v.0.2.9 в рамках борьбы с безграмотностью. 236 | 237 | - **inverter_power_limit_state** (*Опциональный*): Параметры создаваемого датчика состояния функции ограничения мощности. Показывает, включена данная функция в настоящий момент или нет. По очевидным причинам актуально только для инверторных кондиционеров, для "старт-стоп" кондиционеров всегда будет "выключен". Параметры аналогичны датчику дисплея **display_state**. 238 | 239 | - **inverter_power_limit_value** (*Опциональный*): Параметры создаваемого датчика текущего ограничения мощности, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше). 240 | Сенсор отображает текущее значение ограничения максимальной мощности для инверторного кондиционера. Значение в процентах. С кондиционерами "старт-стоп" по очевидным причинам не работает, всегда показывая значение `0%`. Заданное пользователем значения лимита будет отображено только после того, как кондиционер подтвердит полученное значение и начнет с ним работать. 241 | В силу ограничений на уровне железа лимит мощности может быть задан только в пределах от `30%` до `100%`. 242 | 243 | - **preset_reporter** (*Опциональный*): Параметры создаваемого текстового датчика текущего активного пресета. Параметры аналогичны датчику дисплея **display_state**. 244 | Климатические устройства ESPHome не отправляют по MQTT активный пресет (см. **supported_presets** и **custom_presets**), в котором работает устройство. Если вы используете MQTT и хотите получать информацию о пресетах, то пропишите этот датчик в конфигурации. 245 | 246 | - **vlouver_state** (*Опциональный*): Параметры создаваемого сенсора состояния вертикальных жалюзи. Параметры аналогичны датчику дисплея **display_state**. Состояние жалюзи кодируется целочисленными значениями (подробнее смотри [aux_ac.vlouver_set action](#aux_ac_._vlouver_set) ниже). 247 | 248 | - **supported_modes** (*Опциональный*, список): Список поддерживаемых режимов работы. Возможные значения: ``HEAT_COOL``, ``COOL``, ``HEAT``, ``DRY``, ``FAN_ONLY``. Обратите внимание: некоторые производители кондиционеров указывают на пульте режим AUTO, хотя по факту этот режим не работает по расписанию и только лишь поддерживает целевую температуру. Такой режим в ESPHome называется HEAT_COOL. По умолчанию список содержит только значение ``FAN_ONLY``. 249 | 250 | - **custom_fan_modes** (*Опциональный*, список): Список поддерживаемых дополнительных режимов вентилятора. Возможные значения: ``MUTE``, ``TURBO``. По умолчанию никакие дополнительные режимы не установлены. 251 | 252 | - **supported_presets** (*Опциональный*, список): Список поддерживаемых базовых функций кондиционера. Возможные значения: ``SLEEP``. По умолчанию никакие базовые функции не установлены. 253 | 254 | - **custom_presets** (*Опциональный*, список): Список поддерживаемых дополнительных функций кондиционера. Возможные значения: ``CLEAN``, ``HEALTH``, ``ANTIFUNGUS``. По умолчанию никакие дополнительные функции не установлены. 255 | 256 | - **supported_swing_modes** (*Опциональный*, список): Список поддерживаемых режимов качания шторки. Возможные значения: ``VERTICAL``, ``HORIZONTAL``, ``BOTH``. По умолчанию устанавливается, что качание шторки кондиционером не поддерживается. 257 | 258 | - Все остальные параметры [климатического устройства](https://esphome.io/components/climate/index.html#base-climate-configuration) ESPHome. 259 | 260 | ## Действия: ## 261 | ### ``aux_ac.display_on`` ### 262 | Включение экрана температуры на лицевой панели кондиционера. 263 | 264 | ```yaml 265 | on_...: 266 | then: 267 | - aux_ac.display_on: aux_id 268 | ``` 269 | - **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`. 270 | 271 | ### ``aux_ac.display_off`` ### 272 | Выключение экрана температуры на лицевой панели кондиционера. 273 | 274 | ```yaml 275 | on_...: 276 | then: 277 | - aux_ac.display_off: aux_id 278 | ``` 279 | - **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`. 280 | 281 | ### ``aux_ac.vlouver_set`` ### 282 | Переводит жалюзи в указанное состояние. 283 | 284 | Состояние кодируется следующими целочисленными значениями: 285 | - `0`: жалюзи находятся в состоянии `SWING` (качаются вверх-вниз); 286 | - `1`: жалюзи остановлены в каком-то пользовательском положении; 287 | - `2`: жалюзи установлены в верхнее положение; 288 | - `3`: жалюзи установлены в положение на шаг выше среднего; 289 | - `4`: жалюзи установлены в среднее положение; 290 | - `5`: жалюзи установлены в положение на шаг ниже среднего; 291 | - `6`: жалюзи установлены в нижнее положение. 292 | 293 | ```yaml 294 | on_...: 295 | then: 296 | - aux_ac.vlouver_set: 297 | id: aux_id 298 | position: 3 # устанавливаем жалюзи в среднее положение 299 | ``` 300 | - **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`. 301 | - **position** (**Обязательный**, целое число): состояние вертикальных жалюзи. 302 | 303 | ### ``aux_ac.vlouver_stop`` ### 304 | Остановка вертикального движения жалюзи кондиционера. Если жалюзи качались в вертикальном направлении, то можно их остановить в нужном положении. 305 | 306 | ```yaml 307 | on_...: 308 | then: 309 | - aux_ac.vlouver_stop: aux_id 310 | ``` 311 | - **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`. 312 | 313 | ### ``aux_ac.vlouver_swing`` ### 314 | Включение вертикального качания жалюзи кондиционера. 315 | 316 | ```yaml 317 | on_...: 318 | then: 319 | - aux_ac.vlouver_swing: aux_id 320 | ``` 321 | - **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`. 322 | 323 | ### ``aux_ac.vlouver_top`` ### 324 | Установка жалюзи в самое верхнее положение. 325 | 326 | ```yaml 327 | on_...: 328 | then: 329 | - aux_ac.vlouver_top: aux_id 330 | ``` 331 | - **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`. 332 | 333 | ### ``aux_ac.vlouver_middle_above`` ### 334 | Установка жалюзи во второе сверху положение. Это положение между верхним и средним. 335 | 336 | ```yaml 337 | on_...: 338 | then: 339 | - aux_ac.vlouver_middle_above: aux_id 340 | ``` 341 | - **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`. 342 | 343 | ### ``aux_ac.vlouver_middle`` ### 344 | Установка жалюзи в среднее положение. 345 | 346 | ```yaml 347 | on_...: 348 | then: 349 | - aux_ac.vlouver_middle: aux_id 350 | ``` 351 | - **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`. 352 | 353 | ### ``aux_ac.vlouver_middle_below`` ### 354 | Установка жалюзи в положение ниже среднего. 355 | 356 | ```yaml 357 | on_...: 358 | then: 359 | - aux_ac.vlouver_middle_below: aux_id 360 | ``` 361 | - **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`. 362 | 363 | ### ``aux_ac.vlouver_bottom`` ### 364 | Установка жалюзи в самое нижнее положение. 365 | 366 | ```yaml 367 | on_...: 368 | then: 369 | - aux_ac.vlouver_bottom: aux_id 370 | ``` 371 | - **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`. 372 | 373 | ### ``aux_ac.power_limit_off`` ### 374 | Отключает лимит мощности инверторного кондиционера, если такой лимит был установлен. 375 | 376 | ```yaml 377 | on_...: 378 | then: 379 | - aux_ac.power_limit_off: aux_id 380 | ``` 381 | - **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`. 382 | 383 | ### ``aux_ac.power_limit_on`` ### 384 | Включает ограничение мощности для инверторного кондиционера, а также может задавать предельное значение мощности. Для кондиционеров "старт-стоп" не работает, вызов игнорируется. 385 | 386 | ```yaml 387 | on_...: 388 | then: 389 | - aux_ac.power_limit_on: 390 | id: aux_id 391 | limit: 46 # ограничивает максимальную мощность инверторного кондиционера на уровне 46% 392 | ``` 393 | - **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`. 394 | - **limit** (**Опциональный**, целое число): задаваемое пользователем максимальное значение мощности инверторного кондиционера. 395 | При установленном лимите кондиционер не будет превышать это значение в работе. 396 | > **Обратите внимание**, что задание лимита повлияет на эффективность работы сплит-системы. Например, при низком значении лимита кондиционеру может не хватать мощности, чтобы охладить или нагреть комнату до заданной пользователем температуры. Либо время, затраченное кондиционером на нагрев или охлаждение, может вырасти. Имейте это ввиду при установке ограничений. 397 | 398 | В силу ограничений на уровне железа, лимит мощности должен быть в пределах от `30%` до `100%`. Некорректные значения будут приведены к диапазону. 399 | В случае, если включение лимита вызывается без указания параметра `limit`, то будет использовано значение по умолчанию `30%`. 400 | 401 | 402 | ## Простейший пример ## 403 | Исходный код простейшего примера можно найти в файле [aux_ac_simple.yaml](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/examples/simple/aux_ac_simple.yaml). 404 | 405 | Все настройки в нем тривиальны и подробно описаны [в официальной документации на ESPHome](https://esphome.io/index.html) и дополнены в разделе о настройке компонента выше.
406 | Просто скопируйте yaml-файл примера в локальную папку у себя на компьютере, пропишите настройки вашей сети Wi-Fi и откомпилируйте YAML с использованием ESPHome. 407 | 408 | 409 | ## Продвинутый пример ## 410 | Все исходники продвинутого примера лежат [в соответствующей папке](https://github.com/GrKoR/esphome_aux_ac_component/tree/master/examples/advanced). 411 | 412 | В этом примере мы конфигурируем два относительно одинаковых кондиционера на работу с `aux_ac`.
413 | Вводные: представим, что у нас есть два кондея, расположенных в кухне и в гостиной. Эти кондиционеры могут и не быть одного бренда. Главное, чтобы они были совместимы с `aux_ac`.
414 | Поскольку мы ленивы, мы пропишем все общие настройки обоих кондиционеров в общем конфигурационном файле `ac_common.yaml`.
415 | А все параметры, специфичные для каждого конкретного устройства, вынесем в отдельные файлы. Это файлы `ac_kitchen.yaml` и `ac_livingroom.yaml`. В них мы установим значения для подстановок `devicename` и `upper_devicename`, чтобы у устройств в сети были корректные имена самого компонента и его сенсоров. И здесь же мы указываем уникальные для каждого устройства IP-адреса, спрятанные в `secrets.yaml`.
416 | Кстати да! **Не забудьте** присвоить корректные значения `wifi_ip_kitchen`, `wifi_ota_ip_kitchen`, `wifi_ip_livingroom` и `wifi_ota_ip_livingroom` в файле `secrets.yaml` наряду с остальной "секретной" информацией (например пароли, токены и т.п.). Файл `secrets.yaml` по понятным причинам на гитхаб не выложен. 417 | 418 | Если попытаться компилировать файл `ac_common.yaml`, то ESPHome выдаст ошибку. Для корректной прошивки необходимо компилировать `ac_kitchen.yaml` или `ac_livingroom.yaml`. 419 | -------------------------------------------------------------------------------- /components/aux_ac/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/components/aux_ac/__init__.py -------------------------------------------------------------------------------- /components/aux_ac/automation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "aux_ac.h" 4 | #include "esphome/core/automation.h" 5 | #include "esphome/core/component.h" 6 | 7 | namespace esphome { 8 | namespace aux_ac { 9 | 10 | // **************************************** DISPLAY ACTIONS **************************************** 11 | template 12 | class AirConDisplayOffAction : public Action { 13 | public: 14 | explicit AirConDisplayOffAction(AirCon *ac) : ac_(ac) {} 15 | 16 | void play(Ts... x) override { this->ac_->displayOffSequence(); } 17 | 18 | protected: 19 | AirCon *ac_; 20 | }; 21 | 22 | template 23 | class AirConDisplayOnAction : public Action { 24 | public: 25 | explicit AirConDisplayOnAction(AirCon *ac) : ac_(ac) {} 26 | 27 | void play(Ts... x) override { this->ac_->displayOnSequence(); } 28 | 29 | protected: 30 | AirCon *ac_; 31 | }; 32 | 33 | // **************************************** VERTICAL LOUVER ACTIONS **************************************** 34 | template 35 | class AirConVLouverSwingAction : public Action { 36 | public: 37 | explicit AirConVLouverSwingAction(AirCon *ac) : ac_(ac) {} 38 | 39 | void play(Ts... x) override { this->ac_->setVLouverSwingSequence(); } 40 | 41 | protected: 42 | AirCon *ac_; 43 | }; 44 | 45 | template 46 | class AirConVLouverStopAction : public Action { 47 | public: 48 | explicit AirConVLouverStopAction(AirCon *ac) : ac_(ac) {} 49 | 50 | void play(Ts... x) override { this->ac_->setVLouverStopSequence(); } 51 | 52 | protected: 53 | AirCon *ac_; 54 | }; 55 | 56 | template 57 | class AirConVLouverTopAction : public Action { 58 | public: 59 | explicit AirConVLouverTopAction(AirCon *ac) : ac_(ac) {} 60 | 61 | void play(Ts... x) override { this->ac_->setVLouverTopSequence(); } 62 | 63 | protected: 64 | AirCon *ac_; 65 | }; 66 | 67 | template 68 | class AirConVLouverMiddleAboveAction : public Action { 69 | public: 70 | explicit AirConVLouverMiddleAboveAction(AirCon *ac) : ac_(ac) {} 71 | 72 | void play(Ts... x) override { this->ac_->setVLouverMiddleAboveSequence(); } 73 | 74 | protected: 75 | AirCon *ac_; 76 | }; 77 | 78 | template 79 | class AirConVLouverMiddleAction : public Action { 80 | public: 81 | explicit AirConVLouverMiddleAction(AirCon *ac) : ac_(ac) {} 82 | 83 | void play(Ts... x) override { this->ac_->setVLouverMiddleSequence(); } 84 | 85 | protected: 86 | AirCon *ac_; 87 | }; 88 | 89 | template 90 | class AirConVLouverMiddleBelowAction : public Action { 91 | public: 92 | explicit AirConVLouverMiddleBelowAction(AirCon *ac) : ac_(ac) {} 93 | 94 | void play(Ts... x) override { this->ac_->setVLouverMiddleBelowSequence(); } 95 | 96 | protected: 97 | AirCon *ac_; 98 | }; 99 | 100 | template 101 | class AirConVLouverBottomAction : public Action { 102 | public: 103 | explicit AirConVLouverBottomAction(AirCon *ac) : ac_(ac) {} 104 | 105 | void play(Ts... x) override { this->ac_->setVLouverBottomSequence(); } 106 | 107 | protected: 108 | AirCon *ac_; 109 | }; 110 | 111 | template 112 | class AirConVLouverSetAction : public Action { 113 | public: 114 | AirConVLouverSetAction(AirCon *ac) : ac_(ac) {} 115 | TEMPLATABLE_VALUE(uint8_t, value); 116 | 117 | void play(Ts... x) { 118 | vlpos_ = this->value_.value(x...); 119 | this->ac_->setVLouverFrontendSequence((ac_vlouver_frontend)vlpos_); 120 | } 121 | 122 | protected: 123 | AirCon *ac_; 124 | uint8_t vlpos_; 125 | }; 126 | 127 | // **************************************** SEND TEST PACKET ACTION **************************************** 128 | template 129 | class AirConSendTestPacketAction : public Action { 130 | public: 131 | explicit AirConSendTestPacketAction(AirCon *ac) : ac_(ac) {} 132 | void set_data_template(std::function(Ts...)> func) { 133 | this->data_func_ = func; 134 | this->static_ = false; 135 | } 136 | void set_data_static(const std::vector &data) { 137 | this->data_static_ = data; 138 | this->static_ = true; 139 | } 140 | 141 | void play(Ts... x) override { 142 | if (this->static_) { 143 | this->ac_->sendTestPacket(this->data_static_); 144 | } else { 145 | auto val = this->data_func_(x...); 146 | this->ac_->sendTestPacket(val); 147 | } 148 | } 149 | 150 | protected: 151 | AirCon *ac_; 152 | bool static_{false}; 153 | std::function(Ts...)> data_func_{}; 154 | std::vector data_static_{}; 155 | }; 156 | 157 | // **************************************** POWER LIMITATION ACTIONS **************************************** 158 | template 159 | class AirConPowerLimitationOffAction : public Action { 160 | public: 161 | explicit AirConPowerLimitationOffAction(AirCon *ac) : ac_(ac) {} 162 | 163 | void play(Ts... x) override { this->ac_->powerLimitationOffSequence(); } 164 | 165 | protected: 166 | AirCon *ac_; 167 | }; 168 | 169 | template 170 | class AirConPowerLimitationOnAction : public Action { 171 | public: 172 | AirConPowerLimitationOnAction(AirCon *ac) : ac_(ac) {} 173 | TEMPLATABLE_VALUE(uint8_t, value); 174 | 175 | void play(Ts... x) { 176 | this->pwr_lim_ = this->value_.value(x...); 177 | this->ac_->powerLimitationOnSequence(this->pwr_lim_); 178 | } 179 | 180 | protected: 181 | AirCon *ac_; 182 | uint8_t pwr_lim_; 183 | }; 184 | 185 | } // namespace aux_ac 186 | } // namespace esphome -------------------------------------------------------------------------------- /components/aux_ac/climate.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from esphome.core import CORE, Define 3 | import esphome.config_validation as cv 4 | import esphome.codegen as cg 5 | from esphome.components import climate, uart, sensor, binary_sensor, text_sensor 6 | from esphome import automation 7 | from esphome.automation import maybe_simple_id 8 | from esphome.const import ( 9 | CONF_CUSTOM_FAN_MODES, 10 | CONF_CUSTOM_PRESETS, 11 | CONF_DATA, 12 | CONF_ID, 13 | CONF_INTERNAL, 14 | CONF_OPTIMISTIC, 15 | CONF_PERIOD, 16 | CONF_POSITION, 17 | CONF_SUPPORTED_MODES, 18 | CONF_SUPPORTED_SWING_MODES, 19 | CONF_SUPPORTED_PRESETS, 20 | CONF_TIMEOUT, 21 | CONF_UART_ID, 22 | UNIT_CELSIUS, 23 | UNIT_PERCENT, 24 | ICON_POWER, 25 | ICON_THERMOMETER, 26 | DEVICE_CLASS_TEMPERATURE, 27 | DEVICE_CLASS_POWER_FACTOR, 28 | STATE_CLASS_MEASUREMENT, 29 | ) 30 | from esphome.components.climate import ( 31 | ClimateMode, 32 | ClimatePreset, 33 | ClimateSwingMode, 34 | ) 35 | 36 | AUX_AC_FIRMWARE_VERSION = '0.2.15' 37 | AC_PACKET_TIMEOUT_MIN = 150 38 | AC_PACKET_TIMEOUT_MAX = 600 39 | AC_POWER_LIMIT_MIN = 30 40 | AC_POWER_LIMIT_MAX = 100 41 | 42 | _LOGGER = logging.getLogger(__name__) 43 | 44 | CODEOWNERS = ["@GrKoR"] 45 | DEPENDENCIES = ["climate", "uart"] 46 | AUTO_LOAD = ["sensor", "binary_sensor", "text_sensor"] 47 | 48 | CONF_SHOW_ACTION = "show_action" 49 | 50 | CONF_INDOOR_TEMPERATURE = "indoor_temperature" 51 | CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature" 52 | ICON_OUTDOOR_TEMPERATURE = "mdi:home-thermometer-outline" 53 | 54 | CONF_INBOUND_TEMPERATURE = "inbound_temperature" 55 | ICON_INBOUND_TEMPERATURE = "mdi:thermometer-plus" 56 | 57 | CONF_OUTBOUND_TEMPERATURE = "outbound_temperature" 58 | ICON_OUTBOUND_TEMPERATURE = "mdi:thermometer-minus" 59 | 60 | CONF_COMPRESSOR_TEMPERATURE = "compressor_temperature" 61 | ICON_COMPRESSOR_TEMPERATURE = "mdi:thermometer-lines" 62 | 63 | CONF_DISPLAY_STATE = "display_state" 64 | CONF_INVERTER_POWER = "inverter_power" 65 | CONF_INVERTER_POWER_DEPRICATED = "invertor_power" 66 | 67 | CONF_DEFROST_STATE = "defrost_state" 68 | ICON_DEFROST = "mdi:snowflake-melt" 69 | 70 | CONF_DISPLAY_INVERTED = "display_inverted" 71 | ICON_DISPLAY = "mdi:clock-digital" 72 | 73 | CONF_PRESET_REPORTER = "preset_reporter" 74 | ICON_PRESET_REPORTER = "mdi:format-list-group" 75 | 76 | CONF_VLOUVER_STATE = "vlouver_state" 77 | ICON_VLOUVER_STATE = "mdi:compare-vertical" 78 | 79 | CONF_LIMIT = "limit" 80 | CONF_INVERTER_POWER_LIMIT_VALUE = "inverter_power_limit_value" 81 | ICON_INVERTER_POWER_LIMIT_VALUE = "mdi:meter-electric-outline" 82 | CONF_INVERTER_POWER_LIMIT_STATE = "inverter_power_limit_state" 83 | ICON_INVERTER_POWER_LIMIT_STATE = "mdi:meter-electric-outline" 84 | 85 | 86 | aux_ac_ns = cg.esphome_ns.namespace("aux_ac") 87 | AirCon = aux_ac_ns.class_("AirCon", climate.Climate, cg.Component) 88 | Capabilities = aux_ac_ns.namespace("Constants") 89 | 90 | # Display actions 91 | AirConDisplayOffAction = aux_ac_ns.class_("AirConDisplayOffAction", automation.Action) 92 | AirConDisplayOnAction = aux_ac_ns.class_("AirConDisplayOnAction", automation.Action) 93 | 94 | # test packet action 95 | AirConSendTestPacketAction = aux_ac_ns.class_( 96 | "AirConSendTestPacketAction", automation.Action 97 | ) 98 | 99 | # vertical louvers actions 100 | AirConVLouverSwingAction = aux_ac_ns.class_( 101 | "AirConVLouverSwingAction", automation.Action 102 | ) 103 | AirConVLouverStopAction = aux_ac_ns.class_("AirConVLouverStopAction", automation.Action) 104 | AirConVLouverTopAction = aux_ac_ns.class_("AirConVLouverTopAction", automation.Action) 105 | AirConVLouverMiddleAboveAction = aux_ac_ns.class_( 106 | "AirConVLouverMiddleAboveAction", automation.Action 107 | ) 108 | AirConVLouverMiddleAction = aux_ac_ns.class_( 109 | "AirConVLouverMiddleAction", automation.Action 110 | ) 111 | AirConVLouverMiddleBelowAction = aux_ac_ns.class_( 112 | "AirConVLouverMiddleBelowAction", automation.Action 113 | ) 114 | AirConVLouverBottomAction = aux_ac_ns.class_( 115 | "AirConVLouverBottomAction", automation.Action 116 | ) 117 | AirConVLouverSetAction = aux_ac_ns.class_( 118 | "AirConVLouverSetAction", automation.Action 119 | ) 120 | 121 | # power limitation actions 122 | AirConPowerLimitationOffAction = aux_ac_ns.class_( 123 | "AirConPowerLimitationOffAction", automation.Action 124 | ) 125 | AirConPowerLimitationOnAction = aux_ac_ns.class_( 126 | "AirConPowerLimitationOnAction", automation.Action 127 | ) 128 | 129 | 130 | def validate_packet_timeout(value): 131 | minV = AC_PACKET_TIMEOUT_MIN 132 | maxV = AC_PACKET_TIMEOUT_MAX 133 | if value in range(minV, maxV+1): 134 | return cv.Schema(cv.uint32_t)(value) 135 | raise cv.Invalid(f"Timeout should be in range: {minV}..{maxV}.") 136 | 137 | 138 | def validate_power_limit_range(value): 139 | minV = AC_POWER_LIMIT_MIN 140 | maxV = AC_POWER_LIMIT_MAX 141 | if value in range(minV, maxV+1): 142 | return cv.Schema(cv.uint32_t)(value) 143 | raise cv.Invalid(f"Power limit should be in range: {minV}..{maxV}") 144 | 145 | 146 | ALLOWED_CLIMATE_MODES = { 147 | "HEAT_COOL": ClimateMode.CLIMATE_MODE_HEAT_COOL, 148 | "COOL": ClimateMode.CLIMATE_MODE_COOL, 149 | "HEAT": ClimateMode.CLIMATE_MODE_HEAT, 150 | "DRY": ClimateMode.CLIMATE_MODE_DRY, 151 | "FAN_ONLY": ClimateMode.CLIMATE_MODE_FAN_ONLY, 152 | } 153 | validate_modes = cv.enum(ALLOWED_CLIMATE_MODES, upper=True) 154 | 155 | ALLOWED_CLIMATE_PRESETS = { 156 | "SLEEP": ClimatePreset.CLIMATE_PRESET_SLEEP, 157 | } 158 | validate_presets = cv.enum(ALLOWED_CLIMATE_PRESETS, upper=True) 159 | 160 | ALLOWED_CLIMATE_SWING_MODES = { 161 | "BOTH": ClimateSwingMode.CLIMATE_SWING_BOTH, 162 | "VERTICAL": ClimateSwingMode.CLIMATE_SWING_VERTICAL, 163 | "HORIZONTAL": ClimateSwingMode.CLIMATE_SWING_HORIZONTAL, 164 | } 165 | validate_swing_modes = cv.enum(ALLOWED_CLIMATE_SWING_MODES, upper=True) 166 | 167 | CUSTOM_FAN_MODES = { 168 | "MUTE": Capabilities.MUTE, 169 | "TURBO": Capabilities.TURBO, 170 | } 171 | validate_custom_fan_modes = cv.enum(CUSTOM_FAN_MODES, upper=True) 172 | 173 | CUSTOM_PRESETS = { 174 | "CLEAN": Capabilities.CLEAN, 175 | "HEALTH": Capabilities.HEALTH, 176 | "ANTIFUNGUS": Capabilities.ANTIFUNGUS, 177 | } 178 | validate_custom_presets = cv.enum(CUSTOM_PRESETS, upper=True) 179 | 180 | 181 | def validate_raw_data(value): 182 | if isinstance(value, list): 183 | return cv.Schema([cv.hex_uint8_t])(value) 184 | raise cv.Invalid("data must be a list of bytes") 185 | 186 | 187 | def output_info(config): 188 | _LOGGER.info("AUX_AC firmware version: %s", AUX_AC_FIRMWARE_VERSION) 189 | return config 190 | 191 | 192 | CONFIG_SCHEMA = cv.All( 193 | climate.CLIMATE_SCHEMA.extend( 194 | { 195 | cv.GenerateID(): cv.declare_id(AirCon), 196 | cv.Optional(CONF_PERIOD, default="7s"): cv.time_period, 197 | cv.Optional(CONF_SHOW_ACTION, default="true"): cv.boolean, 198 | cv.Optional(CONF_DISPLAY_INVERTED, default="false"): cv.boolean, 199 | cv.Optional(CONF_TIMEOUT, default=AC_PACKET_TIMEOUT_MIN): validate_packet_timeout, 200 | cv.Optional(CONF_OPTIMISTIC, default="true"): cv.boolean, 201 | cv.Optional(CONF_INVERTER_POWER_DEPRICATED): cv.invalid( 202 | "The name of sensor was changed in v.0.2.9 from 'invertor_power' to 'inverter_power'. Update your config please." 203 | ), 204 | cv.Optional(CONF_INVERTER_POWER): sensor.sensor_schema( 205 | unit_of_measurement=UNIT_PERCENT, 206 | icon=ICON_POWER, 207 | accuracy_decimals=0, 208 | device_class=DEVICE_CLASS_POWER_FACTOR, 209 | state_class=STATE_CLASS_MEASUREMENT, 210 | ).extend( 211 | { 212 | cv.Optional(CONF_INTERNAL, default="true"): cv.boolean, 213 | } 214 | ), 215 | 216 | cv.Optional(CONF_INDOOR_TEMPERATURE): sensor.sensor_schema( 217 | unit_of_measurement=UNIT_CELSIUS, 218 | icon=ICON_THERMOMETER, 219 | accuracy_decimals=1, 220 | device_class=DEVICE_CLASS_TEMPERATURE, 221 | state_class=STATE_CLASS_MEASUREMENT, 222 | ).extend( 223 | { 224 | cv.Optional(CONF_INTERNAL, default="true"): cv.boolean, 225 | } 226 | ), 227 | cv.Optional(CONF_OUTDOOR_TEMPERATURE): sensor.sensor_schema( 228 | unit_of_measurement=UNIT_CELSIUS, 229 | icon=ICON_OUTDOOR_TEMPERATURE, 230 | accuracy_decimals=0, 231 | device_class=DEVICE_CLASS_TEMPERATURE, 232 | state_class=STATE_CLASS_MEASUREMENT, 233 | ).extend( 234 | { 235 | cv.Optional(CONF_INTERNAL, default="true"): cv.boolean, 236 | } 237 | ), 238 | cv.Optional(CONF_INBOUND_TEMPERATURE): sensor.sensor_schema( 239 | unit_of_measurement=UNIT_CELSIUS, 240 | icon=ICON_INBOUND_TEMPERATURE, 241 | accuracy_decimals=0, 242 | device_class=DEVICE_CLASS_TEMPERATURE, 243 | state_class=STATE_CLASS_MEASUREMENT, 244 | ).extend( 245 | { 246 | cv.Optional(CONF_INTERNAL, default="true"): cv.boolean, 247 | } 248 | ), 249 | cv.Optional(CONF_OUTBOUND_TEMPERATURE): sensor.sensor_schema( 250 | unit_of_measurement=UNIT_CELSIUS, 251 | icon=ICON_OUTBOUND_TEMPERATURE, 252 | accuracy_decimals=0, 253 | device_class=DEVICE_CLASS_TEMPERATURE, 254 | state_class=STATE_CLASS_MEASUREMENT, 255 | ).extend( 256 | { 257 | cv.Optional(CONF_INTERNAL, default="true"): cv.boolean, 258 | } 259 | ), 260 | cv.Optional(CONF_COMPRESSOR_TEMPERATURE): sensor.sensor_schema( 261 | unit_of_measurement=UNIT_CELSIUS, 262 | icon=ICON_COMPRESSOR_TEMPERATURE, 263 | accuracy_decimals=0, 264 | device_class=DEVICE_CLASS_TEMPERATURE, 265 | state_class=STATE_CLASS_MEASUREMENT, 266 | ).extend( 267 | { 268 | cv.Optional(CONF_INTERNAL, default="true"): cv.boolean, 269 | } 270 | ), 271 | cv.Optional(CONF_VLOUVER_STATE): sensor.sensor_schema( 272 | icon=ICON_VLOUVER_STATE, 273 | accuracy_decimals=0, 274 | ).extend( 275 | { 276 | cv.Optional(CONF_INTERNAL, default="true"): cv.boolean, 277 | } 278 | ), 279 | cv.Optional(CONF_DISPLAY_STATE): binary_sensor.binary_sensor_schema( 280 | icon=ICON_DISPLAY, 281 | ).extend( 282 | { 283 | cv.Optional(CONF_INTERNAL, default="true"): cv.boolean, 284 | } 285 | ), 286 | cv.Optional(CONF_DEFROST_STATE): binary_sensor.binary_sensor_schema( 287 | icon=ICON_DEFROST, 288 | ).extend( 289 | { 290 | cv.Optional(CONF_INTERNAL, default="true"): cv.boolean, 291 | } 292 | ), 293 | cv.Optional(CONF_PRESET_REPORTER): text_sensor.text_sensor_schema( 294 | icon=ICON_PRESET_REPORTER, 295 | ).extend( 296 | { 297 | cv.Optional(CONF_INTERNAL, default="true"): cv.boolean, 298 | } 299 | ), 300 | cv.Optional(CONF_INVERTER_POWER_LIMIT_VALUE): sensor.sensor_schema( 301 | unit_of_measurement=UNIT_PERCENT, 302 | icon=ICON_INVERTER_POWER_LIMIT_VALUE, 303 | accuracy_decimals=0, 304 | device_class=DEVICE_CLASS_POWER_FACTOR, 305 | state_class=STATE_CLASS_MEASUREMENT, 306 | ).extend( 307 | { 308 | cv.Optional(CONF_INTERNAL, default="true"): cv.boolean, 309 | } 310 | ), 311 | cv.Optional(CONF_INVERTER_POWER_LIMIT_STATE): binary_sensor.binary_sensor_schema( 312 | icon=ICON_INVERTER_POWER_LIMIT_STATE, 313 | ).extend( 314 | { 315 | cv.Optional(CONF_INTERNAL, default="true"): cv.boolean, 316 | } 317 | ), 318 | cv.Optional(CONF_SUPPORTED_MODES): cv.ensure_list(validate_modes), 319 | cv.Optional(CONF_SUPPORTED_SWING_MODES): cv.ensure_list( 320 | validate_swing_modes 321 | ), 322 | cv.Optional(CONF_SUPPORTED_PRESETS): cv.ensure_list(validate_presets), 323 | cv.Optional(CONF_CUSTOM_PRESETS): cv.ensure_list(validate_custom_presets), 324 | cv.Optional(CONF_CUSTOM_FAN_MODES): cv.ensure_list( 325 | validate_custom_fan_modes 326 | ), 327 | } 328 | ) 329 | .extend(uart.UART_DEVICE_SCHEMA) 330 | .extend(cv.COMPONENT_SCHEMA), 331 | output_info, 332 | ) 333 | 334 | 335 | async def to_code(config): 336 | CORE.add_define( 337 | Define("AUX_AC_FIRMWARE_VERSION", '"'+AUX_AC_FIRMWARE_VERSION+'"') 338 | ) 339 | CORE.add_define( 340 | Define("AUX_AC_PACKET_TIMEOUT_MIN", AC_PACKET_TIMEOUT_MIN) 341 | ) 342 | CORE.add_define( 343 | Define("AUX_AC_PACKET_TIMEOUT_MAX", AC_PACKET_TIMEOUT_MAX) 344 | ) 345 | CORE.add_define( 346 | Define("AUX_AC_MIN_INVERTER_POWER_LIMIT", AC_POWER_LIMIT_MIN) 347 | ) 348 | CORE.add_define( 349 | Define("AUX_AC_MAX_INVERTER_POWER_LIMIT", AC_POWER_LIMIT_MAX) 350 | ) 351 | var = cg.new_Pvariable(config[CONF_ID]) 352 | await cg.register_component(var, config) 353 | await climate.register_climate(var, config) 354 | 355 | parent = await cg.get_variable(config[CONF_UART_ID]) 356 | cg.add(var.initAC(parent)) 357 | 358 | if CONF_INDOOR_TEMPERATURE in config: 359 | conf = config[CONF_INDOOR_TEMPERATURE] 360 | sens = await sensor.new_sensor(conf) 361 | cg.add(var.set_indoor_temperature_sensor(sens)) 362 | 363 | if CONF_OUTDOOR_TEMPERATURE in config: 364 | conf = config[CONF_OUTDOOR_TEMPERATURE] 365 | sens = await sensor.new_sensor(conf) 366 | cg.add(var.set_outdoor_temperature_sensor(sens)) 367 | 368 | if CONF_OUTBOUND_TEMPERATURE in config: 369 | conf = config[CONF_OUTBOUND_TEMPERATURE] 370 | sens = await sensor.new_sensor(conf) 371 | cg.add(var.set_outbound_temperature_sensor(sens)) 372 | 373 | if CONF_INBOUND_TEMPERATURE in config: 374 | conf = config[CONF_INBOUND_TEMPERATURE] 375 | sens = await sensor.new_sensor(conf) 376 | cg.add(var.set_inbound_temperature_sensor(sens)) 377 | 378 | if CONF_COMPRESSOR_TEMPERATURE in config: 379 | conf = config[CONF_COMPRESSOR_TEMPERATURE] 380 | sens = await sensor.new_sensor(conf) 381 | cg.add(var.set_compressor_temperature_sensor(sens)) 382 | 383 | if CONF_VLOUVER_STATE in config: 384 | conf = config[CONF_VLOUVER_STATE] 385 | sens = await sensor.new_sensor(conf) 386 | cg.add(var.set_vlouver_state_sensor(sens)) 387 | 388 | if CONF_DISPLAY_STATE in config: 389 | conf = config[CONF_DISPLAY_STATE] 390 | sens = await binary_sensor.new_binary_sensor(conf) 391 | cg.add(var.set_display_sensor(sens)) 392 | 393 | if CONF_DEFROST_STATE in config: 394 | conf = config[CONF_DEFROST_STATE] 395 | sens = await binary_sensor.new_binary_sensor(conf) 396 | cg.add(var.set_defrost_state(sens)) 397 | 398 | if CONF_INVERTER_POWER in config: 399 | conf = config[CONF_INVERTER_POWER] 400 | sens = await sensor.new_sensor(conf) 401 | cg.add(var.set_inverter_power_sensor(sens)) 402 | 403 | if CONF_PRESET_REPORTER in config: 404 | conf = config[CONF_PRESET_REPORTER] 405 | sens = await text_sensor.new_text_sensor(conf) 406 | cg.add(var.set_preset_reporter_sensor(sens)) 407 | 408 | if CONF_INVERTER_POWER_LIMIT_VALUE in config: 409 | conf = config[CONF_INVERTER_POWER_LIMIT_VALUE] 410 | sens = await sensor.new_sensor(conf) 411 | cg.add(var.set_inverter_power_limit_value_sensor(sens)) 412 | 413 | if CONF_INVERTER_POWER_LIMIT_STATE in config: 414 | conf = config[CONF_INVERTER_POWER_LIMIT_STATE] 415 | sens = await binary_sensor.new_binary_sensor(conf) 416 | cg.add(var.set_inverter_power_limit_state_sensor(sens)) 417 | 418 | cg.add(var.set_period(config[CONF_PERIOD].total_milliseconds)) 419 | cg.add(var.set_show_action(config[CONF_SHOW_ACTION])) 420 | cg.add(var.set_display_inverted(config[CONF_DISPLAY_INVERTED])) 421 | cg.add(var.set_packet_timeout(config[CONF_TIMEOUT])) 422 | cg.add(var.set_optimistic(config[CONF_OPTIMISTIC])) 423 | if CONF_SUPPORTED_MODES in config: 424 | cg.add(var.set_supported_modes(config[CONF_SUPPORTED_MODES])) 425 | if CONF_SUPPORTED_SWING_MODES in config: 426 | cg.add(var.set_supported_swing_modes(config[CONF_SUPPORTED_SWING_MODES])) 427 | if CONF_SUPPORTED_PRESETS in config: 428 | cg.add(var.set_supported_presets(config[CONF_SUPPORTED_PRESETS])) 429 | if CONF_CUSTOM_PRESETS in config: 430 | cg.add(var.set_custom_presets(config[CONF_CUSTOM_PRESETS])) 431 | if CONF_CUSTOM_FAN_MODES in config: 432 | cg.add(var.set_custom_fan_modes(config[CONF_CUSTOM_FAN_MODES])) 433 | 434 | 435 | DISPLAY_ACTION_SCHEMA = maybe_simple_id( 436 | { 437 | cv.Required(CONF_ID): cv.use_id(AirCon), 438 | } 439 | ) 440 | 441 | 442 | @automation.register_action( 443 | "aux_ac.display_off", AirConDisplayOffAction, DISPLAY_ACTION_SCHEMA 444 | ) 445 | async def display_off_to_code(config, action_id, template_arg, args): 446 | paren = await cg.get_variable(config[CONF_ID]) 447 | return cg.new_Pvariable(action_id, template_arg, paren) 448 | 449 | 450 | @automation.register_action( 451 | "aux_ac.display_on", AirConDisplayOnAction, DISPLAY_ACTION_SCHEMA 452 | ) 453 | async def display_on_to_code(config, action_id, template_arg, args): 454 | paren = await cg.get_variable(config[CONF_ID]) 455 | return cg.new_Pvariable(action_id, template_arg, paren) 456 | 457 | 458 | VLOUVER_ACTION_SCHEMA = maybe_simple_id( 459 | { 460 | cv.Required(CONF_ID): cv.use_id(AirCon), 461 | } 462 | ) 463 | 464 | 465 | @automation.register_action( 466 | "aux_ac.vlouver_stop", AirConVLouverStopAction, VLOUVER_ACTION_SCHEMA 467 | ) 468 | async def vlouver_stop_to_code(config, action_id, template_arg, args): 469 | paren = await cg.get_variable(config[CONF_ID]) 470 | return cg.new_Pvariable(action_id, template_arg, paren) 471 | 472 | 473 | @automation.register_action( 474 | "aux_ac.vlouver_swing", AirConVLouverSwingAction, VLOUVER_ACTION_SCHEMA 475 | ) 476 | async def vlouver_swing_to_code(config, action_id, template_arg, args): 477 | paren = await cg.get_variable(config[CONF_ID]) 478 | return cg.new_Pvariable(action_id, template_arg, paren) 479 | 480 | 481 | @automation.register_action( 482 | "aux_ac.vlouver_top", AirConVLouverTopAction, VLOUVER_ACTION_SCHEMA 483 | ) 484 | async def vlouver_top_to_code(config, action_id, template_arg, args): 485 | paren = await cg.get_variable(config[CONF_ID]) 486 | return cg.new_Pvariable(action_id, template_arg, paren) 487 | 488 | 489 | @automation.register_action( 490 | "aux_ac.vlouver_middle_above", AirConVLouverMiddleAboveAction, VLOUVER_ACTION_SCHEMA 491 | ) 492 | async def vlouver_middle_above_to_code(config, action_id, template_arg, args): 493 | paren = await cg.get_variable(config[CONF_ID]) 494 | return cg.new_Pvariable(action_id, template_arg, paren) 495 | 496 | 497 | @automation.register_action( 498 | "aux_ac.vlouver_middle", AirConVLouverMiddleAction, VLOUVER_ACTION_SCHEMA 499 | ) 500 | async def vlouver_middle_to_code(config, action_id, template_arg, args): 501 | paren = await cg.get_variable(config[CONF_ID]) 502 | return cg.new_Pvariable(action_id, template_arg, paren) 503 | 504 | 505 | @automation.register_action( 506 | "aux_ac.vlouver_middle_below", AirConVLouverMiddleBelowAction, VLOUVER_ACTION_SCHEMA 507 | ) 508 | async def vlouver_middle_below_to_code(config, action_id, template_arg, args): 509 | paren = await cg.get_variable(config[CONF_ID]) 510 | return cg.new_Pvariable(action_id, template_arg, paren) 511 | 512 | 513 | @automation.register_action( 514 | "aux_ac.vlouver_bottom", AirConVLouverBottomAction, VLOUVER_ACTION_SCHEMA 515 | ) 516 | async def vlouver_bottom_to_code(config, action_id, template_arg, args): 517 | paren = await cg.get_variable(config[CONF_ID]) 518 | return cg.new_Pvariable(action_id, template_arg, paren) 519 | 520 | 521 | VLOUVER_SET_ACTION_SCHEMA = cv.Schema( 522 | { 523 | cv.Required(CONF_ID): cv.use_id(AirCon), 524 | cv.Required(CONF_POSITION): cv.templatable(cv.int_range(0, 6)), 525 | } 526 | ) 527 | 528 | 529 | @automation.register_action( 530 | "aux_ac.vlouver_set", AirConVLouverSetAction, VLOUVER_SET_ACTION_SCHEMA 531 | ) 532 | async def vlouver_set_to_code(config, action_id, template_arg, args): 533 | paren = await cg.get_variable(config[CONF_ID]) 534 | var = cg.new_Pvariable(action_id, template_arg, paren) 535 | template_ = await cg.templatable(config[CONF_POSITION], args, int) 536 | cg.add(var.set_value(template_)) 537 | return var 538 | 539 | 540 | POWER_LIMITATION_OFF_ACTION_SCHEMA = maybe_simple_id( 541 | { 542 | cv.Required(CONF_ID): cv.use_id(AirCon), 543 | } 544 | ) 545 | 546 | 547 | @automation.register_action( 548 | "aux_ac.power_limit_off", AirConPowerLimitationOffAction, POWER_LIMITATION_OFF_ACTION_SCHEMA 549 | ) 550 | async def power_limit_off_to_code(config, action_id, template_arg, args): 551 | paren = await cg.get_variable(config[CONF_ID]) 552 | return cg.new_Pvariable(action_id, template_arg, paren) 553 | 554 | 555 | POWER_LIMITATION_ON_ACTION_SCHEMA = cv.Schema( 556 | { 557 | cv.Required(CONF_ID): cv.use_id(AirCon), 558 | cv.Optional(CONF_LIMIT, default=AC_POWER_LIMIT_MIN): validate_power_limit_range, 559 | } 560 | ) 561 | 562 | 563 | @automation.register_action( 564 | "aux_ac.power_limit_on", AirConPowerLimitationOnAction, POWER_LIMITATION_ON_ACTION_SCHEMA 565 | ) 566 | async def power_limit_on_to_code(config, action_id, template_arg, args): 567 | paren = await cg.get_variable(config[CONF_ID]) 568 | var = cg.new_Pvariable(action_id, template_arg, paren) 569 | template_ = await cg.templatable(config[CONF_LIMIT], args, int) 570 | cg.add(var.set_value(template_)) 571 | return var 572 | 573 | 574 | # ********************************************************************************************************* 575 | # ВАЖНО! Только для инженеров! 576 | # Вызывайте метод aux_ac.send_packet только если понимаете, что делаете! Он не проверяет данные, а передаёт 577 | # кондиционеру всё как есть. Какой эффект получится от передачи кондиционеру рандомных байт, никто не знает. 578 | # Вы действуете на свой страх и риск. 579 | # ********************************************************************************************************* 580 | SEND_TEST_PACKET_ACTION_SCHEMA = maybe_simple_id( 581 | { 582 | cv.Required(CONF_ID): cv.use_id(AirCon), 583 | cv.Required(CONF_DATA): cv.templatable(validate_raw_data), 584 | } 585 | ) 586 | 587 | 588 | @automation.register_action( 589 | "aux_ac.send_packet", AirConSendTestPacketAction, SEND_TEST_PACKET_ACTION_SCHEMA 590 | ) 591 | async def send_packet_to_code(config, action_id, template_arg, args): 592 | paren = await cg.get_variable(config[CONF_ID]) 593 | var = cg.new_Pvariable(action_id, template_arg, paren) 594 | 595 | data = config[CONF_DATA] 596 | if isinstance(data, bytes): 597 | data = list(data) 598 | 599 | if cg.is_template(data): 600 | templ = await cg.templatable(data, args, cg.std_vector.template(cg.uint8)) 601 | cg.add(var.set_data_template(templ)) 602 | else: 603 | cg.add(var.set_data_static(data)) 604 | 605 | return var 606 | -------------------------------------------------------------------------------- /docs/AC_TESTED.md: -------------------------------------------------------------------------------- 1 | ## Tested and compatible air conditioners ## 2 | `Aux_ac` has been tested and works successfully with the air conditioners from the list below.
3 | Кондиционеры из списка ниже протестированы и точно совместимы с `aux_ac`. 4 | 5 | + ANDE (models: AND-12/FA+) 6 | + Argo (models: Greenstyle 9000, Greenstyle 12000, Greenstyle 18000) 7 | + AUX (models: ALMD-H48/5DR2 / AL-H48/5DR2(U), AMWM-H07/4R1 multisplit, AMWM-H07/4R2(J) multisplit, AMWM-H12/4R2(J) multisplit, AMWM-H12/4R3 multisplit, ASM-H12LL, ASM-H24LD, ASW-H07A4/DE-R1DI, ASW-H07A4/FP-R1DI, ASW-H07A4/JD-R1, ASW-H09A4/FP-R1DI, ASW-H09A4/LK-700R1, ASW-H09A4/LK-700R1DI, ASW-H09B4/LK-700R1, ASW-H09B7A4, ASW-H12A4/FAR1, ASW-H12A4/HA-R2DI, ASW-H12A4/JD-R2DI, ASW-H12B4/JD-R2DI, ASW-H12C5C4/JER3DI-B8-2, ASW-H12C5C4/JOR3DI-B8, ASW-H12U3/JIR1DI-US, ASW-H18A4/QH-R1DI / AS-H18A4/QH-R1DI, AUX-07JO/I / AUX-M3-21LCLH multisplit, AUX-12JO/I / AUX-M3-21LCLHmultisplit, AUX-18QC/I / AUX-18QC/O, AWM-09G1V4-X, HA-18000BTU, KFR-26GW/BpHRB+3, KFR-26GW/BpQYA2+2R3, KFR-26GW/BpQYD2+2R3, KFR-26GW/BpR3QYA1+1, KFR-26GW/BpR3QYD1+1, KFR-26GW/BpR3QYQ1+1, KFR-26GW/BpR3QYQ2+2, KFR-35GW/BpQYA1+1R3, KFR-35GW/BpQYA2+2R3, KFR-35GW/BpQYD1+1R3, KFR-35GW/BpQYD2+2R3, KFR-35GW/BpR3QYQ1+1, KFR-35GW/BpR3QYQ2+2 (see [issue #71](https://github.com/GrKoR/esphome_aux_ac_component/issues/71) for detais of `Aegean Sea`[爱琴海] AUX family AC connection) 8 | + Ballu (models: BLC_CF/in-60HN1 / BLC_O/out-60HN1, BSUI/in-09HN8 / BSUI/out-09HN8, BSUI/in-12HN8 / BSUI/out-12HN8, BSUI/in-18HN8 / BSUI/out-18HN8, BSW/in-09HN1 / BSW/out-09HN1, BSW/in-12HN1 / BSW/out-12HN1) 9 | + Baymak (models: Elegant Plus 12) 10 | + Centek (models: CT-65A09, CT-65A12, CT-65EDC07, CT-65F09, CT-65F12, CT-65FDC09, CT-65J09, CT-65J12, CT-65K07, CT-65Q09, CT-65Q12, CT-65RDC07, CT-65RDC09, CT-65RDC12, CT-65SDC07, CT-65SDC09, CT-65SDC18, CT-65U13, CT-65U18, CT-65V12, CT-65V24, CT-65X12, CT-65Z10, CT-65Z18) 11 | + Dimstal (model: SMND-QC-12-J-Smart ECO) 12 | + Elgin (models: HWFI09B2IA/ HWFE09B2NA) 13 | + Energolux (models: SAS07L2-A, SAS07L4-A, SAS07M2-AI, SAS09B3-A, SAS09L4-A, SAS09Z4-AI, SAS12BN1-AI, SAS09Z4-AI, SAS18Z4-AI) 14 | + Hyundai (models: H-AR16-07H, H-AR21-07H, H-AR21-09H) 15 | + iClima (models: ICI-09A/IUI-09A) 16 | + Idea (models: ISR-12HR-SA7-DN1 ION) 17 | + IGC (models: RAK-07NH multysplit, RAS-07AX/RAC-07AX, RAS-V09N2X/RAC-V09N2X) 18 | + IKON (models: ASW-H12C5C4/HCR3DI-B8) 19 | + Ishimatsu (models: AVK-09I) 20 | + Loriot (models: LAC-09AS) 21 | + Mirage (models: EWC121E - CWC121E) 22 | + Osaka (models: STVP-12HH3) 23 | + RCool (models: GRA12B0-KSZKLM641) 24 | + Rinnai (models: RINV25RC) 25 | + Roda (models: RS-AL09F, RS-AL24F) 26 | + Rovex (models: RS-07ALS1, RS-09ALS1, RS-12ALS1) 27 | + Royal Clima (models: CO-D 18HNI/CO-E 18HNI, RC-VNR29HN, RCI-SA30HN) 28 | + RVX (models: RS-12ALS) 29 | + Samurai (models: SMA-07HRN1 ION, SMA-09HRN1 ION) 30 | + Subtropic (models: SUB/in-07HN1 / SUB/out-07HN1, SUB/in-09HN1 / SUB/out-09HN1, SUB/in-12HN1 / SUB/out-12HN1) 31 | + Tesla (models: TA35FFML-12410M) 32 | + Tornado (models: ISKA-INV-12 X WIFI EU) 33 | + TOYOTOMI (models: SONZAI THN/THG-A35SZ) 34 | + Vertex (models: Falcon-18A) 35 | + VOX (models: IJO09-SC4D, IVA5-12JR1) 36 | + Xigma (models: XG-SJ56RHA-IDU) 37 | + Zephir (models: ZEL 12000BTU) 38 | + Бирюса (models: B-07DPR/B-07DPQ, B-09FIR/B-09FIQ) 39 | 40 | ## Tested and INCOMPATIBLE air conditioners ## 41 | ACs from the list below are **INCOMPATIBLE** with `aux_ac`.
42 | Кондиционеры из списка ниже протестированы и оказались **НЕСОВМЕСТИМЫ** с компонентом `aux_ac`. 43 | 44 | + Kentatsu (models: KSGMA26HFAN1) 45 | + Royal Clima (models: RCI-PF40HN) 46 | -------------------------------------------------------------------------------- /docs/HARDWARE-EN.md: -------------------------------------------------------------------------------- 1 | ## Hardware ## 2 | I tested it with an esp8266 chip (esp-12e). Minimal scheme: 3 | ![scheme](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/scheme.png?raw=true) 4 | 5 | At the first time in addition to scheme above IO0 (GPIO0) must be pulled down to GND at the boot and ESPHome can be uploaded through UART0. If your ESPHome configuration contains OTA you can pull up IO0 or leave it floating. All further updates can be uploaded over-the-air. 6 | I leave GPIO0 in air cause I don't see any reason to solder additional components for single use. 7 | 8 | ESP-12E before DC-DC and air conditioner connected: 9 | ![esp-12e minimal photo](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/esp-12e.jpg?raw=true) 10 | 11 | Air conditioner internal block has a 5-wire or a 4-wire (pseudo-USB) connection to the wifi-module. There are another types of connection too. For example AUX Aegean Sea ( 爱琴海 ), check [issue #71](https://github.com/GrKoR/esphome_aux_ac_component/issues/71) for details. 12 | 13 | ## 5-wire connection 14 | It use [JST SM](https://www.jst-mfg.com/product/pdf/eng/eSM.pdf) connector for 5-wire connection. 15 | 16 | ### Pinout ### 17 | 1. Yellow: +12V..+14V DC. Measured +14.70V max and +13.70V min. Service manual declares up to +16V. 18 | 2. Black: ground. 19 | 3. White: +5V DC (max: +5.63V; min: +4.43V) Enable signal for the 3V3 buck regulator on the OEM module. It goes directly to the air conditioner microcontroller through resistor 1kOhm. It's non used with the EPS module. 20 | 4. Blue: TX of air conditioner. High is +5V. 21 | 5. Red: RX of air conditioner. High is +5V. 22 | 23 | You should feed your ESP **from +12V..+14V line only**! It is prohibited to use +5V line for this purpose. 24 | +5V line is digital signal line and directly goes to conditioner's controller. It can't provide enough power. In worst scenario you probably can burn down your air conditioner controller. 25 | 26 | ## 4-wire connection (pseudo-USB) 27 | For 4-wire connection it is used USB-like connector. It is only physical USB but its pinout is UART with +12V..+14V power line. 28 | 29 | **ATTENTION!** It is incompatible with normal USB devices! Ordinary USB device like USB flash drive will be damaged if it will be plugged in air conditioner USB connector. 30 | 31 | **ATTENTION #2!** Manufacturer was changed power circuit and connector pinout in 2022-2023: power rail has +8.5V DC and TX/RX pins are swapped. 32 | 33 | ### Pinout ### 34 | 35 | 36 | 1. +12V..+14V DC before 2022-2023, possible +8.5V DC after 2022-2023. Service manual declares up to +16V. 37 | 2. RX of the air conditioner for models manufactured before about Jul.2022, TX of the air conditioner for later modifications. High level is +5V. 38 | 3. TX of the air conditioner for models manufactured before about Jul.2022, RX of the air conditioner for later modifications. High level is +5V. 39 | 4. GND - ground. 40 | 41 | Big thanks to [@diabl0](https://github.com/diabl0) for this pinout in [issue #70](https://github.com/GrKoR/esphome_aux_ac_component/issues/70). 42 | 43 | If you are not sure, on which USB-pins do you have RX and TX lines, than don't afraid to connect it randomly. Neither air conditioner nor ESP will be damaged in this situation, just `aux_ac` can't receive data from the air conditioner. Swap TX and RX and your device will probably work. 44 | 45 | ## Power supply 46 | 47 | For power supply it is possible to use any kind of suitable modules. I use this: 48 | ![power module](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/DD4012SA.jpg?raw=true). 49 | 50 | ## Connections ## 51 | Black wire of AC's connector goes to the middle pin of the power module and to the GND pin of esp-12e. 52 | Yellow wire is connected to the Vin pin of the power module. 53 | Blue wire is connected to the RXD pin of esp-12e. 54 | Red wire is connected to the TXD pin of esp-12e. 55 | 56 | **ATTENTION!** In case you are using board like NodeMCU instead of clean esp8266/esp32 module, you shouldn't connect RX & TX wires of air conditioner to TX & RX pins of board! *(TXD1/RXD1, TXD2/RXD2 are also most likely not suitable.)* Use any other digital pins for UART connection. It doesn't matter if your board will use hardware or software UART. All UART types are working well. 57 | The usage of alternate pins for NodeMCU-like boards is necessary cause RX & TX lines of this boards are often have additional components like resistors or USB-TTL converters connected. This components are violate esp-to-ac UART connection. 58 | 59 | Here is it: 60 | ![connections](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/connections.png?raw=true) 61 | 62 | All connections in custom 3d-printed case looks like this: 63 | ![module assembled](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/assembled.JPG?raw=true) 64 | 65 | Since I didn't have JST SM connectors, I made my own: 66 | ![JST SM connector replica](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/connector.JPG?raw=true). 67 | 68 | It is made of standard 2.54mm pins and 3D-printed case. 69 | All models for 3D-printing are available too: [STL-files for connector](https://github.com/GrKoR/esphome_aux_ac_component/tree/master/enclosure/JST%20SM%20connector), [models of case parts](https://github.com/GrKoR/esphome_aux_ac_component/tree/master/enclosure/case). 70 | 71 | ## The result ## 72 | ![photo 1](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/real-1.JPG?raw=true) 73 | ![photo 2](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/real-2.JPG?raw=true) 74 | ![photo 3](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/real-3.JPG?raw=true) 75 | -------------------------------------------------------------------------------- /docs/HARDWARE.md: -------------------------------------------------------------------------------- 1 | ## Электроника, необходимая для управления кондиционером по wifi ## 2 | Я тестировал проект на esp8266 (esp-12e). Минимальная обвязка традиционна и выглядит так: 3 | ![scheme](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/scheme.png?raw=true) 4 | 5 | Для прошивки esp8266 в первый раз нужно, в дополнение к обвязке, показанной на схеме выше, притянуть к земле пин IO0 (GPIO0). После этого ESPHome может быть загружена в esp8266 по UART0. Если при этом вы указали OTA в конфигурации ESPHome, то в дальнейшем пин IO0 можно подтянуть к питанию или оставить висеть в воздухе. Он никак не будет влиять на загрузку новых прошивок, потому что все апдейты можно будет делать "по воздуху" (то есть по Wi-Fi). Я никуда IO0 не подтягивал и ничего к нему не паял, потому что не вижу смысла это делать ради одного раза. Первую прошивку делал в самодельном переходнике на макетке. 6 | 7 | Плата esp-12e перед подключением кондиционера и модуля питания: 8 | ![esp-12e minimal photo](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/esp-12e.jpg?raw=true) 9 | 10 | Внутренний блок сплит-системы может иметь 5-проводное или 4-проводное подключение (псевдо-USB) к модулю Wi-Fi. Встречаются и другие виды подключения. Например, AUX Aegean Sea ( 爱琴海 ), за подробностями подключения сюда: [issue #71](https://github.com/GrKoR/esphome_aux_ac_component/issues/71). 11 | 12 | ## 5-проводное подключение 13 | Для 5-проводного подключения используется коннектор [JST SM](https://www.jst-mfg.com/product/pdf/eng/eSM.pdf). 14 | 15 | ### Распиновка ### 16 | 1. Желтый: +12В..+14В постоянного тока. Осциллограф показал от +13.70В до +14.70В. В сервисном мануале встречалось, что питание возможно до +16В. 17 | 2. Черный: земля. 18 | 3. Белый: +5В постоянного тока (измерено от +4.43В до +5.63В). По информации от пользователей, это сигнальная линия, включающая по DC-DC конвертор на wifi-модуле по команде с кондиционера. Линия идет напрямую на ножку контроллера в сплите через резистор 1 кОм. Эксперименты с родным Wi-Fi модулем сплит-системы показали, что эта линия в работе Wi-Fi не участвует и имеет всегда высокий уровень. В работе компонента и самодельного wifi-модуля эта линия не используется. 19 | 4. Синий: TX кондиционера. Высокий уровень +5В. 20 | 5. Red: RX кондиционера. Высокий уровень +5В. 21 | 22 | Питание ESP подключать **ТОЛЬКО** к линии +12В..+14В! Имеющийся в 5-проводном подключении контакт с +5В для питания ESP использоваться не должен. Он является сигнальным, подключен через резистор непосредственно на ногу контроллера на материнской плате кондиционера и способен выдавать лишь мизерный ток. При неудачном стечении обстоятельств, повесив питание ESP на эту линию, можно сжечь мозги кондиционеру. 23 | 24 | ## 4-проводное подключение (псевдо-USB) 25 | Для 4-проводного подключения используется USB-коннектор. От настоящего USB здесь только коннектор. По пинам в этом разъеме UART и +12В..+14В питание. 26 | 27 | **ВНИМАНИЕ!** С устройствами c настоящим USB этот интерфейс не совместим! Если вставить в разъём обычную USB-флешку или другое устройство, скорее всего оно просто сгорит. 28 | 29 | **ВНИМАНИЕ №2!** В 2022-2023 производитель поменял распиновку и схему питания. Теперь кондиционеры на USB-коннектор выдают +8.5В. А пины RX и TX поменялись местами. 30 | 31 | ### Распиновка ### 32 | 33 | 34 | 1. +12В..+14В постоянного тока для кондиционеров до 2023 года, возможно +8.5В для кондиционеров 2022-2023 годов и моложе. В сервисном мануале на кондиционеры до 2022 года встречалось, что питание возможно до +16В. 35 | 2. RX кондиционера для моделей, произведенных примерно до 07.2022, TX кондиционера для более поздних модификаций. Высокий уровень +5В. 36 | 3. TX кондиционера для моделей, произведенных примерно до 07.2022, RX кондиционера для более поздних модификаций. Высокий уровень +5В. 37 | 4. земля. 38 | 39 | Большое спасибо [@diabl0](https://github.com/diabl0) за эту распиновку ([issue #70](https://github.com/GrKoR/esphome_aux_ac_component/issues/70)). 40 | 41 | Если вы не знаете, на каких именно пинах USB-разъема в вашем случае расположены TX и RX, то не бойтесь подключить наугад. Ни кондиционер, ни ESP не пострадают, если вы перепутаете линии TX и RX. Просто компонент не увидит кондиционер, о чем будут сообщения в логе. В таком случае просто попробуйте поменять TX и RX местами. 42 | 43 | ## Питание 44 | 45 | Для питания ESP8266 можно использовать любой подходящий DC-DC преобразователь. Я использовал такой: 46 | ![power module](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/DD4012SA.jpg?raw=true | width=200). 47 | 48 | ## Подключение ## 49 | Черный провод (земля) подключается к земле DC-DC преобразователя и к пину GND модуля ESP8266. 50 | Желтый провод подключается ко входу DC-DC преобразователя (в моём случае контакт Vin). 51 | Синий провод подключается к пину RXD модуля esp-12e. 52 | Красный провод подключается к пину TXD модуля esp-12e. 53 | 54 | **ВНИМАНИЕ!** Если вы используете не голый модуль esp32/esp8266, а плату типа NodeMCU, то не подключайте провода TX и RX кондиционера к пинам TX и RX платы! *(TXD1/RXD1, TXD2/RXD2 также скорее всего не подойдут.)* Используйте любые другие свободные пины для UART. При этом для ESP8266 UART будет программный, но это не страшно. Ресурсов ESP8266 хватит для работы. 55 | Использовать альтернативные пины для плат типа NodeMCU необходимо потому, что часто на линиях RX и TX этих плат установлены резисторы, а также на этих пинах висит USB-TTL конвертер (если он есть на плате). Эти компоненты мешают ESP наладить соединение с кондиционером. 56 | 57 | 58 | Вот схема всех соединений: 59 | ![connections](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/connections.png?raw=true) 60 | 61 | Вот так это выглядит внутри самодельного корпуса: 62 | ![module assembled](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/assembled.JPG?raw=true) 63 | 64 | Поскольку у меня не было под рукой коннекторов JST SM, а ехать искать их не хотелось, я сделал свой собственный из стандартных пинов с шагом 2,54 мм и нескольких напечатанных на 3D-принтере деталей: 65 | ![JST SM connector replica](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/connector.JPG?raw=true). 66 | 67 | Все относящиеся к проекту модели для 3D-принтера также доступны: [STL-файлы коннектора](https://github.com/GrKoR/esphome_aux_ac_component/tree/master/enclosure/JST%20SM%20connector), [модельки частей корпуса](https://github.com/GrKoR/esphome_aux_ac_component/tree/master/enclosure/case). 68 | 69 | ## Конечный результат ## 70 | ![photo 1](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/real-1.JPG?raw=true) 71 | ![photo 2](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/real-2.JPG?raw=true) 72 | ![photo 3](https://github.com/GrKoR/esphome_aux_ac_component/blob/master/images/real-3.JPG?raw=true) 73 | -------------------------------------------------------------------------------- /docs/HOW_TO_FEATURE_REQUEST-EN.md: -------------------------------------------------------------------------------- 1 | # How to request a feature for a component # 2 | 3 | With any functions, the alignment is such that they simply cannot be written down by name. 4 | We need a log from someone who has air conditioner with such functions. If you are such a person, then you can help yourself and the community. 5 | 6 | To capture the log you need to do the following steps: 7 | 1. Run a specially written [tool](https://github.com/GrKoR/ac_python_logger) to collect logs. 8 | 2. Turn on the AC. 9 | 3. Wait 10+ seconds. (During this time, the ESP will receive all packets from AC). 10 | 4. Turn on the desired function using AC's IR remote. 11 | 5. Wait 10+ seconds ones more. While you are waiting, you can write down what you have done. 12 | 6. Turn off the desired function. 13 | 7. Wait 10+ seconds again and write down what you've done. 14 | 8. Repeat steps 4..7 for all other functions you interested in. 15 | 9. Stop the log recording with a script. 16 | 10. Send collected log and your notes (explanations to the log) to [issues](https://github.com/GrKoR/esphome_aux_ac_component/issues) or to [telegram chat](https://t.me/aux_ac). 17 | 18 | Instead of a Python script from the step #1, you can simply save the logs from the esphome web-interface with copy-paste or from the command line, but there is a lot of extra stuff there. And it's easy to miss something. But in principle, it is also quite a working option. -------------------------------------------------------------------------------- /docs/HOW_TO_FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | # Как запросить расширение функционала компонента # 2 | 3 | С любыми новыми функциями кондиционера ситуация такая, что просто по названию из инструкции или с пульта их не сделать. Нужен лог от владельца кондиционера, у кого такие функции есть. Если вы такой владелей, то можете помочь себе и сообществу. 4 | 5 | Последовательность действий такая: 6 | 1. Запускате специально написанную [тулзу](https://github.com/GrKoR/ac_python_logger) для сбора логов. 7 | 2. Включете кондиционер. 8 | 3. Ждёте 10+ секунд, чтобы все возможные типы пакетов прошли по UART на ESP. 9 | 4. Включаете нужную функцию с помощью ИК-пульта. 10 | 5. Опять ждёте 10+ секунд. Во время ожидания можно записать в отдельный текстовый файл или на бумажку, что именно сделано. 11 | 6. Выключаете нужную функцию. 12 | 7. Опять ждёте 10+ секунд, не забывая записывать комментарии по сделанному. 13 | 8. Повторяете шаги 4..7 для всех других функций, которые хочется иметь в компоненте `aux_ac`. 14 | 9. Останавливаете запись лога. 15 | 10. Отправляете собранный лог и свои заметки (пояснения к логу) в [issues](https://github.com/GrKoR/esphome_aux_ac_component/issues) или в [телеграм](https://t.me/aux_ac). 16 | 17 | Вместо использования Python-скрипта можно логи из веб-интерфейса esphome сохранять копипастом или из командной строки. Но там много лишнего шлётся и легко что-то пропустить. Но в принципе это тоже вполне рабочий вариант. -------------------------------------------------------------------------------- /enclosure/JST SM connector/pin-cap.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/enclosure/JST SM connector/pin-cap.stl -------------------------------------------------------------------------------- /enclosure/JST SM connector/pin-cover.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/enclosure/JST SM connector/pin-cover.stl -------------------------------------------------------------------------------- /enclosure/JST SM connector/pin-main.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/enclosure/JST SM connector/pin-main.stl -------------------------------------------------------------------------------- /enclosure/case/aircon_cap.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/enclosure/case/aircon_cap.stl -------------------------------------------------------------------------------- /enclosure/case/aircon_case.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/enclosure/case/aircon_case.stl -------------------------------------------------------------------------------- /examples/advanced/.gitignore: -------------------------------------------------------------------------------- 1 | # Gitignore settings for ESPHome 2 | # This is an example and may include too much for your use-case. 3 | # You can modify this file to suit your needs. 4 | /.esphome/ 5 | **/.pioenvs/ 6 | **/.piolibdeps/ 7 | **/lib/ 8 | **/src/ 9 | **/platformio.ini 10 | /secrets.yaml 11 | -------------------------------------------------------------------------------- /examples/advanced/ac_common.yaml: -------------------------------------------------------------------------------- 1 | # DON'T COMPILE THIS FILE 2 | # This file contains common settings for all air conditioners of your house 3 | external_components: 4 | - source: github://GrKoR/esphome_aux_ac_component 5 | components: [ aux_ac ] 6 | refresh: 0s 7 | 8 | esphome: 9 | name: $devicename 10 | platform: ESP8266 11 | board: esp12e 12 | 13 | wifi: 14 | ssid: !secret wifi_ssid 15 | password: !secret wifi_pass 16 | manual_ip: 17 | static_ip: ${wifi_ip} 18 | gateway: !secret wifi_gateway 19 | subnet: !secret wifi_subnet 20 | ap: 21 | ssid: ${upper_devicename} Hotspot 22 | password: !secret wifi_ap_pass 23 | use_address: ${wifi_ota_ip} 24 | 25 | captive_portal: 26 | debug: 27 | 28 | logger: 29 | level: DEBUG 30 | baud_rate: 0 31 | # set hardware_uart to UART1 and comment out baud_rate above in case of boot crashes 32 | # it is suitable if you need hardware loggin 33 | # hardware_uart: UART1 34 | 35 | api: 36 | password: !secret api_pass 37 | 38 | ota: 39 | - platform: esphome 40 | password: !secret ota_pass 41 | 42 | web_server: 43 | port: 80 44 | auth: 45 | username: !secret web_server_user 46 | password: !secret web_server_password 47 | 48 | # UART0 configuration for AUX air conditioner communication 49 | uart: 50 | id: ac_uart_bus 51 | # ATTENTION! Use GPIO4 (D2) and GPIO5 (D1) as the TX and RX for NodeMCU-like boards! 52 | tx_pin: GPIO1 53 | rx_pin: GPIO3 54 | baud_rate: 4800 55 | data_bits: 8 56 | parity: EVEN 57 | stop_bits: 1 58 | 59 | 60 | 61 | climate: 62 | - platform: aux_ac 63 | name: ${upper_devicename} 64 | id: aux_id 65 | uart_id: ac_uart_bus 66 | period: 7s 67 | show_action: true 68 | display_inverted: true 69 | optimistic: true 70 | indoor_temperature: 71 | name: ${upper_devicename} Indoor Temperature 72 | id: ${devicename}_indoor_temp 73 | internal: false 74 | display_state: 75 | name: ${upper_devicename} Display State 76 | id: ${devicename}_display_state 77 | internal: false 78 | outdoor_temperature: 79 | name: ${upper_devicename} Outdoor Temperature 80 | id: ${devicename}_outdoor_temp 81 | internal: false 82 | outbound_temperature: 83 | name: ${upper_devicename} Coolant Outbound Temperature 84 | id: ${devicename}_outbound_temp 85 | internal: false 86 | inbound_temperature: 87 | name: ${upper_devicename} Coolant Inbound Temperature 88 | id: ${devicename}_inbound_temp 89 | internal: false 90 | compressor_temperature: 91 | name: ${upper_devicename} Compressor Temperature 92 | id: ${devicename}_strange_temp 93 | internal: false 94 | defrost_state: 95 | name: ${upper_devicename} Defrost State 96 | id: ${devicename}_defrost_state 97 | internal: false 98 | inverter_power: 99 | name: ${upper_devicename} Invertor Power 100 | id: ${devicename}_inverter_power 101 | internal: false 102 | preset_reporter: 103 | name: ${upper_devicename} Preset Reporter 104 | id: ${devicename}_preset_reporter 105 | internal: false 106 | vlouver_state: 107 | name: ${upper_devicename} VLouvers State 108 | id: ${devicename}_vlouver_state 109 | internal: false 110 | visual: 111 | min_temperature: 16 112 | max_temperature: 32 113 | temperature_step: 0.5 114 | supported_modes: 115 | - HEAT_COOL 116 | - COOL 117 | - HEAT 118 | - DRY 119 | - FAN_ONLY 120 | custom_fan_modes: 121 | - MUTE 122 | - TURBO 123 | supported_presets: 124 | - SLEEP 125 | custom_presets: 126 | - CLEAN 127 | - HEALTH 128 | - ANTIFUNGUS 129 | supported_swing_modes: 130 | - VERTICAL 131 | - HORIZONTAL 132 | - BOTH 133 | 134 | 135 | sensor: 136 | # just wifi signal strength for debug purpose only 137 | - platform: wifi_signal 138 | name: ${upper_devicename} WiFi Signal 139 | update_interval: 30s 140 | unit_of_measurement: "dBa" 141 | accuracy_decimals: 0 142 | 143 | - platform: uptime 144 | name: ${upper_devicename} Uptime Sensor 145 | 146 | switch: 147 | - platform: template 148 | name: ${upper_devicename} Display 149 | lambda: |- 150 | if (id(${devicename}_display_state).state) { 151 | return true; 152 | } else { 153 | return false; 154 | } 155 | turn_on_action: 156 | - aux_ac.display_on: aux_id 157 | turn_off_action: 158 | - aux_ac.display_off: aux_id 159 | 160 | button: 161 | - platform: template 162 | name: ${upper_devicename} VLouver Stop 163 | icon: "mdi:circle-small" 164 | on_press: 165 | - aux_ac.vlouver_stop: aux_id 166 | 167 | - platform: template 168 | name: ${upper_devicename} VLouver Swing 169 | icon: "mdi:pan-vertical" 170 | on_press: 171 | - aux_ac.vlouver_swing: aux_id 172 | 173 | - platform: template 174 | name: ${upper_devicename} VLouver Top 175 | icon: "mdi:pan-up" 176 | on_press: 177 | - aux_ac.vlouver_top: aux_id 178 | 179 | - platform: template 180 | name: ${upper_devicename} VLouver Middle Above 181 | icon: "mdi:pan-top-left" 182 | on_press: 183 | - aux_ac.vlouver_middle_above: aux_id 184 | 185 | - platform: template 186 | name: ${upper_devicename} VLouver Middle 187 | icon: "mdi:pan-left" 188 | on_press: 189 | - aux_ac.vlouver_middle: aux_id 190 | 191 | - platform: template 192 | name: ${upper_devicename} VLouver Middle Below 193 | icon: "mdi:pan-bottom-left" 194 | on_press: 195 | - aux_ac.vlouver_middle_below: aux_id 196 | 197 | - platform: template 198 | name: ${upper_devicename} VLouver Bottom 199 | icon: "mdi:pan-down" 200 | on_press: 201 | - aux_ac.vlouver_bottom: aux_id 202 | 203 | 204 | number: 205 | - platform: template 206 | name: ${upper_devicename} Vertical Louvers 207 | id: ${devicename}_vlouver 208 | icon: "mdi:circle-small" 209 | mode: "slider" 210 | min_value: 0 211 | max_value: 6 212 | step: 1 213 | update_interval: 2s 214 | lambda: |- 215 | return id(${devicename}_vlouver_state).state; 216 | set_action: 217 | then: 218 | - aux_ac.vlouver_set: 219 | id: aux_id 220 | position: !lambda "return x;" 221 | 222 | - platform: template 223 | name: ${upper_devicename} Power Limit 224 | id: ${devicename}_power_limit 225 | icon: "mdi:battery-unknown" 226 | mode: "slider" 227 | min_value: 30 228 | max_value: 100 229 | step: 1 230 | set_action: 231 | then: 232 | - lambda: !lambda "id(aux_id).powerLimitationOnSequence( x );" 233 | -------------------------------------------------------------------------------- /examples/advanced/ac_kitchen.yaml: -------------------------------------------------------------------------------- 1 | # compile this file with ESPHome 2 | # This file contains unique settings for specific air conditioner 3 | 4 | #=================================================================================== 5 | # KITCHEN AIR CONDITIONER 6 | #=================================================================================== 7 | 8 | substitutions: 9 | devicename: kitchen_ac 10 | upper_devicename: Kitchen AC 11 | 12 | # use different wifi_ip and wifi_ota_ip in case of esp ip-address change 13 | # if ip haven't changed wifi_ip and wifi_ota_ip should be the same 14 | wifi_ip: !secret wifi_ip_kitchen 15 | wifi_ota_ip: !secret wifi_ota_ip_kitchen 16 | 17 | <<: !include ac_common.yaml -------------------------------------------------------------------------------- /examples/advanced/ac_livingroom.yaml: -------------------------------------------------------------------------------- 1 | # compile this file with ESPHome 2 | # This file contains unique settings for specific air conditioner 3 | 4 | #=================================================================================== 5 | # LIVINGROOM AIR CONDITIONER 6 | #=================================================================================== 7 | 8 | substitutions: 9 | devicename: livingroom_ac 10 | upper_devicename: Livingroom AC 11 | 12 | # use different wifi_ip and wifi_ota_ip in case of esp ip-address change 13 | # if ip haven't changed wifi_ip and wifi_ota_ip should be the same 14 | wifi_ip: !secret wifi_ip_livingroom 15 | wifi_ota_ip: !secret wifi_ota_ip_livingroom 16 | 17 | <<: !include ac_common.yaml -------------------------------------------------------------------------------- /examples/simple/.gitignore: -------------------------------------------------------------------------------- 1 | # Gitignore settings for ESPHome 2 | # This is an example and may include too much for your use-case. 3 | # You can modify this file to suit your needs. 4 | /.esphome/ 5 | **/.pioenvs/ 6 | **/.piolibdeps/ 7 | **/lib/ 8 | **/src/ 9 | **/platformio.ini 10 | /secrets.yaml 11 | -------------------------------------------------------------------------------- /examples/simple/aux_ac_simple.yaml: -------------------------------------------------------------------------------- 1 | external_components: 2 | - source: github://GrKoR/esphome_aux_ac_component 3 | components: [ aux_ac ] 4 | refresh: 0s 5 | 6 | esphome: 7 | name: aux_air_conditioner 8 | platform: ESP8266 9 | board: esp12e 10 | 11 | # don't forget to set your's wifi settings! 12 | wifi: 13 | ssid: "WIFI SSID" 14 | password: "seCRETpassWORD" 15 | manual_ip: 16 | static_ip: 192.168.0.2 17 | gateway: 192.168.0.1 18 | subnet: 255.255.255.0 19 | ap: 20 | ssid: AUX Hotspot 21 | password: "seCREThotSPOTpassWORD" 22 | 23 | captive_portal: 24 | debug: 25 | 26 | logger: 27 | level: DEBUG 28 | baud_rate: 0 29 | 30 | api: 31 | 32 | ota: 33 | - platform: esphome 34 | 35 | # UART0 configuration for AUX air conditioner communication 36 | uart: 37 | id: ac_uart_bus 38 | # ATTENTION! Use GPIO4 (D2) and GPIO5 (D1) as the TX and RX for NodeMCU-like boards! 39 | tx_pin: GPIO1 40 | rx_pin: GPIO3 41 | baud_rate: 4800 42 | data_bits: 8 43 | parity: EVEN 44 | stop_bits: 1 45 | 46 | climate: 47 | - platform: aux_ac 48 | name: "AC Name" -------------------------------------------------------------------------------- /images/DD4012SA.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/images/DD4012SA.jpg -------------------------------------------------------------------------------- /images/USB-pinout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/images/USB-pinout.png -------------------------------------------------------------------------------- /images/assembled.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/images/assembled.JPG -------------------------------------------------------------------------------- /images/connections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/images/connections.png -------------------------------------------------------------------------------- /images/connector.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/images/connector.JPG -------------------------------------------------------------------------------- /images/esp-12e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/images/esp-12e.jpg -------------------------------------------------------------------------------- /images/real-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/images/real-1.JPG -------------------------------------------------------------------------------- /images/real-2.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/images/real-2.JPG -------------------------------------------------------------------------------- /images/real-3.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/images/real-3.JPG -------------------------------------------------------------------------------- /images/scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GrKoR/esphome_aux_ac_component/7a252e5955f075b66460de25deffc8c2ed266569/images/scheme.png -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | # Gitignore settings for ESPHome 2 | # This is an example and may include too much for your use-case. 3 | # You can modify this file to suit your needs. 4 | /.esphome/ 5 | **/.pioenvs/ 6 | **/.piolibdeps/ 7 | **/lib/ 8 | **/src/ 9 | **/platformio.ini 10 | /secrets.yaml 11 | -------------------------------------------------------------------------------- /tests/ac_send_packet_for_engineer.py: -------------------------------------------------------------------------------- 1 | import time 2 | import aioesphomeapi 3 | import asyncio 4 | import re 5 | import sys 6 | import argparse 7 | from aioesphomeapi.api_pb2 import (LOG_LEVEL_NONE, 8 | LOG_LEVEL_ERROR, 9 | LOG_LEVEL_WARN, 10 | LOG_LEVEL_INFO, 11 | LOG_LEVEL_DEBUG, 12 | LOG_LEVEL_VERBOSE, 13 | LOG_LEVEL_VERY_VERBOSE) 14 | 15 | def createParser (): 16 | parser = argparse.ArgumentParser( 17 | description='''This script is used for collecting logs from ac_aux ESPHome component. 18 | For more info, see https://github.com/GrKoR/ac_python_logger''', 19 | add_help = False) 20 | parent_group = parser.add_argument_group (title='Params') 21 | parent_group.add_argument ('--help', '-h', action='help', help='show this help message and exit') 22 | parent_group.add_argument ('-i', '--ip', nargs=1, required=True, help='IP address of the esphome device') 23 | parent_group.add_argument ('-p', '--pwd', nargs=1, required=True, help='native API password for the esphome device') 24 | return parser 25 | 26 | async def main(): 27 | """Connect to an ESPHome device and wait for state changes.""" 28 | api = aioesphomeapi.APIClient(namespace.ip[0], 6053, namespace.pwd[0]) 29 | 30 | try: 31 | await api.connect(login=True) 32 | except aioesphomeapi.InvalidAuthAPIError as e: 33 | return print(e) 34 | 35 | print(api.api_version) 36 | 37 | async def display_off(): 38 | await api.execute_service( 39 | service, 40 | data={ 41 | # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 42 | "data_buf": [0xBB, 0x00, 0x06, 0x80, 0x01, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x97, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x00], 43 | } 44 | ) 45 | 46 | async def display_on(): 47 | await api.execute_service( 48 | service, 49 | data={ 50 | # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 51 | "data_buf": [0xBB, 0x00, 0x06, 0x80, 0x01, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x97, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00], 52 | } 53 | ) 54 | 55 | async def ac_enable(): 56 | await api.execute_service( 57 | service, 58 | data={ 59 | # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 60 | "data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x00, 0x87, 0xE0, 0x2F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00], 61 | } 62 | ) 63 | 64 | async def ac_disable(): 65 | await api.execute_service( 66 | service, 67 | data={ 68 | # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 69 | "data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x00, 0x87, 0xE0, 0x2F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 70 | } 71 | ) 72 | 73 | async def ac_get11_01(): 74 | await api.execute_service( 75 | service, 76 | data={ 77 | # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 78 | "data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x02, 0x00, 0x11, 0x01], 79 | } 80 | ) 81 | 82 | async def ac_get11_00(): 83 | await api.execute_service( 84 | service, 85 | data={ 86 | # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 87 | "data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x02, 0x00, 0x11, 0x00], 88 | } 89 | ) 90 | 91 | async def ac_set_vlouver(lvr): 92 | await api.execute_service( 93 | service, 94 | data={ 95 | # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 96 | "data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x01, lvr, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00], 97 | } 98 | ) 99 | 100 | async def ac_set_hlouver(lvr): 101 | await api.execute_service( 102 | service, 103 | data={ 104 | # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 105 | "data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x97, lvr, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00], 106 | } 107 | ) 108 | 109 | # key надо искать в выводе list_entities_services 110 | service = aioesphomeapi.UserService( 111 | name="send_data", 112 | key=311254518, 113 | args=[ 114 | aioesphomeapi.UserServiceArg(name="data_buf", type=aioesphomeapi.UserServiceArgType.INT_ARRAY), 115 | ], 116 | ) 117 | 118 | time.sleep(7) 119 | await ac_get11_00() 120 | time.sleep(7) 121 | await ac_get11_01() 122 | 123 | #await ac_set_vlouver( 0b10010000 ) # swing on 124 | #await ac_set_vlouver( 0b10010111 ) # swing off 125 | #await ac_set_vlouver( 0b10010001 ) # 1 126 | #await ac_set_vlouver( 0b10010010 ) # 2 127 | #await ac_set_vlouver( 0b10010011 ) # 3 128 | #await ac_set_vlouver( 0b10010100 ) # 4 129 | #await ac_set_vlouver( 0b10010101 ) # 5 130 | #await ac_set_vlouver( 0b10010110 ) # не работает, сбрасывает на swing on 131 | #time.sleep(5) 132 | 133 | #await ac_set_hlouver( 0b00000000 ) # swing on 134 | #await ac_set_hlouver( 0b11100000 ) # swing off 135 | #await ac_set_hlouver( 0b00100000 ) # не работает, сбрасывает в swing off 136 | #await ac_set_hlouver( 0b01000000 ) # не работает, сбрасывает в swing off 137 | #await ac_set_hlouver( 0b01100000 ) # не работает, сбрасывает в swing off 138 | #await ac_set_hlouver( 0b10000000 ) # не работает, сбрасывает в swing off 139 | #await ac_set_hlouver( 0b10100000 ) # не работает, сбрасывает в swing off 140 | #await ac_set_hlouver( 0b11000000 ) # не работает, сбрасывает в swing off 141 | #time.sleep(5) 142 | 143 | async def test_byte(bt): 144 | await api.execute_service( 145 | service, 146 | data={ 147 | #display on 148 | # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 149 | #"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x97, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00], 150 | #display off 151 | # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 152 | "data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x97, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x00], 153 | # swing on 154 | # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 155 | #"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x90, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00], 156 | # swing off 157 | # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 158 | #"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x97, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00], 159 | } 160 | ) 161 | ''' 162 | не проходит команда, если байт 1 или 7 не 0x00 163 | не проходит команда, если байт 3 не 0x80 164 | 165 | проходит и не меняется, если меняю байт 4 или 5 166 | ''' 167 | 168 | #await test_byte(0b10000110) 169 | #await test_byte(0b01000110) 170 | #await test_byte(0b00100110) 171 | #await test_byte(0b00010110) 172 | time.sleep(2) 173 | 174 | 175 | parser = createParser() 176 | namespace = parser.parse_args() 177 | print("IP: ", namespace.ip[0]) 178 | 179 | 180 | loop = asyncio.get_event_loop() 181 | try: 182 | #asyncio.ensure_future(main()) 183 | #loop.run_forever() 184 | loop.run_until_complete(main()) 185 | except aioesphomeapi.InvalidAuthAPIError as e: 186 | print(e) 187 | except KeyboardInterrupt: 188 | pass 189 | finally: 190 | loop.close() 191 | pass -------------------------------------------------------------------------------- /tests/test-ext-esp32.yaml: -------------------------------------------------------------------------------- 1 | external_components: 2 | - source: github://GrKoR/esphome_aux_ac_component@dev 3 | components: [ aux_ac ] 4 | refresh: 0s 5 | 6 | substitutions: 7 | devicename: test_aux_ac_ext_esp32 8 | upper_devicename: Test AUX 9 | 10 | esphome: 11 | name: $devicename 12 | platform: ESP32 13 | board: nodemcu-32s 14 | 15 | wifi: 16 | ssid: !secret wifi_ssid 17 | password: !secret wifi_pass 18 | manual_ip: 19 | static_ip: 192.168.0.151 # Для примера 20 | gateway: !secret wifi_gateway 21 | subnet: !secret wifi_subnet 22 | dns1: 8.8.8.8 23 | dns2: 1.1.1.1 24 | reboot_timeout: 0s 25 | ap: 26 | ssid: Test AUX Fallback Hotspot 27 | password: !secret wifi_ap_pass 28 | 29 | logger: 30 | level: DEBUG 31 | baud_rate: 0 32 | 33 | api: 34 | password: !secret api_pass 35 | reboot_timeout: 0s 36 | 37 | ota: 38 | - platform: esphome 39 | password: !secret ota_pass 40 | 41 | uart: 42 | id: ac_uart_bus 43 | #tx_pin: GPIO1 44 | #rx_pin: GPIO3 45 | tx_pin: TX 46 | rx_pin: RX 47 | baud_rate: 4800 48 | data_bits: 8 49 | parity: EVEN 50 | stop_bits: 1 51 | 52 | sensor: 53 | - platform: uptime 54 | name: Uptime Sensor 55 | 56 | climate: 57 | - platform: aux_ac 58 | name: $upper_devicename 59 | id: aux_id 60 | uart_id: ac_uart_bus 61 | period: 7s 62 | show_action: true 63 | display_inverted: true 64 | indoor_temperature: 65 | name: $upper_devicename Indoor Temperature 66 | id: ${devicename}_indoor_temp 67 | internal: false 68 | display_state: 69 | name: $upper_devicename Display State 70 | id: ${devicename}_display_state 71 | internal: false 72 | outdoor_temperature: 73 | name: $upper_devicename Outdoor Temperature 74 | id: ${devicename}_outdoor_temp 75 | internal: false 76 | outbound_temperature: 77 | name: $upper_devicename Coolant Outbound Temperature 78 | id: ${devicename}_outbound_temp 79 | internal: false 80 | inbound_temperature: 81 | name: $upper_devicename Coolant Inbound Temperature 82 | id: ${devicename}_inbound_temp 83 | internal: false 84 | compressor_temperature: 85 | name: $upper_devicename Compressor Temperature 86 | id: ${devicename}_strange_temp 87 | internal: false 88 | defrost_state: 89 | name: $upper_devicename Defrost State 90 | id: ${devicename}_defrost_state 91 | internal: false 92 | inverter_power: 93 | name: $upper_devicename Invertor Power 94 | id: ${devicename}_invertor_power 95 | internal: false 96 | preset_reporter: 97 | name: $upper_devicename Preset Reporter 98 | id: ${devicename}_preset_reporter 99 | internal: false 100 | visual: 101 | min_temperature: 16 102 | max_temperature: 32 103 | temperature_step: 0.5 104 | supported_modes: 105 | - HEAT_COOL 106 | - COOL 107 | - HEAT 108 | - DRY 109 | - FAN_ONLY 110 | custom_fan_modes: 111 | - MUTE 112 | - TURBO 113 | supported_presets: 114 | - SLEEP 115 | custom_presets: 116 | - CLEAN 117 | - HEALTH 118 | - ANTIFUNGUS 119 | supported_swing_modes: 120 | - VERTICAL 121 | - HORIZONTAL 122 | - BOTH 123 | -------------------------------------------------------------------------------- /tests/test-ext-for-engineer.yaml: -------------------------------------------------------------------------------- 1 | external_components: 2 | - source: github://GrKoR/esphome_aux_ac_component@dev 3 | components: [ aux_ac ] 4 | refresh: 0s 5 | 6 | substitutions: 7 | devicename: test_aux_ac_ext_engeneer 8 | upper_devicename: Test AUX 9 | 10 | esphome: 11 | name: $devicename 12 | platform: ESP8266 13 | board: esp12e 14 | 15 | wifi: 16 | ssid: !secret wifi_ssid 17 | password: !secret wifi_pass 18 | manual_ip: 19 | static_ip: !secret wifi_ip 20 | gateway: !secret wifi_gateway 21 | subnet: !secret wifi_subnet 22 | dns1: 8.8.8.8 23 | dns2: 1.1.1.1 24 | reboot_timeout: 0s 25 | ap: 26 | ssid: Test AUX Fallback Hotspot 27 | password: !secret wifi_ap_pass 28 | 29 | logger: 30 | level: DEBUG 31 | baud_rate: 0 32 | 33 | api: 34 | password: !secret api_pass 35 | reboot_timeout: 0s 36 | services: 37 | # этот сервис можно вызвать из Home Assistant или Python. Он отправляет полученные байты в кондиционер 38 | - service: send_data 39 | variables: 40 | data_buf: int[] 41 | then: 42 | # ВАЖНО! Только для инженеров! 43 | # Вызывайте метод aux_ac.send_packet только если понимаете, что делаете! Он не проверяет данные, а передаёт 44 | # кондиционеру всё как есть. Какой эффект получится от передачи кондиционеру рандомных байт, никто не знает. 45 | # Вы действуете на свой страх и риск. 46 | - aux_ac.send_packet: 47 | id: aux_id 48 | data: !lambda |- 49 | std::vector data{}; 50 | for (int n : data_buf) { 51 | data.push_back( (uint8_t) n ); 52 | } 53 | return data; 54 | 55 | ota: 56 | - platform: esphome 57 | password: !secret ota_pass 58 | 59 | web_server: 60 | port: 80 61 | 62 | uart: 63 | id: ac_uart_bus 64 | tx_pin: GPIO1 65 | rx_pin: GPIO3 66 | baud_rate: 4800 67 | data_bits: 8 68 | parity: EVEN 69 | stop_bits: 1 70 | 71 | sensor: 72 | - platform: uptime 73 | name: Uptime Sensor 74 | 75 | climate: 76 | - platform: aux_ac 77 | name: $upper_devicename 78 | id: aux_id 79 | uart_id: ac_uart_bus 80 | period: 7s 81 | show_action: true 82 | display_inverted: true 83 | optimistic: true 84 | indoor_temperature: 85 | name: $upper_devicename Indoor Temperature 86 | id: ${devicename}_indoor_temp 87 | internal: false 88 | display_state: 89 | name: $upper_devicename Display State 90 | id: ${devicename}_display_state 91 | internal: false 92 | outdoor_temperature: 93 | name: $upper_devicename Outdoor Temperature 94 | id: ${devicename}_outdoor_temp 95 | internal: false 96 | outbound_temperature: 97 | name: $upper_devicename Coolant Outbound Temperature 98 | id: ${devicename}_outbound_temp 99 | internal: false 100 | inbound_temperature: 101 | name: $upper_devicename Coolant Inbound Temperature 102 | id: ${devicename}_inbound_temp 103 | internal: false 104 | compressor_temperature: 105 | name: $upper_devicename Compressor Temperature 106 | id: ${devicename}_strange_temp 107 | internal: false 108 | defrost_state: 109 | name: $upper_devicename Defrost State 110 | id: ${devicename}_defrost_state 111 | internal: false 112 | inverter_power: 113 | name: $upper_devicename Invertor Power 114 | id: ${devicename}_invertor_power 115 | internal: false 116 | preset_reporter: 117 | name: $upper_devicename Preset Reporter 118 | id: ${devicename}_preset_reporter 119 | internal: false 120 | visual: 121 | min_temperature: 16 122 | max_temperature: 32 123 | temperature_step: 0.5 124 | supported_modes: 125 | - HEAT_COOL 126 | - COOL 127 | - HEAT 128 | - DRY 129 | - FAN_ONLY 130 | custom_fan_modes: 131 | - MUTE 132 | - TURBO 133 | supported_presets: 134 | - SLEEP 135 | custom_presets: 136 | - CLEAN 137 | - HEALTH 138 | - ANTIFUNGUS 139 | supported_swing_modes: 140 | - VERTICAL 141 | - HORIZONTAL 142 | - BOTH 143 | 144 | 145 | switch: 146 | - platform: template 147 | name: AC Display 148 | lambda: |- 149 | if (id(${devicename}_display_state).state) { 150 | return true; 151 | } else { 152 | return false; 153 | } 154 | turn_on_action: 155 | - aux_ac.display_on: aux_id 156 | turn_off_action: 157 | - aux_ac.display_off: aux_id -------------------------------------------------------------------------------- /tests/test-ext-power-limit.yaml: -------------------------------------------------------------------------------- 1 | external_components: 2 | - source: github://GrKoR/esphome_aux_ac_component@dev 3 | components: [ aux_ac ] 4 | refresh: 0s 5 | 6 | substitutions: 7 | devicename: test_ext_power_limitations 8 | upper_devicename: Test AUX 9 | 10 | esphome: 11 | name: $devicename 12 | platform: ESP8266 13 | board: esp12e 14 | 15 | wifi: 16 | ssid: !secret wifi_ssid 17 | password: !secret wifi_pass 18 | manual_ip: 19 | static_ip: !secret wifi_ip 20 | gateway: !secret wifi_gateway 21 | subnet: !secret wifi_subnet 22 | dns1: 8.8.8.8 23 | dns2: 1.1.1.1 24 | reboot_timeout: 0s 25 | ap: 26 | ssid: Test AUX Fallback Hotspot 27 | password: !secret wifi_ap_pass 28 | 29 | logger: 30 | level: DEBUG 31 | baud_rate: 0 32 | 33 | api: 34 | password: !secret api_pass 35 | reboot_timeout: 0s 36 | 37 | ota: 38 | - platform: esphome 39 | password: !secret ota_pass 40 | 41 | web_server: 42 | port: 80 43 | 44 | uart: 45 | id: ac_uart_bus 46 | tx_pin: GPIO1 47 | rx_pin: GPIO3 48 | baud_rate: 4800 49 | data_bits: 8 50 | parity: EVEN 51 | stop_bits: 1 52 | 53 | sensor: 54 | - platform: uptime 55 | name: Uptime Sensor 56 | 57 | climate: 58 | - platform: aux_ac 59 | name: $upper_devicename 60 | id: aux_id 61 | uart_id: ac_uart_bus 62 | period: 7s 63 | show_action: true 64 | display_inverted: true 65 | timeout: 150 66 | indoor_temperature: 67 | name: $upper_devicename Indoor Temperature 68 | id: ${devicename}_indoor_temp 69 | internal: false 70 | display_state: 71 | name: $upper_devicename Display State 72 | id: ${devicename}_display_state 73 | internal: false 74 | outdoor_temperature: 75 | name: $upper_devicename Outdoor Temperature 76 | id: ${devicename}_outdoor_temp 77 | internal: false 78 | outbound_temperature: 79 | name: $upper_devicename Coolant Outbound Temperature 80 | id: ${devicename}_outbound_temp 81 | internal: false 82 | inbound_temperature: 83 | name: $upper_devicename Coolant Inbound Temperature 84 | id: ${devicename}_inbound_temp 85 | internal: false 86 | compressor_temperature: 87 | name: $upper_devicename Compressor Temperature 88 | id: ${devicename}_strange_temp 89 | internal: false 90 | defrost_state: 91 | name: $upper_devicename Defrost State 92 | id: ${devicename}_defrost_state 93 | internal: false 94 | inverter_power: 95 | name: $upper_devicename Inverter Power 96 | id: ${devicename}_invertor_power 97 | internal: false 98 | preset_reporter: 99 | name: $upper_devicename Preset Reporter 100 | id: ${devicename}_preset_reporter 101 | internal: false 102 | inverter_power_limit_value: 103 | name: $upper_devicename Inverter Power Limit Value 104 | id: ${devicename}_inverter_power_limit_value 105 | internal: false 106 | inverter_power_limit_state: 107 | name: $upper_devicename Inverter Power Limit State 108 | id: ${devicename}_inverter_power_limit_state 109 | internal: false 110 | visual: 111 | min_temperature: 16 112 | max_temperature: 32 113 | temperature_step: 0.5 114 | supported_modes: 115 | - HEAT_COOL 116 | - COOL 117 | - HEAT 118 | - DRY 119 | - FAN_ONLY 120 | custom_fan_modes: 121 | - MUTE 122 | - TURBO 123 | supported_presets: 124 | - SLEEP 125 | custom_presets: 126 | - CLEAN 127 | - HEALTH 128 | - ANTIFUNGUS 129 | supported_swing_modes: 130 | - VERTICAL 131 | - HORIZONTAL 132 | - BOTH 133 | 134 | 135 | button: 136 | - platform: template 137 | name: ${upper_devicename} IPower Limit Off 138 | icon: "mdi:power-plug-off-outline" 139 | on_press: 140 | - aux_ac.power_limit_off: aux_id 141 | 142 | - platform: template 143 | name: ${upper_devicename} IPower Limit On Half 144 | icon: "mdi:fraction-one-half" 145 | on_press: 146 | - aux_ac.power_limit_on: 147 | id: aux_id 148 | limit: 50 149 | 150 | number: 151 | - platform: template 152 | name: ${upper_devicename} IPower Limit Value 153 | id: ${devicename}_ipower_limit_value 154 | icon: "mdi:battery-unknown" 155 | mode: "slider" 156 | min_value: 30 157 | max_value: 100 158 | step: 1 159 | set_action: 160 | then: 161 | - lambda: !lambda |- 162 | id(aux_id).powerLimitationOnSequence( x ); 163 | 164 | -------------------------------------------------------------------------------- /tests/test-local-airflow-dir.yaml: -------------------------------------------------------------------------------- 1 | external_components: 2 | - source: 3 | type: local 4 | path: ../components 5 | 6 | substitutions: 7 | devicename: test_local_airflow_dir 8 | upper_devicename: Test AUX 9 | 10 | esphome: 11 | name: $devicename 12 | platform: ESP8266 13 | board: esp12e 14 | 15 | wifi: 16 | ssid: !secret wifi_ssid 17 | password: !secret wifi_pass 18 | manual_ip: 19 | static_ip: !secret wifi_ip 20 | gateway: !secret wifi_gateway 21 | subnet: !secret wifi_subnet 22 | dns1: 8.8.8.8 23 | dns2: 1.1.1.1 24 | reboot_timeout: 0s 25 | ap: 26 | ssid: $upper_devicename Fallback Hotspot 27 | password: !secret wifi_ap_pass 28 | 29 | logger: 30 | level: DEBUG 31 | baud_rate: 0 32 | 33 | api: 34 | password: !secret api_pass 35 | reboot_timeout: 0s 36 | 37 | ota: 38 | - platform: esphome 39 | password: !secret ota_pass 40 | 41 | web_server: 42 | port: 80 43 | 44 | uart: 45 | id: ac_uart_bus 46 | tx_pin: GPIO1 47 | rx_pin: GPIO3 48 | baud_rate: 4800 49 | data_bits: 8 50 | parity: EVEN 51 | stop_bits: 1 52 | 53 | 54 | sensor: 55 | - platform: uptime 56 | name: Uptime Sensor 57 | 58 | 59 | climate: 60 | - platform: aux_ac 61 | name: $upper_devicename 62 | id: aux_id 63 | uart_id: ac_uart_bus 64 | period: 7s 65 | show_action: true 66 | display_inverted: true 67 | 68 | 69 | button: 70 | - platform: template 71 | name: ${upper_devicename} VLouver Stop 72 | icon: "mdi:circle-small" 73 | on_press: 74 | - aux_ac.vlouver_stop: aux_id 75 | 76 | - platform: template 77 | name: ${upper_devicename} VLouver Swing 78 | icon: "mdi:pan-vertical" 79 | on_press: 80 | - aux_ac.vlouver_swing: aux_id 81 | 82 | - platform: template 83 | name: ${upper_devicename} VLouver Top 84 | icon: "mdi:pan-up" 85 | on_press: 86 | - aux_ac.vlouver_top: aux_id 87 | 88 | - platform: template 89 | name: ${upper_devicename} VLouver Middle Above 90 | icon: "mdi:pan-top-left" 91 | on_press: 92 | - aux_ac.vlouver_middle_above: aux_id 93 | 94 | - platform: template 95 | name: ${upper_devicename} VLouver Middle 96 | icon: "mdi:pan-left" 97 | on_press: 98 | - aux_ac.vlouver_middle: aux_id 99 | 100 | - platform: template 101 | name: ${upper_devicename} VLouver Middle Below 102 | icon: "mdi:pan-bottom-left" 103 | on_press: 104 | - aux_ac.vlouver_middle_below: aux_id 105 | 106 | - platform: template 107 | name: ${upper_devicename} VLouver Bottom 108 | icon: "mdi:pan-down" 109 | on_press: 110 | - aux_ac.vlouver_bottom: aux_id 111 | 112 | 113 | number: 114 | - platform: template 115 | name: ${upper_devicename} Vertical Louver 116 | id: ${devicename}_vlouver 117 | icon: "mdi:circle-small" 118 | mode: "slider" 119 | min_value: 0 120 | max_value: 6 121 | step: 1 122 | set_action: 123 | then: 124 | - lambda: !lambda |- 125 | if (x == 6) x = 7; // делаем так, чтобы выключение отрабатывать корректно 126 | id(aux_id).setVLouverSequence( static_cast(x) ); 127 | -------------------------------------------------------------------------------- /tests/test-local-power-limit.yaml: -------------------------------------------------------------------------------- 1 | external_components: 2 | - source: 3 | type: local 4 | path: ../components 5 | 6 | substitutions: 7 | devicename: test_local_power_limitations 8 | upper_devicename: Test AUX 9 | 10 | esphome: 11 | name: $devicename 12 | platform: ESP8266 13 | board: esp12e 14 | 15 | wifi: 16 | ssid: !secret wifi_ssid 17 | password: !secret wifi_pass 18 | manual_ip: 19 | static_ip: !secret wifi_ip 20 | gateway: !secret wifi_gateway 21 | subnet: !secret wifi_subnet 22 | dns1: 8.8.8.8 23 | dns2: 1.1.1.1 24 | reboot_timeout: 0s 25 | ap: 26 | ssid: Test AUX Fallback Hotspot 27 | password: !secret wifi_ap_pass 28 | 29 | logger: 30 | level: DEBUG 31 | baud_rate: 0 32 | 33 | api: 34 | password: !secret api_pass 35 | reboot_timeout: 0s 36 | 37 | ota: 38 | - platform: esphome 39 | password: !secret ota_pass 40 | 41 | web_server: 42 | port: 80 43 | 44 | uart: 45 | id: ac_uart_bus 46 | tx_pin: GPIO1 47 | rx_pin: GPIO3 48 | baud_rate: 4800 49 | data_bits: 8 50 | parity: EVEN 51 | stop_bits: 1 52 | 53 | sensor: 54 | - platform: uptime 55 | name: Uptime Sensor 56 | 57 | climate: 58 | - platform: aux_ac 59 | name: $upper_devicename 60 | id: aux_id 61 | uart_id: ac_uart_bus 62 | period: 7s 63 | show_action: true 64 | display_inverted: true 65 | timeout: 150 66 | indoor_temperature: 67 | name: $upper_devicename Indoor Temperature 68 | id: ${devicename}_indoor_temp 69 | internal: false 70 | display_state: 71 | name: $upper_devicename Display State 72 | id: ${devicename}_display_state 73 | internal: false 74 | outdoor_temperature: 75 | name: $upper_devicename Outdoor Temperature 76 | id: ${devicename}_outdoor_temp 77 | internal: false 78 | outbound_temperature: 79 | name: $upper_devicename Coolant Outbound Temperature 80 | id: ${devicename}_outbound_temp 81 | internal: false 82 | inbound_temperature: 83 | name: $upper_devicename Coolant Inbound Temperature 84 | id: ${devicename}_inbound_temp 85 | internal: false 86 | compressor_temperature: 87 | name: $upper_devicename Compressor Temperature 88 | id: ${devicename}_strange_temp 89 | internal: false 90 | defrost_state: 91 | name: $upper_devicename Defrost State 92 | id: ${devicename}_defrost_state 93 | internal: false 94 | inverter_power: 95 | name: $upper_devicename Inverter Power 96 | id: ${devicename}_invertor_power 97 | internal: false 98 | preset_reporter: 99 | name: $upper_devicename Preset Reporter 100 | id: ${devicename}_preset_reporter 101 | internal: false 102 | inverter_power_limit_value: 103 | name: $upper_devicename Inverter Power Limit Value 104 | id: ${devicename}_inverter_power_limit_value 105 | internal: false 106 | inverter_power_limit_state: 107 | name: $upper_devicename Inverter Power Limit State 108 | id: ${devicename}_inverter_power_limit_state 109 | internal: false 110 | visual: 111 | min_temperature: 16 112 | max_temperature: 32 113 | temperature_step: 0.5 114 | supported_modes: 115 | - HEAT_COOL 116 | - COOL 117 | - HEAT 118 | - DRY 119 | - FAN_ONLY 120 | custom_fan_modes: 121 | - MUTE 122 | - TURBO 123 | supported_presets: 124 | - SLEEP 125 | custom_presets: 126 | - CLEAN 127 | - HEALTH 128 | - ANTIFUNGUS 129 | supported_swing_modes: 130 | - VERTICAL 131 | - HORIZONTAL 132 | - BOTH 133 | 134 | 135 | button: 136 | - platform: template 137 | name: ${upper_devicename} IPower Limit Off 138 | icon: "mdi:power-plug-off-outline" 139 | on_press: 140 | - aux_ac.power_limit_off: aux_id 141 | 142 | - platform: template 143 | name: ${upper_devicename} IPower Limit On Half 144 | icon: "mdi:fraction-one-half" 145 | on_press: 146 | - aux_ac.power_limit_on: 147 | id: aux_id 148 | limit: 50 149 | 150 | number: 151 | - platform: template 152 | name: ${upper_devicename} IPower Limit Value 153 | id: ${devicename}_ipower_limit_value 154 | icon: "mdi:battery-unknown" 155 | mode: "slider" 156 | min_value: 30 157 | max_value: 100 158 | step: 1 159 | set_action: 160 | then: 161 | - lambda: !lambda |- 162 | id(aux_id).powerLimitationOnSequence( x ); 163 | 164 | -------------------------------------------------------------------------------- /tests/test-local.yaml: -------------------------------------------------------------------------------- 1 | external_components: 2 | - source: 3 | type: local 4 | path: ../components 5 | 6 | substitutions: 7 | devicename: test_local_airflow_dir 8 | upper_devicename: Test AUX 9 | 10 | esphome: 11 | name: $devicename 12 | platform: ESP8266 13 | board: esp12e 14 | 15 | wifi: 16 | ssid: !secret wifi_ssid 17 | password: !secret wifi_pass 18 | manual_ip: 19 | static_ip: !secret wifi_ip 20 | gateway: !secret wifi_gateway 21 | subnet: !secret wifi_subnet 22 | dns1: 8.8.8.8 23 | dns2: 1.1.1.1 24 | reboot_timeout: 0s 25 | ap: 26 | ssid: Test AUX Fallback Hotspot 27 | password: !secret wifi_ap_pass 28 | 29 | logger: 30 | level: DEBUG 31 | baud_rate: 0 32 | 33 | api: 34 | password: !secret api_pass 35 | reboot_timeout: 0s 36 | 37 | ota: 38 | - platform: esphome 39 | password: !secret ota_pass 40 | 41 | web_server: 42 | port: 80 43 | 44 | uart: 45 | id: ac_uart_bus 46 | tx_pin: GPIO1 47 | rx_pin: GPIO3 48 | baud_rate: 4800 49 | data_bits: 8 50 | parity: EVEN 51 | stop_bits: 1 52 | 53 | sensor: 54 | - platform: uptime 55 | name: Uptime Sensor 56 | 57 | climate: 58 | - platform: aux_ac 59 | name: $upper_devicename 60 | id: aux_id 61 | uart_id: ac_uart_bus 62 | period: 7s 63 | show_action: true 64 | display_inverted: true 65 | optimistic: true 66 | indoor_temperature: 67 | name: $upper_devicename Indoor Temperature 68 | id: ${devicename}_indoor_temp 69 | internal: false 70 | display_state: 71 | name: $upper_devicename Display State 72 | id: ${devicename}_display_state 73 | internal: false 74 | outdoor_temperature: 75 | name: $upper_devicename Outdoor Temperature 76 | id: ${devicename}_outdoor_temp 77 | internal: false 78 | outbound_temperature: 79 | name: $upper_devicename Coolant Outbound Temperature 80 | id: ${devicename}_outbound_temp 81 | internal: false 82 | inbound_temperature: 83 | name: $upper_devicename Coolant Inbound Temperature 84 | id: ${devicename}_inbound_temp 85 | internal: false 86 | compressor_temperature: 87 | name: $upper_devicename Compressor Temperature 88 | id: ${devicename}_strange_temp 89 | internal: false 90 | defrost_state: 91 | name: $upper_devicename Defrost State 92 | id: ${devicename}_defrost_state 93 | internal: false 94 | inverter_power: 95 | name: $upper_devicename Invertor Power 96 | id: ${devicename}_invertor_power 97 | internal: false 98 | preset_reporter: 99 | name: $upper_devicename Preset Reporter 100 | id: ${devicename}_preset_reporter 101 | internal: false 102 | visual: 103 | min_temperature: 16 104 | max_temperature: 32 105 | temperature_step: 0.5 106 | supported_modes: 107 | - HEAT_COOL 108 | - COOL 109 | - HEAT 110 | - DRY 111 | - FAN_ONLY 112 | custom_fan_modes: 113 | - MUTE 114 | - TURBO 115 | supported_presets: 116 | - SLEEP 117 | custom_presets: 118 | - CLEAN 119 | - HEALTH 120 | - ANTIFUNGUS 121 | supported_swing_modes: 122 | - VERTICAL 123 | - HORIZONTAL 124 | - BOTH 125 | -------------------------------------------------------------------------------- /tests/test-minimal.yaml: -------------------------------------------------------------------------------- 1 | external_components: 2 | - source: 3 | type: local 4 | path: ../components 5 | #- source: github://GrKoR/esphome_aux_ac_component@dev 6 | #components: [ aux_ac ] 7 | #refresh: 0s 8 | 9 | substitutions: 10 | devicename: test_local_minimal 11 | upper_devicename: Test AUX 12 | 13 | esphome: 14 | name: $devicename 15 | platform: ESP8266 16 | board: esp12e 17 | 18 | wifi: 19 | ssid: !secret wifi_ssid 20 | password: !secret wifi_pass 21 | reboot_timeout: 0s 22 | ap: 23 | ssid: $upper_devicename Fallback Hotspot 24 | password: !secret wifi_ap_pass 25 | 26 | logger: 27 | level: DEBUG 28 | baud_rate: 0 29 | 30 | api: 31 | password: !secret api_pass 32 | reboot_timeout: 0s 33 | 34 | ota: 35 | - platform: esphome 36 | password: !secret ota_pass 37 | 38 | uart: 39 | id: ac_uart_bus 40 | tx_pin: GPIO1 41 | rx_pin: GPIO3 42 | baud_rate: 4800 43 | data_bits: 8 44 | parity: EVEN 45 | stop_bits: 1 46 | 47 | climate: 48 | - platform: aux_ac 49 | name: $upper_devicename --------------------------------------------------------------------------------