Merge pull request #26 from GrKoR:GrKoR/issue15

GrKoR/issue15
This commit is contained in:
GK
2022-04-08 01:32:36 +03:00
committed by GitHub
3 changed files with 100 additions and 12 deletions

View File

@@ -0,0 +1,35 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/automation.h"
#include "aux_ac.h"
namespace esphome {
namespace aux_ac {
template <typename... Ts>
class AirConDisplayOffAction : public Action<Ts...>
{
public:
explicit AirConDisplayOffAction(AirCon *ac) : ac_(ac) {}
void play(Ts... x) override { this->ac_->displaySequence(AC_DISPLAY_OFF); }
protected:
AirCon *ac_;
};
template <typename... Ts>
class AirConDisplayOnAction : public Action<Ts...>
{
public:
explicit AirConDisplayOnAction(AirCon *ac) : ac_(ac) {}
void play(Ts... x) override { this->ac_->displaySequence(AC_DISPLAY_ON); }
protected:
AirCon *ac_;
};
} // namespace aux_ac
} // namespace esphome

View File

@@ -890,6 +890,16 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
// разбираем тип пакета // разбираем тип пакета
switch (_inPacket.header->packet_type) { switch (_inPacket.header->packet_type) {
case AC_PTYPE_PING: { // ping-пакет, рассылается кондиционером каждые 3 сек.; модуль на него отвечает case AC_PTYPE_PING: { // ping-пакет, рассылается кондиционером каждые 3 сек.; модуль на него отвечает
if (_inPacket.header->body_length != 0 ) { // у входящего ping-пакета тело должно отсутствовать
// если тело есть, то жалуемся в лог
_debugMsg(F("Parser: ping packet should not to have body. Received one has body length %02X."), ESPHOME_LOG_LEVEL_WARN, __LINE__, _inPacket.header->body_length);
// очищаем пакет
_clearInPacket();
_setStateMachineState(ACSM_IDLE);
break;
}
_debugMsg(F("Parser: ping packet received"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__); _debugMsg(F("Parser: ping packet received"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__);
// поднимаем флаг, что есть коннект с кондиционером // поднимаем флаг, что есть коннект с кондиционером
_has_connection = true; _has_connection = true;
@@ -1023,7 +1033,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
} }
case AC_CMD_STATUS_BIG: // большой пакет статуса кондиционера case AC_CMD_STATUS_BIG: // большой пакет статуса кондиционера
case AC_CMD_STATUS_PERIODIC: { // раз в 10 минут разсылается сплитом, структура аналогична большому пакету статуса case AC_CMD_STATUS_PERIODIC: { // раз в 10 минут рассылается сплитом, структура аналогична большому пакету статуса
// TODO: вроде как AC_CMD_STATUS_PERIODIC могут быть и с другими кодами; пока что другие будут игнорироваться; если это будет критично, надо будет поправить // TODO: вроде как AC_CMD_STATUS_PERIODIC могут быть и с другими кодами; пока что другие будут игнорироваться; если это будет критично, надо будет поправить
_debugMsg(F("Parser: status packet type = big or periodic"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__); _debugMsg(F("Parser: status packet type = big or periodic"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__);
stateChangedFlag = false; stateChangedFlag = false;
@@ -2342,6 +2352,36 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
return true; return true;
} }
// загружает на выполнение последовательность команд на включение/выключение табло с температурой
bool displaySequence(ac_display dsp = AC_DISPLAY_ON){
// нет смысла в последовательности, если нет коннекта с кондиционером
if (!get_has_connection()) {
_debugMsg(F("displaySequence: no pings from HVAC. It seems like no AC connected."), ESPHOME_LOG_LEVEL_ERROR, __LINE__);
return false;
}
if (dsp == AC_DISPLAY_UNTOUCHED) return false; // выходим, чтобы не тратить время
// формируем команду
ac_command_t cmd;
_clearCommand(&cmd); // не забываем очищать, а то будет мусор
cmd.display = dsp;
// добавляем команду в последовательность
if (!commandSequence(&cmd)) return false;
_debugMsg(F("displaySequence: loaded (display = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, dsp);
return true;
}
// выключает экран
bool displayOffSequence(){
return displaySequence(AC_DISPLAY_OFF);
}
// включает экран
bool displayOnSequence(){
return displaySequence(AC_DISPLAY_ON);
}
void set_period(uint32_t ms) { this->_update_period = ms; }; void set_period(uint32_t ms) { this->_update_period = ms; };
uint32_t get_period() { return this->_update_period; }; uint32_t get_period() { return this->_update_period; };
void set_show_action(bool show_action) { this->_show_action = show_action; }; void set_show_action(bool show_action) { this->_show_action = show_action; };
@@ -2391,16 +2431,6 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
if (get_has_connection()) getStatusBigAndSmall(); if (get_has_connection()) getStatusBigAndSmall();
} }
/*
// это экспериментальная секция для отладки функционала
static uint32_t debug_millis = millis();
if (millis()-debug_millis > 10000){
debug_millis = millis();
//_debugMsg(F("Test!"), ESPHOME_LOG_LEVEL_WARN, __LINE__);
//if (_current_ac_state.power == AC_POWER_OFF) powerSequence(AC_POWER_ON);
//else powerSequence(AC_POWER_OFF);
}
*/
}; };
}; };

View File

@@ -2,6 +2,8 @@ import logging
import esphome.config_validation as cv import esphome.config_validation as cv
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import climate, uart, sensor from esphome.components import climate, uart, sensor
from esphome import automation
from esphome.automation import maybe_simple_id
from esphome.const import ( from esphome.const import (
CONF_ID, CONF_ID,
CONF_UART_ID, CONF_UART_ID,
@@ -19,6 +21,7 @@ from esphome.components.climate import (
ClimatePreset, ClimatePreset,
ClimateSwingMode, ClimateSwingMode,
) )
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CODEOWNERS = ["@GrKoR"] CODEOWNERS = ["@GrKoR"]
@@ -35,6 +38,9 @@ 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)
Capabilities = aux_ac_ns.namespace("Constants") Capabilities = aux_ac_ns.namespace("Constants")
AirConDisplayOffAction = aux_ac_ns.class_("AirConDisplayOffAction", automation.Action)
AirConDisplayOnAction = aux_ac_ns.class_("AirConDisplayOnAction", automation.Action)
ALLOWED_CLIMATE_MODES = { ALLOWED_CLIMATE_MODES = {
"HEAT_COOL": ClimateMode.CLIMATE_MODE_HEAT_COOL, "HEAT_COOL": ClimateMode.CLIMATE_MODE_HEAT_COOL,
"COOL": ClimateMode.CLIMATE_MODE_COOL, "COOL": ClimateMode.CLIMATE_MODE_COOL,
@@ -130,4 +136,21 @@ async def to_code(config):
cg.add(var.set_custom_presets(config[CONF_CUSTOM_PRESETS])) cg.add(var.set_custom_presets(config[CONF_CUSTOM_PRESETS]))
if CONF_CUSTOM_FAN_MODES in config: if CONF_CUSTOM_FAN_MODES in 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(
{
cv.Required(CONF_ID): cv.use_id(AirCon),
}
)
@automation.register_action("aux_ac.display_off", AirConDisplayOffAction, DISPLAY_ACTION_SCHEMA)
async def switch_toggle_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)
@automation.register_action("aux_ac.display_on", AirConDisplayOnAction, DISPLAY_ACTION_SCHEMA)
async def switch_toggle_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)