diff --git a/README.md b/README.md index f6b827f..579885a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,94 @@ -Подключение к системе умного дома Home Assistant, используя внешний компонент ESPHome, кондиционеров типа: -- TCL TAC-07CHSA/TPG / TAC-09CHSA/TPG / TAC-12CHSA/TPG +Внешний компонент кондиционеров TCL и аналогов для Home Assistant, используя ESPHome. +Поддерживаются кондиционеры типа TAC-07CHSA и подобные. Увы, предположить точно получится подключить кондиционер или нет практически +невозможно из-за огромного разбега в комплектациях: даже одна и та же модель, буквально буква-в-букву может, например, не иметь +родного модуля WiFI, не иметь провода с USB разъемом или вовсе на плате управления может не быть впаян разъем UART. +Однако, в целом, с пайкой или без, проверены следующие кондиционеры: +- TCL TAC-07CHSA/TPG-W +- TCL TAC-09CHSA/TPG +- TCL TAC-12CHSA/TPG +- TCL TAC-09CHSA/DSEI-W - Daichi AIR20AVQ1/AIR20FV1 ____ -Пост по проекту находится [в моем канале на Дзене](https://dzen.ru/b/Zgnvt3VNQhfUZ99X) +Пост по проекту находится [в моем канале на Дзене](https://dzen.ru/b/Zhmd3bLEd3GbU8mD) + +Это хоть и не готовый вариант, но вполне себе образец для бета-тестирования, есть уже почти все, что хотелось добавить и это все +вполне неплохо и довольно корректно работает. А вот на сколько неплохо и корректно- это и предстоит выяснить. +Используя компонент прфямо сейчас Вы уже не рискуете душевным здоровьем, но внезапные глюки вполне могут напасть. Если вдруг такое +случиться именно с Вами- прошу сообщить мне на Дзене, приму меры. +Я все еще не оставляю подробного описания, уповая на то, что проверять компонент и проводить эксперименты будут сколь-нибудь +подкованные в этом деле люди, не боящиеся наброситься с палкой на багованного медведя. МОжно ли этим пользоваться "на повседневку"? +Можно. Но лучше подождать окончательного варианта- оно ведь так надежнее. ____ -Это все здесь, я даже не знаю, пре-альфа, потому как функционал я просто и без затей пилил по ходу вникания в суть происходящего. -Используя этот кусок кода Вы рискуете своим душевным здоровьем. -Если Вам надо- разберетесь, если не разберетесь- это Вам не надо, дождитесь нормального результата работы. -Образец для конфигурации ESPHome в файле TCL-Conditioner.yaml \ No newline at end of file +Образец для конфигурации ESPHome в файле TCL-Conditioner.yaml. Скачайте к себе и используйте в ESPHome, или просто скопируйте из него +всю конфигурацию и вставьте вместо своей, однако, не забыв отредактировать все поля. в файле есть подсказки по каждому полю. + +Вопрос может возникнуть с 2 моментами: платформа (чип или модуль) и подгружаемые файлы. Попробую объяснить. + +## Настройка платформы +Платформа настраивается точно так же, как ей и полагается настраиваться в ESPHome. Например, так выглядит кусок кода для ESP-01S: +```yaml +esp8266: + board: esp01_1m +``` +А вот так выглядит кусок кода для модуля Hommyn HDN/WFN-02-01 из первой статьи про кондиционер: +```yaml +esp32: + board: esp32-c3-devkitm-1 + framework: + type: arduino +``` +Можно подключать платформу и через основной конфиг, вот предложенный подписчиком пример для Esp32 WROOM32: +```yaml +esphome: + platform: ESP32 + board: nodemcu-32s +``` +В общем- все то же самое, как и обычно, вариант под свою платформу легко ищется в интернете. +**Важно не забыть закомментировать или удалить строки других платформ!** + +## Настройка подгружаемых файлов +Для добавления или удаления определенных частей конфига я решил использовать подгружаемые файлы- они загружаются ESPHome автоматически, +если у сервера с Home Assistant есть доступ в интернет. Такой подход позволяет редактировать и обновлять не весь конфиг куском, +а частями, не трогая то, что работает. +Еще один плюс- не нужно километровые куски кода комментировать или раскомментировать, не нужно зжнать разметку, чтобы не считать +проклятые пробелы и прочее. Все делается добавлением или удалением ссылок на файлы. Итак, вот так выглядит блок подгружаемых файлов: +```yaml +packages: + remote_package: + url: https://github.com/I-am-nightingale/tclac.git + ref: master + files: + # v - равнение строк с опциями вот по этой позиции, иначе глючить будет + - packages/core.yaml # Ядро всего сущего + # - packages/leds.yaml + refresh: 30s +``` +Все подгружаемые файлы указываются в секции **files:**. Для работы необходимо, чтобы был хотя-бы +```yaml +- packages/core.yaml # Ядро всего сущего +``` +Все остальные модули по желанию(их описание в том же файле чуть выше). **Важно**, чтобы все строки с файлами были выровнены по +импровизированной метке, которую я специально указал, иначе у ESPHome возникнет много вопросов к Вам. Например, **должно быть так:** +```yaml +packages: + remote_package: + url: https://github.com/I-am-nightingale/tclac.git + ref: master + files: + # v - равнение строк с опциями вот по этой позиции, иначе глючить будет + - packages/core.yaml # Ядро всего сущего + - packages/leds.yaml + refresh: 30s +``` +А вот так уже **не правильно:** +```yaml +packages: + remote_package: + url: https://github.com/I-am-nightingale/tclac.git + ref: master + files: + # v - равнение строк с опциями вот по этой позиции, иначе глючить будет + - packages/core.yaml # Ядро всего сущего + - packages/leds.yaml + refresh: 30s +``` \ No newline at end of file diff --git a/TCL-Conditioner.yaml b/TCL-Conditioner.yaml index d8b1e78..2f63c28 100644 --- a/TCL-Conditioner.yaml +++ b/TCL-Conditioner.yaml @@ -20,18 +20,23 @@ substitutions: # Выводы модуля, к которым подключен UART: uart_rx: GPIO3 uart_tx: GPIO1 -# Выводы модуля для подключения сигнальных светодиодов, для работы надо раскомментировать "leds" в packages +# Выводы модуля для подключения сигнальных светодиодов, для работы надо раскомментировать "leds" в "packages" # иначе работать не будет совсем и можно писать сюда вообще что угодною. Для тех, кто просил их удалить. receive_led: GPIO6 transmit_led: GPIO4 +# Подгружаемые файлы- загружаются и обновляются автоматически из интернета, раскомментировать нужные +# Описание опций: +# - packages/leds.yaml - светодиоды для индикации приема/передачи, пины указываются в receive_led / transmit_led +# +# Выравнивать раскомментированные строки обязательно по указанной позиции! packages: remote_package: url: https://github.com/I-am-nightingale/tclac.git ref: master files: + # v - равнение строк с опциями вот по этой позиции, иначе глючить будет - packages/core.yaml # Ядро всего сущего - # Подключение дополнительных опций: # - packages/leds.yaml refresh: 30s diff --git a/components/tclac/climate.py b/components/tclac/climate.py index 3b558ad..29c31ec 100644 --- a/components/tclac/climate.py +++ b/components/tclac/climate.py @@ -25,7 +25,7 @@ from esphome.components.climate import ( ) AUTO_LOAD = ["climate"] -CODEOWNERS = ["@I-am-nightingale"] +CODEOWNERS = ["@I-am-nightingale", "@xaxexa", "@junkfix"] DEPENDENCIES = ["climate", "uart"] TCLAC_MIN_TEMPERATURE = 16.0 diff --git a/components/tclac/tclac.cpp b/components/tclac/tclac.cpp index 0a46959..8cc8e7b 100644 --- a/components/tclac/tclac.cpp +++ b/components/tclac/tclac.cpp @@ -1,3 +1,9 @@ +/** +* Create by Miguel Ángel López on 20/07/19 +* and modify by xaxexa +* Refactoring & component making: +* Соловей с паяльником 15.03.2024 +**/ #include "esphome.h" #include "esphome/core/defines.h" #include "tclac.h" @@ -18,15 +24,11 @@ ClimateTraits tclacClimate::traits() { traits.set_supported_fan_modes(this->supported_fan_modes_); traits.set_supported_swing_modes(this->supported_swing_modes_); - traits.add_supported_mode(climate::CLIMATE_MODE_OFF); // Выключенный режим кондиционера доступен всегда - traits.add_supported_mode(climate::CLIMATE_MODE_AUTO); // Автоматический режим кондиционера тоже - traits.add_supported_fan_mode(climate::CLIMATE_FAN_AUTO); // Автоматический режим вентилятора доступен всегда - traits.add_supported_preset(ClimatePreset::CLIMATE_PRESET_NONE); // На всякий случай без предустановок - traits.add_supported_swing_mode(climate::CLIMATE_SWING_OFF);// Выключенный режим качания заслонок доступен всегда - -// traits.set_visual_temperature_step(STEP_TEMPERATURE); -// traits.set_visual_min_temperature(MIN_SET_TEMPERATURE); -// traits.set_visual_max_temperature(MAX_SET_TEMPERATURE); + traits.add_supported_mode(climate::CLIMATE_MODE_OFF); // Выключенный режим кондиционера доступен всегда + traits.add_supported_mode(climate::CLIMATE_MODE_AUTO); // Автоматический режим кондиционера тоже + traits.add_supported_fan_mode(climate::CLIMATE_FAN_AUTO); // Автоматический режим вентилятора доступен всегда + traits.add_supported_swing_mode(climate::CLIMATE_SWING_OFF); // Выключенный режим качания заслонок доступен всегда + traits.add_supported_preset(ClimatePreset::CLIMATE_PRESET_NONE);// На всякий случай без предустановок return traits; } @@ -84,7 +86,7 @@ void tclacClimate::loop() { tclacClimate::dataShow(0,0); return; } else { - ESP_LOGD("TCL", "checksum OK %x", check); + //ESP_LOGD("TCL", "checksum OK %x", check); } tclacClimate::dataShow(0,0); // Прочитав все из буфера приступаем к разбору данных @@ -96,7 +98,7 @@ void tclacClimate::update() { tclacClimate::dataShow(1,1); this->esphome::uart::UARTDevice::write_array(poll, sizeof(poll)); auto raw = tclacClimate::getHex(poll, sizeof(poll)); - ESP_LOGD("TCL", "chek status sended"); + //ESP_LOGD("TCL", "chek status sended"); tclacClimate::dataShow(1,0); } @@ -105,7 +107,7 @@ void tclacClimate::readData() { current_temperature = float((( (dataRX[17] << 8) | dataRX[18] ) / 374 - 32)/1.8); target_temperature = (dataRX[FAN_SPEED_POS] & SET_TEMP_MASK) + 16; - ESP_LOGD("TCL", "TEMP: %f ", current_temperature); + //ESP_LOGD("TCL", "TEMP: %f ", current_temperature); if (dataRX[MODE_POS] & ( 1 << 4)) { // Если кондиционер включен, то разбираем данные для отображения @@ -208,7 +210,6 @@ void tclacClimate::control(const ClimateCall &call) { switch_climate_mode = mode; } - // Запрашиваем данные из переключателя предустановок кондиционера if (call.get_preset().has_value()){ switch_preset = call.get_preset().value(); @@ -245,11 +246,10 @@ void tclacClimate::control(const ClimateCall &call) { void tclacClimate::takeControl() { - dataTX[7] = 0b00000000;//eco,display,beep,ontimerenable, offtimerenable,power,0,0 - dataTX[8] = 0b00000000;//mute,0,turbo,health,mode(4) 0=cool 1=fan 2=dry 3=heat 4=auto - dataTX[9] = 0b00000000;//[9] = 0,0,0,0,temp(4) 31 - value - dataTX[10] = 0b00000000;//[10] = 0,timerindicator,swingv(3),fan(3) 0=auto 1=low 2=med 3=high - // {0,2,3,5,0}; + dataTX[7] = 0b00000000; + dataTX[8] = 0b00000000; + dataTX[9] = 0b00000000; + dataTX[10] = 0b00000000; dataTX[11] = 0b00000000; dataTX[19] = 0b00000000; dataTX[32] = 0b00000000; @@ -622,12 +622,10 @@ void tclacClimate::set_display_state(bool state) { } } } - // Получение состояния режима принудительного применения настроек void tclacClimate::set_force_mode_state(bool state) { this->force_mode_status_ = state; } - // Получение пина светодиода приема данных #ifdef CONF_RX_LED void tclacClimate::set_rx_led_pin(GPIOPin *rx_led_pin) { @@ -692,23 +690,10 @@ void tclacClimate::set_supported_fan_modes(const std::set &modes) { this->supported_swing_modes_ = modes; } - - +// Получение доступных предустановок void tclacClimate::set_supported_presets(const std::set &presets) { this->supported_presets_ = presets; } -// Заготовки функций запроса состояния, может пригодиться в будущем, если делать обратную связь. Очень не хочется, будет очень костыльно. - -//bool tclacClimate::get_beeper_state() const { return this->beeper_status_; } -//bool tclacClimate::get_display_state() const { return this->display_status_; } -//bool tclacClimate::get_module_display_state() const { return this->module_display_status_; } -//AirflowVerticalDirection tclacClimate::get_vertical_airflow() const { return this->vertical_direction_; }; -//AirflowHorizontalDirection tclacClimate::get_horizontal_airflow() const { return this->horizontal_direction_; } -//VerticalSwingDirection tclacClimate::get_vertical_swing_direction() const { return this->vertical_swing_direction_; } -//HorizontalSwingDirection tclacClimate::get_horizontal_swing_direction() const { return this->horizontal_swing_direction_; } - - - } } \ No newline at end of file diff --git a/components/tclac/tclac.h b/components/tclac/tclac.h index 3101613..b4264d7 100644 --- a/components/tclac/tclac.h +++ b/components/tclac/tclac.h @@ -30,7 +30,6 @@ namespace tclac { #define FAN_SPEED_POS 8 #define FAN_QUIET_POS 33 - #define FAN_AUTO 0b10000000 //auto #define FAN_QUIET 0x80 //silent #define FAN_LOW 0b10010000 // | @@ -41,7 +40,6 @@ namespace tclac { #define FAN_DIFFUSE 0b10000000 // POWER [7] #define FAN_SPEED_MASK 0b11110000 //FAN SPEED MASK - #define SWING_POS 10 #define SWING_OFF 0b00000000 #define SWING_HORIZONTAL 0b00100000 @@ -49,10 +47,6 @@ namespace tclac { #define SWING_BOTH 0b01100000 #define SWING_MODE_MASK 0b01100000 -#define STEP_TEMPERATURE 1 -#define MIN_SET_TEMPERATURE 16 -#define MAX_SET_TEMPERATURE 31 - using climate::ClimateCall; using climate::ClimateMode; using climate::ClimatePreset; @@ -122,28 +116,17 @@ class tclacClimate : public climate::Climate, public esphome::uart::UARTDevice, void loop() override; void setup() override; void update() override; - void dataShow(bool flow, bool shine); - void sendData(byte * message, byte size); - static String getHex(byte *message, byte size); - static byte getChecksum(const byte * message, size_t size); - void control(const ClimateCall &call) override; // Climate control - - // Заготовки функций запроса состояния, может пригодиться в будущем, если делать обратную связь. Очень не хочется, будет очень костыльно. - - //bool get_beeper_state() const; - //bool get_display_state() const; - //bool tclacClimate::get_module_display_state() const; - //AirflowVerticalDirection get_vertical_airflow() const; - //AirflowHorizontalDirection get_horizontal_airflow() const; - //VerticalSwingDirection tclacClimate::get_vertical_swing_direction() const; - //HorizontalSwingDirection tclacClimate::get_horizontal_swing_direction() const; - void set_beeper_state(bool state); void set_display_state(bool state); + void dataShow(bool flow, bool shine); void set_force_mode_state(bool state); void set_rx_led_pin(GPIOPin *rx_led_pin); void set_tx_led_pin(GPIOPin *tx_led_pin); + void sendData(byte * message, byte size); void set_module_display_state(bool state); + static String getHex(byte *message, byte size); + void control(const ClimateCall &call) override; + static byte getChecksum(const byte * message, size_t size); void set_vertical_airflow(AirflowVerticalDirection direction); void set_horizontal_airflow(AirflowHorizontalDirection direction); void set_vertical_swing_direction(VerticalSwingDirection direction); @@ -165,10 +148,8 @@ class tclacClimate : public climate::Climate, public esphome::uart::UARTDevice, VerticalSwingDirection vertical_swing_direction_; std::set supported_swing_modes_{}; HorizontalSwingDirection horizontal_swing_direction_; - }; - } } -#endif //TCL_ESP_TCL_H +#endif //TCL_ESP_TCL_H \ No newline at end of file diff --git a/packages/core.yaml b/packages/core.yaml index 39db174..7222e34 100644 --- a/packages/core.yaml +++ b/packages/core.yaml @@ -158,7 +158,7 @@ switch: id(${device_name}climate).set_display_state(false); # Светодиодная индикация обмена данными с кондиционером, по умолчанию выключена - - name: Module display + - name: Display on module platform: template device_class: switch id: ledflash_mode