Добавить сенсор "Положение жалюзей"

Fixes #51
This commit is contained in:
GrKoR
2022-06-13 20:50:44 +03:00
parent 2acd934bbe
commit 809fddf13a
6 changed files with 235 additions and 27 deletions

View File

@@ -123,6 +123,10 @@ climate:
name: AC Preset Reporter
id: ac_preset_reporter
internal: false
vlouver_state:
name: AC Vertical Louvers State
id: ac_vlouver_state
internal: false
visual:
min_temperature: 16
max_temperature: 32
@@ -176,7 +180,8 @@ climate:
- **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 invertor power sensor. 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 report their active presets (from **supported_presets** and **custom_presets** lists) to MQTT. 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 report their active presets (from **supported_presets** and **custom_presets** lists) to MQTT. 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).
- **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.
- **supported_presets** (*Optional*, list): List of supported presets. Possible values are: ``SLEEP``. No presets by default.
@@ -205,6 +210,28 @@ on_...:
```
- **aux_id** (**Requared**, string): ID of `aux_ac` component.
### ``aux_ac.vlouver_set`` ###
This action moves HVAC vertical louvers to the specified position.
The position is encoded by the following values:
- `0`: the vertical louvers are in `SWING` mode (they are moving up and down);
- `1`: the louvers are stopped in a user position;
- `2`: the louvers are in the topmost position;
- `3`: the louvers are in one step above middle position;
- `4`: the louvers are in the middle position;
- `5`: the louvers are in one step below middle position;
- `6`: the louvers are in the lowest position.
```yaml
on_...:
then:
- aux_ac.vlouver_set:
id: aux_id
position: 3 # moves the louvers to the middle position
```
- **aux_id** (**Requared**, string): ID of `aux_ac` component.
- **position** (**Requared**, integer): position of the vertical louvers.
### ``aux_ac.vlouver_stop`` ###
This action stops vertical swing of louvers.

View File

@@ -132,6 +132,10 @@ climate:
name: AC Preset Reporter
id: ac_preset_reporter
internal: false
vlouver_state:
name: AC Vertical Louvers State
id: ac_vlouver_state
internal: false
visual:
min_temperature: 16
max_temperature: 32
@@ -185,7 +189,8 @@ climate:
- **defrost_state** (*Опциональный*): Параметры создаваемого датчика состояния разморозки (включена или выключена), если такой датчик нужен. Параметры аналогичны датчику дисплея **display_state**.
- **invertor_power** (*Опциональный*): Параметры создаваемого датчика мощности инвертора, если такой датчик нужен. Параметры аналогичны датчику дисплея **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) ниже).
- **supported_modes** (*Опциональный*, список): Список поддерживаемых режимов работы. Возможные значения: ``HEAT_COOL``, ``COOL``, ``HEAT``, ``DRY``, ``FAN_ONLY``. Обратите внимание: некоторые производители кондиционеров указывают на пульте режим AUTO, хотя по факту этот режим не работает по расписанию и только лишь поддерживает целевую температуру. Такой режим в ESPHome называется HEAT_COOL. По умолчанию список содержит только значение ``FAN_ONLY``.
- **custom_fan_modes** (*Опциональный*, список): Список поддерживаемых дополнительных режимов вентилятора. Возможные значения: ``MUTE``, ``TURBO``. По умолчанию никакие дополнительные режимы не установлены.
- **supported_presets** (*Опциональный*, список): Список поддерживаемых базовых функций кондиционера. Возможные значения: ``SLEEP``. По умолчанию никакие базовые функции не установлены.
@@ -214,6 +219,28 @@ on_...:
```
- **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`.
### ``aux_ac.vlouver_set`` ###
Переводит жалюзи в указанное состояние.
Состояние кодируется следующими целочисленными значениями:
- `0`: жалюзи находятся в состоянии `SWING` (качаются вверх-вниз);
- `1`: жалюзи остановлены в каком-то пользовательском положении;
- `2`: жалюзи установлены в верхнее положение;
- `3`: жалюзи установдены в положение на шаг выше среднего;
- `4`: жалюзи установены в среднее положение;
- `5`: жалюзи установдены в положение на шаг ниже среднего;
- `6`: жалюзи установлены в нижнее положение.
```yaml
on_...:
then:
- aux_ac.vlouver_set:
id: aux_id
position: 3 # устанавливаем жалюзи в среднее положение
```
- **aux_id** (**Обязательный**, строка): ID компонента `aux_ac`.
- **position** (**Обязательный**, целое число): состояние вертикальных жалюзи.
### ``aux_ac.vlouver_stop`` ###
Остановка вертикального движения жалюзи кондиционера. Если жалюзи качались в вертикальном направлении, то можно их остановить в нужном положении.

View File

@@ -119,6 +119,22 @@ namespace aux_ac {
AirCon *ac_;
};
template<typename... Ts>
class AirConVLouverSetAction : public Action<Ts...>
{
public:
AirConVLouverSetAction(AirCon *ac) : ac_(ac) {}
TEMPLATABLE_VALUE(uint8_t, value);
void play(Ts... x) {
vlpos_ = this->value_.value(x...);
this->ac_->setVLouverFrontendSequence( (ac_vlouver_frontend)vlpos_);
}
protected:
AirCon *ac_;
uint8_t vlpos_;
};
// **************************************** SEND TEST PACKET ACTION ****************************************

View File

@@ -63,7 +63,7 @@ public:
static const uint32_t AC_STATES_REQUEST_INTERVAL;
};
const std::string Constants::AC_FIRMWARE_VERSION = "0.2.5";
const std::string Constants::AC_FIRMWARE_VERSION = "0.2.6";
const char *const Constants::TAG = "AirCon";
// custom fan modes
@@ -440,6 +440,18 @@ enum ac_mildew : uint8_t { AC_MILDEW_OFF = 0x00, AC_MILDEW_ON = 0x08, AC_MILDEW_
// GK: define убрал, т.к. считаю, что сбрасывать счетчик не надо.
// #define AC_MIN_COUNTER_MASK 0b00111111
// положение вертикальных жалюзи для фронтенда
enum ac_vlouver_frontend : uint8_t {
AC_VLOUVER_FRONTEND_SWING = 0x00,
AC_VLOUVER_FRONTEND_STOP = 0x01,
AC_VLOUVER_FRONTEND_TOP = 0x02,
AC_VLOUVER_FRONTEND_MIDDLE_ABOVE = 0x03,
AC_VLOUVER_FRONTEND_MIDDLE = 0x04,
AC_VLOUVER_FRONTEND_MIDDLE_BELOW = 0x05,
AC_VLOUVER_FRONTEND_BOTTOM = 0x06,
};
/** команда для кондиционера
*
* ВАЖНО! В коде используется копирование команд простым присваиванием.
@@ -1788,18 +1800,15 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
}
// сенсоры, отображающие параметры сплита
esphome::sensor::Sensor *sensor_indoor_temperature_ = nullptr;
esphome::sensor::Sensor *sensor_outdoor_temperature_ = nullptr;
esphome::sensor::Sensor *sensor_inbound_temperature_ =nullptr;
esphome::sensor::Sensor *sensor_outbound_temperature_ =nullptr;
esphome::sensor::Sensor *sensor_compressor_temperature_ =nullptr;
// текущая мощность компрессора
esphome::sensor::Sensor *sensor_invertor_power_ = nullptr;
// бинарный сенсор, отображающий состояние дисплея
esphome::binary_sensor::BinarySensor *sensor_display_ = nullptr;
// бинарный сенсор состония разморозки
esphome::binary_sensor::BinarySensor *sensor_defrost_ = nullptr;
// текстовый сенсор, отображающий текущий режим работы сплита
esphome::sensor::Sensor *sensor_indoor_temperature_ = nullptr;
esphome::sensor::Sensor *sensor_outdoor_temperature_ = nullptr;
esphome::sensor::Sensor *sensor_inbound_temperature_ = nullptr;
esphome::sensor::Sensor *sensor_outbound_temperature_ = nullptr;
esphome::sensor::Sensor *sensor_compressor_temperature_ = nullptr;
esphome::sensor::Sensor *sensor_invertor_power_ = nullptr;
esphome::sensor::Sensor *sensor_vlouver_state_ = nullptr;
esphome::binary_sensor::BinarySensor *sensor_display_ = nullptr;
esphome::binary_sensor::BinarySensor *sensor_defrost_ = nullptr;
esphome::text_sensor::TextSensor *sensor_preset_reporter_ = nullptr;
@@ -1913,6 +1922,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
void set_inbound_temperature_sensor(sensor::Sensor *temperature_sensor) { sensor_inbound_temperature_ = temperature_sensor; }
void set_outbound_temperature_sensor(sensor::Sensor *temperature_sensor) { sensor_outbound_temperature_ = temperature_sensor; }
void set_compressor_temperature_sensor(sensor::Sensor *temperature_sensor) { sensor_compressor_temperature_ = temperature_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_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; }
@@ -2241,6 +2251,9 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
// флаг режима разморозки
if (sensor_defrost_ != nullptr)
sensor_defrost_->publish_state(_current_ac_state.defrost);
// положение вертикальных жалюзи
if (sensor_vlouver_state_ != nullptr)
sensor_vlouver_state_->publish_state( (float) this->getCurrentVlouverFrontendState() );
// сенсор состояния сплита
if (sensor_preset_reporter_ != nullptr) {
@@ -2408,6 +2421,20 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
}
}
if ((this->sensor_vlouver_state_) != nullptr) {
ESP_LOGCONFIG(Constants::TAG, "%s%s '%s'", " ", LOG_STR_LITERAL("Vertical louvers state"), (this->sensor_vlouver_state_)->get_name().c_str());
ESP_LOGCONFIG(Constants::TAG, "%s Accuracy Decimals: %d", " ", (this->sensor_vlouver_state_)->get_accuracy_decimals());
if (!(this->sensor_vlouver_state_)->get_icon().empty()) {
ESP_LOGCONFIG(Constants::TAG, "%s Icon: '%s'", " ", (this->sensor_vlouver_state_)->get_icon().c_str());
}
if (!(this->sensor_vlouver_state_)->unique_id().empty()) {
ESP_LOGV(Constants::TAG, "%s Unique ID: '%s'", " ", (this->sensor_vlouver_state_)->unique_id().c_str());
}
if ((this->sensor_vlouver_state_)->get_force_update()) {
ESP_LOGV(Constants::TAG, "%s Force Update: YES", " ");
}
}
if ((this->sensor_defrost_) != nullptr) {
ESP_LOGCONFIG(Constants::TAG, "%s%s '%s'", " ", LOG_STR_LITERAL("Defrost status"), (this->sensor_defrost_)->get_name().c_str());
if (!(this->sensor_defrost_)->get_device_class().empty()) {
@@ -3059,7 +3086,72 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
return true;
}
// устанавливает жалюзи в нужное положение
// конвертирует состояние жалюзи из кодов сплита в коды для фронтенда
ac_vlouver_frontend AUXvlouverToVlouverFrontend(const ac_louver_V vLouver){
switch (vLouver) {
case AC_LOUVERV_SWING_UPDOWN:
return AC_VLOUVER_FRONTEND_SWING;
case AC_LOUVERV_OFF:
return AC_VLOUVER_FRONTEND_STOP;
case AC_LOUVERV_SWING_TOP:
return AC_VLOUVER_FRONTEND_TOP;
case AC_LOUVERV_SWING_MIDDLE_ABOVE:
return AC_VLOUVER_FRONTEND_MIDDLE_ABOVE;
case AC_LOUVERV_SWING_MIDDLE:
return AC_VLOUVER_FRONTEND_MIDDLE;
case AC_LOUVERV_SWING_MIDDLE_BELOW:
return AC_VLOUVER_FRONTEND_MIDDLE_BELOW;
case AC_LOUVERV_SWING_BOTTOM:
return AC_VLOUVER_FRONTEND_BOTTOM;
default:
_debugMsg(F("AUXvlouverToVlouverFrontend: unknown vertical louver state = %u"), ESPHOME_LOG_LEVEL_DEBUG, __LINE__, _current_ac_state.louver.louver_v);
return AC_VLOUVER_FRONTEND_STOP; //
}
}
// возвращает текущее положение шторок в кодах для фронтенда
ac_vlouver_frontend getCurrentVlouverFrontendState(){
return AUXvlouverToVlouverFrontend(_current_ac_state.louver.louver_v);
}
// конвертирует состояние жалюзи из кодов для фронтенда в коды сплита
ac_louver_V vlouverFrontendToAUXvlouver(const ac_vlouver_frontend vLouver){
switch (vLouver) {
case AC_VLOUVER_FRONTEND_SWING:
return AC_LOUVERV_SWING_UPDOWN;
case AC_VLOUVER_FRONTEND_STOP:
return AC_LOUVERV_OFF;
case AC_VLOUVER_FRONTEND_TOP:
return AC_LOUVERV_SWING_TOP;
case AC_VLOUVER_FRONTEND_MIDDLE_ABOVE:
return AC_LOUVERV_SWING_MIDDLE_ABOVE;
case AC_VLOUVER_FRONTEND_MIDDLE:
return AC_LOUVERV_SWING_MIDDLE;
case AC_VLOUVER_FRONTEND_MIDDLE_BELOW:
return AC_LOUVERV_SWING_MIDDLE_BELOW;
case AC_VLOUVER_FRONTEND_BOTTOM:
return AC_LOUVERV_SWING_BOTTOM;
default:
_debugMsg(F("vlouverFrontendToAUXvlouver: unknown vertical louver state = %u"), ESPHOME_LOG_LEVEL_DEBUG, __LINE__, _current_ac_state.louver.louver_v);
return AC_LOUVERV_OFF; //
}
}
// устанавливает жалюзи в нужное положение по коду сплита
bool setVLouverSequence(const ac_louver_V vLouver){
// нет смысла в последовательности, если нет коннекта с кондиционером
if (!get_has_connection()) {
@@ -3081,6 +3173,11 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
return true;
}
// устанавливает жалюзи в нужное положение по коду для фронтенда
bool setVLouverFrontendSequence(const ac_vlouver_frontend vLouver){
return setVLouverSequence(vlouverFrontendToAUXvlouver(vLouver));
}
// установка жалюзи в определенные положения
bool setVLouverSwingSequence() { return setVLouverSequence(AC_LOUVERV_SWING_UPDOWN); }
bool setVLouverStopSequence() { return setVLouverSequence(AC_LOUVERV_OFF); }

View File

@@ -22,6 +22,7 @@ from esphome.const import (
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_POWER_FACTOR,
STATE_CLASS_MEASUREMENT,
CONF_POSITION,
)
from esphome.components.climate import (
ClimateMode,
@@ -53,14 +54,22 @@ CONF_DISPLAY_INVERTED = 'display_inverted'
ICON_DISPLAY = "mdi:clock-digital"
CONF_PRESET_REPORTER = "preset_reporter"
ICON_PRESET_REPORTER = "mdi:format-list-group"
CONF_VLOUVER_STATE = "vlouver_state"
ICON_VLOUVER_STATE = "mdi:compare-vertical"
aux_ac_ns = cg.esphome_ns.namespace("aux_ac")
AirCon = aux_ac_ns.class_("AirCon", climate.Climate, cg.Component)
Capabilities = aux_ac_ns.namespace("Constants")
# Display actions
AirConDisplayOffAction = aux_ac_ns.class_("AirConDisplayOffAction", automation.Action)
AirConDisplayOnAction = aux_ac_ns.class_("AirConDisplayOnAction", automation.Action)
# test packet
AirConSendTestPacketAction = aux_ac_ns.class_("AirConSendTestPacketAction", automation.Action)
# vertical louvers actions
AirConVLouverSwingAction = aux_ac_ns.class_("AirConVLouverSwingAction", automation.Action)
AirConVLouverStopAction = aux_ac_ns.class_("AirConVLouverStopAction", automation.Action)
AirConVLouverTopAction = aux_ac_ns.class_("AirConVLouverTopAction", automation.Action)
@@ -68,7 +77,8 @@ AirConVLouverMiddleAboveAction = aux_ac_ns.class_("AirConVLouverMiddleAboveActio
AirConVLouverMiddleAction = aux_ac_ns.class_("AirConVLouverMiddleAction", automation.Action)
AirConVLouverMiddleBelowAction = aux_ac_ns.class_("AirConVLouverMiddleBelowAction", automation.Action)
AirConVLouverBottomAction = aux_ac_ns.class_("AirConVLouverBottomAction", automation.Action)
AirConSendTestPacketAction = aux_ac_ns.class_("AirConSendTestPacketAction", automation.Action)
AirConVLouverSetAction = aux_ac_ns.class_("AirConVLouverSetAction", automation.Action)
ALLOWED_CLIMATE_MODES = {
"HEAT_COOL": ClimateMode.CLIMATE_MODE_HEAT_COOL,
@@ -190,6 +200,14 @@ CONFIG_SCHEMA = cv.All(
cv.Optional(CONF_INTERNAL, default="true"): cv.boolean,
}
),
cv.Optional(CONF_VLOUVER_STATE): sensor.sensor_schema(
icon=ICON_VLOUVER_STATE,
accuracy_decimals=0,
).extend(
{
cv.Optional(CONF_INTERNAL, default="true"): cv.boolean,
}
),
cv.Optional(CONF_DISPLAY_STATE): binary_sensor.binary_sensor_schema(
icon=ICON_DISPLAY,
).extend(
@@ -258,6 +276,11 @@ async def to_code(config):
sens = await sensor.new_sensor(conf)
cg.add(var.set_compressor_temperature_sensor(sens))
if CONF_VLOUVER_STATE in config:
conf = config[CONF_VLOUVER_STATE]
sens = await sensor.new_sensor(conf)
cg.add(var.set_vlouver_state_sensor(sens))
if CONF_DISPLAY_STATE in config:
conf = config[CONF_DISPLAY_STATE]
sens = await binary_sensor.new_binary_sensor(conf)
@@ -353,6 +376,21 @@ async def vlouver_bottom_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)
VLOUVER_SET_ACTION_SCHEMA = cv.Schema(
{
cv.Required(CONF_ID): cv.use_id(AirCon),
cv.Required(CONF_POSITION): cv.templatable(cv.int_range(0, 6)),
}
)
@automation.register_action("aux_ac.vlouver_set", AirConVLouverSetAction, VLOUVER_SET_ACTION_SCHEMA)
async def vlouver_set_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_POSITION], args, int)
cg.add(var.set_value(template_))
return var
# *********************************************************************************************************
# ВАЖНО! Только для инженеров!
@@ -367,11 +405,7 @@ SEND_TEST_PACKET_ACTION_SCHEMA = maybe_simple_id(
}
)
@automation.register_action(
"aux_ac.send_packet",
AirConSendTestPacketAction,
SEND_TEST_PACKET_ACTION_SCHEMA
)
@automation.register_action( "aux_ac.send_packet", AirConSendTestPacketAction, SEND_TEST_PACKET_ACTION_SCHEMA )
async def send_packet_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)

View File

@@ -100,6 +100,10 @@ climate:
name: ${upper_devicename} Preset Reporter
id: ${devicename}_preset_reporter
internal: false
vlouver_state:
name: ${upper_devicename} VLouvers State
id: ${devicename}_vlouver_state
internal: false
visual:
min_temperature: 16
max_temperature: 32
@@ -194,15 +198,18 @@ button:
number:
- platform: template
name: ${upper_devicename} Vertical Louver
name: ${upper_devicename} Vertical Louvers
id: ${devicename}_vlouver
icon: "mdi:circle-small"
mode: "slider"
min_value: 0
max_value: 6
step: 1
update_interval: 2s
lambda: |-
return id(${devicename}_vlouver_state).state;
set_action:
then:
- lambda: !lambda |-
if (x == 6) x = 7; // 6 is incorrect louver position, 7 is stopped louver
id(aux_id).setVLouverSequence( static_cast<esphome::aux_ac::ac_louver_V>(x) );
- aux_ac.vlouver_set:
id: aux_id
position: !lambda "return x;"