new send packet action. It for engineers only

This commit is contained in:
GrKoR
2022-05-22 23:53:03 +03:00
parent 47d6a427c8
commit aceec8dce6
5 changed files with 321 additions and 6 deletions

View File

@@ -17,7 +17,7 @@ namespace aux_ac {
protected:
AirCon *ac_;
};
};
template <typename... Ts>
class AirConDisplayOnAction : public Action<Ts...>
@@ -29,7 +29,37 @@ namespace aux_ac {
protected:
AirCon *ac_;
};
};
template <typename... Ts>
class AirConSendTestPacketAction : public Action<Ts...>
{
public:
explicit AirConSendTestPacketAction(AirCon *ac) : ac_(ac) {}
void set_data_template(std::function<std::vector<uint8_t>(Ts...)> func) {
this->data_func_ = func;
this->static_ = false;
}
void set_data_static(const std::vector<uint8_t> &data) {
this->data_static_ = data;
this->static_ = true;
}
void play(Ts... x) override {
if (this->static_) {
this->ac_->sendTestPacket(this->data_static_);
} else {
auto val = this->data_func_(x...);
this->ac_->sendTestPacket(val);
}
}
protected:
AirCon *ac_;
bool static_{false};
std::function<std::vector<uint8_t>(Ts...)> data_func_{};
std::vector<uint8_t> data_static_{};
};
} // namespace aux_ac
} // namespace esphome

View File

@@ -513,6 +513,9 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
packet_t _inPacket;
packet_t _outPacket;
// пакет для тестирования всякой фигни
packet_t _outTestPacket;
// последовательность пакетов текущий шаг в последовательности
sequence_item_t _sequence[AC_SEQUENCE_MAX_LEN];
uint8_t _sequence_current_step;
@@ -1576,6 +1579,24 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
return relevant;
}
// отправка запроса с тестовым пакетом
bool sq_requestTestPacket(){
// если исходящий пакет не пуст, то выходим и ждем освобождения
if (_outPacket.bytesLoaded > 0) return true;
_copyPacket(&_outPacket, &_outTestPacket);
_copyPacket(&_sequence[_sequence_current_step].packet, &_outTestPacket);
_sequence[_sequence_current_step].packet_type = AC_SPT_SENT_PACKET;
// Отчитываемся в лог
_debugMsg(F("Sequence [step %u]: Test Packet request generated:"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, _sequence_current_step);
_debugPrintPacket(&_outPacket, ESPHOME_LOG_LEVEL_VERBOSE, __LINE__);
// увеличиваем текущий шаг
_sequence_current_step++;
return true;
}
// сенсоры, отображающие параметры сплита
//esphome::sensor::Sensor *sensor_indoor_temperature = new esphome::sensor::Sensor();
esphome::sensor::Sensor *sensor_indoor_temperature_ = nullptr;
@@ -1613,6 +1634,10 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
_clearInPacket();
_clearOutPacket();
_clearPacket(&_outTestPacket);
_outTestPacket.header->start_byte = AC_PACKET_START_BYTE;
_outTestPacket.header->wifi = AC_PACKET_ANSWER;
_setStateMachineState(ACSM_IDLE);
_ac_serial = parent;
_hw_initialized = (_ac_serial != nullptr);
@@ -2435,6 +2460,67 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
return _displaySequence(dsp);
}
// отправляет сплиту заданный набор байт
// Перед отправкой проверяет пакет на корректность структуры. CRC16 рассчитывает самостоятельно и перезаписывает.
bool sendTestPacket(const std::vector<uint8_t> &data){
//bool sendTestPacket(uint8_t *data = nullptr, uitn8_t data_length = 0){
//if (data == nullptr) return false;
//if (data_length == 0) return false;
if (data.size() == 0) return false;
//if (data_length > AC_BUFFER_SIZE) return false;
if (data.size() > AC_BUFFER_SIZE) return false;
// нет смысла в отправке, если нет коннекта с кондиционером
if (!get_has_connection()) {
_debugMsg(F("sendTestPacket: no pings from HVAC. It seems like no AC connected."), ESPHOME_LOG_LEVEL_ERROR, __LINE__);
return false;
}
// очищаем пакет
_clearPacket(&_outTestPacket);
// копируем данные в пакет
//memcpy(_outTestPacket.data, data, data_length);
uint8_t i = 0;
for (uint8_t n : data) {
_outTestPacket.data[i] = n;
i++;
}
// на всякий случай указываем правильные некоторые байты
_outTestPacket.header->start_byte = AC_PACKET_START_BYTE;
//_outTestPacket.header->wifi = AC_PACKET_ANSWER;
_outTestPacket.msec = millis();
_outTestPacket.body = &(_outTestPacket.data[AC_HEADER_SIZE]);
_outTestPacket.bytesLoaded = AC_HEADER_SIZE + _outTestPacket.header->body_length + 2;
// рассчитываем и записываем в пакет CRC
_outTestPacket.crc = (packet_crc_t *) &(_outTestPacket.data[AC_HEADER_SIZE + _outTestPacket.header->body_length]);
_setCRC16(&_outTestPacket);
_debugMsg(F("sendTestPacket: test packet loaded."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
_debugPrintPacket(&_outTestPacket, ESPHOME_LOG_LEVEL_WARN, __LINE__);
// ниже блок добавления отправки пакета в последовательность команд
//*****************************************************************
// есть ли место на запрос в последовательности команд?
if (_getFreeSequenceSpace() < 1) {
_debugMsg(F("sendTestPacket: not enough space in command sequence. Sequence steps doesn't loaded."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
return false;
}
/*************************************** sendTestPacket request ***********************************************/
if (!_addSequenceFuncStep(&AirCon::sq_requestTestPacket)) {
_debugMsg(F("sendTestPacket: sendTestPacket request sequence step fail."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
return false;
}
/**************************************************************************************/
_debugMsg(F("sendTestPacket: loaded to sequence"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__);
return true;
}
void set_period(uint32_t ms) { this->_update_period = ms; }
uint32_t get_period() { return this->_update_period; }
@@ -2485,7 +2571,7 @@ class AirCon : public esphome::Component, public esphome::climate::Climate {
// обычный wifi-модуль запрашивает маленький пакет статуса
// но нам никто не мешает запрашивать и большой и маленький, чтобы чаще обновлять комнатную температуру
// делаем этот запросом только в случае, если есть коннект с кондиционером
// делаем этот запрос только в случае, если есть коннект с кондиционером
if (get_has_connection()) getStatusBigAndSmall();
}

View File

@@ -11,6 +11,7 @@ from esphome.const import (
CONF_CUSTOM_FAN_MODES,
CONF_CUSTOM_PRESETS,
CONF_INTERNAL,
CONF_DATA,
UNIT_CELSIUS,
ICON_THERMOMETER,
DEVICE_CLASS_TEMPERATURE,
@@ -44,6 +45,7 @@ Capabilities = aux_ac_ns.namespace("Constants")
AirConDisplayOffAction = aux_ac_ns.class_("AirConDisplayOffAction", automation.Action)
AirConDisplayOnAction = aux_ac_ns.class_("AirConDisplayOnAction", automation.Action)
AirConSendTestPacketAction = aux_ac_ns.class_("AirConSendTestPacketAction", automation.Action)
ALLOWED_CLIMATE_MODES = {
"HEAT_COOL": ClimateMode.CLIMATE_MODE_HEAT_COOL,
@@ -80,6 +82,15 @@ CUSTOM_PRESETS = {
}
validate_custom_presets = cv.enum(CUSTOM_PRESETS, upper=True)
def validate_raw_data(value):
if isinstance(value, list):
return cv.Schema([cv.hex_uint8_t])(value)
raise cv.Invalid(
"data must be a list of bytes"
)
def output_info(config):
"""_LOGGER.info(config)"""
return config
@@ -164,11 +175,47 @@ DISPLAY_ACTION_SCHEMA = maybe_simple_id(
)
@automation.register_action("aux_ac.display_off", AirConDisplayOffAction, DISPLAY_ACTION_SCHEMA)
async def switch_toggle_to_code(config, action_id, template_arg, args):
async def display_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)
@automation.register_action("aux_ac.display_on", AirConDisplayOnAction, DISPLAY_ACTION_SCHEMA)
async def switch_toggle_to_code(config, action_id, template_arg, args):
async def display_on_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)
return cg.new_Pvariable(action_id, template_arg, paren)
SEND_TEST_PACKET_ACTION_SCHEMA = maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(AirCon),
cv.Required(CONF_DATA): cv.templatable(validate_raw_data),
}
)
# *********************************************************************************************************
# ВАЖНО! Только для инженеров!
# Вызывайте метод aux_ac.send_packet только если понимаете, что делаете! Он не проверяет данные, а передаёт
# кондиционеру всё как есть. Какой эффект получится от передачи кондиционеру рандомных байт, никто не знает.
# Вы действуете на свой страх и риск.
# *********************************************************************************************************
@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)
data = config[CONF_DATA]
if isinstance(data, bytes):
data = list(data)
if cg.is_template(data):
templ = await cg.templatable(data, args, cg.std_vector.template(cg.uint8))
cg.add(var.set_data_template(templ))
else:
cg.add(var.set_data_static(data))
return var