mirror of
https://github.com/GrKoR/esphome_aux_ac_component.git
synced 2025-12-06 11:36:55 +03:00
unfinished
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@
|
|||||||
# You can modify this file to suit your needs.
|
# You can modify this file to suit your needs.
|
||||||
**/.vscode/
|
**/.vscode/
|
||||||
**/.esphome/
|
**/.esphome/
|
||||||
|
**/esphome/
|
||||||
**/.pioenvs/
|
**/.pioenvs/
|
||||||
**/.piolibdeps/
|
**/.piolibdeps/
|
||||||
**/lib/
|
**/lib/
|
||||||
|
|||||||
148
components/aux_ac/aux_frame.h
Normal file
148
components/aux_ac/aux_frame.h
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h> // for memcpy and memset, move to .cpp later if needed
|
||||||
|
|
||||||
|
namespace esphome
|
||||||
|
{
|
||||||
|
namespace aux_ac
|
||||||
|
{
|
||||||
|
|
||||||
|
class AuxFrame
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// CRC of the AUX frame
|
||||||
|
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_crc
|
||||||
|
union frame_crc_t
|
||||||
|
{
|
||||||
|
uint16_t crc16;
|
||||||
|
uint8_t crc[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
// frame header
|
||||||
|
// https://github.com/GrKoR/AUX_HVAC_Protocol#packet_header
|
||||||
|
struct frame_header_t
|
||||||
|
{
|
||||||
|
uint8_t startByte;
|
||||||
|
uint8_t _unknown1;
|
||||||
|
uint8_t frameType;
|
||||||
|
uint8_t wifi;
|
||||||
|
uint8_t pingAnswer;
|
||||||
|
uint8_t _unknown2;
|
||||||
|
uint8_t bodyLength;
|
||||||
|
uint8_t _unknown3;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t *_rawData = nullptr;
|
||||||
|
frame_header_t *_header = nullptr;
|
||||||
|
uint8_t *_body = nullptr;
|
||||||
|
frame_crc_t *_crc = nullptr;
|
||||||
|
|
||||||
|
bool _isValid = false;
|
||||||
|
|
||||||
|
uint8_t const AC_PACKET_START_BYTE = 0xBB;
|
||||||
|
uint8_t const AC_HEADER_SIZE = 8;
|
||||||
|
uint8_t const AC_BODY_LENGTH_OFFSET = 6;
|
||||||
|
|
||||||
|
uint8_t const AC_BUFFER_SIZE = 35; // TODO: integrate it with aux_uart.h
|
||||||
|
|
||||||
|
uint16_t _CRC16(uint8_t *data, uint8_t len)
|
||||||
|
{
|
||||||
|
uint32_t crc = 0;
|
||||||
|
|
||||||
|
uint8_t _crcBuffer[AC_BUFFER_SIZE];
|
||||||
|
memset(_crcBuffer, 0, AC_BUFFER_SIZE);
|
||||||
|
memcpy(_crcBuffer, data, len);
|
||||||
|
|
||||||
|
if ((len % 2) == 1)
|
||||||
|
len++;
|
||||||
|
|
||||||
|
uint32_t word = 0;
|
||||||
|
for (uint8_t i = 0; i < len; i += 2)
|
||||||
|
{
|
||||||
|
word = (_crcBuffer[i] << 8) + _crcBuffer[i + 1];
|
||||||
|
crc += word;
|
||||||
|
}
|
||||||
|
crc = (crc >> 16) + (crc & 0xFFFF);
|
||||||
|
crc = ~crc;
|
||||||
|
|
||||||
|
return crc & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _checkCRC()
|
||||||
|
{
|
||||||
|
frame_crc_t crc;
|
||||||
|
crc.crc16 = _CRC16(this->_rawData, AC_HEADER_SIZE + this->_rawData[AC_BODY_LENGTH_OFFSET]);
|
||||||
|
|
||||||
|
return ((this->_crc->crc[0] == crc.crc[1]) && (this->_crc->crc[1] == crc.crc[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _checkFrame()
|
||||||
|
{
|
||||||
|
this->_isValid = false;
|
||||||
|
if (this->_rawData == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this->_header->startByte != AC_PACKET_START_BYTE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!this->_checkCRC())
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->_isValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
AuxFrame() = default;
|
||||||
|
~AuxFrame() {};
|
||||||
|
|
||||||
|
void set_data(uint8_t *data)
|
||||||
|
{
|
||||||
|
clearData();
|
||||||
|
if (data == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->_rawData = data;
|
||||||
|
this->_header = (frame_header_t *)this->_rawData;
|
||||||
|
this->_crc = (frame_crc_t *)(this->_rawData + AC_HEADER_SIZE + this->_header->bodyLength);
|
||||||
|
if (this->_header->bodyLength > 0)
|
||||||
|
this->_body = this->_rawData + AC_HEADER_SIZE;
|
||||||
|
else
|
||||||
|
this->_body = nullptr;
|
||||||
|
this->_checkFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearData()
|
||||||
|
{
|
||||||
|
this->_rawData = nullptr;
|
||||||
|
this->_header = nullptr;
|
||||||
|
this->_crc = nullptr;
|
||||||
|
this->_body = nullptr;
|
||||||
|
this->_isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const
|
||||||
|
{
|
||||||
|
return this->_isValid;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t frameSize() const
|
||||||
|
{
|
||||||
|
if (!this->isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return AC_HEADER_SIZE + this->_header->bodyLength + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t bodyLength() const
|
||||||
|
{
|
||||||
|
if (!this->isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return this->_header->bodyLength;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace aux_ac
|
||||||
|
|
||||||
|
} // namespace esphome
|
||||||
100
components/aux_ac/aux_logger.cpp
Normal file
100
components/aux_ac/aux_logger.cpp
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#include "aux_logger.h"
|
||||||
|
|
||||||
|
namespace esphome
|
||||||
|
{
|
||||||
|
namespace aux_ac
|
||||||
|
{
|
||||||
|
static const char *const TAG = "AirCon"; // TODO: verify if this tag is appropriate
|
||||||
|
|
||||||
|
/** вывод отладочной информации в лог
|
||||||
|
*
|
||||||
|
* dbgLevel - уровень сообщения, определен в ESPHome. За счет его использования можно из ESPHome управлять полнотой сведений в логе.
|
||||||
|
* msg - сообщение, выводимое в лог
|
||||||
|
* line - строка, на которой произошел вызов (удобно при отладке)
|
||||||
|
*/
|
||||||
|
void debugMsg(const /*String &*/ char *msg, uint8_t dbgLevel, unsigned int line, ...)
|
||||||
|
{
|
||||||
|
if (dbgLevel < ESPHOME_LOG_LEVEL_NONE)
|
||||||
|
dbgLevel = ESPHOME_LOG_LEVEL_NONE;
|
||||||
|
if (dbgLevel > ESPHOME_LOG_LEVEL_VERY_VERBOSE)
|
||||||
|
dbgLevel = ESPHOME_LOG_LEVEL_VERY_VERBOSE;
|
||||||
|
|
||||||
|
if (line == 0)
|
||||||
|
line = __LINE__; // если строка не передана, берем текущую строку
|
||||||
|
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl, line);
|
||||||
|
esp_log_vprintf_(dbgLevel, TAG, line, msg, vl);
|
||||||
|
va_end(vl);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** выводим данные пакета в лог для отладки
|
||||||
|
*
|
||||||
|
* dbgLevel - уровень сообщения, определен в ESPHome. За счет его использования можно из ESPHome управлять полнотой сведений в логе.
|
||||||
|
* packet - указатель на пакет для вывода;
|
||||||
|
* если указатель на crc равен nullptr или первый байт в буфере не AC_PACKET_START_BYTE, то считаем, что передан битый пакет
|
||||||
|
* или не пакет вовсе. Для такого выводим только массив байт.
|
||||||
|
* Для нормального пакета данные выводятся с форматированием.
|
||||||
|
* line - строка, на которой произошел вызов (удобно при отладке)
|
||||||
|
**/
|
||||||
|
void debugPrintPacket(packet_t *packet, uint8_t dbgLevel, unsigned int line)
|
||||||
|
{
|
||||||
|
// определяем, полноценный ли пакет нам передан
|
||||||
|
bool notAPacket = false;
|
||||||
|
/*
|
||||||
|
// указатель заголовка всегда установден на начало буфера
|
||||||
|
notAPacket = notAPacket || (packet->crc == nullptr);
|
||||||
|
notAPacket = notAPacket || (packet->data[0] != AC_PACKET_START_BYTE);
|
||||||
|
|
||||||
|
String st = "";
|
||||||
|
char textBuf[11];
|
||||||
|
|
||||||
|
// заполняем время получения пакета
|
||||||
|
memset(textBuf, 0, 11);
|
||||||
|
sprintf(textBuf, "%010" PRIu32, packet->msec);
|
||||||
|
st = st + textBuf + ": ";
|
||||||
|
|
||||||
|
// формируем преамбулы
|
||||||
|
if (packet == &_inPacket)
|
||||||
|
{
|
||||||
|
st += "[<=] "; // преамбула входящего пакета
|
||||||
|
}
|
||||||
|
else if (packet == &_outPacket)
|
||||||
|
{
|
||||||
|
st += "[=>] "; // преамбула исходящего пакета
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
st += "[--] "; // преамбула для "непакета"
|
||||||
|
}
|
||||||
|
|
||||||
|
// формируем данные
|
||||||
|
for (int i = 0; i < packet->bytesLoaded; i++)
|
||||||
|
{
|
||||||
|
// для заголовков нормальных пакетов надо отработать скобки (если они есть)
|
||||||
|
if ((!notAPacket) && (i == 0))
|
||||||
|
st += HOLMES_HEADER_BRACKET_OPEN;
|
||||||
|
// для CRC нормальных пакетов надо отработать скобки (если они есть)
|
||||||
|
if ((!notAPacket) && (i == packet->header->body_length + AC_HEADER_SIZE))
|
||||||
|
st += HOLMES_CRC_BRACKET_OPEN;
|
||||||
|
|
||||||
|
memset(textBuf, 0, 11);
|
||||||
|
sprintf(textBuf, HOLMES_BYTE_FORMAT, packet->data[i]);
|
||||||
|
st += textBuf;
|
||||||
|
|
||||||
|
// для заголовков нормальных пакетов надо отработать скобки (если они есть)
|
||||||
|
if ((!notAPacket) && (i == AC_HEADER_SIZE - 1))
|
||||||
|
st += HOLMES_HEADER_BRACKET_CLOSE;
|
||||||
|
// для CRC нормальных пакетов надо отработать скобки (если они есть)
|
||||||
|
if ((!notAPacket) && (i == packet->header->body_length + AC_HEADER_SIZE + 2 - 1))
|
||||||
|
st += HOLMES_CRC_BRACKET_CLOSE;
|
||||||
|
|
||||||
|
st += HOLMES_DELIMITER;
|
||||||
|
}
|
||||||
|
|
||||||
|
_debugMsg(st, dbgLevel, line);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace aux_ac
|
||||||
|
} // namespace esphome
|
||||||
15
components/aux_ac/aux_logger.h
Normal file
15
components/aux_ac/aux_logger.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome
|
||||||
|
{
|
||||||
|
namespace aux_ac
|
||||||
|
{
|
||||||
|
using packet_t = uint8_t; // TODO: Replace with actual packet_t definition
|
||||||
|
|
||||||
|
void debugMsg(const char *msg, uint8_t dbgLevel, unsigned int line = 0, ...);
|
||||||
|
void debugPrintPacket(packet_t *packet, uint8_t dbgLevel = ESPHOME_LOG_LEVEL_DEBUG, unsigned int line = __LINE__);
|
||||||
|
} // namespace aux_ac
|
||||||
|
} // namespace esphome
|
||||||
68
components/aux_ac/aux_uart.cpp
Normal file
68
components/aux_ac/aux_uart.cpp
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#include "aux_uart.h"
|
||||||
|
|
||||||
|
namespace esphome
|
||||||
|
{
|
||||||
|
namespace aux_ac
|
||||||
|
{
|
||||||
|
void AuxUart::send_frame(const std::vector<uint8_t> &frame)
|
||||||
|
{
|
||||||
|
this->write_array(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AuxUart::read_frame(std::vector<uint8_t> &frame)
|
||||||
|
{
|
||||||
|
// Check if enough data is available
|
||||||
|
if (this->available() < 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Peek at the first 3 bytes to determine the frame length
|
||||||
|
uint8_t header[3];
|
||||||
|
if (!this->peek_array(header, 3))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Validate start byte
|
||||||
|
if (header[0] != 0xAA)
|
||||||
|
{
|
||||||
|
// Invalid start byte, discard one byte and return false
|
||||||
|
uint8_t discard;
|
||||||
|
this->read_byte(&discard);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine frame length from the second byte
|
||||||
|
size_t frame_length = header[1];
|
||||||
|
if (frame_length < 3 || frame_length > AC_BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
// Invalid length, discard one byte and return false
|
||||||
|
uint8_t discard;
|
||||||
|
this->read_byte(&discard);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the full frame is available
|
||||||
|
if (this->available() < frame_length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Read the full frame into the internal buffer
|
||||||
|
if (!this->read_array(this->_data, frame_length))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Validate checksum
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
for (size_t i = 0; i < frame_length - 1; i++)
|
||||||
|
{
|
||||||
|
checksum += this->_data[i];
|
||||||
|
}
|
||||||
|
if (checksum != this->_data[frame_length - 1])
|
||||||
|
{
|
||||||
|
// Invalid checksum, discard the frame and return false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the valid frame to the output vector
|
||||||
|
frame.assign(this->_data, this->_data + frame_length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace aux_ac
|
||||||
|
} // namespace esphome
|
||||||
30
components/aux_ac/aux_uart.h
Normal file
30
components/aux_ac/aux_uart.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/uart/uart.h"
|
||||||
|
|
||||||
|
#define AC_BUFFER_SIZE 35
|
||||||
|
|
||||||
|
using namespace esphome::uart;
|
||||||
|
|
||||||
|
namespace esphome
|
||||||
|
{
|
||||||
|
namespace aux_ac
|
||||||
|
{
|
||||||
|
class AuxUart : public UARTDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AuxUart() = delete;
|
||||||
|
explicit AuxUart(UARTComponent *parent) : UARTDevice(parent) {}
|
||||||
|
~AuxUart() = default;
|
||||||
|
|
||||||
|
void send_frame(const std::vector<uint8_t> &frame);
|
||||||
|
bool read_frame(std::vector<uint8_t> &frame);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Internal buffer for incoming data
|
||||||
|
uint8_t _data[AC_BUFFER_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace aux_ac
|
||||||
|
} // namespace esphome
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import logging
|
||||||
|
from esphome.core import CORE, Define
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import uart, climate
|
||||||
|
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_DATA,
|
||||||
|
CONF_ID,
|
||||||
|
CONF_UART_ID,
|
||||||
|
)
|
||||||
|
|
||||||
|
AUX_AC_FIRMWARE_VERSION = '0.2.17'
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
CODEOWNERS = ["@GrKoR"]
|
||||||
|
DEPENDENCIES = ["uart"]
|
||||||
|
|
||||||
|
aux_ac_ns = cg.esphome_ns.namespace("aux_ac")
|
||||||
|
|
||||||
|
AuxUart = aux_ac_ns.class_("AuxUart", uart.UARTDevice)
|
||||||
|
|
||||||
|
def output_info(config):
|
||||||
|
_LOGGER.info("AUX_AC firmware version: %s", AUX_AC_FIRMWARE_VERSION)
|
||||||
|
return config
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.All(
|
||||||
|
uart.UART_DEVICE_SCHEMA
|
||||||
|
.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(AuxUart),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
output_info,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
CORE.add_define(
|
||||||
|
Define("AUX_AC_FIRMWARE_VERSION", '"'+AUX_AC_FIRMWARE_VERSION+'"')
|
||||||
|
)
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
# await cg.register_component(var, config)
|
||||||
|
|
||||||
|
parent = await cg.get_variable(config[CONF_UART_ID])
|
||||||
|
cg.add(var.initAC(parent))
|
||||||
|
|
||||||
|
if CONF_INDOOR_TEMPERATURE in config:
|
||||||
|
conf = config[CONF_INDOOR_TEMPERATURE]
|
||||||
|
sens = await sensor.new_sensor(conf)
|
||||||
|
cg.add(var.set_indoor_temperature_sensor(sens))
|
||||||
|
|
||||||
|
if CONF_OUTDOOR_TEMPERATURE in config:
|
||||||
|
conf = config[CONF_OUTDOOR_TEMPERATURE]
|
||||||
|
sens = await sensor.new_sensor(conf)
|
||||||
|
cg.add(var.set_outdoor_temperature_sensor(sens))
|
||||||
|
|
||||||
|
if CONF_OUTBOUND_TEMPERATURE in config:
|
||||||
|
conf = config[CONF_OUTBOUND_TEMPERATURE]
|
||||||
|
sens = await sensor.new_sensor(conf)
|
||||||
|
cg.add(var.set_outbound_temperature_sensor(sens))
|
||||||
|
|
||||||
|
if CONF_INBOUND_TEMPERATURE in config:
|
||||||
|
conf = config[CONF_INBOUND_TEMPERATURE]
|
||||||
|
sens = await sensor.new_sensor(conf)
|
||||||
|
cg.add(var.set_inbound_temperature_sensor(sens))
|
||||||
|
|
||||||
|
if CONF_COMPRESSOR_TEMPERATURE in config:
|
||||||
|
conf = config[CONF_COMPRESSOR_TEMPERATURE]
|
||||||
|
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)
|
||||||
|
cg.add(var.set_display_sensor(sens))
|
||||||
|
|
||||||
|
if CONF_DEFROST_STATE in config:
|
||||||
|
conf = config[CONF_DEFROST_STATE]
|
||||||
|
sens = await binary_sensor.new_binary_sensor(conf)
|
||||||
|
cg.add(var.set_defrost_state(sens))
|
||||||
|
|
||||||
|
if CONF_INVERTER_POWER in config:
|
||||||
|
conf = config[CONF_INVERTER_POWER]
|
||||||
|
sens = await sensor.new_sensor(conf)
|
||||||
|
cg.add(var.set_inverter_power_sensor(sens))
|
||||||
|
|
||||||
|
if CONF_PRESET_REPORTER in config:
|
||||||
|
conf = config[CONF_PRESET_REPORTER]
|
||||||
|
sens = await text_sensor.new_text_sensor(conf)
|
||||||
|
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_show_action(config[CONF_SHOW_ACTION]))
|
||||||
|
cg.add(var.set_display_inverted(config[CONF_DISPLAY_INVERTED]))
|
||||||
|
cg.add(var.set_packet_timeout(config[CONF_TIMEOUT]))
|
||||||
|
cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))
|
||||||
|
if CONF_SUPPORTED_MODES in config:
|
||||||
|
cg.add(var.set_supported_modes(config[CONF_SUPPORTED_MODES]))
|
||||||
|
if CONF_SUPPORTED_SWING_MODES in config:
|
||||||
|
cg.add(var.set_supported_swing_modes(config[CONF_SUPPORTED_SWING_MODES]))
|
||||||
|
if CONF_SUPPORTED_PRESETS in config:
|
||||||
|
cg.add(var.set_supported_presets(config[CONF_SUPPORTED_PRESETS]))
|
||||||
|
if CONF_CUSTOM_PRESETS in config:
|
||||||
|
cg.add(var.set_custom_presets(config[CONF_CUSTOM_PRESETS]))
|
||||||
|
if CONF_CUSTOM_FAN_MODES in config:
|
||||||
|
cg.add(var.set_custom_fan_modes(config[CONF_CUSTOM_FAN_MODES]))
|
||||||
|
|||||||
Reference in New Issue
Block a user