mirror of
https://github.com/GrKoR/esphome_aux_ac_component.git
synced 2025-12-06 11:36:55 +03:00
v.0.2.9: new feature - power limitation for inverter ACs; communication timeout was took out to the yaml config
v.0.2.9: new feature - power limitation for inverter ACs
This commit is contained in:
79
README-EN.md
79
README-EN.md
@@ -99,6 +99,7 @@ climate:
|
|||||||
period: 7s
|
period: 7s
|
||||||
show_action: true
|
show_action: true
|
||||||
display_inverted: false
|
display_inverted: false
|
||||||
|
timeout: 150
|
||||||
indoor_temperature:
|
indoor_temperature:
|
||||||
name: AC Indoor Temperature
|
name: AC Indoor Temperature
|
||||||
id: ac_indoor_temp
|
id: ac_indoor_temp
|
||||||
@@ -128,9 +129,17 @@ climate:
|
|||||||
name: AC Defrost State
|
name: AC Defrost State
|
||||||
id: ac_defrost_state
|
id: ac_defrost_state
|
||||||
internal: false
|
internal: false
|
||||||
invertor_power:
|
inverter_power:
|
||||||
name: AC Invertor Power
|
name: AC Inverter Power
|
||||||
id: ac_invertor_power
|
id: ac_inverter_power
|
||||||
|
internal: false
|
||||||
|
inverter_power_limit_value:
|
||||||
|
name: AC Inverter Power Limit Value
|
||||||
|
id: ac_inverter_power_limit_value
|
||||||
|
internal: false
|
||||||
|
inverter_power_limit_state:
|
||||||
|
name: AC Inverter Power Limit State
|
||||||
|
id: ac_inverter_power_limit_state
|
||||||
internal: false
|
internal: false
|
||||||
preset_reporter:
|
preset_reporter:
|
||||||
name: AC Preset Reporter
|
name: AC Preset Reporter
|
||||||
@@ -166,43 +175,77 @@ climate:
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Configuration variables: ##
|
## Configuration variables: ##
|
||||||
|
|
||||||
- **name** (**Required**, string): The name of the climate device. At least one of `id` or `name` is required!
|
- **name** (**Required**, string): The name of the climate device. At least one of `id` or `name` is required!
|
||||||
|
|
||||||
- **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!
|
- **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!
|
||||||
|
|
||||||
- **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.
|
- **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.
|
||||||
|
|
||||||
- **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.
|
- **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.
|
||||||
|
|
||||||
- **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:
|
- **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:
|
||||||
- HEATING: AC is heating the air in the room;
|
- HEATING: AC is heating the air in the room;
|
||||||
- IDLE: AC is working in the FAN mode, cause the target temperature is reached;
|
- IDLE: AC is working in the FAN mode, cause the target temperature is reached;
|
||||||
- COOLING: AC is cooling the air.
|
- COOLING: AC is cooling the air.
|
||||||
The same thing will be in HEAT or COOL modes, with the only difference of the list of actions (IDLE + HEATING or IDLE + COOLING).
|
The same thing will be in HEAT or COOL modes, with the only difference of the list of actions (IDLE + HEATING or IDLE + COOLING).
|
||||||
|
|
||||||
- **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.
|
- **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.
|
||||||
|
|
||||||
|
- **timeout** (*Optional*, unsigned integer, default ``150``): Packet timeout for `aux_ac` data receiver.
|
||||||
|
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.
|
||||||
|
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.
|
||||||
|
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.
|
||||||
|
|
||||||
- **indoor_temperature** (*Optional*): Parameters of the room air temperature sensor.
|
- **indoor_temperature** (*Optional*): Parameters of the room air temperature sensor.
|
||||||
- **name** (**Required**, string): The name for the temperature sensor.
|
- **name** (**Required**, string): The name for the temperature sensor.
|
||||||
- **id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Set the ID of this sensor for use in lambdas.
|
- **id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Set the ID of this sensor for use in lambdas.
|
||||||
- **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.
|
- **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.
|
||||||
- All other options from [Sensor](https://esphome.io/components/sensor/index.html#base-sensor-configuration).
|
- All other options from [Sensor](https://esphome.io/components/sensor/index.html#base-sensor-configuration).
|
||||||
|
|
||||||
- **outdoor_temperature** (*Optional*): Parameters of the outdoor temperature sensor. They are the same as the **indoor_temperature** (see description above).
|
- **outdoor_temperature** (*Optional*): Parameters of the outdoor temperature sensor. They are the same as the **indoor_temperature** (see description above).
|
||||||
**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 is 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 direct copy the value of **outbound_temperature** to the template sensor in AC off mode, because these temperatures are not identical.
|
> **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.
|
||||||
|
|
||||||
- **inbound_temperature** (*Optional*): Parameters of the coolant inbound temperature sensor. They are the same as the **indoor_temperature** (see description above).
|
- **inbound_temperature** (*Optional*): Parameters of the coolant inbound temperature sensor. They are the same as the **indoor_temperature** (see description above).
|
||||||
|
|
||||||
- **outbound_temperature** (*Optional*): Parameters of the coolant outbound temperature sensor. They are the same as the **indoor_temperature** (see description above).
|
- **outbound_temperature** (*Optional*): Parameters of the coolant outbound temperature sensor. They are the same as the **indoor_temperature** (see description above).
|
||||||
|
|
||||||
- **compressor_temperature** (*Optional*): Parameters of the compressor temperature sensor. They are the same as the **indoor_temperature** (see description above).
|
- **compressor_temperature** (*Optional*): Parameters of the compressor temperature sensor. They are the same as the **indoor_temperature** (see description above).
|
||||||
|
|
||||||
- **display_state** (*Optional*): The information for the HVAC display state sensor (is display ON or OFF)
|
- **display_state** (*Optional*): The information for the HVAC display state sensor (is display ON or OFF)
|
||||||
- **name** (**Required**, string): The name for the display state sensor.
|
- **name** (**Required**, string): The name for the display state sensor.
|
||||||
- **id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Set the ID of this sensor for use in lambdas.
|
- **id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Set the ID of this sensor for use in lambdas.
|
||||||
- **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.
|
- **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.
|
||||||
- All other options from [Binary Sensor](https://esphome.io/components/binary_sensor/index.html#base-binary-sensor-configuration).
|
- All other options from [Binary Sensor](https://esphome.io/components/binary_sensor/index.html#base-binary-sensor-configuration).
|
||||||
|
|
||||||
- **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).
|
- **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).
|
||||||
- **invertor_power** (*Optional*): The information for the inverter power sensor. (Yes, I know about a mistake in the name of this parameter... I'll correct it... Sometimes :) ) All settings are the same as for the **display_state** (see description above).
|
|
||||||
|
- **inverter_power** (*Optional*): The information for the inverter power sensor. All settings are the same as for the **indoor_temperature** (see description above).
|
||||||
|
> **ATTENTION!** The parameter name was changed in v.0.2.9 due to incorrect spelling.
|
||||||
|
|
||||||
|
- **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).
|
||||||
|
|
||||||
|
- **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).
|
||||||
|
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.
|
||||||
|
|
||||||
- **preset_reporter** (*Optional*): Parameters of text sensor with current preset. All settings are the same as for the **display_state** (see description above).
|
- **preset_reporter** (*Optional*): Parameters of text sensor with current preset. All settings are the same as for the **display_state** (see description above).
|
||||||
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.
|
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.
|
||||||
|
|
||||||
- **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).
|
- **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).
|
||||||
|
|
||||||
- **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``.
|
- **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``.
|
||||||
|
|
||||||
- **custom_fan_modes** (*Optional*, list): List of supported custom fan modes. Possible values are: ``MUTE``, ``TURBO``. No custom fan modes by default.
|
- **custom_fan_modes** (*Optional*, list): List of supported custom fan modes. Possible values are: ``MUTE``, ``TURBO``. No custom fan modes by default.
|
||||||
|
|
||||||
- **supported_presets** (*Optional*, list): List of supported presets. Possible values are: ``SLEEP``. No presets by default.
|
- **supported_presets** (*Optional*, list): List of supported presets. Possible values are: ``SLEEP``. No presets by default.
|
||||||
|
|
||||||
- **custom_presets** (*Optional*, list): List of supported custom presets. Possible values are: ``CLEAN``, ``HEALTH``, ``ANTIFUNGUS``. No custom presets by default.
|
- **custom_presets** (*Optional*, list): List of supported custom presets. Possible values are: ``CLEAN``, ``HEALTH``, ``ANTIFUNGUS``. No custom presets by default.
|
||||||
|
|
||||||
- **supported_swing_modes** (*Optional*, list): List of supported swing modes. Possible values are: ``VERTICAL``, ``HORIZONTAL``, ``BOTH``. No swing modes by default.
|
- **supported_swing_modes** (*Optional*, list): List of supported swing modes. Possible values are: ``VERTICAL``, ``HORIZONTAL``, ``BOTH``. No swing modes by default.
|
||||||
|
|
||||||
- All other options from [Climate](https://esphome.io/components/climate/index.html#base-climate-configuration).
|
- All other options from [Climate](https://esphome.io/components/climate/index.html#base-climate-configuration).
|
||||||
|
|
||||||
|
|
||||||
## Actions: ##
|
## Actions: ##
|
||||||
### ``aux_ac.display_on`` ###
|
### ``aux_ac.display_on`` ###
|
||||||
This action turns a HVAC temperature display on when executed.
|
This action turns a HVAC temperature display on when executed.
|
||||||
@@ -316,6 +359,32 @@ on_...:
|
|||||||
```
|
```
|
||||||
- **aux_id** (**Required**, string): ID of `aux_ac` component.
|
- **aux_id** (**Required**, string): ID of `aux_ac` component.
|
||||||
|
|
||||||
|
### ``aux_ac.aux_ac.power_limit_off`` ###
|
||||||
|
This action disables inverter HVAC power limitation.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
on_...:
|
||||||
|
then:
|
||||||
|
- aux_ac.power_limit_off: aux_id
|
||||||
|
```
|
||||||
|
- **aux_id** (**Required**, string): ID of `aux_ac` component.
|
||||||
|
|
||||||
|
### ``aux_ac.power_limit_on`` ###
|
||||||
|
This action enables inverter HVAC power limitation and sets this limit value.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
on_...:
|
||||||
|
then:
|
||||||
|
- aux_ac.power_limit_on:
|
||||||
|
id: aux_id
|
||||||
|
limit: 46 # limits the maximum power of the inverter HVAC at 46%
|
||||||
|
```
|
||||||
|
- **aux_id** (**Required**, string): ID of `aux_ac` component.
|
||||||
|
- **limit** (**Optional**, integer): the maximum power of the inverter HVAC. If the power limitation is enabled, the inverter HVAC will limits its power.
|
||||||
|
> **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.
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Simple example ##
|
## Simple example ##
|
||||||
|
|||||||
80
README.md
80
README.md
@@ -97,6 +97,7 @@ climate:
|
|||||||
period: 7s
|
period: 7s
|
||||||
show_action: true
|
show_action: true
|
||||||
display_inverted: false
|
display_inverted: false
|
||||||
|
timeout: 150
|
||||||
indoor_temperature:
|
indoor_temperature:
|
||||||
name: AC Indoor Temperature
|
name: AC Indoor Temperature
|
||||||
id: ac_indoor_temp
|
id: ac_indoor_temp
|
||||||
@@ -126,9 +127,17 @@ climate:
|
|||||||
name: AC Defrost State
|
name: AC Defrost State
|
||||||
id: ac_defrost_state
|
id: ac_defrost_state
|
||||||
internal: false
|
internal: false
|
||||||
invertor_power:
|
inverter_power:
|
||||||
name: AC Invertor Power
|
name: AC Inverter Power
|
||||||
id: ac_invertor_power
|
id: ac_inverter_power
|
||||||
|
internal: false
|
||||||
|
inverter_power_limit_value:
|
||||||
|
name: AC Inverter Power Limit Value
|
||||||
|
id: ac_inverter_power_limit_value
|
||||||
|
internal: false
|
||||||
|
inverter_power_limit_state:
|
||||||
|
name: AC Inverter Power Limit State
|
||||||
|
id: ac_inverter_power_limit_state
|
||||||
internal: false
|
internal: false
|
||||||
preset_reporter:
|
preset_reporter:
|
||||||
name: AC Preset Reporter
|
name: AC Preset Reporter
|
||||||
@@ -164,41 +173,75 @@ climate:
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Параметры компонента: ##
|
## Параметры компонента: ##
|
||||||
|
|
||||||
- **name** (**Обязательный**, строка): Имя кондиционера. Как минимум один из параметров `id` или `name` должен быть указан!
|
- **name** (**Обязательный**, строка): Имя кондиционера. Как минимум один из параметров `id` или `name` должен быть указан!
|
||||||
|
|
||||||
- **id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Укажите идентификатор кондиционера чтобы обращаться к нему из кода. Как минимум один из параметров `id` или `name` должен быть указан!
|
- **id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Укажите идентификатор кондиционера чтобы обращаться к нему из кода. Как минимум один из параметров `id` или `name` должен быть указан!
|
||||||
|
|
||||||
- **uart_id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Укажите ID [шины UART](https://esphome.io/components/uart.html), к которой подключен кондиционер. Если сконфигурирована одна шина, то компонент подключит её автоматически. Если шин несколько, то лучше указать вручную.
|
- **uart_id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Укажите ID [шины UART](https://esphome.io/components/uart.html), к которой подключен кондиционер. Если сконфигурирована одна шина, то компонент подключит её автоматически. Если шин несколько, то лучше указать вручную.
|
||||||
|
|
||||||
- **period** (*Опциональный*, [время](https://esphome.io/guides/configuration-types.html#config-time), по умолчанию ``7s``): Период между запросами статуса кондиционера. `Aux_ac` получает новое состояние кондиционера только после регулярного запроса, потому что сам кондиционер об изменении параметров своеё работы не уведомляет. Поэтому нужно запрашивать его, вдруг пользователь установил иной режим работы с помощью ИК-пульта.
|
- **period** (*Опциональный*, [время](https://esphome.io/guides/configuration-types.html#config-time), по умолчанию ``7s``): Период между запросами статуса кондиционера. `Aux_ac` получает новое состояние кондиционера только после регулярного запроса, потому что сам кондиционер об изменении параметров своеё работы не уведомляет. Поэтому нужно запрашивать его, вдруг пользователь установил иной режим работы с помощью ИК-пульта.
|
||||||
|
|
||||||
- **show_action** (*Опциональный*, логическое, по умолчанию ``true``): Показывать ли текущую задачу кондиционера (экспериментальная функция). Например, в режиме HEAT-COOL кондиционер может выполнять одну из следующих задач:
|
- **show_action** (*Опциональный*, логическое, по умолчанию ``true``): Показывать ли текущую задачу кондиционера (экспериментальная функция). Например, в режиме HEAT-COOL кондиционер может выполнять одну из следующих задач:
|
||||||
- НАГРЕВ: нагревает воздух в комнате;
|
- НАГРЕВ: нагревает воздух в комнате;
|
||||||
- ПРОСТОЙ: кондиционер работает в режиме вентилятора для перемешивания воздуха в комнате, поскольку целевая температура уже достигнута;
|
- ПРОСТОЙ: кондиционер работает в режиме вентилятора для перемешивания воздуха в комнате, поскольку целевая температура уже достигнута;
|
||||||
- ОХЛАЖДЕНИЕ: кондиционер охлаждает воздух в комнате.
|
- ОХЛАЖДЕНИЕ: кондиционер охлаждает воздух в комнате.
|
||||||
Аналогично будут отображаться действия кондиционера и для режимов ОТОПЛЕНИЕ и ОХЛАЖДЕНИЕ. Единственная разница будет в количестве действий: ПРОСТОЙ+НАГРЕВ для режима отопления и ПРОСТОЙ+ОХЛАЖДЕНИЕ для режима охлаждения комнаты.
|
Аналогично будут отображаться действия кондиционера и для режимов ОТОПЛЕНИЕ и ОХЛАЖДЕНИЕ. Единственная разница будет в количестве действий: ПРОСТОЙ+НАГРЕВ для режима отопления и ПРОСТОЙ+ОХЛАЖДЕНИЕ для режима охлаждения комнаты.
|
||||||
|
|
||||||
- **display_inverted** (*Опциональный*, логическое, по умолчанию ``false``): Настраивает способ управления дисплеем. Как выяснилось (issue [#31](https://github.com/GrKoR/esphome_aux_ac_component/issues/31)), включение-выключение дисплея обрабатывается кондиционерами по разному. Кондиционеры Rovex включают дисплей по `0` в соответствующем бите команды и выключают по биту `1`. Многие другие модели кондиционеров поступают наоборот.
|
- **display_inverted** (*Опциональный*, логическое, по умолчанию ``false``): Настраивает способ управления дисплеем. Как выяснилось (issue [#31](https://github.com/GrKoR/esphome_aux_ac_component/issues/31)), включение-выключение дисплея обрабатывается кондиционерами по разному. Кондиционеры Rovex включают дисплей по `0` в соответствующем бите команды и выключают по биту `1`. Многие другие модели кондиционеров поступают наоборот.
|
||||||
|
|
||||||
|
- **timeout** (*Опциональный*, неотрицательное целое, по умолчанию ``150``): Таймаут получения пакета для ресивера данных `aux_ac`.
|
||||||
|
Чаще всего вам это значение никогда не понадобится. Поскольку этот параметр опционален, то его можно смело пропустить, если нет необходимости менять таймауты.
|
||||||
|
Единственная ситуация, когда вам может пригодиться этот параметр, - это сильно загруженная ESP. Если по какой-то неподдающейся логике причине вы кроме `aux_ac` нагрузили свою ESP кучей дополнительных ресурсоемких задач, то у компонента может просто не хватать времени для оперативного приёма ответов от кондиционера. В этом в логе будут сообщения о том, что последовательность команд была прервана по таймауту. Чтобы это исправить, лучше, конечно, немного разгрузить ESP. Если это вам не подходит, тогда можно увеличить таймаут.
|
||||||
|
Значение таймаута в прошивке ограничено диапазоном от `150` до `600` миллисекунд. Устанавливать значения выше можно только отредактировав исходные коды компонента. Но сильно задирать таймаут не стоит. Кондиционер периодически рассылает пакеты без запроса со стороны `aux_ac` и это приводит к сбою в отправке команды.
|
||||||
|
|
||||||
- **indoor_temperature** (*Опциональный*): Параметры создаваемого датчика температуры воздуха, если такой датчик нужен
|
- **indoor_temperature** (*Опциональный*): Параметры создаваемого датчика температуры воздуха, если такой датчик нужен
|
||||||
- **name** (**Обязательный**, строка): Имя датчика температуры.
|
- **name** (**Обязательный**, строка): Имя датчика температуры.
|
||||||
- **id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Можно указать свой ID для датчика для использования в лямбдах.
|
- **id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Можно указать свой ID для датчика для использования в лямбдах.
|
||||||
- **internal** (*Опциональный*, логическое): Пометить данный датчик как внутренний. Внутренний датчик не будет передаваться во фронтэнд (такой как Home Assistant). В противоположность стандартному поведению [сенсоров](https://esphome.io/components/sensor/index.html#base-sensor-configuration) этот параметр для датчика в кондиционере **всегда выставлен в true** за исключением случаев, когда пользователь не установил его в `false`. То есть по умолчанию значение сенсора не будет передаваться во фронтенд даже если указано `name` для сенсора.
|
- **internal** (*Опциональный*, логическое): Пометить данный датчик как внутренний. Внутренний датчик не будет передаваться во фронтэнд (такой как Home Assistant). В противоположность стандартному поведению [сенсоров](https://esphome.io/components/sensor/index.html#base-sensor-configuration) этот параметр для датчика в кондиционере **всегда выставлен в true** за исключением случаев, когда пользователь не установил его в `false`. То есть по умолчанию значение сенсора не будет передаваться во фронтенд даже если указано `name` для сенсора.
|
||||||
- Все остальные параметры [сенсора](https://esphome.io/components/sensor/index.html#base-sensor-configuration) ESPHome.
|
- Все остальные параметры [сенсора](https://esphome.io/components/sensor/index.html#base-sensor-configuration) ESPHome.
|
||||||
|
|
||||||
- **outdoor_temperature** (*Опциональный*): Параметры создаваемого датчика уличной температуры воздуха, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше).
|
- **outdoor_temperature** (*Опциональный*): Параметры создаваемого датчика уличной температуры воздуха, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше).
|
||||||
**ВНИМАНИЕ!** Когда кондиционер выключен, температура наружного воздуха обновляется редко (раз в 6-7 часов). Это не баг компонента, а особенность работы железа кондиционера. Единственный способ получать изменения чаще - создать шаблонный сенсор, температуру которого изменять в ручную. Когда кондиционер работает, значение такого сенсора можно копировать из **outdoor_temperature**. Когда кондиционер выключен, значение температуры пересчитывать по динамике сенсора **outbound_temperature** (он изменяется часто и при выключенном кондее показывает значения близкие к температуре воздуха). Заморочки с пересчетом нужны потому, что показания сенсоров не идентичны и на графике значений шаблонного сенсора могут быть ступеньки при переходе с **outdoor_temperature** на **outbound_temperature** и обратно.
|
> **ВНИМАНИЕ!** Когда кондиционер выключен, температура наружного воздуха обновляется редко (раз в 6-7 часов). Это не баг компонента, а особенность работы железа кондиционера. Единственный способ получать изменения чаще - создать шаблонный сенсор, температуру которого изменять в ручную. Когда кондиционер работает, значение такого сенсора можно копировать из **outdoor_temperature**. Когда кондиционер выключен, значение температуры пересчитывать по динамике сенсора **outbound_temperature** (он изменяется часто и при выключенном кондее показывает значения близкие к температуре воздуха). Заморочки с пересчетом нужны потому, что показания сенсоров не идентичны и на графике значений шаблонного сенсора могут быть ступеньки при переходе с **outdoor_temperature** на **outbound_temperature** и обратно.
|
||||||
|
|
||||||
- **inbound_temperature** (*Опциональный*): Параметры создаваемого датчика температуры на подаче теплоносителя, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше).
|
- **inbound_temperature** (*Опциональный*): Параметры создаваемого датчика температуры на подаче теплоносителя, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше).
|
||||||
|
|
||||||
- **outbound_temperature** (*Опциональный*): Параметры создаваемого датчика температуры на обратке теплоносителя, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше).
|
- **outbound_temperature** (*Опциональный*): Параметры создаваемого датчика температуры на обратке теплоносителя, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше).
|
||||||
|
|
||||||
- **compressor_temperature** (*Опциональный*): Параметры создаваемого датчика температуры компрессора, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше).
|
- **compressor_temperature** (*Опциональный*): Параметры создаваемого датчика температуры компрессора, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше).
|
||||||
|
|
||||||
- **display_state** (*Опциональный*): Параметры создаваемого датчика дисплея (включен или выключен), если такой датчик нужен.
|
- **display_state** (*Опциональный*): Параметры создаваемого датчика дисплея (включен или выключен), если такой датчик нужен.
|
||||||
- **name** (**Обязательный**, строка): Имя датчика дисплея.
|
- **name** (**Обязательный**, строка): Имя датчика дисплея.
|
||||||
- **id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Можно указать свой ID для датчика для использования в лямбдах.
|
- **id** (*Опциональный*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Можно указать свой ID для датчика для использования в лямбдах.
|
||||||
- **internal** (*Опциональный*, логическое): Пометить данный датчик как внутренний. Внутренний датчик не будет передаваться во фронтэнд (такой как Home Assistant). В противоположность стандартному поведению [бинарных сенсоров](https://esphome.io/components/binary_sensor/index.html#base-binary-sensor-configuration) этот параметр для датчика в кондиционере **всегда выставлен в true** за исключением случаев, когда пользователь не установил его в `false`. То есть по умолчанию значение сенсора не будет передаваться во фронтенд даже если указано `name` для сенсора.
|
- **internal** (*Опциональный*, логическое): Пометить данный датчик как внутренний. Внутренний датчик не будет передаваться во фронтэнд (такой как Home Assistant). В противоположность стандартному поведению [бинарных сенсоров](https://esphome.io/components/binary_sensor/index.html#base-binary-sensor-configuration) этот параметр для датчика в кондиционере **всегда выставлен в true** за исключением случаев, когда пользователь не установил его в `false`. То есть по умолчанию значение сенсора не будет передаваться во фронтенд даже если указано `name` для сенсора.
|
||||||
- Все остальные параметры [бинарного сенсора](https://esphome.io/components/binary_sensor/index.html#base-binary-sensor-configuration) ESPHome.
|
- Все остальные параметры [бинарного сенсора](https://esphome.io/components/binary_sensor/index.html#base-binary-sensor-configuration) ESPHome.
|
||||||
|
|
||||||
- **defrost_state** (*Опциональный*): Параметры создаваемого датчика состояния разморозки (включена или выключена), если такой датчик нужен. Параметры аналогичны датчику дисплея **display_state**.
|
- **defrost_state** (*Опциональный*): Параметры создаваемого датчика состояния разморозки (включена или выключена), если такой датчик нужен. Параметры аналогичны датчику дисплея **display_state**.
|
||||||
- **invertor_power** (*Опциональный*): Параметры создаваемого датчика мощности инвертора, если такой датчик нужен. Параметры аналогичны датчику дисплея **display_state**.
|
|
||||||
|
- **inverter_power** (*Опциональный*): Параметры создаваемого датчика мощности инвертора, если такой датчик нужен. Параметры аналогичны датчику дисплея **indoor_temperature**.
|
||||||
|
> **ВНИМАНИЕ!** Название параметра было изменено в версии v.0.2.9 в рамках борьбы с безграмотностью.
|
||||||
|
|
||||||
|
- **inverter_power_limit_state** (*Опциональный*): Параметры создаваемого датчика состояния функции ограничения мощности. Показывает, включена данная функция в настоящий момент или нет. По очевидным причинам актуально только для инверторных кондиционеров, для "старт-стоп" кондиционеров всегда будет "выключен". Параметры аналогичны датчику дисплея **display_state**.
|
||||||
|
|
||||||
|
- **inverter_power_limit_value** (*Опциональный*): Параметры создаваемого датчика текущего ограничения мощности, если такой датчик нужен. Параметры аналогичны датчику внутренней температуры **indoor_temperature** (см. выше).
|
||||||
|
Сенсор отображает текущее значение ограничения максимальной мощности для инверторного кондиционера. Значение в процентах. С кондиционерами "старт-стоп" по очевидным причинам не работает, всегда показывая значение `0%`. Заданное пользователем значения лимита будет отображено только после того, как кондиционер подтвердит полученное значение и начнет с ним работать.
|
||||||
|
В силу ограничений на уровне железа лимит мощности может быть задан только в пределах от `30%` до `100%`.
|
||||||
|
|
||||||
- **preset_reporter** (*Опциональный*): Параметры создаваемого текстового датчика текущего активного пресета. Параметры аналогичны датчику дисплея **display_state**.
|
- **preset_reporter** (*Опциональный*): Параметры создаваемого текстового датчика текущего активного пресета. Параметры аналогичны датчику дисплея **display_state**.
|
||||||
Климатические устройства ESPHome не отправляют по MQTT активный пресет (см. **supported_presets** и **custom_presets**), в котором работает устройство. Если вы используете MQTT и хотите получать информацию о пресетах, то пропишите этот датчик в конфигурации.
|
Климатические устройства ESPHome не отправляют по MQTT активный пресет (см. **supported_presets** и **custom_presets**), в котором работает устройство. Если вы используете MQTT и хотите получать информацию о пресетах, то пропишите этот датчик в конфигурации.
|
||||||
|
|
||||||
- **vlouver_state** (*Опциональный*): Параметры создаваемого сенсора состояния вертикальных жалюзи. Параметры аналогичны датчику дисплея **display_state**. Состояние желюзи кодируется целочисленными значениями (подробнее смотри [aux_ac.vlouver_set action](#aux_ac_._vlouver_set) ниже).
|
- **vlouver_state** (*Опциональный*): Параметры создаваемого сенсора состояния вертикальных жалюзи. Параметры аналогичны датчику дисплея **display_state**. Состояние желюзи кодируется целочисленными значениями (подробнее смотри [aux_ac.vlouver_set action](#aux_ac_._vlouver_set) ниже).
|
||||||
|
|
||||||
- **supported_modes** (*Опциональный*, список): Список поддерживаемых режимов работы. Возможные значения: ``HEAT_COOL``, ``COOL``, ``HEAT``, ``DRY``, ``FAN_ONLY``. Обратите внимание: некоторые производители кондиционеров указывают на пульте режим AUTO, хотя по факту этот режим не работает по расписанию и только лишь поддерживает целевую температуру. Такой режим в ESPHome называется HEAT_COOL. По умолчанию список содержит только значение ``FAN_ONLY``.
|
- **supported_modes** (*Опциональный*, список): Список поддерживаемых режимов работы. Возможные значения: ``HEAT_COOL``, ``COOL``, ``HEAT``, ``DRY``, ``FAN_ONLY``. Обратите внимание: некоторые производители кондиционеров указывают на пульте режим AUTO, хотя по факту этот режим не работает по расписанию и только лишь поддерживает целевую температуру. Такой режим в ESPHome называется HEAT_COOL. По умолчанию список содержит только значение ``FAN_ONLY``.
|
||||||
|
|
||||||
- **custom_fan_modes** (*Опциональный*, список): Список поддерживаемых дополнительных режимов вентилятора. Возможные значения: ``MUTE``, ``TURBO``. По умолчанию никакие дополнительные режимы не установлены.
|
- **custom_fan_modes** (*Опциональный*, список): Список поддерживаемых дополнительных режимов вентилятора. Возможные значения: ``MUTE``, ``TURBO``. По умолчанию никакие дополнительные режимы не установлены.
|
||||||
|
|
||||||
- **supported_presets** (*Опциональный*, список): Список поддерживаемых базовых функций кондиционера. Возможные значения: ``SLEEP``. По умолчанию никакие базовые функции не установлены.
|
- **supported_presets** (*Опциональный*, список): Список поддерживаемых базовых функций кондиционера. Возможные значения: ``SLEEP``. По умолчанию никакие базовые функции не установлены.
|
||||||
|
|
||||||
- **custom_presets** (*Опциональный*, список): Список поддерживаемых дополнительных функций кондиционера. Возможные значения: ``CLEAN``, ``HEALTH``, ``ANTIFUNGUS``. По умолчанию никакие дополнительные функции не установлены.
|
- **custom_presets** (*Опциональный*, список): Список поддерживаемых дополнительных функций кондиционера. Возможные значения: ``CLEAN``, ``HEALTH``, ``ANTIFUNGUS``. По умолчанию никакие дополнительные функции не установлены.
|
||||||
|
|
||||||
- **supported_swing_modes** (*Опциональный*, список): Список поддерживаемых режимов качания шторки. Возможные значения: ``VERTICAL``, ``HORIZONTAL``, ``BOTH``. По умолчанию устанавливается, что качание шторки кондиционером не поддерживается.
|
- **supported_swing_modes** (*Опциональный*, список): Список поддерживаемых режимов качания шторки. Возможные значения: ``VERTICAL``, ``HORIZONTAL``, ``BOTH``. По умолчанию устанавливается, что качание шторки кондиционером не поддерживается.
|
||||||
|
|
||||||
- Все остальные параметры [климатического устройства](https://esphome.io/components/climate/index.html#base-climate-configuration) ESPHome.
|
- Все остальные параметры [климатического устройства](https://esphome.io/components/climate/index.html#base-climate-configuration) ESPHome.
|
||||||
|
|
||||||
## Действия: ##
|
## Действия: ##
|
||||||
@@ -314,6 +357,33 @@ on_...:
|
|||||||
```
|
```
|
||||||
- **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`.
|
- **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`.
|
||||||
|
|
||||||
|
### ``aux_ac.power_limit_off`` ###
|
||||||
|
Отключает лимит мощности инверторного кондиционера, если такой лимит был установлен.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
on_...:
|
||||||
|
then:
|
||||||
|
- aux_ac.power_limit_off: aux_id
|
||||||
|
```
|
||||||
|
- **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`.
|
||||||
|
|
||||||
|
### ``aux_ac.power_limit_on`` ###
|
||||||
|
Включает ограничение мощности для инверторного кондиционера, а также может задавать предельное значение мощности. Для кондиционеров "старт-стоп" не работает, вызов игнорируется.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
on_...:
|
||||||
|
then:
|
||||||
|
- aux_ac.power_limit_on:
|
||||||
|
id: aux_id
|
||||||
|
limit: 46 # ограничивает максимальную мощность инверторного кондиционера на уровне 46%
|
||||||
|
```
|
||||||
|
- **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`.
|
||||||
|
- **limit** (**Опциональный**, целое число): задаваемое пользователем максимальное значение мощности инверторного кондиционера.
|
||||||
|
При установленном лимите кондиционер не будет превышать это значение в работе.
|
||||||
|
> **Обратите внимание**, что задание лимита повлияет на эффективность работы сплит-системы. Например, при низком значении лимита кондиционеру может не хватать мощности, чтобы охладить или нагреть комнату до заданной пользователем температуры. Либо время, затраченное кондиционером на нагрев или охлаждение, может вырасти. Имейте это ввиду при установке ограничений.
|
||||||
|
|
||||||
|
В силу ограничений на уровне железа, лимит мощности должен быть в пределах от `30%` до `100%`. Некорректные значения будут приведены к диапазону.
|
||||||
|
В случае, если включение лимита вызывается без указания параметра `limit`, то будет использовано значение по умолчанию `30%`.
|
||||||
|
|
||||||
|
|
||||||
## Простейший пример ##
|
## Простейший пример ##
|
||||||
|
|||||||
@@ -154,5 +154,33 @@ class AirConSendTestPacketAction : public Action<Ts...> {
|
|||||||
std::vector<uint8_t> data_static_{};
|
std::vector<uint8_t> data_static_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// **************************************** POWER LIMITATION ACTIONS ****************************************
|
||||||
|
template <typename... Ts>
|
||||||
|
class AirConPowerLimitationOffAction : public Action<Ts...> {
|
||||||
|
public:
|
||||||
|
explicit AirConPowerLimitationOffAction(AirCon *ac) : ac_(ac) {}
|
||||||
|
|
||||||
|
void play(Ts... x) override { this->ac_->powerLimitationOffSequence(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AirCon *ac_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
class AirConPowerLimitationOnAction : public Action<Ts...> {
|
||||||
|
public:
|
||||||
|
AirConPowerLimitationOnAction(AirCon *ac) : ac_(ac) {}
|
||||||
|
TEMPLATABLE_VALUE(uint8_t, value);
|
||||||
|
|
||||||
|
void play(Ts... x) {
|
||||||
|
this->pwr_lim_ = this->value_.value(x...);
|
||||||
|
this->ac_->powerLimitationOnSequence(this->pwr_lim_);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AirCon *ac_;
|
||||||
|
uint8_t pwr_lim_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace aux_ac
|
} // namespace aux_ac
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
@@ -26,8 +26,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// раскоментируй ключ HOLMS для вывода лога под Эксель, значение ключа - размер пакетов которые будут видны
|
|
||||||
//#define HOLMS 19
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace aux_ac {
|
namespace aux_ac {
|
||||||
@@ -40,6 +38,47 @@ using climate::ClimatePreset;
|
|||||||
using climate::ClimateSwingMode;
|
using climate::ClimateSwingMode;
|
||||||
using climate::ClimateTraits;
|
using climate::ClimateTraits;
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
//**************************************************** Packet logger configuration *******************************************************************
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
// v.0.2.9: замена директиве HOLMS
|
||||||
|
#ifdef HOLMS
|
||||||
|
#undef HOLMS
|
||||||
|
#warning "HOLMS was deprecated in v.0.2.9. Use HOLMES_x instead (see below)."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Директива HOLMES_WORKS позволяет включить (true) или выключить (false) вывод пакетов в лог
|
||||||
|
// Причём отключение вывода пакетов не затронет вывод остальных данных
|
||||||
|
#define HOLMES_WORKS true
|
||||||
|
|
||||||
|
// Директива HOLMES_BYTE_FORMAT задаёт формат вывод каждого байта пакета в лог в формате sprintf.
|
||||||
|
// Для вывода в шестнадцатиричном виде с двумя знаками, задайте "%02X".
|
||||||
|
// Для вывода в десятичном виде с тремя знаками, задайте "%03d".
|
||||||
|
#define HOLMES_BYTE_FORMAT "%02X"
|
||||||
|
|
||||||
|
// Директива HOLMES_FILTER_LEN обеспечивает фильтрацию вывода пакетов в лог.
|
||||||
|
// Все корректные пакеты, длина тела которых короче HOLMES_FILTER_LEN, будут проигнорированы.
|
||||||
|
// Все корректные пакеты, длина тела которых HOLMES_FILTER_LEN и более, попадут в лог.
|
||||||
|
// Все данные, не являющиеся корректными пакетами, попадут в лог в любом случае. Это нужно для целей отладки.
|
||||||
|
// В протоколе встречаются пакеты с телом следующей длины: 0, 1, 2, 4, 8, 15, 23
|
||||||
|
#define HOLMES_FILTER_LEN 0
|
||||||
|
|
||||||
|
// Директива HOLMES_DELIMITER позволяет задать разделитель байт при выводе в лог
|
||||||
|
// Для "классического" вывода задайте " "
|
||||||
|
// Для вывода "под Excel" задайте ";"
|
||||||
|
#define HOLMES_DELIMITER " "
|
||||||
|
|
||||||
|
// Директивы HOLMES_x_BRACKET_OPEN и HOLMES_x_BRACKET_CLOSE задают открывающую и
|
||||||
|
// закрывающую скобки для заголовка и CRC.
|
||||||
|
// Если вместо скобок указать "", то в логе скобок не будет.
|
||||||
|
#define HOLMES_HEADER_BRACKET_OPEN "["
|
||||||
|
#define HOLMES_HEADER_BRACKET_CLOSE "]"
|
||||||
|
#define HOLMES_CRC_BRACKET_OPEN "["
|
||||||
|
#define HOLMES_CRC_BRACKET_CLOSE "]"
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
//************************************************* Constants for ESPHome integration ****************************************************************
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
class Constants {
|
class Constants {
|
||||||
public:
|
public:
|
||||||
static const std::string AC_FIRMWARE_VERSION;
|
static const std::string AC_FIRMWARE_VERSION;
|
||||||
@@ -56,13 +95,23 @@ class Constants {
|
|||||||
/// шаг изменения целевой температуры, градусы Цельсия
|
/// шаг изменения целевой температуры, градусы Цельсия
|
||||||
static const float AC_TEMPERATURE_STEP;
|
static const float AC_TEMPERATURE_STEP;
|
||||||
|
|
||||||
|
/// минимальное и максимальное значение мощности инвертора при установке ограничений
|
||||||
|
static const uint8_t AC_MIN_INVERTER_POWER_LIMIT;
|
||||||
|
static const uint8_t AC_MAX_INVERTER_POWER_LIMIT;
|
||||||
|
|
||||||
// периодичность опроса кондиционера на предмет изменения состояния
|
// периодичность опроса кондиционера на предмет изменения состояния
|
||||||
// изменение параметров с пульта не сообщается в UART, поэтому надо запрашивать состояние, чтобы быть в курсе
|
// изменение параметров с пульта не сообщается в UART, поэтому надо запрашивать состояние, чтобы быть в курсе
|
||||||
// значение в миллисекундах
|
// значение в миллисекундах
|
||||||
static const uint32_t AC_STATES_REQUEST_INTERVAL;
|
static const uint32_t AC_STATES_REQUEST_INTERVAL;
|
||||||
|
|
||||||
|
// границы допустимого диапазона таймаута загрузки пакета
|
||||||
|
// таймаут загрузки - через такое количиство миллисекунд конечный автомат перейдет из
|
||||||
|
// состояния ACSM_RECEIVING_PACKET в ACSM_IDLE, если пакет не будет загружен
|
||||||
|
static const uint32_t AC_PACKET_TIMEOUT_MAX;
|
||||||
|
static const uint32_t AC_PACKET_TIMEOUT_MIN;
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::string Constants::AC_FIRMWARE_VERSION = "0.2.8";
|
const std::string Constants::AC_FIRMWARE_VERSION = "0.2.9";
|
||||||
|
|
||||||
// custom fan modes
|
// custom fan modes
|
||||||
const std::string Constants::MUTE = "mute";
|
const std::string Constants::MUTE = "mute";
|
||||||
@@ -77,8 +126,26 @@ const std::string Constants::ANTIFUNGUS = "Antifungus";
|
|||||||
const float Constants::AC_MIN_TEMPERATURE = 16.0;
|
const float Constants::AC_MIN_TEMPERATURE = 16.0;
|
||||||
const float Constants::AC_MAX_TEMPERATURE = 32.0;
|
const float Constants::AC_MAX_TEMPERATURE = 32.0;
|
||||||
const float Constants::AC_TEMPERATURE_STEP = 0.5;
|
const float Constants::AC_TEMPERATURE_STEP = 0.5;
|
||||||
|
const uint8_t Constants::AC_MIN_INVERTER_POWER_LIMIT = 30; // 30%
|
||||||
|
const uint8_t Constants::AC_MAX_INVERTER_POWER_LIMIT = 100; // 100%
|
||||||
const uint32_t Constants::AC_STATES_REQUEST_INTERVAL = 7000;
|
const uint32_t Constants::AC_STATES_REQUEST_INTERVAL = 7000;
|
||||||
|
// таймаут загрузки пакета
|
||||||
|
// По расчетам выходит:
|
||||||
|
// - получение и обработка посимвольно не должна длиться дольше 600 мсек.
|
||||||
|
// - получение и обработка пакетов целиком не должна длиться дольше 150 мсек.
|
||||||
|
// Мы будем обрабатывать пакетами, поэтому 150.
|
||||||
|
// Растягивать приём пакетов очередью команд нельзя, так как кондиционер иногда посылает
|
||||||
|
// информационные пакеты без запроса. Такие пакеты будут рушить последовательность команд,
|
||||||
|
// команды будут теряться. От такой коллизии мы не защищены в любом случае. Но чем меньше таймаут,
|
||||||
|
// тем меньше шансов на коллизию.
|
||||||
|
// Из этих соображений выбраны границы диапазона (_MIN и _MAX значения).
|
||||||
|
const uint32_t Constants::AC_PACKET_TIMEOUT_MAX = 600;
|
||||||
|
const uint32_t Constants::AC_PACKET_TIMEOUT_MIN = 150;
|
||||||
|
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
//********************************************************* ОСНОВНЫЕ СТРУКТУРЫ ***********************************************************************
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
class AirCon;
|
class AirCon;
|
||||||
|
|
||||||
// состояния конечного автомата компонента
|
// состояния конечного автомата компонента
|
||||||
@@ -98,17 +165,6 @@ enum acsm_state : uint8_t {
|
|||||||
// поэтому буффер увеличен
|
// поэтому буффер увеличен
|
||||||
#define AC_BUFFER_SIZE 35
|
#define AC_BUFFER_SIZE 35
|
||||||
|
|
||||||
/**
|
|
||||||
* таймаут загрузки пакета
|
|
||||||
*
|
|
||||||
* через такое количиство миллисекунд конечный автомат перейдет из состояния ACSM_RECEIVING_PACKET в ACSM_IDLE, если пакет не будет загружен
|
|
||||||
* По расчетам выходит:
|
|
||||||
* - получение и обработка посимвольно не должна длиться дольше 600 мсек.
|
|
||||||
* - получение и обработка пакетов целиком не должна длиться дольше 150 мсек.
|
|
||||||
* Мы будем обрабатывать пакетами.
|
|
||||||
**/
|
|
||||||
#define AC_PACKET_TIMEOUT 150
|
|
||||||
|
|
||||||
// типы пакетов
|
// типы пакетов
|
||||||
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_types
|
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_types
|
||||||
#define AC_PTYPE_PING 0x01 // ping-пакет
|
#define AC_PTYPE_PING 0x01 // ping-пакет
|
||||||
@@ -187,9 +243,9 @@ struct packet_big_info_body_t {
|
|||||||
// байт 2 тела (байт 10 пакета)
|
// байт 2 тела (байт 10 пакета)
|
||||||
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_21_b10
|
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_21_b10
|
||||||
uint8_t reserv20 : 2;
|
uint8_t reserv20 : 2;
|
||||||
bool is_invertor_periodic : 1; // флаг периодического пакета инверторного кондиционера
|
bool is_inverter_periodic : 1; // флаг периодического пакета инверторного кондиционера
|
||||||
uint8_t reserv23 : 2;
|
uint8_t reserv23 : 2;
|
||||||
bool is_invertor : 1; // флаг инвертора
|
bool is_inverter : 1; // флаг инвертора
|
||||||
uint8_t reserv26 : 2;
|
uint8_t reserv26 : 2;
|
||||||
|
|
||||||
// байт 3 тела (байт 11 пакета)
|
// байт 3 тела (байт 11 пакета)
|
||||||
@@ -282,7 +338,7 @@ struct packet_big_info_body_t {
|
|||||||
|
|
||||||
// байт 16 тела (байт 24 пакета)
|
// байт 16 тела (байт 24 пакета)
|
||||||
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_21_b24
|
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_21_b24
|
||||||
uint8_t invertor_power; // мощность инвертора (от 0 до 100) в %
|
uint8_t inverter_power; // мощность инвертора (от 0 до 100) в %
|
||||||
|
|
||||||
// байт 17 тела (байт 25 пакета)
|
// байт 17 тела (байт 25 пакета)
|
||||||
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_21_b25
|
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_21_b25
|
||||||
@@ -319,20 +375,50 @@ struct packet_big_info_body_t {
|
|||||||
// тело малого информационного пакета
|
// тело малого информационного пакета
|
||||||
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11
|
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11
|
||||||
struct packet_small_info_body_t {
|
struct packet_small_info_body_t {
|
||||||
|
// байт 8 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b08
|
||||||
uint8_t byte_01;
|
uint8_t byte_01;
|
||||||
|
|
||||||
|
// байт 9 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b09
|
||||||
uint8_t cmd_answer;
|
uint8_t cmd_answer;
|
||||||
|
|
||||||
|
// байт 10 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b10
|
||||||
uint8_t target_temp_int_and_v_louver;
|
uint8_t target_temp_int_and_v_louver;
|
||||||
|
|
||||||
|
// байт 11 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b11
|
||||||
uint8_t h_louver;
|
uint8_t h_louver;
|
||||||
|
|
||||||
|
// байт 12 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b12
|
||||||
uint8_t target_temp_frac;
|
uint8_t target_temp_frac;
|
||||||
|
|
||||||
|
// байт 13 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b13
|
||||||
uint8_t fan_speed;
|
uint8_t fan_speed;
|
||||||
|
|
||||||
|
// байт 14 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b14
|
||||||
uint8_t fan_turbo_and_mute;
|
uint8_t fan_turbo_and_mute;
|
||||||
|
|
||||||
|
// байт 15 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b15
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
|
|
||||||
|
// байт 16 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b16
|
||||||
uint8_t zero1; // всегда 0x00
|
uint8_t zero1; // всегда 0x00
|
||||||
|
|
||||||
|
// байт 17 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b17
|
||||||
uint8_t zero2; // всегда 0x00
|
uint8_t zero2; // всегда 0x00
|
||||||
|
|
||||||
|
// байт 18 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b18
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
|
||||||
|
// байт 19 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b19
|
||||||
uint8_t zero3; // всегда 0x00
|
uint8_t zero3; // всегда 0x00
|
||||||
|
|
||||||
|
// байт 20 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b20
|
||||||
uint8_t display_and_mildew;
|
uint8_t display_and_mildew;
|
||||||
uint8_t zero4; // всегда 0x00
|
|
||||||
|
// байт 21 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b21
|
||||||
|
uint8_t inverter_power_limitation_value : 7;
|
||||||
|
bool inverter_power_limitation_enable : 1;
|
||||||
|
|
||||||
|
// байт 22 пакета: https://github.com/GrKoR/AUX_HVAC_Protocol#packet_cmd_11_b22
|
||||||
uint8_t target_temp_frac2;
|
uint8_t target_temp_frac2;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -475,6 +561,11 @@ enum ac_mildew : uint8_t { AC_MILDEW_OFF = 0x00,
|
|||||||
// GK: define убрал, т.к. считаю, что сбрасывать счетчик не надо.
|
// GK: define убрал, т.к. считаю, что сбрасывать счетчик не надо.
|
||||||
// #define AC_MIN_COUNTER_MASK 0b00111111
|
// #define AC_MIN_COUNTER_MASK 0b00111111
|
||||||
|
|
||||||
|
// маски ограничения мощности для инверторного кондиционера
|
||||||
|
#define AC_INVERTER_POWER_LIMITATION_ENABLE_MASK 0b10000000
|
||||||
|
#define AC_INVERTER_POWER_LIMITATION_VALUE_MASK 0b01111111
|
||||||
|
#define AC_INVERTER_POWER_LIMITATION_VALUE_UNTOUCHED 0xFF
|
||||||
|
|
||||||
// положение вертикальных жалюзи для фронтенда
|
// положение вертикальных жалюзи для фронтенда
|
||||||
enum ac_vlouver_frontend : uint8_t {
|
enum ac_vlouver_frontend : uint8_t {
|
||||||
AC_VLOUVER_FRONTEND_SWING = 0x00,
|
AC_VLOUVER_FRONTEND_SWING = 0x00,
|
||||||
@@ -544,8 +635,10 @@ struct ac_command_t {
|
|||||||
int8_t temp_outbound; // температура исходящая
|
int8_t temp_outbound; // температура исходящая
|
||||||
int8_t temp_compressor; // температура компрессора
|
int8_t temp_compressor; // температура компрессора
|
||||||
ac_realFan realFanSpeed; // текущая скорость вентилятора
|
ac_realFan realFanSpeed; // текущая скорость вентилятора
|
||||||
uint8_t invertor_power; // мощность инвертора
|
uint8_t inverter_power; // мощность инвертора
|
||||||
bool defrost; // режим разморозки внешнего блока (накопление тепла + прогрев испарителя)
|
bool defrost; // режим разморозки внешнего блока (накопление тепла + прогрев испарителя)
|
||||||
|
bool inverter_power_limitation_enable; // ограничение мощности инвертора
|
||||||
|
uint8_t inverter_power_limitation_value; // значение ограничения мощности инвертора
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ac_command_t ac_state_t; // текущее состояние параметров кондея можно хранить в таком же формате, как и комманды
|
typedef ac_command_t ac_state_t; // текущее состояние параметров кондея можно хранить в таком же формате, как и комманды
|
||||||
@@ -662,7 +755,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
// будет работать, но будет ниже, переменная устанавливается при первом получении большого пакета;
|
// будет работать, но будет ниже, переменная устанавливается при первом получении большого пакета;
|
||||||
// если эта переменная установлена, то режим работы не инверторного кондиционера будет распознаваться
|
// если эта переменная установлена, то режим работы не инверторного кондиционера будет распознаваться
|
||||||
// как "в простое" (IDLE)
|
// как "в простое" (IDLE)
|
||||||
bool _is_invertor = false;
|
bool _is_inverter = false;
|
||||||
|
|
||||||
// поддерживаемые кондиционером опции
|
// поддерживаемые кондиционером опции
|
||||||
std::set<ClimateMode> _supported_modes{};
|
std::set<ClimateMode> _supported_modes{};
|
||||||
@@ -710,16 +803,12 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
// пакет для тестирования всякой фигни
|
// пакет для тестирования всякой фигни
|
||||||
packet_t _outTestPacket;
|
packet_t _outTestPacket;
|
||||||
|
|
||||||
|
// таймаут загрузки пакета, по дефолту минимальный
|
||||||
|
uint32_t _packet_timeout = Constants::AC_PACKET_TIMEOUT_MIN;
|
||||||
|
|
||||||
// сырые данные последних полученных большого и маленького информационных пакетов
|
// сырые данные последних полученных большого и маленького информационных пакетов
|
||||||
ac_last_raw_data _last_raw_data;
|
ac_last_raw_data _last_raw_data;
|
||||||
|
|
||||||
// последовательность пакетов текущий шаг в последовательности
|
|
||||||
sequence_item_t _sequence[AC_SEQUENCE_MAX_LEN];
|
|
||||||
uint8_t _sequence_current_step;
|
|
||||||
|
|
||||||
// флаг успешного выполнения стартовой последовательности команд
|
|
||||||
bool _startupSequenceComlete = false;
|
|
||||||
|
|
||||||
// нормализация показаний температуры, приведение в диапазон
|
// нормализация показаний температуры, приведение в диапазон
|
||||||
float _temp_target_normalise(float temp) {
|
float _temp_target_normalise(float temp) {
|
||||||
auto traits = this->get_traits();
|
auto traits = this->get_traits();
|
||||||
@@ -732,6 +821,20 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// нормализация лимита ограничения мощности инвертора, приведение в диапазон
|
||||||
|
uint8_t _power_limitation_value_normalise(uint8_t power_limitation_value) {
|
||||||
|
if (power_limitation_value < Constants::AC_MIN_INVERTER_POWER_LIMIT) power_limitation_value = Constants::AC_MIN_INVERTER_POWER_LIMIT;
|
||||||
|
if (power_limitation_value > Constants::AC_MAX_INVERTER_POWER_LIMIT) power_limitation_value = Constants::AC_MAX_INVERTER_POWER_LIMIT;
|
||||||
|
return power_limitation_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// последовательность пакетов текущий шаг в последовательности
|
||||||
|
sequence_item_t _sequence[AC_SEQUENCE_MAX_LEN];
|
||||||
|
uint8_t _sequence_current_step;
|
||||||
|
|
||||||
|
// флаг успешного выполнения стартовой последовательности команд
|
||||||
|
bool _startupSequenceComlete = false;
|
||||||
|
|
||||||
// очистка последовательности команд
|
// очистка последовательности команд
|
||||||
void _clearSequence() {
|
void _clearSequence() {
|
||||||
for (uint8_t i = 0; i < AC_SEQUENCE_MAX_LEN; i++) {
|
for (uint8_t i = 0; i < AC_SEQUENCE_MAX_LEN; i++) {
|
||||||
@@ -907,8 +1010,10 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
cmd->temp_outbound = 0;
|
cmd->temp_outbound = 0;
|
||||||
cmd->temp_compressor = 0;
|
cmd->temp_compressor = 0;
|
||||||
cmd->realFanSpeed = AC_REAL_FAN_UNTOUCHED;
|
cmd->realFanSpeed = AC_REAL_FAN_UNTOUCHED;
|
||||||
cmd->invertor_power = 0;
|
cmd->inverter_power = 0;
|
||||||
cmd->defrost = false;
|
cmd->defrost = false;
|
||||||
|
cmd->inverter_power_limitation_enable = false;
|
||||||
|
cmd->inverter_power_limitation_value = AC_INVERTER_POWER_LIMITATION_VALUE_UNTOUCHED;
|
||||||
};
|
};
|
||||||
|
|
||||||
// очистка буфера размером AC_BUFFER_SIZE
|
// очистка буфера размером AC_BUFFER_SIZE
|
||||||
@@ -1075,7 +1180,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// если пакет не загружен, а время вышло, то надо вернуться в IDLE
|
// если пакет не загружен, а время вышло, то надо вернуться в IDLE
|
||||||
if (millis() - _inPacket.msec >= AC_PACKET_TIMEOUT) {
|
if (millis() - _inPacket.msec >= this->_packet_timeout) {
|
||||||
_debugMsg(F("Receiver: packet timed out!"), ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
_debugMsg(F("Receiver: packet timed out!"), ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
||||||
_debugPrintPacket(&_inPacket, ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
_debugPrintPacket(&_inPacket, ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
||||||
_clearInPacket();
|
_clearInPacket();
|
||||||
@@ -1238,6 +1343,16 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
stateChangedFlag = stateChangedFlag || (_current_ac_state.mildew != (ac_mildew)stateByte);
|
stateChangedFlag = stateChangedFlag || (_current_ac_state.mildew != (ac_mildew)stateByte);
|
||||||
_current_ac_state.mildew = (ac_mildew)stateByte;
|
_current_ac_state.mildew = (ac_mildew)stateByte;
|
||||||
|
|
||||||
|
// enable flag of power limitation for inverter ACs
|
||||||
|
bool temp = small_info_body->inverter_power_limitation_enable;
|
||||||
|
stateChangedFlag = stateChangedFlag || (_current_ac_state.inverter_power_limitation_enable != temp);
|
||||||
|
_current_ac_state.inverter_power_limitation_enable = temp;
|
||||||
|
|
||||||
|
// the limit value of power limitation for inverter ACs
|
||||||
|
stateByte = small_info_body->inverter_power_limitation_value;
|
||||||
|
stateChangedFlag = stateChangedFlag || (_current_ac_state.inverter_power_limitation_value != stateByte);
|
||||||
|
_current_ac_state.inverter_power_limitation_value = stateByte;
|
||||||
|
|
||||||
// уведомляем об изменении статуса сплита
|
// уведомляем об изменении статуса сплита
|
||||||
if (stateChangedFlag) stateChanged();
|
if (stateChangedFlag) stateChanged();
|
||||||
|
|
||||||
@@ -1255,8 +1370,8 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
big_info_body = (packet_big_info_body_t *)(_inPacket.body);
|
big_info_body = (packet_big_info_body_t *)(_inPacket.body);
|
||||||
|
|
||||||
// тип кондея (инвертор или старт стоп)
|
// тип кондея (инвертор или старт стоп)
|
||||||
_is_invertor = big_info_body->is_invertor;
|
_is_inverter = big_info_body->is_inverter;
|
||||||
|
|
||||||
// температура воздуха в помещении по версии сплит-системы
|
// температура воздуха в помещении по версии сплит-системы
|
||||||
stateFloat = big_info_body->ambient_temperature_int - 0x20 + (float)(big_info_body->ambient_temperature_frac & 0x0f) / 10.0;
|
stateFloat = big_info_body->ambient_temperature_int - 0x20 + (float)(big_info_body->ambient_temperature_frac & 0x0f) / 10.0;
|
||||||
stateChangedFlag = stateChangedFlag || (_current_ac_state.temp_ambient != stateFloat);
|
stateChangedFlag = stateChangedFlag || (_current_ac_state.temp_ambient != stateFloat);
|
||||||
@@ -1283,15 +1398,15 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
stateChangedFlag = stateChangedFlag || (_current_ac_state.temp_compressor != stateFloat);
|
stateChangedFlag = stateChangedFlag || (_current_ac_state.temp_compressor != stateFloat);
|
||||||
_current_ac_state.temp_compressor = stateFloat;
|
_current_ac_state.temp_compressor = stateFloat;
|
||||||
|
|
||||||
// реальная скорость проперлера
|
// реальная скорость пропеллера
|
||||||
stateFloat = big_info_body->realFanSpeed;
|
stateFloat = big_info_body->realFanSpeed;
|
||||||
stateChangedFlag = stateChangedFlag || (_current_ac_state.realFanSpeed != (ac_realFan)stateFloat);
|
stateChangedFlag = stateChangedFlag || (_current_ac_state.realFanSpeed != (ac_realFan)stateFloat);
|
||||||
_current_ac_state.realFanSpeed = (ac_realFan)stateFloat;
|
_current_ac_state.realFanSpeed = (ac_realFan)stateFloat;
|
||||||
|
|
||||||
// мощность инвертора
|
// мощность инвертора
|
||||||
stateFloat = big_info_body->invertor_power;
|
stateFloat = big_info_body->inverter_power;
|
||||||
stateChangedFlag = stateChangedFlag || (_current_ac_state.invertor_power != stateFloat);
|
stateChangedFlag = stateChangedFlag || (_current_ac_state.inverter_power != stateFloat);
|
||||||
_current_ac_state.invertor_power = stateFloat;
|
_current_ac_state.inverter_power = stateFloat;
|
||||||
|
|
||||||
// режим разморозки
|
// режим разморозки
|
||||||
//bool temp = (big_info_body->needDefrost && big_info_body->defrostMode);
|
//bool temp = (big_info_body->needDefrost && big_info_body->defrostMode);
|
||||||
@@ -1309,8 +1424,8 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
|
|
||||||
case AC_CMD_SET_PARAMS: { // такой статусный пакет присылается кондиционером в ответ на команду установки параметров
|
case AC_CMD_SET_PARAMS: { // такой статусный пакет присылается кондиционером в ответ на команду установки параметров
|
||||||
// в теле пакета нет ничего примечательного
|
// в теле пакета нет ничего примечательного
|
||||||
// в байтах 2 и 3 тела похоже передается CRC пакета поступившей команды, на которую сплит отвечает
|
// в байтах 2 и 3 тела передается CRC пакета поступившей команды, на которую сплит отвечает
|
||||||
// но я решил этот момент тут не проверять и не контролировать.
|
// я решил этот момент тут не проверять и не контролировать.
|
||||||
// корректную установку параметров можно определить, запросив статус кондиционера сразу после получения этой команды кондея
|
// корректную установку параметров можно определить, запросив статус кондиционера сразу после получения этой команды кондея
|
||||||
// в настоящий момент проверка сделана в механизме sequences
|
// в настоящий момент проверка сделана в механизме sequences
|
||||||
break;
|
break;
|
||||||
@@ -1387,13 +1502,19 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
* Для нормального пакета данные выводятся с форматированием.
|
* Для нормального пакета данные выводятся с форматированием.
|
||||||
* line - строка, на которой произошел вызов (удобно при отладке)
|
* line - строка, на которой произошел вызов (удобно при отладке)
|
||||||
**/
|
**/
|
||||||
void _debugPrintPacket(packet_t *packet, uint8_t dbgLevel = ESPHOME_LOG_LEVEL_DEBUG, unsigned int line = 0) {
|
void _debugPrintPacket(packet_t *packet, uint8_t dbgLevel = ESPHOME_LOG_LEVEL_DEBUG, unsigned int line = __LINE__) {
|
||||||
// определяем, полноценный ли пакет нам передан
|
// определяем, полноценный ли пакет нам передан
|
||||||
bool notAPacket = false;
|
bool notAPacket = false;
|
||||||
// указатель заголовка всегда установден на начало буфера
|
// указатель заголовка всегда установден на начало буфера
|
||||||
notAPacket = notAPacket || (packet->crc == nullptr);
|
notAPacket = notAPacket || (packet->crc == nullptr);
|
||||||
notAPacket = notAPacket || (packet->data[0] != AC_PACKET_START_BYTE);
|
notAPacket = notAPacket || (packet->data[0] != AC_PACKET_START_BYTE);
|
||||||
|
|
||||||
|
// если пакет по длине меньше, чем указано в фильтре, то не выводим.
|
||||||
|
// если вывод пакетов отключен с помощью директивы HOLMES_WORKS, то тоже не выводим.
|
||||||
|
// "не пакеты" выводим всегда, так как от них зависит отладка багов
|
||||||
|
if ((!notAPacket) && (packet->header->body_length < HOLMES_FILTER_LEN)) return;
|
||||||
|
if ((!notAPacket) && (!HOLMES_WORKS)) return;
|
||||||
|
|
||||||
String st = "";
|
String st = "";
|
||||||
char textBuf[11];
|
char textBuf[11];
|
||||||
|
|
||||||
@@ -1411,44 +1532,26 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
st += "[--] "; // преамбула для "непакета"
|
st += "[--] "; // преамбула для "непакета"
|
||||||
}
|
}
|
||||||
|
|
||||||
// формируем данные
|
// формируем данные
|
||||||
#ifdef HOLMS
|
|
||||||
// если этот дефайн объявлен, то в лог попадут только пакеты больше указанного в дефайне размера
|
|
||||||
// при этом весь вывод будет в десятичном виде, данные будут разделены ";"
|
|
||||||
// и не будет выделения заголовков и CRC квадратными скобками
|
|
||||||
dbgLevel = ESPHOME_LOG_LEVEL_ERROR;
|
|
||||||
if (packet->header->body_length > HOLMS) {
|
|
||||||
for (int i = 0; i < packet->bytesLoaded; i++) {
|
|
||||||
sprintf(textBuf, "%03d;", packet->data[i]);
|
|
||||||
st += textBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line == 0) line = __LINE__;
|
|
||||||
_debugMsg(st, dbgLevel, line);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// если дефайна HOLMS нет, то выводим пакеты в HEX и все подряд
|
|
||||||
for (int i = 0; i < packet->bytesLoaded; i++) {
|
for (int i = 0; i < packet->bytesLoaded; i++) {
|
||||||
// для нормальных пакетов надо заключить заголовок в []
|
// для заголовков нормальных пакетов надо отработать скобки (если они есть)
|
||||||
if ((!notAPacket) && (i == 0)) st += "[";
|
if ((!notAPacket) && (i == 0)) st += HOLMES_HEADER_BRACKET_OPEN;
|
||||||
// для нормальных пакетов надо заключить CRC в []
|
// для CRC нормальных пакетов надо отработать скобки (если они есть)
|
||||||
if ((!notAPacket) && (i == packet->header->body_length + AC_HEADER_SIZE)) st += "[";
|
if ((!notAPacket) && (i == packet->header->body_length + AC_HEADER_SIZE)) st += HOLMES_CRC_BRACKET_OPEN;
|
||||||
|
|
||||||
memset(textBuf, 0, 11);
|
memset(textBuf, 0, 11);
|
||||||
sprintf(textBuf, "%02X", packet->data[i]);
|
sprintf(textBuf, HOLMES_BYTE_FORMAT, packet->data[i]);
|
||||||
st += textBuf;
|
st += textBuf;
|
||||||
|
|
||||||
// для нормальных пакетов надо заключить заголовок в []
|
// для заголовков нормальных пакетов надо отработать скобки (если они есть)
|
||||||
if ((!notAPacket) && (i == AC_HEADER_SIZE - 1)) st += "]";
|
if ((!notAPacket) && (i == AC_HEADER_SIZE - 1)) st += HOLMES_HEADER_BRACKET_CLOSE;
|
||||||
// для нормальных пакетов надо заключить CRC в []
|
// для CRC нормальных пакетов надо отработать скобки (если они есть)
|
||||||
if ((!notAPacket) && (i == packet->header->body_length + AC_HEADER_SIZE + 2 - 1)) st += "]";
|
if ((!notAPacket) && (i == packet->header->body_length + AC_HEADER_SIZE + 2 - 1)) st += HOLMES_CRC_BRACKET_CLOSE;
|
||||||
|
|
||||||
st += " ";
|
st += HOLMES_DELIMITER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line == 0) line = __LINE__;
|
|
||||||
_debugMsg(st, dbgLevel, line);
|
_debugMsg(st, dbgLevel, line);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** расчет CRC16 для блока данных data длиной len
|
/** расчет CRC16 для блока данных data длиной len
|
||||||
@@ -1604,6 +1707,13 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ограничение мощности инвертора
|
||||||
|
if (cmd->inverter_power_limitation_value != AC_INVERTER_POWER_LIMITATION_VALUE_UNTOUCHED) {
|
||||||
|
pack->body[13] = (pack->body[13] & ~AC_INVERTER_POWER_LIMITATION_ENABLE_MASK) | (cmd->inverter_power_limitation_enable << 7);
|
||||||
|
cmd->inverter_power_limitation_value = _power_limitation_value_normalise(cmd->inverter_power_limitation_value);
|
||||||
|
pack->body[13] = (pack->body[13] & ~AC_INVERTER_POWER_LIMITATION_VALUE_MASK) | cmd->inverter_power_limitation_value;
|
||||||
|
}
|
||||||
|
|
||||||
// обнулить счетчик минут с последней команды
|
// обнулить счетчик минут с последней команды
|
||||||
// GK: считаю, что так делать не надо. Штатный wifi-модуль не сбрасывает счетчик минут.
|
// GK: считаю, что так делать не надо. Штатный wifi-модуль не сбрасывает счетчик минут.
|
||||||
// pack->body[4] &= ~ AC_MIN_COUNTER_MASK ;
|
// pack->body[4] &= ~ AC_MIN_COUNTER_MASK ;
|
||||||
@@ -1869,11 +1979,13 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
esphome::sensor::Sensor *sensor_inbound_temperature_ = nullptr;
|
esphome::sensor::Sensor *sensor_inbound_temperature_ = nullptr;
|
||||||
esphome::sensor::Sensor *sensor_outbound_temperature_ = nullptr;
|
esphome::sensor::Sensor *sensor_outbound_temperature_ = nullptr;
|
||||||
esphome::sensor::Sensor *sensor_compressor_temperature_ = nullptr;
|
esphome::sensor::Sensor *sensor_compressor_temperature_ = nullptr;
|
||||||
esphome::sensor::Sensor *sensor_invertor_power_ = nullptr;
|
esphome::sensor::Sensor *sensor_inverter_power_ = nullptr;
|
||||||
esphome::sensor::Sensor *sensor_vlouver_state_ = nullptr;
|
esphome::sensor::Sensor *sensor_vlouver_state_ = nullptr;
|
||||||
esphome::binary_sensor::BinarySensor *sensor_display_ = nullptr;
|
esphome::binary_sensor::BinarySensor *sensor_display_ = nullptr;
|
||||||
esphome::binary_sensor::BinarySensor *sensor_defrost_ = nullptr;
|
esphome::binary_sensor::BinarySensor *sensor_defrost_ = nullptr;
|
||||||
esphome::text_sensor::TextSensor *sensor_preset_reporter_ = nullptr;
|
esphome::text_sensor::TextSensor *sensor_preset_reporter_ = nullptr;
|
||||||
|
esphome::sensor::Sensor *sensor_inverter_power_limit_value_ = nullptr;
|
||||||
|
esphome::binary_sensor::BinarySensor *sensor_inverter_power_limit_state_ = nullptr;
|
||||||
|
|
||||||
// загружает на выполнение последовательность команд на включение/выключение табло с температурой
|
// загружает на выполнение последовательность команд на включение/выключение табло с температурой
|
||||||
bool _displaySequence(ac_display dsp = AC_DISPLAY_ON) {
|
bool _displaySequence(ac_display dsp = AC_DISPLAY_ON) {
|
||||||
@@ -1960,6 +2072,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
_ac_serial = parent;
|
_ac_serial = parent;
|
||||||
_hw_initialized = (_ac_serial != nullptr);
|
_hw_initialized = (_ac_serial != nullptr);
|
||||||
_has_connection = false;
|
_has_connection = false;
|
||||||
|
_packet_timeout = Constants::AC_PACKET_TIMEOUT_MIN;
|
||||||
|
|
||||||
// заполняем структуру состояния начальными значениями
|
// заполняем структуру состояния начальными значениями
|
||||||
_clearCommand((ac_command_t *)&_current_ac_state);
|
_clearCommand((ac_command_t *)&_current_ac_state);
|
||||||
@@ -1989,8 +2102,10 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
void set_vlouver_state_sensor(sensor::Sensor *vlouver_state_sensor) { sensor_vlouver_state_ = vlouver_state_sensor; }
|
void set_vlouver_state_sensor(sensor::Sensor *vlouver_state_sensor) { sensor_vlouver_state_ = vlouver_state_sensor; }
|
||||||
void set_defrost_state(binary_sensor::BinarySensor *defrost_state_sensor) { sensor_defrost_ = defrost_state_sensor; }
|
void set_defrost_state(binary_sensor::BinarySensor *defrost_state_sensor) { sensor_defrost_ = defrost_state_sensor; }
|
||||||
void set_display_sensor(binary_sensor::BinarySensor *display_sensor) { sensor_display_ = display_sensor; }
|
void set_display_sensor(binary_sensor::BinarySensor *display_sensor) { sensor_display_ = display_sensor; }
|
||||||
void set_invertor_power_sensor(sensor::Sensor *invertor_power_sensor) { sensor_invertor_power_ = invertor_power_sensor; }
|
void set_inverter_power_sensor(sensor::Sensor *inverter_power_sensor) { sensor_inverter_power_ = inverter_power_sensor; }
|
||||||
void set_preset_reporter_sensor(text_sensor::TextSensor *preset_reporter_sensor) { sensor_preset_reporter_ = preset_reporter_sensor; }
|
void set_preset_reporter_sensor(text_sensor::TextSensor *preset_reporter_sensor) { sensor_preset_reporter_ = preset_reporter_sensor; }
|
||||||
|
void set_inverter_power_limit_value_sensor(sensor::Sensor *inverter_power_limit_value_sensor) { sensor_inverter_power_limit_value_ = inverter_power_limit_value_sensor; }
|
||||||
|
void set_inverter_power_limit_state_sensor(binary_sensor::BinarySensor *inverter_power_limit_state_sensor) { sensor_inverter_power_limit_state_ = inverter_power_limit_state_sensor; }
|
||||||
|
|
||||||
bool get_hw_initialized() { return _hw_initialized; };
|
bool get_hw_initialized() { return _hw_initialized; };
|
||||||
bool get_has_connection() { return _has_connection; };
|
bool get_has_connection() { return _has_connection; };
|
||||||
@@ -2004,11 +2119,12 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
void stateChanged() {
|
void stateChanged() {
|
||||||
_debugMsg(F("State changed, let's publish it."), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__);
|
_debugMsg(F("State changed, let's publish it."), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__);
|
||||||
|
|
||||||
|
// экшины кондиционера (информация для пользователя, что кондиционер сейчас делает)
|
||||||
// сейчас экшины рассчётные и могут не отражать реального положения дел, но других вариантов не придумалось
|
// сейчас экшины рассчётные и могут не отражать реального положения дел, но других вариантов не придумалось
|
||||||
if (_is_invertor) {
|
if (_is_inverter) {
|
||||||
// анализ режима для инвертора точнее потому, что использует показания мощности инвертора
|
// анализ режима для инвертора точнее потому, что использует показания мощности инвертора
|
||||||
static uint32_t timerInv = 0;
|
static uint32_t timerInv = 0;
|
||||||
if (_current_ac_state.invertor_power == 0) { // инвертор выключен
|
if (_current_ac_state.inverter_power == 0) { // инвертор выключен
|
||||||
timerInv = millis();
|
timerInv = millis();
|
||||||
if (_current_ac_state.realFanSpeed == AC_REAL_FAN_OFF &&
|
if (_current_ac_state.realFanSpeed == AC_REAL_FAN_OFF &&
|
||||||
_current_ac_state.power == AC_POWER_OFF) { // внутренний кулер остановлен, кондей выключен
|
_current_ac_state.power == AC_POWER_OFF) { // внутренний кулер остановлен, кондей выключен
|
||||||
@@ -2053,7 +2169,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
this->action = climate::CLIMATE_ACTION_FAN; // другие режимы - вентиляция
|
this->action = climate::CLIMATE_ACTION_FAN; // другие режимы - вентиляция
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // if(_is_invertor)
|
} else { // if(_is_inverter)
|
||||||
// для on-off сплита рассчет экшена упрощен
|
// для on-off сплита рассчет экшена упрощен
|
||||||
if (_current_ac_state.realFanSpeed == AC_REAL_FAN_OFF &&
|
if (_current_ac_state.realFanSpeed == AC_REAL_FAN_OFF &&
|
||||||
_current_ac_state.power == AC_POWER_OFF) {
|
_current_ac_state.power == AC_POWER_OFF) {
|
||||||
@@ -2306,14 +2422,20 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
if (sensor_compressor_temperature_ != nullptr)
|
if (sensor_compressor_temperature_ != nullptr)
|
||||||
sensor_compressor_temperature_->publish_state(_current_ac_state.temp_compressor);
|
sensor_compressor_temperature_->publish_state(_current_ac_state.temp_compressor);
|
||||||
// мощность инвертора
|
// мощность инвертора
|
||||||
if (sensor_invertor_power_ != nullptr)
|
if (sensor_inverter_power_ != nullptr)
|
||||||
sensor_invertor_power_->publish_state(_current_ac_state.invertor_power);
|
sensor_inverter_power_->publish_state(_current_ac_state.inverter_power);
|
||||||
// флаг режима разморозки
|
// флаг режима разморозки
|
||||||
if (sensor_defrost_ != nullptr)
|
if (sensor_defrost_ != nullptr)
|
||||||
sensor_defrost_->publish_state(_current_ac_state.defrost);
|
sensor_defrost_->publish_state(_current_ac_state.defrost);
|
||||||
// положение вертикальных жалюзи
|
// положение вертикальных жалюзи
|
||||||
if (sensor_vlouver_state_ != nullptr)
|
if (sensor_vlouver_state_ != nullptr)
|
||||||
sensor_vlouver_state_->publish_state((float)this->getCurrentVlouverFrontendState());
|
sensor_vlouver_state_->publish_state((float)this->getCurrentVlouverFrontendState());
|
||||||
|
// флаг включенного ограничения мощности инвертора
|
||||||
|
if (sensor_inverter_power_limit_state_ != nullptr)
|
||||||
|
sensor_inverter_power_limit_state_->publish_state(_current_ac_state.inverter_power_limitation_enable);
|
||||||
|
// значение ограничения мощности инвертора
|
||||||
|
if (sensor_inverter_power_limit_value_ != nullptr)
|
||||||
|
sensor_inverter_power_limit_value_->publish_state(_current_ac_state.inverter_power_limitation_value);
|
||||||
|
|
||||||
// сенсор состояния сплита
|
// сенсор состояния сплита
|
||||||
if (sensor_preset_reporter_ != nullptr) {
|
if (sensor_preset_reporter_ != nullptr) {
|
||||||
@@ -2341,19 +2463,23 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
ESP_LOGCONFIG(TAG, " [x] Period: %dms", this->get_period());
|
ESP_LOGCONFIG(TAG, " [x] Period: %dms", this->get_period());
|
||||||
ESP_LOGCONFIG(TAG, " [x] Show action: %s", TRUEFALSE(this->get_show_action()));
|
ESP_LOGCONFIG(TAG, " [x] Show action: %s", TRUEFALSE(this->get_show_action()));
|
||||||
ESP_LOGCONFIG(TAG, " [x] Display inverted: %s", TRUEFALSE(this->get_display_inverted()));
|
ESP_LOGCONFIG(TAG, " [x] Display inverted: %s", TRUEFALSE(this->get_display_inverted()));
|
||||||
|
ESP_LOGCONFIG(TAG, " [x] Packet timeout: %dms", this->get_packet_timeout());
|
||||||
|
|
||||||
#if defined(PRESETS_SAVING)
|
#if defined(PRESETS_SAVING)
|
||||||
ESP_LOGCONFIG(TAG, " [x] Save settings %s", TRUEFALSE(this->get_store_settings()));
|
ESP_LOGCONFIG(TAG, " [x] Save settings %s", TRUEFALSE(this->get_store_settings()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ESP_LOGCONFIG(TAG, " [?] Is invertor %s", millis() > _update_period + 1000 ? YESNO(_is_invertor) : "pending...");
|
ESP_LOGCONFIG(TAG, " [?] Is inverter %s", millis() > _update_period + 1000 ? YESNO(_is_inverter) : "pending...");
|
||||||
|
|
||||||
|
LOG_SENSOR(" ", "Inverter Power", this->sensor_inverter_power_);
|
||||||
|
LOG_SENSOR(" ", "Inverter Power Limit Value", this->sensor_inverter_power_limit_value_);
|
||||||
|
LOG_BINARY_SENSOR(" ", "Inverter Power Limit State", this->sensor_inverter_power_limit_state_);
|
||||||
|
|
||||||
LOG_SENSOR(" ", "Indoor Temperature", this->sensor_indoor_temperature_);
|
LOG_SENSOR(" ", "Indoor Temperature", this->sensor_indoor_temperature_);
|
||||||
LOG_SENSOR(" ", "Outdoor Temperature", this->sensor_outdoor_temperature_);
|
LOG_SENSOR(" ", "Outdoor Temperature", this->sensor_outdoor_temperature_);
|
||||||
LOG_SENSOR(" ", "Inbound Temperature", this->sensor_inbound_temperature_);
|
LOG_SENSOR(" ", "Inbound Temperature", this->sensor_inbound_temperature_);
|
||||||
LOG_SENSOR(" ", "Outbound Temperature", this->sensor_outbound_temperature_);
|
LOG_SENSOR(" ", "Outbound Temperature", this->sensor_outbound_temperature_);
|
||||||
LOG_SENSOR(" ", "Compressor Temperature", this->sensor_compressor_temperature_);
|
LOG_SENSOR(" ", "Compressor Temperature", this->sensor_compressor_temperature_);
|
||||||
LOG_SENSOR(" ", "Inverter Power", this->sensor_invertor_power_);
|
|
||||||
LOG_BINARY_SENSOR(" ", "Defrost Status", this->sensor_defrost_);
|
LOG_BINARY_SENSOR(" ", "Defrost Status", this->sensor_defrost_);
|
||||||
LOG_BINARY_SENSOR(" ", "Display", this->sensor_display_);
|
LOG_BINARY_SENSOR(" ", "Display", this->sensor_display_);
|
||||||
LOG_TEXT_SENSOR(" ", "Preset Reporter", this->sensor_preset_reporter_);
|
LOG_TEXT_SENSOR(" ", "Preset Reporter", this->sensor_preset_reporter_);
|
||||||
@@ -2965,6 +3091,56 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// выключает ограничение мощности сплита
|
||||||
|
bool powerLimitationOffSequence() {
|
||||||
|
// нет смысла в последовательности, если нет коннекта с кондиционером
|
||||||
|
if (!get_has_connection()) {
|
||||||
|
_debugMsg(F("powerLimitationOffSequence: no pings from HVAC. It seems like no AC connected."), ESPHOME_LOG_LEVEL_ERROR, __LINE__);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->_is_inverter) return false; // если кондиционер не инверторный, то выходим
|
||||||
|
|
||||||
|
// формируем команду
|
||||||
|
ac_command_t cmd;
|
||||||
|
_clearCommand(&cmd); // не забываем очищать, а то будет мусор
|
||||||
|
cmd.inverter_power_limitation_enable = false;
|
||||||
|
cmd.inverter_power_limitation_value = this->_current_ac_state.inverter_power_limitation_value;
|
||||||
|
// добавляем команду в последовательность
|
||||||
|
if (!commandSequence(&cmd)) return false;
|
||||||
|
|
||||||
|
_debugMsg(F("powerLimitationOffSequence: loaded (value = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, cmd.inverter_power_limitation_enable);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// включает ограничение мощности сплита на нужный уровень
|
||||||
|
bool powerLimitationOnSequence(uint8_t power_limit = Constants::AC_MIN_INVERTER_POWER_LIMIT) {
|
||||||
|
// нет смысла в последовательности, если нет коннекта с кондиционером
|
||||||
|
if (!get_has_connection()) {
|
||||||
|
_debugMsg(F("powerLimitationOnSequence: no pings from HVAC. It seems like no AC connected."), ESPHOME_LOG_LEVEL_ERROR, __LINE__);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->_is_inverter) { // если кондиционер не инверторный, то выходим
|
||||||
|
_debugMsg(F("powerLimitationOnSequence: unsupported for noninverter AC."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
power_limit = this->_power_limitation_value_normalise(power_limit);
|
||||||
|
|
||||||
|
// формируем команду
|
||||||
|
ac_command_t cmd;
|
||||||
|
_clearCommand(&cmd); // не забываем очищать, а то будет мусор
|
||||||
|
cmd.inverter_power_limitation_enable = true;
|
||||||
|
cmd.inverter_power_limitation_value = power_limit;
|
||||||
|
// добавляем команду в последовательность
|
||||||
|
if (!commandSequence(&cmd)) return false;
|
||||||
|
|
||||||
|
_debugMsg(F("powerLimitationOnSequence: loaded (power limit = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, power_limit);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// конвертирует состояние жалюзи из кодов сплита в коды для фронтенда
|
// конвертирует состояние жалюзи из кодов сплита в коды для фронтенда
|
||||||
ac_vlouver_frontend AUXvlouverToVlouverFrontend(const ac_louver_V vLouver) {
|
ac_vlouver_frontend AUXvlouverToVlouverFrontend(const ac_louver_V vLouver) {
|
||||||
switch (vLouver) {
|
switch (vLouver) {
|
||||||
@@ -3048,7 +3224,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
// добавляем команду в последовательность
|
// добавляем команду в последовательность
|
||||||
if (!commandSequence(&cmd)) return false;
|
if (!commandSequence(&cmd)) return false;
|
||||||
|
|
||||||
_debugMsg(F("setVLouverSequence: loaded (power = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, vLouver);
|
_debugMsg(F("setVLouverSequence: loaded (vLouver = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, vLouver);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3075,6 +3251,13 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
|
|||||||
void set_display_inverted(bool display_inverted) { this->_display_inverted = display_inverted; }
|
void set_display_inverted(bool display_inverted) { this->_display_inverted = display_inverted; }
|
||||||
bool get_display_inverted() { return this->_display_inverted; }
|
bool get_display_inverted() { return this->_display_inverted; }
|
||||||
|
|
||||||
|
void set_packet_timeout(uint32_t ms) {
|
||||||
|
if (ms < Constants::AC_PACKET_TIMEOUT_MIN) ms = Constants::AC_PACKET_TIMEOUT_MIN;
|
||||||
|
if (ms > Constants::AC_PACKET_TIMEOUT_MAX) ms = Constants::AC_PACKET_TIMEOUT_MIN;
|
||||||
|
this->_packet_timeout = ms;
|
||||||
|
}
|
||||||
|
uint32_t get_packet_timeout() { return this->_packet_timeout; }
|
||||||
|
|
||||||
// возможно функции get и не нужны, но вроде как должны быть
|
// возможно функции get и не нужны, но вроде как должны быть
|
||||||
void set_supported_modes(const std::set<ClimateMode> &modes) { this->_supported_modes = modes; }
|
void set_supported_modes(const std::set<ClimateMode> &modes) { this->_supported_modes = modes; }
|
||||||
std::set<ClimateMode> get_supported_modes() { return this->_supported_modes; }
|
std::set<ClimateMode> get_supported_modes() { return this->_supported_modes; }
|
||||||
|
|||||||
@@ -5,16 +5,18 @@ from esphome.components import climate, uart, sensor, binary_sensor, text_sensor
|
|||||||
from esphome import automation
|
from esphome import automation
|
||||||
from esphome.automation import maybe_simple_id
|
from esphome.automation import maybe_simple_id
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_ID,
|
|
||||||
CONF_UART_ID,
|
|
||||||
CONF_PERIOD,
|
|
||||||
CONF_CUSTOM_FAN_MODES,
|
CONF_CUSTOM_FAN_MODES,
|
||||||
CONF_CUSTOM_PRESETS,
|
CONF_CUSTOM_PRESETS,
|
||||||
CONF_INTERNAL,
|
|
||||||
CONF_DATA,
|
CONF_DATA,
|
||||||
|
CONF_ID,
|
||||||
|
CONF_INTERNAL,
|
||||||
|
CONF_PERIOD,
|
||||||
|
CONF_POSITION,
|
||||||
CONF_SUPPORTED_MODES,
|
CONF_SUPPORTED_MODES,
|
||||||
CONF_SUPPORTED_SWING_MODES,
|
CONF_SUPPORTED_SWING_MODES,
|
||||||
CONF_SUPPORTED_PRESETS,
|
CONF_SUPPORTED_PRESETS,
|
||||||
|
CONF_TIMEOUT,
|
||||||
|
CONF_UART_ID,
|
||||||
UNIT_CELSIUS,
|
UNIT_CELSIUS,
|
||||||
UNIT_PERCENT,
|
UNIT_PERCENT,
|
||||||
ICON_POWER,
|
ICON_POWER,
|
||||||
@@ -22,7 +24,6 @@ from esphome.const import (
|
|||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
DEVICE_CLASS_POWER_FACTOR,
|
DEVICE_CLASS_POWER_FACTOR,
|
||||||
STATE_CLASS_MEASUREMENT,
|
STATE_CLASS_MEASUREMENT,
|
||||||
CONF_POSITION,
|
|
||||||
)
|
)
|
||||||
from esphome.components.climate import (
|
from esphome.components.climate import (
|
||||||
ClimateMode,
|
ClimateMode,
|
||||||
@@ -37,26 +38,42 @@ DEPENDENCIES = ["climate", "uart"]
|
|||||||
AUTO_LOAD = ["sensor", "binary_sensor", "text_sensor"]
|
AUTO_LOAD = ["sensor", "binary_sensor", "text_sensor"]
|
||||||
|
|
||||||
CONF_SHOW_ACTION = "show_action"
|
CONF_SHOW_ACTION = "show_action"
|
||||||
|
|
||||||
CONF_INDOOR_TEMPERATURE = "indoor_temperature"
|
CONF_INDOOR_TEMPERATURE = "indoor_temperature"
|
||||||
CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature"
|
CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature"
|
||||||
ICON_OUTDOOR_TEMPERATURE = "mdi:home-thermometer-outline"
|
ICON_OUTDOOR_TEMPERATURE = "mdi:home-thermometer-outline"
|
||||||
|
|
||||||
CONF_INBOUND_TEMPERATURE = "inbound_temperature"
|
CONF_INBOUND_TEMPERATURE = "inbound_temperature"
|
||||||
ICON_INBOUND_TEMPERATURE = "mdi:thermometer-plus"
|
ICON_INBOUND_TEMPERATURE = "mdi:thermometer-plus"
|
||||||
|
|
||||||
CONF_OUTBOUND_TEMPERATURE = "outbound_temperature"
|
CONF_OUTBOUND_TEMPERATURE = "outbound_temperature"
|
||||||
ICON_OUTBOUND_TEMPERATURE = "mdi:thermometer-minus"
|
ICON_OUTBOUND_TEMPERATURE = "mdi:thermometer-minus"
|
||||||
|
|
||||||
CONF_COMPRESSOR_TEMPERATURE = "compressor_temperature"
|
CONF_COMPRESSOR_TEMPERATURE = "compressor_temperature"
|
||||||
ICON_COMPRESSOR_TEMPERATURE = "mdi:thermometer-lines"
|
ICON_COMPRESSOR_TEMPERATURE = "mdi:thermometer-lines"
|
||||||
|
|
||||||
CONF_DISPLAY_STATE = "display_state"
|
CONF_DISPLAY_STATE = "display_state"
|
||||||
CONF_INVERTOR_POWER = "invertor_power"
|
CONF_INVERTER_POWER = "inverter_power"
|
||||||
|
CONF_INVERTER_POWER_DEPRICATED = "invertor_power"
|
||||||
|
|
||||||
CONF_DEFROST_STATE = "defrost_state"
|
CONF_DEFROST_STATE = "defrost_state"
|
||||||
ICON_DEFROST = "mdi:snowflake-melt"
|
ICON_DEFROST = "mdi:snowflake-melt"
|
||||||
|
|
||||||
CONF_DISPLAY_INVERTED = "display_inverted"
|
CONF_DISPLAY_INVERTED = "display_inverted"
|
||||||
ICON_DISPLAY = "mdi:clock-digital"
|
ICON_DISPLAY = "mdi:clock-digital"
|
||||||
|
|
||||||
CONF_PRESET_REPORTER = "preset_reporter"
|
CONF_PRESET_REPORTER = "preset_reporter"
|
||||||
ICON_PRESET_REPORTER = "mdi:format-list-group"
|
ICON_PRESET_REPORTER = "mdi:format-list-group"
|
||||||
|
|
||||||
CONF_VLOUVER_STATE = "vlouver_state"
|
CONF_VLOUVER_STATE = "vlouver_state"
|
||||||
ICON_VLOUVER_STATE = "mdi:compare-vertical"
|
ICON_VLOUVER_STATE = "mdi:compare-vertical"
|
||||||
|
|
||||||
|
CONF_LIMIT = "limit"
|
||||||
|
CONF_INVERTER_POWER_LIMIT_VALUE = "inverter_power_limit_value"
|
||||||
|
ICON_INVERTER_POWER_LIMIT_VALUE = "mdi:meter-electric-outline"
|
||||||
|
CONF_INVERTER_POWER_LIMIT_STATE = "inverter_power_limit_state"
|
||||||
|
ICON_INVERTER_POWER_LIMIT_STATE = "mdi:meter-electric-outline"
|
||||||
|
|
||||||
|
|
||||||
aux_ac_ns = cg.esphome_ns.namespace("aux_ac")
|
aux_ac_ns = cg.esphome_ns.namespace("aux_ac")
|
||||||
AirCon = aux_ac_ns.class_("AirCon", climate.Climate, cg.Component)
|
AirCon = aux_ac_ns.class_("AirCon", climate.Climate, cg.Component)
|
||||||
@@ -66,7 +83,7 @@ Capabilities = aux_ac_ns.namespace("Constants")
|
|||||||
AirConDisplayOffAction = aux_ac_ns.class_("AirConDisplayOffAction", automation.Action)
|
AirConDisplayOffAction = aux_ac_ns.class_("AirConDisplayOffAction", automation.Action)
|
||||||
AirConDisplayOnAction = aux_ac_ns.class_("AirConDisplayOnAction", automation.Action)
|
AirConDisplayOnAction = aux_ac_ns.class_("AirConDisplayOnAction", automation.Action)
|
||||||
|
|
||||||
# test packet
|
# test packet action
|
||||||
AirConSendTestPacketAction = aux_ac_ns.class_(
|
AirConSendTestPacketAction = aux_ac_ns.class_(
|
||||||
"AirConSendTestPacketAction", automation.Action
|
"AirConSendTestPacketAction", automation.Action
|
||||||
)
|
)
|
||||||
@@ -89,8 +106,38 @@ AirConVLouverMiddleBelowAction = aux_ac_ns.class_(
|
|||||||
AirConVLouverBottomAction = aux_ac_ns.class_(
|
AirConVLouverBottomAction = aux_ac_ns.class_(
|
||||||
"AirConVLouverBottomAction", automation.Action
|
"AirConVLouverBottomAction", automation.Action
|
||||||
)
|
)
|
||||||
|
AirConVLouverSetAction = aux_ac_ns.class_(
|
||||||
|
"AirConVLouverSetAction", automation.Action
|
||||||
|
)
|
||||||
|
|
||||||
|
# power limitation actions
|
||||||
|
AirConPowerLimitationOffAction = aux_ac_ns.class_(
|
||||||
|
"AirConPowerLimitationOffAction", automation.Action
|
||||||
|
)
|
||||||
|
AirConPowerLimitationOnAction = aux_ac_ns.class_(
|
||||||
|
"AirConPowerLimitationOnAction", automation.Action
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
AC_PACKET_TIMEOUT_MIN = 150
|
||||||
|
AC_PACKET_TIMEOUT_MAX = 600
|
||||||
|
def validate_packet_timeout(value):
|
||||||
|
minV = AC_PACKET_TIMEOUT_MIN
|
||||||
|
maxV = AC_PACKET_TIMEOUT_MAX
|
||||||
|
if value in range(minV, maxV+1):
|
||||||
|
return cv.Schema(cv.uint32_t)(value)
|
||||||
|
raise cv.Invalid(f"Timeout should be in range: {minV}..{maxV}.")
|
||||||
|
|
||||||
|
|
||||||
|
AC_POWER_LIMIT_MIN = 30
|
||||||
|
AC_POWER_LIMIT_MAX = 100
|
||||||
|
def validate_power_limit_range(value):
|
||||||
|
minV = AC_POWER_LIMIT_MIN
|
||||||
|
maxV = AC_POWER_LIMIT_MAX
|
||||||
|
if value in range(minV, maxV+1):
|
||||||
|
return cv.Schema(cv.uint32_t)(value)
|
||||||
|
raise cv.Invalid(f"Power limit should be in range: {minV}..{maxV}")
|
||||||
|
|
||||||
AirConVLouverSetAction = aux_ac_ns.class_("AirConVLouverSetAction", automation.Action)
|
|
||||||
|
|
||||||
ALLOWED_CLIMATE_MODES = {
|
ALLOWED_CLIMATE_MODES = {
|
||||||
"HEAT_COOL": ClimateMode.CLIMATE_MODE_HEAT_COOL,
|
"HEAT_COOL": ClimateMode.CLIMATE_MODE_HEAT_COOL,
|
||||||
@@ -134,7 +181,7 @@ def validate_raw_data(value):
|
|||||||
|
|
||||||
|
|
||||||
def output_info(config):
|
def output_info(config):
|
||||||
"""_LOGGER.info(config)"""
|
"""_LOGGER.info(config.items())"""
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
@@ -145,7 +192,12 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
cv.Optional(CONF_PERIOD, default="7s"): cv.time_period,
|
cv.Optional(CONF_PERIOD, default="7s"): cv.time_period,
|
||||||
cv.Optional(CONF_SHOW_ACTION, default="true"): cv.boolean,
|
cv.Optional(CONF_SHOW_ACTION, default="true"): cv.boolean,
|
||||||
cv.Optional(CONF_DISPLAY_INVERTED, default="false"): cv.boolean,
|
cv.Optional(CONF_DISPLAY_INVERTED, default="false"): cv.boolean,
|
||||||
cv.Optional(CONF_INVERTOR_POWER): sensor.sensor_schema(
|
cv.Optional(CONF_TIMEOUT, default=AC_PACKET_TIMEOUT_MIN): validate_packet_timeout,
|
||||||
|
|
||||||
|
cv.Optional(CONF_INVERTER_POWER_DEPRICATED): cv.invalid(
|
||||||
|
"The name of sensor was changed in v.0.2.9 from 'invertor_power' to 'inverter_power'. Update your config please."
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_INVERTER_POWER): sensor.sensor_schema(
|
||||||
unit_of_measurement=UNIT_PERCENT,
|
unit_of_measurement=UNIT_PERCENT,
|
||||||
icon=ICON_POWER,
|
icon=ICON_POWER,
|
||||||
accuracy_decimals=0,
|
accuracy_decimals=0,
|
||||||
@@ -156,6 +208,7 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
cv.Optional(CONF_INTERNAL, default="true"): cv.boolean,
|
cv.Optional(CONF_INTERNAL, default="true"): cv.boolean,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
||||||
cv.Optional(CONF_INDOOR_TEMPERATURE): sensor.sensor_schema(
|
cv.Optional(CONF_INDOOR_TEMPERATURE): sensor.sensor_schema(
|
||||||
unit_of_measurement=UNIT_CELSIUS,
|
unit_of_measurement=UNIT_CELSIUS,
|
||||||
icon=ICON_THERMOMETER,
|
icon=ICON_THERMOMETER,
|
||||||
@@ -240,6 +293,24 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
cv.Optional(CONF_INTERNAL, default="true"): cv.boolean,
|
cv.Optional(CONF_INTERNAL, default="true"): cv.boolean,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
cv.Optional(CONF_INVERTER_POWER_LIMIT_VALUE): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_PERCENT,
|
||||||
|
icon=ICON_INVERTER_POWER_LIMIT_VALUE,
|
||||||
|
accuracy_decimals=0,
|
||||||
|
device_class=DEVICE_CLASS_POWER_FACTOR,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
).extend(
|
||||||
|
{
|
||||||
|
cv.Optional(CONF_INTERNAL, default="true"): cv.boolean,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_INVERTER_POWER_LIMIT_STATE): binary_sensor.binary_sensor_schema(
|
||||||
|
icon=ICON_INVERTER_POWER_LIMIT_STATE,
|
||||||
|
).extend(
|
||||||
|
{
|
||||||
|
cv.Optional(CONF_INTERNAL, default="true"): cv.boolean,
|
||||||
|
}
|
||||||
|
),
|
||||||
cv.Optional(CONF_SUPPORTED_MODES): cv.ensure_list(validate_modes),
|
cv.Optional(CONF_SUPPORTED_MODES): cv.ensure_list(validate_modes),
|
||||||
cv.Optional(CONF_SUPPORTED_SWING_MODES): cv.ensure_list(
|
cv.Optional(CONF_SUPPORTED_SWING_MODES): cv.ensure_list(
|
||||||
validate_swing_modes
|
validate_swing_modes
|
||||||
@@ -258,8 +329,6 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
"""_LOGGER.info("--------------")"""
|
|
||||||
"""_LOGGER.info(config)"""
|
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
await climate.register_climate(var, config)
|
await climate.register_climate(var, config)
|
||||||
@@ -307,19 +376,30 @@ async def to_code(config):
|
|||||||
sens = await binary_sensor.new_binary_sensor(conf)
|
sens = await binary_sensor.new_binary_sensor(conf)
|
||||||
cg.add(var.set_defrost_state(sens))
|
cg.add(var.set_defrost_state(sens))
|
||||||
|
|
||||||
if CONF_INVERTOR_POWER in config:
|
if CONF_INVERTER_POWER in config:
|
||||||
conf = config[CONF_INVERTOR_POWER]
|
conf = config[CONF_INVERTER_POWER]
|
||||||
sens = await sensor.new_sensor(conf)
|
sens = await sensor.new_sensor(conf)
|
||||||
cg.add(var.set_invertor_power_sensor(sens))
|
cg.add(var.set_inverter_power_sensor(sens))
|
||||||
|
|
||||||
if CONF_PRESET_REPORTER in config:
|
if CONF_PRESET_REPORTER in config:
|
||||||
conf = config[CONF_PRESET_REPORTER]
|
conf = config[CONF_PRESET_REPORTER]
|
||||||
sens = await text_sensor.new_text_sensor(conf)
|
sens = await text_sensor.new_text_sensor(conf)
|
||||||
cg.add(var.set_preset_reporter_sensor(sens))
|
cg.add(var.set_preset_reporter_sensor(sens))
|
||||||
|
|
||||||
|
if CONF_INVERTER_POWER_LIMIT_VALUE in config:
|
||||||
|
conf = config[CONF_INVERTER_POWER_LIMIT_VALUE]
|
||||||
|
sens = await sensor.new_sensor(conf)
|
||||||
|
cg.add(var.set_inverter_power_limit_value_sensor(sens))
|
||||||
|
|
||||||
|
if CONF_INVERTER_POWER_LIMIT_STATE in config:
|
||||||
|
conf = config[CONF_INVERTER_POWER_LIMIT_STATE]
|
||||||
|
sens = await binary_sensor.new_binary_sensor(conf)
|
||||||
|
cg.add(var.set_inverter_power_limit_state_sensor(sens))
|
||||||
|
|
||||||
cg.add(var.set_period(config[CONF_PERIOD].total_milliseconds))
|
cg.add(var.set_period(config[CONF_PERIOD].total_milliseconds))
|
||||||
cg.add(var.set_show_action(config[CONF_SHOW_ACTION]))
|
cg.add(var.set_show_action(config[CONF_SHOW_ACTION]))
|
||||||
cg.add(var.set_display_inverted(config[CONF_DISPLAY_INVERTED]))
|
cg.add(var.set_display_inverted(config[CONF_DISPLAY_INVERTED]))
|
||||||
|
cg.add(var.set_packet_timeout(config[CONF_TIMEOUT]))
|
||||||
if CONF_SUPPORTED_MODES in config:
|
if CONF_SUPPORTED_MODES in config:
|
||||||
cg.add(var.set_supported_modes(config[CONF_SUPPORTED_MODES]))
|
cg.add(var.set_supported_modes(config[CONF_SUPPORTED_MODES]))
|
||||||
if CONF_SUPPORTED_SWING_MODES in config:
|
if CONF_SUPPORTED_SWING_MODES in config:
|
||||||
@@ -332,13 +412,13 @@ async def to_code(config):
|
|||||||
cg.add(var.set_custom_fan_modes(config[CONF_CUSTOM_FAN_MODES]))
|
cg.add(var.set_custom_fan_modes(config[CONF_CUSTOM_FAN_MODES]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DISPLAY_ACTION_SCHEMA = maybe_simple_id(
|
DISPLAY_ACTION_SCHEMA = maybe_simple_id(
|
||||||
{
|
{
|
||||||
cv.Required(CONF_ID): cv.use_id(AirCon),
|
cv.Required(CONF_ID): cv.use_id(AirCon),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
"aux_ac.display_off", AirConDisplayOffAction, DISPLAY_ACTION_SCHEMA
|
"aux_ac.display_off", AirConDisplayOffAction, DISPLAY_ACTION_SCHEMA
|
||||||
)
|
)
|
||||||
@@ -346,7 +426,6 @@ async def display_off_to_code(config, action_id, template_arg, args):
|
|||||||
paren = await cg.get_variable(config[CONF_ID])
|
paren = await cg.get_variable(config[CONF_ID])
|
||||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
"aux_ac.display_on", AirConDisplayOnAction, DISPLAY_ACTION_SCHEMA
|
"aux_ac.display_on", AirConDisplayOnAction, DISPLAY_ACTION_SCHEMA
|
||||||
)
|
)
|
||||||
@@ -355,13 +434,13 @@ async def display_on_to_code(config, action_id, template_arg, args):
|
|||||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
VLOUVER_ACTION_SCHEMA = maybe_simple_id(
|
VLOUVER_ACTION_SCHEMA = maybe_simple_id(
|
||||||
{
|
{
|
||||||
cv.Required(CONF_ID): cv.use_id(AirCon),
|
cv.Required(CONF_ID): cv.use_id(AirCon),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
"aux_ac.vlouver_stop", AirConVLouverStopAction, VLOUVER_ACTION_SCHEMA
|
"aux_ac.vlouver_stop", AirConVLouverStopAction, VLOUVER_ACTION_SCHEMA
|
||||||
)
|
)
|
||||||
@@ -369,7 +448,6 @@ async def vlouver_stop_to_code(config, action_id, template_arg, args):
|
|||||||
paren = await cg.get_variable(config[CONF_ID])
|
paren = await cg.get_variable(config[CONF_ID])
|
||||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
"aux_ac.vlouver_swing", AirConVLouverSwingAction, VLOUVER_ACTION_SCHEMA
|
"aux_ac.vlouver_swing", AirConVLouverSwingAction, VLOUVER_ACTION_SCHEMA
|
||||||
)
|
)
|
||||||
@@ -377,7 +455,6 @@ async def vlouver_swing_to_code(config, action_id, template_arg, args):
|
|||||||
paren = await cg.get_variable(config[CONF_ID])
|
paren = await cg.get_variable(config[CONF_ID])
|
||||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
"aux_ac.vlouver_top", AirConVLouverTopAction, VLOUVER_ACTION_SCHEMA
|
"aux_ac.vlouver_top", AirConVLouverTopAction, VLOUVER_ACTION_SCHEMA
|
||||||
)
|
)
|
||||||
@@ -385,7 +462,6 @@ async def vlouver_top_to_code(config, action_id, template_arg, args):
|
|||||||
paren = await cg.get_variable(config[CONF_ID])
|
paren = await cg.get_variable(config[CONF_ID])
|
||||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
"aux_ac.vlouver_middle_above", AirConVLouverMiddleAboveAction, VLOUVER_ACTION_SCHEMA
|
"aux_ac.vlouver_middle_above", AirConVLouverMiddleAboveAction, VLOUVER_ACTION_SCHEMA
|
||||||
)
|
)
|
||||||
@@ -393,7 +469,6 @@ async def vlouver_middle_above_to_code(config, action_id, template_arg, args):
|
|||||||
paren = await cg.get_variable(config[CONF_ID])
|
paren = await cg.get_variable(config[CONF_ID])
|
||||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
"aux_ac.vlouver_middle", AirConVLouverMiddleAction, VLOUVER_ACTION_SCHEMA
|
"aux_ac.vlouver_middle", AirConVLouverMiddleAction, VLOUVER_ACTION_SCHEMA
|
||||||
)
|
)
|
||||||
@@ -401,7 +476,6 @@ async def vlouver_middle_to_code(config, action_id, template_arg, args):
|
|||||||
paren = await cg.get_variable(config[CONF_ID])
|
paren = await cg.get_variable(config[CONF_ID])
|
||||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
"aux_ac.vlouver_middle_below", AirConVLouverMiddleBelowAction, VLOUVER_ACTION_SCHEMA
|
"aux_ac.vlouver_middle_below", AirConVLouverMiddleBelowAction, VLOUVER_ACTION_SCHEMA
|
||||||
)
|
)
|
||||||
@@ -409,7 +483,6 @@ async def vlouver_middle_below_to_code(config, action_id, template_arg, args):
|
|||||||
paren = await cg.get_variable(config[CONF_ID])
|
paren = await cg.get_variable(config[CONF_ID])
|
||||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
"aux_ac.vlouver_bottom", AirConVLouverBottomAction, VLOUVER_ACTION_SCHEMA
|
"aux_ac.vlouver_bottom", AirConVLouverBottomAction, VLOUVER_ACTION_SCHEMA
|
||||||
)
|
)
|
||||||
@@ -418,6 +491,7 @@ async def vlouver_bottom_to_code(config, action_id, template_arg, args):
|
|||||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
VLOUVER_SET_ACTION_SCHEMA = cv.Schema(
|
VLOUVER_SET_ACTION_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
cv.Required(CONF_ID): cv.use_id(AirCon),
|
cv.Required(CONF_ID): cv.use_id(AirCon),
|
||||||
@@ -425,7 +499,6 @@ VLOUVER_SET_ACTION_SCHEMA = cv.Schema(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
"aux_ac.vlouver_set", AirConVLouverSetAction, VLOUVER_SET_ACTION_SCHEMA
|
"aux_ac.vlouver_set", AirConVLouverSetAction, VLOUVER_SET_ACTION_SCHEMA
|
||||||
)
|
)
|
||||||
@@ -437,6 +510,41 @@ async def vlouver_set_to_code(config, action_id, template_arg, args):
|
|||||||
return var
|
return var
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
POWER_LIMITATION_OFF_ACTION_SCHEMA = maybe_simple_id(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_ID): cv.use_id(AirCon),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@automation.register_action(
|
||||||
|
"aux_ac.power_limit_off", AirConPowerLimitationOffAction, POWER_LIMITATION_OFF_ACTION_SCHEMA
|
||||||
|
)
|
||||||
|
async def power_limit_off_to_code(config, action_id, template_arg, args):
|
||||||
|
paren = await cg.get_variable(config[CONF_ID])
|
||||||
|
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
POWER_LIMITATION_ON_ACTION_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_ID): cv.use_id(AirCon),
|
||||||
|
cv.Optional(CONF_LIMIT, default=AC_POWER_LIMIT_MIN): validate_power_limit_range,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@automation.register_action(
|
||||||
|
"aux_ac.power_limit_on", AirConPowerLimitationOnAction, POWER_LIMITATION_ON_ACTION_SCHEMA
|
||||||
|
)
|
||||||
|
async def power_limit_on_to_code(config, action_id, template_arg, args):
|
||||||
|
paren = await cg.get_variable(config[CONF_ID])
|
||||||
|
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
template_ = await cg.templatable(config[CONF_LIMIT], args, int)
|
||||||
|
cg.add(var.set_value(template_))
|
||||||
|
return var
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# *********************************************************************************************************
|
# *********************************************************************************************************
|
||||||
# ВАЖНО! Только для инженеров!
|
# ВАЖНО! Только для инженеров!
|
||||||
# Вызывайте метод aux_ac.send_packet только если понимаете, что делаете! Он не проверяет данные, а передаёт
|
# Вызывайте метод aux_ac.send_packet только если понимаете, что делаете! Он не проверяет данные, а передаёт
|
||||||
|
|||||||
162
tests/test-ext-power-limit.yaml
Normal file
162
tests/test-ext-power-limit.yaml
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
external_components:
|
||||||
|
- source: github://GrKoR/esphome_aux_ac_component@dev
|
||||||
|
components: [ aux_ac ]
|
||||||
|
refresh: 0s
|
||||||
|
|
||||||
|
substitutions:
|
||||||
|
devicename: test_ext_power_limitations
|
||||||
|
upper_devicename: Test AUX
|
||||||
|
|
||||||
|
esphome:
|
||||||
|
name: $devicename
|
||||||
|
platform: ESP8266
|
||||||
|
board: esp12e
|
||||||
|
|
||||||
|
wifi:
|
||||||
|
ssid: !secret wifi_ssid
|
||||||
|
password: !secret wifi_pass
|
||||||
|
manual_ip:
|
||||||
|
static_ip: !secret wifi_ip
|
||||||
|
gateway: !secret wifi_gateway
|
||||||
|
subnet: !secret wifi_subnet
|
||||||
|
dns1: 8.8.8.8
|
||||||
|
dns2: 1.1.1.1
|
||||||
|
reboot_timeout: 0s
|
||||||
|
ap:
|
||||||
|
ssid: Test AUX Fallback Hotspot
|
||||||
|
password: !secret wifi_ap_pass
|
||||||
|
|
||||||
|
logger:
|
||||||
|
level: DEBUG
|
||||||
|
baud_rate: 0
|
||||||
|
|
||||||
|
api:
|
||||||
|
password: !secret api_pass
|
||||||
|
reboot_timeout: 0s
|
||||||
|
|
||||||
|
ota:
|
||||||
|
password: !secret ota_pass
|
||||||
|
|
||||||
|
web_server:
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
uart:
|
||||||
|
id: ac_uart_bus
|
||||||
|
tx_pin: GPIO1
|
||||||
|
rx_pin: GPIO3
|
||||||
|
baud_rate: 4800
|
||||||
|
data_bits: 8
|
||||||
|
parity: EVEN
|
||||||
|
stop_bits: 1
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: uptime
|
||||||
|
name: Uptime Sensor
|
||||||
|
|
||||||
|
climate:
|
||||||
|
- platform: aux_ac
|
||||||
|
name: $upper_devicename
|
||||||
|
id: aux_id
|
||||||
|
uart_id: ac_uart_bus
|
||||||
|
period: 7s
|
||||||
|
show_action: true
|
||||||
|
display_inverted: true
|
||||||
|
timeout: 150
|
||||||
|
indoor_temperature:
|
||||||
|
name: $upper_devicename Indoor Temperature
|
||||||
|
id: ${devicename}_indoor_temp
|
||||||
|
internal: false
|
||||||
|
display_state:
|
||||||
|
name: $upper_devicename Display State
|
||||||
|
id: ${devicename}_display_state
|
||||||
|
internal: false
|
||||||
|
outdoor_temperature:
|
||||||
|
name: $upper_devicename Outdoor Temperature
|
||||||
|
id: ${devicename}_outdoor_temp
|
||||||
|
internal: false
|
||||||
|
outbound_temperature:
|
||||||
|
name: $upper_devicename Colant Outbound Temperature
|
||||||
|
id: ${devicename}_outbound_temp
|
||||||
|
internal: false
|
||||||
|
inbound_temperature:
|
||||||
|
name: $upper_devicename Colant Inbound Temperature
|
||||||
|
id: ${devicename}_inbound_temp
|
||||||
|
internal: false
|
||||||
|
compressor_temperature:
|
||||||
|
name: $upper_devicename Compressor Temperature
|
||||||
|
id: ${devicename}_strange_temp
|
||||||
|
internal: false
|
||||||
|
defrost_state:
|
||||||
|
name: $upper_devicename Defrost State
|
||||||
|
id: ${devicename}_defrost_state
|
||||||
|
internal: false
|
||||||
|
inverter_power:
|
||||||
|
name: $upper_devicename Inverter Power
|
||||||
|
id: ${devicename}_invertor_power
|
||||||
|
internal: false
|
||||||
|
preset_reporter:
|
||||||
|
name: $upper_devicename Preset Reporter
|
||||||
|
id: ${devicename}_preset_reporter
|
||||||
|
internal: false
|
||||||
|
inverter_power_limit_value:
|
||||||
|
name: $upper_devicename Inverter Power Limit Value
|
||||||
|
id: ${devicename}_inverter_power_limit_value
|
||||||
|
internal: false
|
||||||
|
inverter_power_limit_state:
|
||||||
|
name: $upper_devicename Inverter Power Limit State
|
||||||
|
id: ${devicename}_inverter_power_limit_state
|
||||||
|
internal: false
|
||||||
|
visual:
|
||||||
|
min_temperature: 16
|
||||||
|
max_temperature: 32
|
||||||
|
temperature_step: 0.5
|
||||||
|
supported_modes:
|
||||||
|
- HEAT_COOL
|
||||||
|
- COOL
|
||||||
|
- HEAT
|
||||||
|
- DRY
|
||||||
|
- FAN_ONLY
|
||||||
|
custom_fan_modes:
|
||||||
|
- MUTE
|
||||||
|
- TURBO
|
||||||
|
supported_presets:
|
||||||
|
- SLEEP
|
||||||
|
custom_presets:
|
||||||
|
- CLEAN
|
||||||
|
- HEALTH
|
||||||
|
- ANTIFUNGUS
|
||||||
|
supported_swing_modes:
|
||||||
|
- VERTICAL
|
||||||
|
- HORIZONTAL
|
||||||
|
- BOTH
|
||||||
|
|
||||||
|
|
||||||
|
button:
|
||||||
|
- platform: template
|
||||||
|
name: ${upper_devicename} IPower Limit Off
|
||||||
|
icon: "mdi:power-plug-off-outline"
|
||||||
|
on_press:
|
||||||
|
- aux_ac.power_limit_off: aux_id
|
||||||
|
|
||||||
|
- platform: template
|
||||||
|
name: ${upper_devicename} IPower Limit On Half
|
||||||
|
icon: "mdi:fraction-one-half"
|
||||||
|
on_press:
|
||||||
|
- aux_ac.power_limit_on:
|
||||||
|
id: aux_id
|
||||||
|
limit: 50
|
||||||
|
|
||||||
|
number:
|
||||||
|
- platform: template
|
||||||
|
name: ${upper_devicename} IPower Limit Value
|
||||||
|
id: ${devicename}_ipower_limit_value
|
||||||
|
icon: "mdi:battery-unknown"
|
||||||
|
mode: "slider"
|
||||||
|
min_value: 30
|
||||||
|
max_value: 100
|
||||||
|
step: 1
|
||||||
|
set_action:
|
||||||
|
then:
|
||||||
|
- lambda: !lambda |-
|
||||||
|
id(aux_id).powerLimitationOnSequence( x );
|
||||||
|
|
||||||
162
tests/test-local-power-limit.yaml
Normal file
162
tests/test-local-power-limit.yaml
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
external_components:
|
||||||
|
- source:
|
||||||
|
type: local
|
||||||
|
path: ../components
|
||||||
|
|
||||||
|
substitutions:
|
||||||
|
devicename: test_local_power_limitations
|
||||||
|
upper_devicename: Test AUX
|
||||||
|
|
||||||
|
esphome:
|
||||||
|
name: $devicename
|
||||||
|
platform: ESP8266
|
||||||
|
board: esp12e
|
||||||
|
|
||||||
|
wifi:
|
||||||
|
ssid: !secret wifi_ssid
|
||||||
|
password: !secret wifi_pass
|
||||||
|
manual_ip:
|
||||||
|
static_ip: !secret wifi_ip
|
||||||
|
gateway: !secret wifi_gateway
|
||||||
|
subnet: !secret wifi_subnet
|
||||||
|
dns1: 8.8.8.8
|
||||||
|
dns2: 1.1.1.1
|
||||||
|
reboot_timeout: 0s
|
||||||
|
ap:
|
||||||
|
ssid: Test AUX Fallback Hotspot
|
||||||
|
password: !secret wifi_ap_pass
|
||||||
|
|
||||||
|
logger:
|
||||||
|
level: DEBUG
|
||||||
|
baud_rate: 0
|
||||||
|
|
||||||
|
api:
|
||||||
|
password: !secret api_pass
|
||||||
|
reboot_timeout: 0s
|
||||||
|
|
||||||
|
ota:
|
||||||
|
password: !secret ota_pass
|
||||||
|
|
||||||
|
web_server:
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
uart:
|
||||||
|
id: ac_uart_bus
|
||||||
|
tx_pin: GPIO1
|
||||||
|
rx_pin: GPIO3
|
||||||
|
baud_rate: 4800
|
||||||
|
data_bits: 8
|
||||||
|
parity: EVEN
|
||||||
|
stop_bits: 1
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: uptime
|
||||||
|
name: Uptime Sensor
|
||||||
|
|
||||||
|
climate:
|
||||||
|
- platform: aux_ac
|
||||||
|
name: $upper_devicename
|
||||||
|
id: aux_id
|
||||||
|
uart_id: ac_uart_bus
|
||||||
|
period: 7s
|
||||||
|
show_action: true
|
||||||
|
display_inverted: true
|
||||||
|
timeout: 150
|
||||||
|
indoor_temperature:
|
||||||
|
name: $upper_devicename Indoor Temperature
|
||||||
|
id: ${devicename}_indoor_temp
|
||||||
|
internal: false
|
||||||
|
display_state:
|
||||||
|
name: $upper_devicename Display State
|
||||||
|
id: ${devicename}_display_state
|
||||||
|
internal: false
|
||||||
|
outdoor_temperature:
|
||||||
|
name: $upper_devicename Outdoor Temperature
|
||||||
|
id: ${devicename}_outdoor_temp
|
||||||
|
internal: false
|
||||||
|
outbound_temperature:
|
||||||
|
name: $upper_devicename Colant Outbound Temperature
|
||||||
|
id: ${devicename}_outbound_temp
|
||||||
|
internal: false
|
||||||
|
inbound_temperature:
|
||||||
|
name: $upper_devicename Colant Inbound Temperature
|
||||||
|
id: ${devicename}_inbound_temp
|
||||||
|
internal: false
|
||||||
|
compressor_temperature:
|
||||||
|
name: $upper_devicename Compressor Temperature
|
||||||
|
id: ${devicename}_strange_temp
|
||||||
|
internal: false
|
||||||
|
defrost_state:
|
||||||
|
name: $upper_devicename Defrost State
|
||||||
|
id: ${devicename}_defrost_state
|
||||||
|
internal: false
|
||||||
|
inverter_power:
|
||||||
|
name: $upper_devicename Inverter Power
|
||||||
|
id: ${devicename}_invertor_power
|
||||||
|
internal: false
|
||||||
|
preset_reporter:
|
||||||
|
name: $upper_devicename Preset Reporter
|
||||||
|
id: ${devicename}_preset_reporter
|
||||||
|
internal: false
|
||||||
|
inverter_power_limit_value:
|
||||||
|
name: $upper_devicename Inverter Power Limit Value
|
||||||
|
id: ${devicename}_inverter_power_limit_value
|
||||||
|
internal: false
|
||||||
|
inverter_power_limit_state:
|
||||||
|
name: $upper_devicename Inverter Power Limit State
|
||||||
|
id: ${devicename}_inverter_power_limit_state
|
||||||
|
internal: false
|
||||||
|
visual:
|
||||||
|
min_temperature: 16
|
||||||
|
max_temperature: 32
|
||||||
|
temperature_step: 0.5
|
||||||
|
supported_modes:
|
||||||
|
- HEAT_COOL
|
||||||
|
- COOL
|
||||||
|
- HEAT
|
||||||
|
- DRY
|
||||||
|
- FAN_ONLY
|
||||||
|
custom_fan_modes:
|
||||||
|
- MUTE
|
||||||
|
- TURBO
|
||||||
|
supported_presets:
|
||||||
|
- SLEEP
|
||||||
|
custom_presets:
|
||||||
|
- CLEAN
|
||||||
|
- HEALTH
|
||||||
|
- ANTIFUNGUS
|
||||||
|
supported_swing_modes:
|
||||||
|
- VERTICAL
|
||||||
|
- HORIZONTAL
|
||||||
|
- BOTH
|
||||||
|
|
||||||
|
|
||||||
|
button:
|
||||||
|
- platform: template
|
||||||
|
name: ${upper_devicename} IPower Limit Off
|
||||||
|
icon: "mdi:power-plug-off-outline"
|
||||||
|
on_press:
|
||||||
|
- aux_ac.power_limit_off: aux_id
|
||||||
|
|
||||||
|
- platform: template
|
||||||
|
name: ${upper_devicename} IPower Limit On Half
|
||||||
|
icon: "mdi:fraction-one-half"
|
||||||
|
on_press:
|
||||||
|
- aux_ac.power_limit_on:
|
||||||
|
id: aux_id
|
||||||
|
limit: 50
|
||||||
|
|
||||||
|
number:
|
||||||
|
- platform: template
|
||||||
|
name: ${upper_devicename} IPower Limit Value
|
||||||
|
id: ${devicename}_ipower_limit_value
|
||||||
|
icon: "mdi:battery-unknown"
|
||||||
|
mode: "slider"
|
||||||
|
min_value: 30
|
||||||
|
max_value: 100
|
||||||
|
step: 1
|
||||||
|
set_action:
|
||||||
|
then:
|
||||||
|
- lambda: !lambda |-
|
||||||
|
id(aux_id).powerLimitationOnSequence( x );
|
||||||
|
|
||||||
Reference in New Issue
Block a user