77 Commits

Author SHA1 Message Date
GrKoR
efa0991dd0 fix: automations play() method fixed 2025-11-27 17:57:13 -08:00
GrKoR
2e0c421c9f fix: removed module dependency" 2025-11-26 23:28:20 -08:00
GrKoR
53414d8ab4 fix: python code generator fix for custom presets & custom fan modes 2025-11-26 21:14:46 -08:00
GrKoR
5a165d3a3d upd: version++ 2025-11-26 18:58:36 -08:00
GK
02887baa04 Merge pull request #187 from nonitex/master
Preserve swing mode and vertical vane position when toggling the othe…
2025-11-26 18:53:38 -08:00
GrKoR
5f9d2c0c0f fix: esphome 2025.11.0 breacing changes 2025-11-26 17:38:20 -08:00
nonitex
7a4bacfb9a Preserve swing mode and vertical vane position when toggling the other axis
Added helper functions to normalize louver states for consistent swing detection across different AUX models. Updated swing mode logic to utilize these helpers for improved clarity and functionality.
2025-10-20 03:52:29 +02:00
GrKoR
c959d7be7e new AC tested: Elgin HWFI30B2IA / HWFE30B2NA 2025-08-04 18:51:33 -07:00
GrKoR
60d6f56fcf upd: version++, CLIMATE_SCHEMA warning fixed 2025-06-30 22:54:30 -07:00
GK
a8eba8882e fix (#152): WARNING Using climate.CLIMATE_SCHEMA is deprecated (PR #174) 2025-06-30 22:51:44 -07:00
GrKoR
96455e5882 fix (#152): WARNING Using climate.CLIMATE_SCHEMA is deprecated 2025-06-30 22:47:39 -07:00
GrKoR
89db23434b fix: exclude local tests from repo 2025-06-30 22:36:59 -07:00
GK
945d2603f1 Merge pull request #173 from GrKoR/esp-idf-support
Esp idf support
2025-06-30 22:05:56 -07:00
GrKoR
6291828cec Merge branch 'master' into esp-idf-support 2025-06-30 22:05:18 -07:00
GrKoR
8dc9f0f478 New ACs tested: Elgin HIFI09C2WA / HIFE09C2CA and Elgin HJFI12C2WB 2025-06-30 20:45:29 -07:00
GK
03e0ee0d9a Merge pull request #172 from GrKoR/GrKoR/issue145
a list of new tested ACs
2025-06-30 19:56:54 -07:00
GrKoR
848fd8f6c1 New AC tested: VORTEX VAI-A 1219F JMRV 2025-06-30 19:55:04 -07:00
GrKoR
e77d49c52a New AC tested: SEVRA SEV-09JO 2025-06-30 19:49:39 -07:00
GrKoR
42fd8d5ba1 New AC tested: Centek CT-65J24 2025-06-30 19:36:39 -07:00
GrKoR
00aa426bfc New AC tested: Centek CT-65FDC07 2025-06-30 19:32:38 -07:00
GrKoR
029d92be96 New AC tested: IGC Freddo S DC Inverter RAS-V12NQR / RAC-V12NQR 2025-06-30 19:29:39 -07:00
GrKoR
d1e64af8a4 New AC tested: Fujico ACF-I07AHRDN1 2025-06-30 19:26:57 -07:00
GrKoR
d238c8b661 New AC tested: AUX ALLD-H18/4R1C / AL-H18/4R1C(U) 2025-06-30 19:24:00 -07:00
GrKoR
140447ceab New AC tested: Royal Clima Renaissance RC-RNC28HN 2025-06-30 19:17:15 -07:00
GrKoR
6920102969 New AC tested: Royal Clima CO-D 24HNI/CO-E 24HNI 2025-06-30 19:13:05 -07:00
GrKoR
f20f89cb93 New AC tested: Scarlett Comfort RRI-09-MPI 2025-06-30 19:06:53 -07:00
GrKoR
6a98c47ada New AC tested: Ballu Orbis BPAC-08 OR/N6 2025-06-30 18:54:19 -07:00
GrKoR
b5e88f7abc New AC tested: Ballu BSW/in-18HN1 / BSW/out-18HN1 2025-06-30 18:49:57 -07:00
GrKoR
a166d18ede New AC tested: Electrolux EACS/I-09HIX-BLACK/N8 2025-06-30 18:43:52 -07:00
GK
7de56fb656 Merge pull request #171 from GrKoR/GrKoR/issue145
New AC: Electrolux EACS/I-07HSK/N3_24Y SKANDI DC INVERTER
2025-06-30 18:34:14 -07:00
GrKoR
cf5c88662d New AC: Electrolux EACS/I-07HSK/N3_24Y SKANDI DC INVERTER
Fixes #145
2025-06-30 18:29:18 -07:00
GrKoR
a7d2a73802 upd: platform keyword was removed according to the esphome ver. 2025.2.0 + minor fixes 2025-02-20 22:20:45 -08:00
GrKoR
078a6b20cf new AC: Ishimatsu: AVK-07I 2025-02-20 21:35:21 -08:00
GrKoR
69eebdb8c8 new AC: AUX ASW-12A3INV/SS 2025-02-20 21:33:03 -08:00
GrKoR
fe00198764 new AC: AUX AUX-09CAA/I / ASW-H09A4/CAR3DI-C3 2025-02-20 21:30:08 -08:00
GrKoR
da5fcd5848 new AC: AUX ALMD-H24/4DR2A / AL-H24/4DR2A(U) 2025-02-20 21:26:42 -08:00
GrKoR
9d4930d290 new AC: AUX ASW-H18E3A4 2025-02-20 21:19:07 -08:00
GrKoR
26ae9c248c new AC: Costway FP10524US-22WH & FP10318US-22WH 2025-02-20 21:13:00 -08:00
GrKoR
e67898997d new AC: Baymak Elegant Plus 9 2025-02-20 21:04:03 -08:00
GrKoR
e158586268 new AC: Ande AND-AMWM-H12(JA) / AND-AM2-H18/4DR3 2025-02-20 20:58:32 -08:00
GrKoR
2d446f88e4 new AC: Arielli ASW-H09B4/FGR3DI-EU 2025-02-20 20:52:12 -08:00
GrKoR
5591b91f7b new AC: AUX AUX-12F3H 2025-02-20 20:48:27 -08:00
GrKoR
551c476549 new AC: Elgin HJFI12C2WB 2025-02-20 20:40:46 -08:00
GrKoR
bdbd1478b7 version++ 2024-10-26 23:25:36 +03:00
GrKoR
9c2daf0615 fix: esp8266 compatibility 2024-10-26 23:25:08 +03:00
GrKoR
3ca873450d fix: String class was changed to std::string as part of esp-idf support 2024-10-26 20:46:01 +03:00
GK
5e1b78df9f Merge pull request #131 from itay-sho/feature/support-esp-idf
feat: support esp-idf
2024-10-26 21:22:06 +04:00
GK
7a252e5955 new AC tested: AUX ASW-H09B7A4 2024-10-26 21:16:30 +04:00
GK
79f23c341d fix: Tornado AC typo 2024-10-26 21:14:25 +04:00
GK
360d274088 Merge pull request #132 from itay-sho/chore/add-tested-acs-to-the-list
docs: adding Tornado ISKA 12 WIFI to the list
2024-10-26 21:12:34 +04:00
Itay Shoshani
973f961e5f docs: adding Tornado ISKA 12 WIFI to the list
adding AUX ASW-H09B7A4 as well, since the tornado is just a sticker to the "real" model.
2024-10-26 17:25:29 +03:00
Itay Shoshani
cf990eb467 fix: using correct int types to reduce compilation warnings / errors
required due to the fact that esp32-c6 compiler raises errors due to that
2024-10-26 09:47:32 +03:00
Itay Shoshani
1c6575a264 feat: support esp-idf 2024-10-26 09:46:26 +03:00
GrKoR
7f68f3fdac new AC tested: Centek CT-65A09 2024-08-03 20:40:44 +03:00
GrKoR
e7bca33f35 new AC tested: Centek CT-65V12 2024-08-03 20:38:27 +03:00
GrKoR
f859e656a4 upd: OTA in examples and tests was changed to match the ESPHome 2024.6.0 2024-07-20 23:01:50 +03:00
GrKoR
5b229da380 new AC tested: AUX ASW-H18A4/QH-R1DI / AS-H18A4/QH-R1DI 2024-07-17 19:32:53 +03:00
GrKoR
656344dda6 new AC tested: ANDE AND-12/FA+ 2024-07-14 17:14:08 +03:00
GrKoR
b10a2f5dab new AC tested: Rinnai RINV25RC 2024-07-13 19:52:31 +03:00
GrKoR
b80f4972f0 new AC tested: AUX AUX-07JO/I / AUX-M3-21LCLH multisplit and AUX-12JO/I / AUX-M3-21LCLHmultisplit 2024-07-13 19:47:57 +03:00
GrKoR
2a38208628 new AC tested: AUX ASW-H12A4/JD-R2DI 2024-07-13 19:33:36 +03:00
GrKoR
07a98e5789 ref: list of tested ACs was reordered 2024-07-13 19:32:47 +03:00
GrKoR
fe323a6f65 new AC tested: AUX AMWM-H07/4R2(J) multisplit and AMWM-H12/4R2(J) multisplit 2024-07-13 18:45:25 +03:00
GrKoR
584ef0d57a new AC tested: AUX ASW-H07A4/JD-R1 2024-07-12 12:54:24 +03:00
GrKoR
d15272f437 new AC tested: Centek CT-65U18 2024-07-02 17:07:37 +03:00
GrKoR
23584bf53a new AC tested: Osaka STVP-12HH3 2024-07-01 10:26:33 +03:00
GrKoR
1b3bcdfa0f new AC tested: RVX RS-12ALS 2024-06-30 12:42:55 +03:00
GrKoR
558922047e delete from AC tested: Energolux SAS12CH1-AI and SAS12Z3-AI 2024-06-30 12:28:59 +03:00
GrKoR
9f362f475b new AC tested: Vertex Falcon-18A 2024-06-30 12:21:53 +03:00
GrKoR
dad7025632 new AC tested: AUX ASW-H12C5C4/JER3DI-B8-2 2024-06-20 01:13:45 +03:00
GrKoR
16824c10cc new AC tested: Baymak Elegant Plus 12 2024-06-20 01:09:04 +03:00
GrKoR
f31cfb3c16 new AC tested: IKON ASW-H12C5C4/HCR3DI-B8 2024-06-20 01:01:08 +03:00
GrKoR
35d0364655 new AC tested: AUX HA-18000BTU 2024-06-20 00:53:44 +03:00
GrKoR
25ab6feb4f new AC tested: Energolux SAS09Z4-AI and SAS18Z4-AI 2024-06-20 00:48:18 +03:00
GrKoR
3f1b31bb52 new AC tested: Centek CT-65X12 2024-06-06 12:53:52 +03:00
GrKoR
06388ebb2c new AC tested: Centek CT-65RDC07, CT-65RDC09, CT-65RDC12, CT-65SDC07, CT-65SDC09, CT-65SDC18 2024-05-24 15:31:23 +03:00
GrKoR
1f11db4ae0 new AC tested: Centek CT-65K07 2024-05-18 20:31:43 +03:00
18 changed files with 556 additions and 1331 deletions

4
.gitignore vendored
View File

@@ -12,6 +12,6 @@
**/livingroom_ac/
**/kitchen_ac/
/examples/*/*.h
**/tests/test_*
**/__pycache__
**/private/
**/private/
**/tests

View File

@@ -36,7 +36,7 @@ The best way to report about your test results is writing a message in the [tele
For correct component operation, you need hardware and firmware. The hardware description is located [in a separate file](docs/HARDWARE-EN.md).
### Firmware: Integration aux_ac to your configuration ###
You need [ESPHome](https://esphome.io) v.1.18.0 or above. `External_components` have appeared in this version. But it is better to use ESPHome v.1.20.4 or above, cause there were a lot of `external_components` errors corrected before this version.
You need [ESPHome](https://esphome.io) v.2025.2.0 or above. You can try esphome before 2025.2.0 but I can't guarantee error-free compilation of the examples.
## Installing ##
1. Declare external component. Read [the manual](https://esphome.io/components/external_components.html?highlight=external) for details.

View File

@@ -43,7 +43,7 @@ AUX - это один из нескольких OEM-производителей
Для работы с кондиционером понадобится "железо" и прошивка. Описание электроники вынесено [в отдельный файл](docs/HARDWARE.md).
### Прошивка: интеграция aux_ac в вашу конфигурацию ESPHome ###
Для использования требуется [ESPHome](https://esphome.io) версией не ниже 1.18.0. Именно в этой версии появились `external_components`. Но лучше использовать версию 1.20.4 или старше, так как до этой версии массированно исправлялись ошибки в механизме подключения внешних компонентов.<br />
Для использования требуется [ESPHome](https://esphome.io) версией не ниже 2025.2.0. Работа с более ранними версиями возможна, но не гарантируется.<br />
## Установка ##
1. Подключите компонент.

View File

@@ -4,183 +4,238 @@
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
namespace esphome {
namespace aux_ac {
namespace esphome
{
namespace aux_ac
{
// **************************************** DISPLAY ACTIONS ****************************************
template <typename... Ts>
class AirConDisplayOffAction : public Action<Ts...> {
public:
explicit AirConDisplayOffAction(AirCon *ac) : ac_(ac) {}
// **************************************** DISPLAY ACTIONS ****************************************
template <typename... Ts>
class AirConDisplayOffAction : public Action<Ts...>
{
public:
explicit AirConDisplayOffAction(AirCon *ac) : ac_(ac) {}
void play(Ts... x) override { this->ac_->displayOffSequence(); }
void play(const Ts &...x) override
{
this->ac_->displayOffSequence();
}
protected:
AirCon *ac_;
};
protected:
AirCon *ac_;
};
template <typename... Ts>
class AirConDisplayOnAction : public Action<Ts...> {
public:
explicit AirConDisplayOnAction(AirCon *ac) : ac_(ac) {}
template <typename... Ts>
class AirConDisplayOnAction : public Action<Ts...>
{
public:
explicit AirConDisplayOnAction(AirCon *ac) : ac_(ac) {}
void play(Ts... x) override { this->ac_->displayOnSequence(); }
void play(const Ts &...x) override
{
this->ac_->displayOnSequence();
}
protected:
AirCon *ac_;
};
protected:
AirCon *ac_;
};
// **************************************** VERTICAL LOUVER ACTIONS ****************************************
template <typename... Ts>
class AirConVLouverSwingAction : public Action<Ts...> {
public:
explicit AirConVLouverSwingAction(AirCon *ac) : ac_(ac) {}
// **************************************** VERTICAL LOUVER ACTIONS ****************************************
template <typename... Ts>
class AirConVLouverSwingAction : public Action<Ts...>
{
public:
explicit AirConVLouverSwingAction(AirCon *ac) : ac_(ac) {}
void play(Ts... x) override { this->ac_->setVLouverSwingSequence(); }
void play(const Ts &...x) override
{
this->ac_->setVLouverSwingSequence();
}
protected:
AirCon *ac_;
};
protected:
AirCon *ac_;
};
template <typename... Ts>
class AirConVLouverStopAction : public Action<Ts...> {
public:
explicit AirConVLouverStopAction(AirCon *ac) : ac_(ac) {}
template <typename... Ts>
class AirConVLouverStopAction : public Action<Ts...>
{
public:
explicit AirConVLouverStopAction(AirCon *ac) : ac_(ac) {}
void play(Ts... x) override { this->ac_->setVLouverStopSequence(); }
void play(const Ts &...x) override
{
this->ac_->setVLouverStopSequence();
}
protected:
AirCon *ac_;
};
protected:
AirCon *ac_;
};
template <typename... Ts>
class AirConVLouverTopAction : public Action<Ts...> {
public:
explicit AirConVLouverTopAction(AirCon *ac) : ac_(ac) {}
template <typename... Ts>
class AirConVLouverTopAction : public Action<Ts...>
{
public:
explicit AirConVLouverTopAction(AirCon *ac) : ac_(ac) {}
void play(Ts... x) override { this->ac_->setVLouverTopSequence(); }
void play(const Ts &...x) override
{
this->ac_->setVLouverTopSequence();
}
protected:
AirCon *ac_;
};
protected:
AirCon *ac_;
};
template <typename... Ts>
class AirConVLouverMiddleAboveAction : public Action<Ts...> {
public:
explicit AirConVLouverMiddleAboveAction(AirCon *ac) : ac_(ac) {}
template <typename... Ts>
class AirConVLouverMiddleAboveAction : public Action<Ts...>
{
public:
explicit AirConVLouverMiddleAboveAction(AirCon *ac) : ac_(ac) {}
void play(Ts... x) override { this->ac_->setVLouverMiddleAboveSequence(); }
void play(const Ts &...x) override
{
this->ac_->setVLouverMiddleAboveSequence();
}
protected:
AirCon *ac_;
};
protected:
AirCon *ac_;
};
template <typename... Ts>
class AirConVLouverMiddleAction : public Action<Ts...> {
public:
explicit AirConVLouverMiddleAction(AirCon *ac) : ac_(ac) {}
template <typename... Ts>
class AirConVLouverMiddleAction : public Action<Ts...>
{
public:
explicit AirConVLouverMiddleAction(AirCon *ac) : ac_(ac) {}
void play(Ts... x) override { this->ac_->setVLouverMiddleSequence(); }
void play(const Ts &...x) override
{
this->ac_->setVLouverMiddleSequence();
}
protected:
AirCon *ac_;
};
protected:
AirCon *ac_;
};
template <typename... Ts>
class AirConVLouverMiddleBelowAction : public Action<Ts...> {
public:
explicit AirConVLouverMiddleBelowAction(AirCon *ac) : ac_(ac) {}
template <typename... Ts>
class AirConVLouverMiddleBelowAction : public Action<Ts...>
{
public:
explicit AirConVLouverMiddleBelowAction(AirCon *ac) : ac_(ac) {}
void play(Ts... x) override { this->ac_->setVLouverMiddleBelowSequence(); }
void play(const Ts &...x) override
{
this->ac_->setVLouverMiddleBelowSequence();
}
protected:
AirCon *ac_;
};
protected:
AirCon *ac_;
};
template <typename... Ts>
class AirConVLouverBottomAction : public Action<Ts...> {
public:
explicit AirConVLouverBottomAction(AirCon *ac) : ac_(ac) {}
template <typename... Ts>
class AirConVLouverBottomAction : public Action<Ts...>
{
public:
explicit AirConVLouverBottomAction(AirCon *ac) : ac_(ac) {}
void play(Ts... x) override { this->ac_->setVLouverBottomSequence(); }
void play(const Ts &...x) override
{
this->ac_->setVLouverBottomSequence();
}
protected:
AirCon *ac_;
};
protected:
AirCon *ac_;
};
template <typename... Ts>
class AirConVLouverSetAction : public Action<Ts...> {
public:
AirConVLouverSetAction(AirCon *ac) : ac_(ac) {}
TEMPLATABLE_VALUE(uint8_t, value);
template <typename... Ts>
class AirConVLouverSetAction : public Action<Ts...>
{
public:
TEMPLATABLE_VALUE(uint8_t, value);
void play(Ts... x) {
vlpos_ = this->value_.value(x...);
this->ac_->setVLouverFrontendSequence((ac_vlouver_frontend)vlpos_);
}
AirConVLouverSetAction(AirCon *ac) : ac_(ac) {};
protected:
AirCon *ac_;
uint8_t vlpos_;
};
void play(const Ts &...x) override
{
vlpos_ = this->value_.value(x...);
this->ac_->setVLouverFrontendSequence((ac_vlouver_frontend)vlpos_);
};
// **************************************** SEND TEST PACKET ACTION ****************************************
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;
}
protected:
AirCon *ac_;
uint8_t vlpos_;
};
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);
}
}
// **************************************** SEND TEST PACKET ACTION ****************************************
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;
}
protected:
AirCon *ac_;
bool static_{false};
std::function<std::vector<uint8_t>(Ts...)> data_func_{};
std::vector<uint8_t> data_static_{};
};
void play(const Ts &...x) override
{
if (this->static_)
{
this->ac_->sendTestPacket(this->data_static_);
}
else
{
auto val = this->data_func_(x...);
this->ac_->sendTestPacket(val);
}
}
// **************************************** POWER LIMITATION ACTIONS ****************************************
template <typename... Ts>
class AirConPowerLimitationOffAction : public Action<Ts...> {
public:
explicit AirConPowerLimitationOffAction(AirCon *ac) : ac_(ac) {}
protected:
AirCon *ac_;
bool static_{false};
std::function<std::vector<uint8_t>(Ts...)> data_func_{};
std::vector<uint8_t> data_static_{};
};
void play(Ts... x) override { this->ac_->powerLimitationOffSequence(); }
// **************************************** POWER LIMITATION ACTIONS ****************************************
template <typename... Ts>
class AirConPowerLimitationOffAction : public Action<Ts...>
{
public:
explicit AirConPowerLimitationOffAction(AirCon *ac) : ac_(ac) {}
protected:
AirCon *ac_;
};
void play(const Ts &...x) override
{
this->ac_->powerLimitationOffSequence();
}
template <typename... Ts>
class AirConPowerLimitationOnAction : public Action<Ts...> {
public:
AirConPowerLimitationOnAction(AirCon *ac) : ac_(ac) {}
TEMPLATABLE_VALUE(uint8_t, value);
protected:
AirCon *ac_;
};
void play(Ts... x) {
this->pwr_lim_ = this->value_.value(x...);
this->ac_->powerLimitationOnSequence(this->pwr_lim_);
}
template <typename... Ts>
class AirConPowerLimitationOnAction : public Action<Ts...>
{
public:
TEMPLATABLE_VALUE(uint8_t, value);
protected:
AirCon *ac_;
uint8_t pwr_lim_;
};
AirConPowerLimitationOnAction(AirCon *ac) : ac_(ac) {};
} // namespace aux_ac
} // namespace esphome
void play(const Ts &...x) override
{
this->pwr_lim_ = this->value_.value(x...);
this->ac_->powerLimitationOnSequence(this->pwr_lim_);
}
protected:
AirCon *ac_;
uint8_t pwr_lim_;
};
} // namespace aux_ac
} // namespace esphome

View File

@@ -4,8 +4,8 @@
/// немного переработанная версия старого компонента
#pragma once
#include <Arduino.h>
#include <stdarg.h>
#include <cinttypes>
#include "esphome.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
@@ -15,6 +15,12 @@
#include "esphome/components/uart/uart.h"
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#include "esphome/core/version.h"
#ifndef USE_ARDUINO
using String = std::string;
#define F(string_literal) (string_literal)
#endif
// весь функционал сохранения пресетов прячу под дефайн
// #define PRESETS_SAVING
@@ -38,6 +44,11 @@ namespace esphome
using climate::ClimatePreset;
using climate::ClimateSwingMode;
using climate::ClimateTraits;
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
using climate::ClimateModeMask;
using climate::ClimateSwingModeMask;
using climate::ClimatePresetMask;
#endif
//****************************************************************************************************************************************************
//**************************************************** Packet logger configuration *******************************************************************
@@ -710,16 +721,16 @@ namespace esphome
{
AC_COMMAND_BASE;
ac_health_status health_status;
float temp_ambient; // внутренняя температура
int8_t temp_outdoor; // внешняя температура
int8_t temp_inbound; // температура входящая
int8_t temp_outbound; // температура исходящая
int8_t temp_compressor; // температура компрессора
ac_realFan realFanSpeed; // текущая скорость вентилятора
uint8_t inverter_power; // мощность инвертора
bool defrost; // режим разморозки внешнего блока (накопление тепла + прогрев испарителя)
ac_powLim_state power_lim_state; // статус ограничения мощности инвертора
uint8_t power_lim_value; // значение ограничения мощности инвертора
float temp_ambient; // внутренняя температура
int8_t temp_outdoor; // внешняя температура
int8_t temp_inbound; // температура входящая
int8_t temp_outbound; // температура исходящая
int8_t temp_compressor; // температура компрессора
ac_realFan realFanSpeed; // текущая скорость вентилятора
uint8_t inverter_power; // мощность инвертора
bool defrost; // режим разморозки внешнего блока (накопление тепла + прогрев испарителя)
ac_powLim_state power_lim_state; // статус ограничения мощности инвертора
uint8_t power_lim_value; // значение ограничения мощности инвертора
};
typedef ac_command_t ac_state_t; // текущее состояние параметров кондея можно хранить в таком же формате, как и комманды
@@ -847,12 +858,19 @@ namespace esphome
// как "в простое" (IDLE)
bool _is_inverter = false;
// поддерживаемые кондиционером опции
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
ClimateModeMask _supported_modes{};
ClimateSwingModeMask _supported_swing_modes{};
ClimatePresetMask _supported_presets{};
std::vector<const char *> _supported_custom_fan_modes{};
std::vector<const char *> _supported_custom_presets{};
#else
std::set<ClimateMode> _supported_modes{};
std::set<ClimateSwingMode> _supported_swing_modes{};
std::set<ClimatePreset> _supported_presets{};
std::set<std::string> _supported_custom_presets{};
std::set<std::string> _supported_custom_fan_modes{};
#endif
// The capabilities of the climate device
// Шаблон параметров отображения виджета
@@ -1520,15 +1538,15 @@ namespace esphome
stateByte = small_info_body->display_and_mildew & AC_MILDEW_MASK;
stateChangedFlag = stateChangedFlag || (_current_ac_state.mildew != (ac_mildew)stateByte);
_current_ac_state.mildew = (ac_mildew)stateByte;
stateByte = AC_POWLIMSTAT_ON * small_info_body->inverter_power_limitation_enable;
stateChangedFlag = stateChangedFlag || (_current_ac_state.power_lim_state != (ac_powLim_state)stateByte);
_current_ac_state.power_lim_state = (ac_powLim_state)stateByte;
_current_ac_state.power_lim_state = (ac_powLim_state)stateByte;
stateByte = small_info_body->inverter_power_limitation_value;
stateChangedFlag = stateChangedFlag || (_current_ac_state.power_lim_value != stateByte);
_current_ac_state.power_lim_value = stateByte;
// уведомляем об изменении статуса сплита
if (stateChangedFlag)
stateChanged();
@@ -1710,7 +1728,7 @@ namespace esphome
// заполняем время получения пакета
memset(textBuf, 0, 11);
sprintf(textBuf, "%010u", packet->msec);
sprintf(textBuf, "%010" PRIu32, packet->msec);
st = st + textBuf + ": ";
// формируем преамбулы
@@ -2386,11 +2404,16 @@ namespace esphome
// первоначальная инициализация
this->preset = climate::CLIMATE_PRESET_NONE;
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
this->clear_custom_preset_();
this->clear_custom_fan_mode_();
#else
this->custom_preset = (std::string) "";
this->custom_fan_mode = (std::string) "";
#endif
this->mode = climate::CLIMATE_MODE_OFF;
this->action = climate::CLIMATE_ACTION_IDLE;
this->fan_mode = climate::CLIMATE_FAN_LOW;
this->custom_fan_mode = (std::string) "";
};
float get_setup_priority() const override { return esphome::setup_priority::DATA; }
@@ -2411,6 +2434,22 @@ namespace esphome
bool get_hw_initialized() { return _hw_initialized; };
bool get_has_connection() { return _has_connection; };
// --- Helper functions for consistent louver interpretation ---
// Some AUX-based models use 0x20 for "horizontal off", while others (e.g., ROVEX, Royal Clima) use 0xE0.
// These helpers normalize those differences so swing detection stays consistent.
// Keeping both encodings here replaces the old workaround that caused HA to jump back to OFF
// when horizontal was swinging and vertical was fixed.
static inline bool is_h_off(uint8_t h) {
return (h == AC_LOUVERH_OFF_AUX) || (h == AC_LOUVERH_OFF_ALTERNATIVE);
}
static inline bool is_h_swing(uint8_t h) {
return (h == AC_LOUVERH_SWING_LEFTRIGHT);
}
static inline bool is_v_swing(uint8_t v) {
return (v == AC_LOUVERV_SWING_UPDOWN);
}
// возвращает, есть ли елементы в последовательности команд
bool hasSequence()
{
@@ -2614,15 +2653,24 @@ namespace esphome
switch (_current_ac_state.fanTurbo)
{
case AC_FANTURBO_ON:
// if ((_current_ac_state.mode == AC_MODE_HEAT) || (_current_ac_state.mode == AC_MODE_COOL)) {
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
this->set_custom_fan_mode_(Constants::TURBO.c_str());
#else
this->custom_fan_mode = Constants::TURBO;
//}
#endif
break;
case AC_FANTURBO_OFF:
default:
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
if (this->has_custom_fan_mode()) {
if (strcmp(this->get_custom_fan_mode(), Constants::TURBO.c_str()) == 0)
this->clear_custom_fan_mode_();
}
#else
if (this->custom_fan_mode == Constants::TURBO)
this->custom_fan_mode = (std::string) "";
#endif
break;
}
@@ -2634,15 +2682,24 @@ namespace esphome
switch (_current_ac_state.fanMute)
{
case AC_FANMUTE_ON:
// if (_current_ac_state.mode == AC_MODE_FAN) {
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
this->set_custom_fan_mode_(Constants::MUTE.c_str());
#else
this->custom_fan_mode = Constants::MUTE;
//}
#endif
break;
case AC_FANMUTE_OFF:
default:
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
if (this->has_custom_fan_mode()) {
if (strcmp(this->get_custom_fan_mode(), Constants::MUTE.c_str()) == 0)
this->clear_custom_fan_mode_();
}
#else
if (this->custom_fan_mode == Constants::MUTE)
this->custom_fan_mode = (std::string) "";
#endif
break;
}
@@ -2654,14 +2711,25 @@ namespace esphome
if (_current_ac_state.health == AC_HEALTH_ON &&
_current_ac_state.power == AC_POWER_ON)
{
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
this->set_custom_preset_(Constants::HEALTH.c_str());
#else
this->custom_preset = Constants::HEALTH;
#endif
}
// AC_HEALTH_OFF
// только в том случае, если до этого пресет был установлен
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
else if (this->has_custom_preset() && strcmp(this->get_custom_preset(), Constants::HEALTH.c_str()) == 0)
{
this->clear_custom_preset_();
}
#else
else if (this->custom_preset == Constants::HEALTH)
{
// AC_HEALTH_OFF
// только в том случае, если до этого пресет был установлен
this->custom_preset = (std::string) "";
}
#endif
_debugMsg(F("Climate HEALTH preset: %i"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, _current_ac_state.health);
@@ -2689,14 +2757,25 @@ namespace esphome
if (_current_ac_state.clean == AC_CLEAN_ON &&
_current_ac_state.power == AC_POWER_OFF)
{
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
this->set_custom_preset_(Constants::CLEAN.c_str());
#else
this->custom_preset = Constants::CLEAN;
#endif
}
// AC_CLEAN_OFF
// только в том случае, если до этого пресет был установлен
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
else if (this->has_custom_preset() && strcmp(this->get_custom_preset(), Constants::CLEAN.c_str()) == 0)
{
this->clear_custom_preset_();
}
#else
else if (this->custom_preset == Constants::CLEAN)
{
// AC_CLEAN_OFF
// только в том случае, если до этого пресет был установлен
this->custom_preset = (std::string) "";
}
#endif
_debugMsg(F("Climate CLEAN preset: %i"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, _current_ac_state.clean);
@@ -2719,43 +2798,50 @@ namespace esphome
switch (_current_ac_state.mildew)
{
case AC_MILDEW_ON:
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
this->set_custom_preset_(Constants::ANTIFUNGUS.c_str());
#else
this->custom_preset = Constants::ANTIFUNGUS;
#endif
break;
case AC_MILDEW_OFF:
default:
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
if (this->has_custom_preset() && strcmp(this->get_custom_preset(), Constants::ANTIFUNGUS.c_str()) == 0)
{
this->clear_custom_preset_();
}
#else
if (this->custom_preset == Constants::ANTIFUNGUS)
this->custom_preset = (std::string) "";
break;
#endif
}
_debugMsg(F("Climate ANTIFUNGUS preset: %i"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, _current_ac_state.mildew);
/*************************** LOUVERs ***************************/
this->swing_mode = climate::CLIMATE_SWING_OFF;
if (_current_ac_state.power == AC_POWER_ON)
{
if (_current_ac_state.louver.louver_h == AC_LOUVERH_SWING_LEFTRIGHT && _current_ac_state.louver.louver_v == AC_LOUVERV_OFF)
{
this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
}
else if (_current_ac_state.louver.louver_h == AC_LOUVERH_OFF_AUX && _current_ac_state.louver.louver_v == AC_LOUVERV_SWING_UPDOWN)
{
// TODO: КОСТЫЛЬ!
this->swing_mode = climate::CLIMATE_SWING_VERTICAL;
}
else if (_current_ac_state.louver.louver_h == AC_LOUVERH_OFF_ALTERNATIVE && _current_ac_state.louver.louver_v == AC_LOUVERV_SWING_UPDOWN)
{
// TODO: КОСТЫЛЬ!
// временно сделал так. Сделать нормально - это надо подумать.
// На AUX и многих других марках выключенный режим горизонтальных жалюзи равен 0x20, а на ROVEX и Royal Clima 0xE0
// Из-за этого происходил сброс на OFF во фронтенде Home Assistant. Пришлось городить это.
// Надо как-то изящнее решить эту историю
this->swing_mode = climate::CLIMATE_SWING_VERTICAL;
}
else if (_current_ac_state.louver.louver_h == AC_LOUVERH_SWING_LEFTRIGHT && _current_ac_state.louver.louver_v == AC_LOUVERV_SWING_UPDOWN)
{
if (_current_ac_state.power == AC_POWER_ON) {
const uint8_t h = _current_ac_state.louver.louver_h;
const uint8_t v = _current_ac_state.louver.louver_v;
const bool hSwing = is_h_swing(h);
const bool hOff = is_h_off(h);
const bool vSwing = is_v_swing(v);
if (hSwing && vSwing) {
this->swing_mode = climate::CLIMATE_SWING_BOTH;
} else if (hSwing) {
// Horizontal swings even if vertical is fixed to a position
this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
} else if (vSwing && hOff) {
// Vertical swings while horizontal is not swinging
this->swing_mode = climate::CLIMATE_SWING_VERTICAL;
} else {
this->swing_mode = climate::CLIMATE_SWING_OFF;
}
}
@@ -2816,10 +2902,17 @@ namespace esphome
{
state_str += "SLEEP";
}
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
else if (this->has_custom_preset())
{
state_str += this->get_custom_preset();
}
#else
else if (this->custom_preset.has_value() && this->custom_preset.value().length() > 0)
{
state_str += this->custom_preset.value().c_str();
}
#endif
else
{
state_str += "NONE";
@@ -2839,11 +2932,11 @@ namespace esphome
{
ESP_LOGCONFIG(TAG, "AUX HVAC:");
ESP_LOGCONFIG(TAG, " [x] Firmware version: %s", Constants::AC_FIRMWARE_VERSION.c_str());
ESP_LOGCONFIG(TAG, " [x] Period: %dms", this->get_period());
ESP_LOGCONFIG(TAG, " [x] Period: %" PRIu32 "ms", this->get_period());
ESP_LOGCONFIG(TAG, " [x] Show action: %s", TRUEFALSE(this->get_show_action()));
ESP_LOGCONFIG(TAG, " [x] Display inverted: %s", TRUEFALSE(this->get_display_inverted()));
ESP_LOGCONFIG(TAG, " [x] Optimistic: %s", TRUEFALSE(this->get_optimistic()));
ESP_LOGCONFIG(TAG, " [x] Packet timeout: %dms", this->get_packet_timeout());
ESP_LOGCONFIG(TAG, " [x] Packet timeout: %" PRIu32 "ms", this->get_packet_timeout());
#if defined(PRESETS_SAVING)
ESP_LOGCONFIG(TAG, " [x] Save settings %s", TRUEFALSE(this->get_store_settings()));
@@ -3009,6 +3102,32 @@ namespace esphome
break;
}
}
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
else if (call.has_custom_fan_mode())
{
const char *customfanmode = call.get_custom_fan_mode();
if (strcmp(customfanmode, Constants::TURBO.c_str()) == 0)
{
// TURBO fan mode is suitable in COOL and HEAT modes.
// Other modes don't accept TURBO fan mode.
hasCommand = true;
cmd.fanTurbo = AC_FANTURBO_ON;
cmd.fanMute = AC_FANMUTE_OFF;
this->set_custom_fan_mode_(customfanmode);
}
else if (strcmp(customfanmode, Constants::MUTE.c_str()) == 0)
{
// MUTE fan mode is suitable in FAN mode only for Rovex air conditioner.
// In COOL mode AC receives command without any changes.
// May be other AUX-based air conditioners do the same.
hasCommand = true;
cmd.fanMute = AC_FANMUTE_ON;
cmd.fanTurbo = AC_FANTURBO_OFF;
this->set_custom_fan_mode_(customfanmode);
}
}
#else
else if (call.get_custom_fan_mode().has_value())
{
std::string customfanmode = *call.get_custom_fan_mode();
@@ -3050,6 +3169,7 @@ namespace esphome
//}
}
}
#endif
// Пользователь выбрал пресет
if (call.get_preset().has_value())
@@ -3100,6 +3220,80 @@ namespace esphome
break;
}
}
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
else if (call.has_custom_preset())
{
const char *custom_preset = call.get_custom_preset();
if (strcmp(custom_preset, Constants::CLEAN.c_str()) == 0)
{
// режим очистки кондиционера, включается (или должен включаться) при AC_POWER_OFF
// TODO: надо отдебажить выключение этого режима
if (cmd.power == AC_POWER_OFF or _current_ac_state.power == AC_POWER_OFF)
{
hasCommand = true;
cmd.clean = AC_CLEAN_ON;
cmd.mildew = AC_MILDEW_OFF;
this->set_custom_preset_(custom_preset);
}
else
{
_debugMsg(F("CLEAN preset is suitable in POWER_OFF mode only."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
}
}
else if (strcmp(custom_preset, Constants::HEALTH.c_str()) == 0)
{
if (cmd.power == AC_POWER_ON ||
_current_ac_state.power == AC_POWER_ON)
{
hasCommand = true;
cmd.health = AC_HEALTH_ON;
cmd.fanTurbo = AC_FANTURBO_OFF;
cmd.fanMute = AC_FANMUTE_OFF;
cmd.sleep = AC_SLEEP_OFF;
if (cmd.mode == AC_MODE_COOL ||
cmd.mode == AC_MODE_HEAT ||
cmd.mode == AC_MODE_AUTO ||
_current_ac_state.mode == AC_MODE_COOL ||
_current_ac_state.mode == AC_MODE_HEAT ||
_current_ac_state.mode == AC_MODE_AUTO)
{
cmd.fanSpeed = AC_FANSPEED_AUTO; // зависимость от health
}
else if (cmd.mode == AC_MODE_FAN ||
_current_ac_state.mode == AC_MODE_FAN)
{
cmd.fanSpeed = AC_FANSPEED_MEDIUM; // зависимость от health
}
this->set_custom_preset_(custom_preset);
}
else
{
_debugMsg(F("HEALTH preset is suitable in POWER_ON mode only."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
}
}
else if (strcmp(custom_preset, Constants::ANTIFUNGUS.c_str()) == 0)
{
// включение-выключение функции "Антиплесень".
// По факту: после выключения сплита он оставляет минут на 5 открытые жалюзи и глушит вентилятор.
// Уличный блок при этом гудит и тарахтит. Возможно, прогревается теплообменник для высыхания.
// Через некоторое время внешний блок замолкает и сплит закрывает жалюзи.
// Brokly:
// включение-выключение функции "Антиплесень".
// у меня пульт отправляет 5 посылок и на включение и на выключение, но реагирует на эту кнопку
// только в режиме POWER_OFF
// TODO: надо уточнить, в каких режимах штатно включается этот режим у кондиционера
cmd.mildew = AC_MILDEW_ON;
cmd.clean = AC_CLEAN_OFF; // для логики пресетов
hasCommand = true;
this->set_custom_preset_(custom_preset);
}
}
#else
else if (call.get_custom_preset().has_value())
{
std::string custom_preset = *call.get_custom_preset();
@@ -3173,6 +3367,7 @@ namespace esphome
this->custom_preset = custom_preset;
}
}
#endif
// User requested swing_mode change
if (call.get_swing_mode().has_value())
@@ -3186,8 +3381,16 @@ namespace esphome
// But the ROVEX IR-remote does not provide this features. Therefore this features haven't been tested.
// May be suitable for other models of AUX-based ACs.
case climate::CLIMATE_SWING_OFF:
// Stop BOTH axes, but don't disturb vertical if it was already fixed (2..6)
cmd.louver.louver_h = AC_LOUVERH_OFF_ALTERNATIVE;
cmd.louver.louver_v = AC_LOUVERV_OFF;
if (_current_ac_state.louver.louver_v == AC_LOUVERV_SWING_UPDOWN) {
// If vertical was swinging, stop it.
cmd.louver.louver_v = AC_LOUVERV_OFF;
} else {
// Keep existing fixed position (2..6).
cmd.louver.louver_v = _current_ac_state.louver.louver_v;
}
hasCommand = true;
this->swing_mode = swingmode;
break;
@@ -3208,7 +3411,12 @@ namespace esphome
case climate::CLIMATE_SWING_HORIZONTAL:
cmd.louver.louver_h = AC_LOUVERH_SWING_LEFTRIGHT;
cmd.louver.louver_v = AC_LOUVERV_OFF;
// Stop vertical only if it was swinging; otherwise preserve prior fixed position
if (_current_ac_state.louver.louver_v == AC_LOUVERV_SWING_UPDOWN) {
cmd.louver.louver_v = AC_LOUVERV_OFF;
} else {
cmd.louver.louver_v = _current_ac_state.louver.louver_v;
}
hasCommand = true;
this->swing_mode = swingmode;
break;
@@ -3545,7 +3753,7 @@ namespace esphome
}
// устанавливает ограничение мощности сплита на нужный уровень
bool powerLimitationSetSequence(uint8_t power_limit, bool set_on=false)
bool powerLimitationSetSequence(uint8_t power_limit, bool set_on = false)
{
// нет смысла в последовательности, если нет коннекта с кондиционером
if (!get_has_connection())
@@ -3560,12 +3768,12 @@ namespace esphome
return false;
}
if(power_limit != this->_power_limitation_value_normalise(power_limit))
if (power_limit != this->_power_limitation_value_normalise(power_limit))
{
_debugMsg(F("powerLimitationSetSequence: incorrect power limit value."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
return false;
}
// формируем команду
ac_command_t cmd;
_clearCommand(&cmd); // не забываем очищать, а то будет мусор
@@ -3577,12 +3785,14 @@ namespace esphome
// добавляем команду в последовательность
if (!commandSequence(&cmd))
return false;
if (set_on)
{
_debugMsg(F("powerLimitationSetSequence: loaded (state = %02X, power limit = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, cmd.power_lim_state, power_limit);
} else {
_debugMsg(F("powerLimitationSetSequence: loaded (power limit = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, power_limit);
_debugMsg(F("powerLimitationSetSequence: loaded (state = %02X, power limit = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, cmd.power_lim_state, power_limit);
}
else
{
_debugMsg(F("powerLimitationSetSequence: loaded (power limit = %02X)"), ESPHOME_LOG_LEVEL_VERBOSE, __LINE__, power_limit);
}
return true;
}
@@ -3602,14 +3812,17 @@ namespace esphome
_debugMsg(F("powerLimitationOnSequence: unsupported for noninverter AC."), ESPHOME_LOG_LEVEL_WARN, __LINE__);
return false; // если кондиционер не инверторный, то выходим
}
// формируем команду
ac_command_t cmd;
_clearCommand(&cmd); // не забываем очищать, а то будет мусор
if(enable_limit){
cmd.power_lim_state = AC_POWLIMSTAT_ON; // включить ограничение мощности
} else {
cmd.power_lim_state = AC_POWLIMSTAT_OFF; // отключить ограничение мощности
if (enable_limit)
{
cmd.power_lim_state = AC_POWLIMSTAT_ON; // включить ограничение мощности
}
else
{
cmd.power_lim_state = AC_POWLIMSTAT_OFF; // отключить ограничение мощности
}
// добавляем команду в последовательность
if (!commandSequence(&cmd))
@@ -3622,19 +3835,19 @@ namespace esphome
// включает ограничение мощности сплита
bool powerLimitationOnSequence()
{
return powerLimitationOnOffSequence(true);
return powerLimitationOnOffSequence(true);
}
// включает ограничение мощности сплита на нужный уровень
bool powerLimitationOnSequence(uint8_t power_limit)
{
return powerLimitationSetSequence(power_limit, true);
return powerLimitationSetSequence(power_limit, true);
}
// выключает ограничение мощности сплита
bool powerLimitationOffSequence()
{
return powerLimitationOnOffSequence(false);
return powerLimitationOnOffSequence(false);
}
// конвертирует состояние жалюзи из кодов сплита в коды для фронтенда
@@ -3771,7 +3984,13 @@ namespace esphome
void set_optimistic(bool optimistic) { this->_optimistic = optimistic; }
bool get_optimistic() { return this->_optimistic; }
// возможно функции get и не нужны, но вроде как должны быть
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
void set_supported_modes(ClimateModeMask modes) { this->_supported_modes = modes; }
void set_supported_swing_modes(ClimateSwingModeMask modes) { this->_supported_swing_modes = modes; }
void set_supported_presets(ClimatePresetMask presets) { this->_supported_presets = presets; }
void set_custom_presets(std::initializer_list<const char *> presets) { this->_supported_custom_presets = presets; }
void set_custom_fan_modes(std::initializer_list<const char *> modes) { this->_supported_custom_fan_modes = modes; }
#else
void set_supported_modes(const std::set<ClimateMode> &modes) { this->_supported_modes = modes; }
std::set<ClimateMode> get_supported_modes() { return this->_supported_modes; }
@@ -3786,6 +4005,7 @@ namespace esphome
void set_custom_fan_modes(const std::set<std::string> &modes) { this->_supported_custom_fan_modes = modes; }
const std::set<std::string> &get_supported_custom_fan_modes() { return this->_supported_custom_fan_modes; }
#endif
#if defined(PRESETS_SAVING)
void set_store_settings(bool store_settings) { this->_store_settings = store_settings; }
@@ -3803,8 +4023,13 @@ namespace esphome
// заполнение шаблона параметров отображения виджета
// GK: всё же похоже правильнее это делать тут, а не в initAC()
// initAC() в формируемом питоном коде вызывается до вызова aux_ac.set_supported_***() с установленными пользователем в конфиге параметрами
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
_traits.add_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE);
_traits.add_feature_flags(climate::CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE);
#else
_traits.set_supports_current_temperature(true);
_traits.set_supports_two_point_target_temperature(false); // if the climate device's target temperature should be split in target_temperature_low and target_temperature_high instead of just the single target_temperature
#endif
_traits.set_supported_modes(this->_supported_modes);
_traits.set_supported_swing_modes(this->_supported_swing_modes);
@@ -3833,7 +4058,14 @@ namespace esphome
//_traits.add_supported_preset(ClimatePreset::CLIMATE_PRESET_SLEEP);
// if the climate device supports reporting the active current action of the device with the action property.
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
if (this->_show_action)
{
_traits.add_feature_flags(climate::CLIMATE_SUPPORTS_ACTION);
}
#else
_traits.set_supports_action(this->_show_action);
#endif
};
void loop() override
@@ -3889,4 +4121,4 @@ namespace esphome
};
} // namespace aux_ac
} // namespace esphome
} // namespace esphome

View File

@@ -26,6 +26,7 @@ from esphome.const import (
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_POWER_FACTOR,
STATE_CLASS_MEASUREMENT,
__version__
)
from esphome.components.climate import (
ClimateMode,
@@ -33,7 +34,7 @@ from esphome.components.climate import (
ClimateSwingMode,
)
AUX_AC_FIRMWARE_VERSION = '0.2.15'
AUX_AC_FIRMWARE_VERSION = '0.3.1'
AC_PACKET_TIMEOUT_MIN = 150
AC_PACKET_TIMEOUT_MAX = 600
AC_POWER_LIMIT_MIN = 30
@@ -127,6 +128,12 @@ AirConPowerLimitationOnAction = aux_ac_ns.class_(
)
def use_new_api():
esphome_current_version = tuple(map(int, __version__.split('.')))
esphome_bc_version = tuple(map(int, "2025.11.0".split('.')))
return esphome_current_version >= esphome_bc_version
def validate_packet_timeout(value):
minV = AC_PACKET_TIMEOUT_MIN
maxV = AC_PACKET_TIMEOUT_MAX
@@ -190,7 +197,7 @@ def output_info(config):
CONFIG_SCHEMA = cv.All(
climate.CLIMATE_SCHEMA.extend(
climate.climate_schema(climate.Climate).extend(
{
cv.GenerateID(): cv.declare_id(AirCon),
cv.Optional(CONF_PERIOD, default="7s"): cv.time_period,
@@ -426,10 +433,20 @@ async def to_code(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]))
if use_new_api():
if CONF_CUSTOM_PRESETS in config:
presets = config[CONF_CUSTOM_PRESETS]
c_str_presets = [cg.RawExpression(f"aux_ac::Constants::{p}.c_str()") for p in presets]
cg.add(var.set_custom_presets(c_str_presets))
if CONF_CUSTOM_FAN_MODES in config:
fan_modes = config[CONF_CUSTOM_FAN_MODES]
c_str_fan_modes = [cg.RawExpression(f"aux_ac::Constants::{p}.c_str()") for p in fan_modes]
cg.add(var.set_custom_fan_modes(c_str_fan_modes))
else:
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]))
DISPLAY_ACTION_SCHEMA = maybe_simple_id(

View File

@@ -2,29 +2,44 @@
`Aux_ac` has been tested and works successfully with the air conditioners from the list below.<br/>
Кондиционеры из списка ниже протестированы и точно совместимы с `aux_ac`.
+ ANDE (models: AND-12/FA+, AND-AMWM-H12(JA) / AND-AM2-H18/4DR3)
+ Argo (models: Greenstyle 9000, Greenstyle 12000, Greenstyle 18000)
+ AUX (models: ALMD-H48/5DR2 / AL-H48/5DR2(U), AMWM-H07/4R1 multisplit, AMWM-H12/4R3 multisplit, ASM-H12LL, ASM-H24LD, ASW-H07A4/DE-R1DI, ASW-H07A4/FP-R1DI, ASW-H09A4/FP-R1DI, ASW-H12A4/HA-R2DI, ASW-H09A4/LK-700R1, ASW-H09A4/LK-700R1DI, ASW-H12B4/JD-R2DI, ASW-H12A4/FAR1, ASW-H09B4/LK-700R1, ASW-H12C5C4/JOR3DI-B8, ASW-H12U3/JIR1DI-US, AUX-18QC/I / AUX-18QC/O, AWM-09G1V4-X, KFR-26GW/BpHRB+3, KFR-26GW/BpQYA2+2R3, KFR-26GW/BpQYD2+2R3, KFR-26GW/BpR3QYA1+1, KFR-26GW/BpR3QYD1+1, KFR-26GW/BpR3QYQ1+1, KFR-26GW/BpR3QYQ2+2, KFR-35GW/BpQYA1+1R3, KFR-35GW/BpQYA2+2R3, KFR-35GW/BpQYD1+1R3, KFR-35GW/BpQYD2+2R3, KFR-35GW/BpR3QYQ1+1, KFR-35GW/BpR3QYQ2+2 (see [issue #71](https://github.com/GrKoR/esphome_aux_ac_component/issues/71) for detais of `Aegean Sea`[爱琴海] AUX family AC connection)
+ Ballu (models: BLC_CF-60HN1, BSUI-09HN8, BSUI-12HN8, BSUI-18HN8, BSW-09HN1, BSW-12HN1)
+ Centek (models: CT-65A12, CT-65EDC07, CT-65F09, CT-65F12, CT-65FDC09, CT-65J09, CT-65J12, CT-65Q09, CT-65Q12, CT-65U13, CT-65V24, CT-65Z10, CT-65Z18)
+ Arielli (models: ASW-H09B4/FGR3DI-EU)
+ AUX (models: ALLD-H18/4R1C / AL-H18/4R1C(U), ALMD-H48/5DR2 / AL-H48/5DR2(U), ALMD-H24/4DR2A / AL-H24/4DR2A(U), AMWM-H07/4R1 multisplit, AMWM-H07/4R2(J) multisplit, AMWM-H12/4R2(J) multisplit, AMWM-H12/4R3 multisplit, ASM-H12LL, ASM-H24LD, ASW-12A3INV/SS, ASW-H07A4/DE-R1DI, ASW-H07A4/FP-R1DI, ASW-H07A4/JD-R1, ASW-H09A4/FP-R1DI, ASW-H09A4/LK-700R1, ASW-H09A4/LK-700R1DI, ASW-H09B4/LK-700R1, ASW-H09B7A4, ASW-H12A4/FAR1, ASW-H12A4/HA-R2DI, ASW-H12A4/JD-R2DI, ASW-H12B4/JD-R2DI, ASW-H12C5C4/JER3DI-B8-2, ASW-H12C5C4/JOR3DI-B8, ASW-H12U3/JIR1DI-US, ASW-H18A4/QH-R1DI / AS-H18A4/QH-R1DI, ASW-H18E3A4, AUX-07JO/I / AUX-M3-21LCLH multisplit, AUX-09CAA/I / ASW-H09A4/CAR3DI-C3, AUX-12JO/I / AUX-M3-21LCLH multisplit, AUX-12F3H, AUX-18QC/I / AUX-18QC/O, AWM-09G1V4-X, HA-18000BTU, KFR-26GW/BpHRB+3, KFR-26GW/BpQYA2+2R3, KFR-26GW/BpQYD2+2R3, KFR-26GW/BpR3QYA1+1, KFR-26GW/BpR3QYD1+1, KFR-26GW/BpR3QYQ1+1, KFR-26GW/BpR3QYQ2+2, KFR-35GW/BpQYA1+1R3, KFR-35GW/BpQYA2+2R3, KFR-35GW/BpQYD1+1R3, KFR-35GW/BpQYD2+2R3, KFR-35GW/BpR3QYQ1+1, KFR-35GW/BpR3QYQ2+2 (see [issue #71](https://github.com/GrKoR/esphome_aux_ac_component/issues/71) for detais of `Aegean Sea`[爱琴海] AUX family AC connection)
+ Ballu (models: BLC_CF/in-60HN1 / BLC_O/out-60HN1, Orbis BPAC-08 OR/N6, BSUI/in-09HN8 / BSUI/out-09HN8, BSUI/in-12HN8 / BSUI/out-12HN8, BSUI/in-18HN8 / BSUI/out-18HN8, BSW/in-09HN1 / BSW/out-09HN1, BSW/in-12HN1 / BSW/out-12HN1, BSW/in-18HN1 / BSW/out-18HN1)
+ Baymak (models: Elegant Plus 9, Elegant Plus 12)
+ Centek (models: CT-65A09, CT-65A12, CT-65EDC07, CT-65F09, CT-65F12, CT-65FDC07, CT-65FDC09, CT-65J09, CT-65J12, CT-65J24, CT-65K07, CT-65Q09, CT-65Q12, CT-65RDC07, CT-65RDC09, CT-65RDC12, CT-65SDC07, CT-65SDC09, CT-65SDC18, CT-65U13, CT-65U18, CT-65V12, CT-65V24, CT-65X12, CT-65Z10, CT-65Z18)
+ Costway (models: FP10318US-22WH, FP10524US-22WH)
+ Dimstal (model: SMND-QC-12-J-Smart ECO)
+ Elgin (models: HWFI09B2IA/ HWFE09B2NA)
+ Energolux (models: SAS07L2-A, SAS07L4-A, SAS07M2-AI, SAS09B3-A, SAS09L4-A, SAS09Z4-AI, SAS12BN1-AI, SAS12CH1-AI, SAS12Z3-AI)
+ Electrolux (models: EACS/I-07HSK/N3, EACS/I-09HIX-BLACK/N8)
+ Elgin (models: HIFI09C2WA / HIFE09C2CA, HJFI12C2WB, HWFI09B2IA / HWFE09B2NA, HWFI30B2IA / HWFE30B2NA)
+ Energolux (models: SAS07L2-A, SAS07L4-A, SAS07M2-AI, SAS09B3-A, SAS09L4-A, SAS09Z4-AI, SAS12BN1-AI, SAS09Z4-AI, SAS18Z4-AI)
+ Fujico (models: ACF-I07AHRDN1)
+ Hyundai (models: H-AR16-07H, H-AR21-07H, H-AR21-09H)
+ iClima (models: ICI-09A/IUI-09A)
+ Idea (models: ISR-12HR-SA7-DN1 ION)
+ IGC (models: RAK-07NH multysplit, RAS-07AX/RAC-07AX, RAS-V09N2X/RAC-V09N2X)
+ Ishimatsu (models: AVK-09I)
+ IGC (models: RAK-07NH multysplit, RAS-07AX/RAC-07AX, RAS-V09N2X/RAC-V09N2X, RAS-V12NQR/RAC-V12NQR)
+ IKON (models: ASW-H12C5C4/HCR3DI-B8)
+ Ishimatsu (models: AVK-07I, AVK-09I)
+ Loriot (models: LAC-09AS)
+ Mirage (models: EWC121E - CWC121E)
+ Osaka (models: STVP-12HH3)
+ RCool (models: GRA12B0-KSZKLM641)
+ Rinnai (models: RINV25RC)
+ Roda (models: RS-AL09F, RS-AL24F)
+ Rovex (models: RS-07ALS1, RS-09ALS1, RS-12ALS1)
+ Royal Clima (models: CO-D 18HNI/CO-E 18HNI, RC-VNR29HN, RCI-SA30HN)
+ Royal Clima (models: CO-D 18HNI/CO-E 18HNI, CO-D 24HNI/CO-E 24HNI, RC-VNR29HN, RC-RNC28HN, RCI-SA30HN)
+ RVX (models: RS-12ALS)
+ Samurai (models: SMA-07HRN1 ION, SMA-09HRN1 ION)
+ Subtropic (models: SUB-07HN1, SUB-09HN1, SUB-12HN1)
+ Scarlett (models: RRI-09-MPI)
+ SEVRA (models: SEV-09JO)
+ Subtropic (models: SUB/in-07HN1 / SUB/out-07HN1, SUB/in-09HN1 / SUB/out-09HN1, SUB/in-12HN1 / SUB/out-12HN1)
+ Tesla (models: TA35FFML-12410M)
+ Tornado (models: ISKA-INV-12 X WIFI EU)
+ TOYOTOMI (models: SONZAI THN/THG-A35SZ)
+ VOX (models: IVA5-12JR1, IJO09-SC4D)
+ Vertex (models: Falcon-18A)
+ VORTEX (models: VAI-A 1219F JMRV)
+ VOX (models: IJO09-SC4D, IVA5-12JR1)
+ Xigma (models: XG-SJ56RHA-IDU)
+ Zephir (models: ZEL 12000BTU)
+ Бирюса (models: B-07DPR/B-07DPQ, B-09FIR/B-09FIQ)

View File

@@ -7,7 +7,8 @@ external_components:
esphome:
name: $devicename
platform: ESP8266
esp8266:
board: esp12e
wifi:
@@ -36,7 +37,8 @@ api:
password: !secret api_pass
ota:
password: !secret ota_pass
- platform: esphome
password: !secret ota_pass
web_server:
port: 80

View File

@@ -5,7 +5,8 @@ external_components:
esphome:
name: aux_air_conditioner
platform: ESP8266
esp8266:
board: esp12e
# don't forget to set your's wifi settings!
@@ -30,6 +31,7 @@ logger:
api:
ota:
- platform: esphome
# UART0 configuration for AUX air conditioner communication
uart:

10
tests/.gitignore vendored
View File

@@ -1,10 +0,0 @@
# Gitignore settings for ESPHome
# This is an example and may include too much for your use-case.
# You can modify this file to suit your needs.
/.esphome/
**/.pioenvs/
**/.piolibdeps/
**/lib/
**/src/
**/platformio.ini
/secrets.yaml

View File

@@ -1,191 +0,0 @@
import time
import aioesphomeapi
import asyncio
import re
import sys
import argparse
from aioesphomeapi.api_pb2 import (LOG_LEVEL_NONE,
LOG_LEVEL_ERROR,
LOG_LEVEL_WARN,
LOG_LEVEL_INFO,
LOG_LEVEL_DEBUG,
LOG_LEVEL_VERBOSE,
LOG_LEVEL_VERY_VERBOSE)
def createParser ():
parser = argparse.ArgumentParser(
description='''This script is used for collecting logs from ac_aux ESPHome component.
For more info, see https://github.com/GrKoR/ac_python_logger''',
add_help = False)
parent_group = parser.add_argument_group (title='Params')
parent_group.add_argument ('--help', '-h', action='help', help='show this help message and exit')
parent_group.add_argument ('-i', '--ip', nargs=1, required=True, help='IP address of the esphome device')
parent_group.add_argument ('-p', '--pwd', nargs=1, required=True, help='native API password for the esphome device')
return parser
async def main():
"""Connect to an ESPHome device and wait for state changes."""
api = aioesphomeapi.APIClient(namespace.ip[0], 6053, namespace.pwd[0])
try:
await api.connect(login=True)
except aioesphomeapi.InvalidAuthAPIError as e:
return print(e)
print(api.api_version)
async def display_off():
await api.execute_service(
service,
data={
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x01, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x97, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x00],
}
)
async def display_on():
await api.execute_service(
service,
data={
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x01, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x97, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00],
}
)
async def ac_enable():
await api.execute_service(
service,
data={
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x00, 0x87, 0xE0, 0x2F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00],
}
)
async def ac_disable():
await api.execute_service(
service,
data={
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x00, 0x87, 0xE0, 0x2F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
}
)
async def ac_get11_01():
await api.execute_service(
service,
data={
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x02, 0x00, 0x11, 0x01],
}
)
async def ac_get11_00():
await api.execute_service(
service,
data={
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x02, 0x00, 0x11, 0x00],
}
)
async def ac_set_vlouver(lvr):
await api.execute_service(
service,
data={
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x01, lvr, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00],
}
)
async def ac_set_hlouver(lvr):
await api.execute_service(
service,
data={
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x97, lvr, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00],
}
)
# key надо искать в выводе list_entities_services
service = aioesphomeapi.UserService(
name="send_data",
key=311254518,
args=[
aioesphomeapi.UserServiceArg(name="data_buf", type=aioesphomeapi.UserServiceArgType.INT_ARRAY),
],
)
time.sleep(7)
await ac_get11_00()
time.sleep(7)
await ac_get11_01()
#await ac_set_vlouver( 0b10010000 ) # swing on
#await ac_set_vlouver( 0b10010111 ) # swing off
#await ac_set_vlouver( 0b10010001 ) # 1
#await ac_set_vlouver( 0b10010010 ) # 2
#await ac_set_vlouver( 0b10010011 ) # 3
#await ac_set_vlouver( 0b10010100 ) # 4
#await ac_set_vlouver( 0b10010101 ) # 5
#await ac_set_vlouver( 0b10010110 ) # не работает, сбрасывает на swing on
#time.sleep(5)
#await ac_set_hlouver( 0b00000000 ) # swing on
#await ac_set_hlouver( 0b11100000 ) # swing off
#await ac_set_hlouver( 0b00100000 ) # не работает, сбрасывает в swing off
#await ac_set_hlouver( 0b01000000 ) # не работает, сбрасывает в swing off
#await ac_set_hlouver( 0b01100000 ) # не работает, сбрасывает в swing off
#await ac_set_hlouver( 0b10000000 ) # не работает, сбрасывает в swing off
#await ac_set_hlouver( 0b10100000 ) # не работает, сбрасывает в swing off
#await ac_set_hlouver( 0b11000000 ) # не работает, сбрасывает в swing off
#time.sleep(5)
async def test_byte(bt):
await api.execute_service(
service,
data={
#display on
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x97, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00],
#display off
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x97, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x00],
# swing on
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x90, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00],
# swing off
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#"data_buf": [0xBB, 0x00, 0x06, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x01, 0x97, 0xE0, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00],
}
)
'''
не проходит команда, если байт 1 или 7 не 0x00
не проходит команда, если байт 3 не 0x80
проходит и не меняется, если меняю байт 4 или 5
'''
#await test_byte(0b10000110)
#await test_byte(0b01000110)
#await test_byte(0b00100110)
#await test_byte(0b00010110)
time.sleep(2)
parser = createParser()
namespace = parser.parse_args()
print("IP: ", namespace.ip[0])
loop = asyncio.get_event_loop()
try:
#asyncio.ensure_future(main())
#loop.run_forever()
loop.run_until_complete(main())
except aioesphomeapi.InvalidAuthAPIError as e:
print(e)
except KeyboardInterrupt:
pass
finally:
loop.close()
pass

View File

@@ -1,121 +0,0 @@
external_components:
- source: github://GrKoR/esphome_aux_ac_component@dev
components: [ aux_ac ]
refresh: 0s
substitutions:
devicename: test_aux_ac_ext_esp32
upper_devicename: Test AUX
esphome:
name: $devicename
platform: ESP32
board: nodemcu-32s
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_pass
manual_ip:
static_ip: 192.168.0.151 # Для примера
gateway: !secret wifi_gateway
subnet: !secret wifi_subnet
dns1: 8.8.8.8
dns2: 1.1.1.1
reboot_timeout: 0s
ap:
ssid: Test AUX Fallback Hotspot
password: !secret wifi_ap_pass
logger:
level: DEBUG
baud_rate: 0
api:
password: !secret api_pass
reboot_timeout: 0s
ota:
password: !secret ota_pass
uart:
id: ac_uart_bus
#tx_pin: GPIO1
#rx_pin: GPIO3
tx_pin: TX
rx_pin: RX
baud_rate: 4800
data_bits: 8
parity: EVEN
stop_bits: 1
sensor:
- platform: uptime
name: Uptime Sensor
climate:
- platform: aux_ac
name: $upper_devicename
id: aux_id
uart_id: ac_uart_bus
period: 7s
show_action: true
display_inverted: true
indoor_temperature:
name: $upper_devicename Indoor Temperature
id: ${devicename}_indoor_temp
internal: false
display_state:
name: $upper_devicename Display State
id: ${devicename}_display_state
internal: false
outdoor_temperature:
name: $upper_devicename Outdoor Temperature
id: ${devicename}_outdoor_temp
internal: false
outbound_temperature:
name: $upper_devicename Coolant Outbound Temperature
id: ${devicename}_outbound_temp
internal: false
inbound_temperature:
name: $upper_devicename Coolant Inbound Temperature
id: ${devicename}_inbound_temp
internal: false
compressor_temperature:
name: $upper_devicename Compressor Temperature
id: ${devicename}_strange_temp
internal: false
defrost_state:
name: $upper_devicename Defrost State
id: ${devicename}_defrost_state
internal: false
inverter_power:
name: $upper_devicename Invertor Power
id: ${devicename}_invertor_power
internal: false
preset_reporter:
name: $upper_devicename Preset Reporter
id: ${devicename}_preset_reporter
internal: false
visual:
min_temperature: 16
max_temperature: 32
temperature_step: 0.5
supported_modes:
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
custom_fan_modes:
- MUTE
- TURBO
supported_presets:
- SLEEP
custom_presets:
- CLEAN
- HEALTH
- ANTIFUNGUS
supported_swing_modes:
- VERTICAL
- HORIZONTAL
- BOTH

View File

@@ -1,156 +0,0 @@
external_components:
- source: github://GrKoR/esphome_aux_ac_component@dev
components: [ aux_ac ]
refresh: 0s
substitutions:
devicename: test_aux_ac_ext_engeneer
upper_devicename: Test AUX
esphome:
name: $devicename
platform: ESP8266
board: esp12e
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_pass
manual_ip:
static_ip: !secret wifi_ip
gateway: !secret wifi_gateway
subnet: !secret wifi_subnet
dns1: 8.8.8.8
dns2: 1.1.1.1
reboot_timeout: 0s
ap:
ssid: Test AUX Fallback Hotspot
password: !secret wifi_ap_pass
logger:
level: DEBUG
baud_rate: 0
api:
password: !secret api_pass
reboot_timeout: 0s
services:
# этот сервис можно вызвать из Home Assistant или Python. Он отправляет полученные байты в кондиционер
- service: send_data
variables:
data_buf: int[]
then:
# ВАЖНО! Только для инженеров!
# Вызывайте метод aux_ac.send_packet только если понимаете, что делаете! Он не проверяет данные, а передаёт
# кондиционеру всё как есть. Какой эффект получится от передачи кондиционеру рандомных байт, никто не знает.
# Вы действуете на свой страх и риск.
- aux_ac.send_packet:
id: aux_id
data: !lambda |-
std::vector<uint8_t> data{};
for (int n : data_buf) {
data.push_back( (uint8_t) n );
}
return data;
ota:
password: !secret ota_pass
web_server:
port: 80
uart:
id: ac_uart_bus
tx_pin: GPIO1
rx_pin: GPIO3
baud_rate: 4800
data_bits: 8
parity: EVEN
stop_bits: 1
sensor:
- platform: uptime
name: Uptime Sensor
climate:
- platform: aux_ac
name: $upper_devicename
id: aux_id
uart_id: ac_uart_bus
period: 7s
show_action: true
display_inverted: true
optimistic: true
indoor_temperature:
name: $upper_devicename Indoor Temperature
id: ${devicename}_indoor_temp
internal: false
display_state:
name: $upper_devicename Display State
id: ${devicename}_display_state
internal: false
outdoor_temperature:
name: $upper_devicename Outdoor Temperature
id: ${devicename}_outdoor_temp
internal: false
outbound_temperature:
name: $upper_devicename Coolant Outbound Temperature
id: ${devicename}_outbound_temp
internal: false
inbound_temperature:
name: $upper_devicename Coolant Inbound Temperature
id: ${devicename}_inbound_temp
internal: false
compressor_temperature:
name: $upper_devicename Compressor Temperature
id: ${devicename}_strange_temp
internal: false
defrost_state:
name: $upper_devicename Defrost State
id: ${devicename}_defrost_state
internal: false
inverter_power:
name: $upper_devicename Invertor Power
id: ${devicename}_invertor_power
internal: false
preset_reporter:
name: $upper_devicename Preset Reporter
id: ${devicename}_preset_reporter
internal: false
visual:
min_temperature: 16
max_temperature: 32
temperature_step: 0.5
supported_modes:
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
custom_fan_modes:
- MUTE
- TURBO
supported_presets:
- SLEEP
custom_presets:
- CLEAN
- HEALTH
- ANTIFUNGUS
supported_swing_modes:
- VERTICAL
- HORIZONTAL
- BOTH
switch:
- platform: template
name: AC Display
lambda: |-
if (id(${devicename}_display_state).state) {
return true;
} else {
return false;
}
turn_on_action:
- aux_ac.display_on: aux_id
turn_off_action:
- aux_ac.display_off: aux_id

View File

@@ -1,162 +0,0 @@
external_components:
- source: github://GrKoR/esphome_aux_ac_component@dev
components: [ aux_ac ]
refresh: 0s
substitutions:
devicename: test_ext_power_limitations
upper_devicename: Test AUX
esphome:
name: $devicename
platform: ESP8266
board: esp12e
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_pass
manual_ip:
static_ip: !secret wifi_ip
gateway: !secret wifi_gateway
subnet: !secret wifi_subnet
dns1: 8.8.8.8
dns2: 1.1.1.1
reboot_timeout: 0s
ap:
ssid: Test AUX Fallback Hotspot
password: !secret wifi_ap_pass
logger:
level: DEBUG
baud_rate: 0
api:
password: !secret api_pass
reboot_timeout: 0s
ota:
password: !secret ota_pass
web_server:
port: 80
uart:
id: ac_uart_bus
tx_pin: GPIO1
rx_pin: GPIO3
baud_rate: 4800
data_bits: 8
parity: EVEN
stop_bits: 1
sensor:
- platform: uptime
name: Uptime Sensor
climate:
- platform: aux_ac
name: $upper_devicename
id: aux_id
uart_id: ac_uart_bus
period: 7s
show_action: true
display_inverted: true
timeout: 150
indoor_temperature:
name: $upper_devicename Indoor Temperature
id: ${devicename}_indoor_temp
internal: false
display_state:
name: $upper_devicename Display State
id: ${devicename}_display_state
internal: false
outdoor_temperature:
name: $upper_devicename Outdoor Temperature
id: ${devicename}_outdoor_temp
internal: false
outbound_temperature:
name: $upper_devicename Coolant Outbound Temperature
id: ${devicename}_outbound_temp
internal: false
inbound_temperature:
name: $upper_devicename Coolant Inbound Temperature
id: ${devicename}_inbound_temp
internal: false
compressor_temperature:
name: $upper_devicename Compressor Temperature
id: ${devicename}_strange_temp
internal: false
defrost_state:
name: $upper_devicename Defrost State
id: ${devicename}_defrost_state
internal: false
inverter_power:
name: $upper_devicename Inverter Power
id: ${devicename}_invertor_power
internal: false
preset_reporter:
name: $upper_devicename Preset Reporter
id: ${devicename}_preset_reporter
internal: false
inverter_power_limit_value:
name: $upper_devicename Inverter Power Limit Value
id: ${devicename}_inverter_power_limit_value
internal: false
inverter_power_limit_state:
name: $upper_devicename Inverter Power Limit State
id: ${devicename}_inverter_power_limit_state
internal: false
visual:
min_temperature: 16
max_temperature: 32
temperature_step: 0.5
supported_modes:
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
custom_fan_modes:
- MUTE
- TURBO
supported_presets:
- SLEEP
custom_presets:
- CLEAN
- HEALTH
- ANTIFUNGUS
supported_swing_modes:
- VERTICAL
- HORIZONTAL
- BOTH
button:
- platform: template
name: ${upper_devicename} IPower Limit Off
icon: "mdi:power-plug-off-outline"
on_press:
- aux_ac.power_limit_off: aux_id
- platform: template
name: ${upper_devicename} IPower Limit On Half
icon: "mdi:fraction-one-half"
on_press:
- aux_ac.power_limit_on:
id: aux_id
limit: 50
number:
- platform: template
name: ${upper_devicename} IPower Limit Value
id: ${devicename}_ipower_limit_value
icon: "mdi:battery-unknown"
mode: "slider"
min_value: 30
max_value: 100
step: 1
set_action:
then:
- lambda: !lambda |-
id(aux_id).powerLimitationOnSequence( x );

View File

@@ -1,125 +0,0 @@
external_components:
- source:
type: local
path: ../components
substitutions:
devicename: test_local_airflow_dir
upper_devicename: Test AUX
esphome:
name: $devicename
platform: ESP8266
board: esp12e
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_pass
manual_ip:
static_ip: !secret wifi_ip
gateway: !secret wifi_gateway
subnet: !secret wifi_subnet
dns1: 8.8.8.8
dns2: 1.1.1.1
reboot_timeout: 0s
ap:
ssid: $upper_devicename Fallback Hotspot
password: !secret wifi_ap_pass
logger:
level: DEBUG
baud_rate: 0
api:
password: !secret api_pass
reboot_timeout: 0s
ota:
password: !secret ota_pass
web_server:
port: 80
uart:
id: ac_uart_bus
tx_pin: GPIO1
rx_pin: GPIO3
baud_rate: 4800
data_bits: 8
parity: EVEN
stop_bits: 1
sensor:
- platform: uptime
name: Uptime Sensor
climate:
- platform: aux_ac
name: $upper_devicename
id: aux_id
uart_id: ac_uart_bus
period: 7s
show_action: true
display_inverted: true
button:
- platform: template
name: ${upper_devicename} VLouver Stop
icon: "mdi:circle-small"
on_press:
- aux_ac.vlouver_stop: aux_id
- platform: template
name: ${upper_devicename} VLouver Swing
icon: "mdi:pan-vertical"
on_press:
- aux_ac.vlouver_swing: aux_id
- platform: template
name: ${upper_devicename} VLouver Top
icon: "mdi:pan-up"
on_press:
- aux_ac.vlouver_top: aux_id
- platform: template
name: ${upper_devicename} VLouver Middle Above
icon: "mdi:pan-top-left"
on_press:
- aux_ac.vlouver_middle_above: aux_id
- platform: template
name: ${upper_devicename} VLouver Middle
icon: "mdi:pan-left"
on_press:
- aux_ac.vlouver_middle: aux_id
- platform: template
name: ${upper_devicename} VLouver Middle Below
icon: "mdi:pan-bottom-left"
on_press:
- aux_ac.vlouver_middle_below: aux_id
- platform: template
name: ${upper_devicename} VLouver Bottom
icon: "mdi:pan-down"
on_press:
- aux_ac.vlouver_bottom: aux_id
number:
- platform: template
name: ${upper_devicename} Vertical Louver
id: ${devicename}_vlouver
icon: "mdi:circle-small"
mode: "slider"
min_value: 0
max_value: 6
step: 1
set_action:
then:
- lambda: !lambda |-
if (x == 6) x = 7; // делаем так, чтобы выключение отрабатывать корректно
id(aux_id).setVLouverSequence( static_cast<esphome::aux_ac::ac_louver_V>(x) );

View File

@@ -1,162 +0,0 @@
external_components:
- source:
type: local
path: ../components
substitutions:
devicename: test_local_power_limitations
upper_devicename: Test AUX
esphome:
name: $devicename
platform: ESP8266
board: esp12e
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_pass
manual_ip:
static_ip: !secret wifi_ip
gateway: !secret wifi_gateway
subnet: !secret wifi_subnet
dns1: 8.8.8.8
dns2: 1.1.1.1
reboot_timeout: 0s
ap:
ssid: Test AUX Fallback Hotspot
password: !secret wifi_ap_pass
logger:
level: DEBUG
baud_rate: 0
api:
password: !secret api_pass
reboot_timeout: 0s
ota:
password: !secret ota_pass
web_server:
port: 80
uart:
id: ac_uart_bus
tx_pin: GPIO1
rx_pin: GPIO3
baud_rate: 4800
data_bits: 8
parity: EVEN
stop_bits: 1
sensor:
- platform: uptime
name: Uptime Sensor
climate:
- platform: aux_ac
name: $upper_devicename
id: aux_id
uart_id: ac_uart_bus
period: 7s
show_action: true
display_inverted: true
timeout: 150
indoor_temperature:
name: $upper_devicename Indoor Temperature
id: ${devicename}_indoor_temp
internal: false
display_state:
name: $upper_devicename Display State
id: ${devicename}_display_state
internal: false
outdoor_temperature:
name: $upper_devicename Outdoor Temperature
id: ${devicename}_outdoor_temp
internal: false
outbound_temperature:
name: $upper_devicename Coolant Outbound Temperature
id: ${devicename}_outbound_temp
internal: false
inbound_temperature:
name: $upper_devicename Coolant Inbound Temperature
id: ${devicename}_inbound_temp
internal: false
compressor_temperature:
name: $upper_devicename Compressor Temperature
id: ${devicename}_strange_temp
internal: false
defrost_state:
name: $upper_devicename Defrost State
id: ${devicename}_defrost_state
internal: false
inverter_power:
name: $upper_devicename Inverter Power
id: ${devicename}_invertor_power
internal: false
preset_reporter:
name: $upper_devicename Preset Reporter
id: ${devicename}_preset_reporter
internal: false
inverter_power_limit_value:
name: $upper_devicename Inverter Power Limit Value
id: ${devicename}_inverter_power_limit_value
internal: false
inverter_power_limit_state:
name: $upper_devicename Inverter Power Limit State
id: ${devicename}_inverter_power_limit_state
internal: false
visual:
min_temperature: 16
max_temperature: 32
temperature_step: 0.5
supported_modes:
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
custom_fan_modes:
- MUTE
- TURBO
supported_presets:
- SLEEP
custom_presets:
- CLEAN
- HEALTH
- ANTIFUNGUS
supported_swing_modes:
- VERTICAL
- HORIZONTAL
- BOTH
button:
- platform: template
name: ${upper_devicename} IPower Limit Off
icon: "mdi:power-plug-off-outline"
on_press:
- aux_ac.power_limit_off: aux_id
- platform: template
name: ${upper_devicename} IPower Limit On Half
icon: "mdi:fraction-one-half"
on_press:
- aux_ac.power_limit_on:
id: aux_id
limit: 50
number:
- platform: template
name: ${upper_devicename} IPower Limit Value
id: ${devicename}_ipower_limit_value
icon: "mdi:battery-unknown"
mode: "slider"
min_value: 30
max_value: 100
step: 1
set_action:
then:
- lambda: !lambda |-
id(aux_id).powerLimitationOnSequence( x );

View File

@@ -1,123 +0,0 @@
external_components:
- source:
type: local
path: ../components
substitutions:
devicename: test_local_airflow_dir
upper_devicename: Test AUX
esphome:
name: $devicename
platform: ESP8266
board: esp12e
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_pass
manual_ip:
static_ip: !secret wifi_ip
gateway: !secret wifi_gateway
subnet: !secret wifi_subnet
dns1: 8.8.8.8
dns2: 1.1.1.1
reboot_timeout: 0s
ap:
ssid: Test AUX Fallback Hotspot
password: !secret wifi_ap_pass
logger:
level: DEBUG
baud_rate: 0
api:
password: !secret api_pass
reboot_timeout: 0s
ota:
password: !secret ota_pass
web_server:
port: 80
uart:
id: ac_uart_bus
tx_pin: GPIO1
rx_pin: GPIO3
baud_rate: 4800
data_bits: 8
parity: EVEN
stop_bits: 1
sensor:
- platform: uptime
name: Uptime Sensor
climate:
- platform: aux_ac
name: $upper_devicename
id: aux_id
uart_id: ac_uart_bus
period: 7s
show_action: true
display_inverted: true
optimistic: true
indoor_temperature:
name: $upper_devicename Indoor Temperature
id: ${devicename}_indoor_temp
internal: false
display_state:
name: $upper_devicename Display State
id: ${devicename}_display_state
internal: false
outdoor_temperature:
name: $upper_devicename Outdoor Temperature
id: ${devicename}_outdoor_temp
internal: false
outbound_temperature:
name: $upper_devicename Coolant Outbound Temperature
id: ${devicename}_outbound_temp
internal: false
inbound_temperature:
name: $upper_devicename Coolant Inbound Temperature
id: ${devicename}_inbound_temp
internal: false
compressor_temperature:
name: $upper_devicename Compressor Temperature
id: ${devicename}_strange_temp
internal: false
defrost_state:
name: $upper_devicename Defrost State
id: ${devicename}_defrost_state
internal: false
inverter_power:
name: $upper_devicename Invertor Power
id: ${devicename}_invertor_power
internal: false
preset_reporter:
name: $upper_devicename Preset Reporter
id: ${devicename}_preset_reporter
internal: false
visual:
min_temperature: 16
max_temperature: 32
temperature_step: 0.5
supported_modes:
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
custom_fan_modes:
- MUTE
- TURBO
supported_presets:
- SLEEP
custom_presets:
- CLEAN
- HEALTH
- ANTIFUNGUS
supported_swing_modes:
- VERTICAL
- HORIZONTAL
- BOTH

View File

@@ -1,48 +0,0 @@
external_components:
- source:
type: local
path: ../components
#- source: github://GrKoR/esphome_aux_ac_component@dev
#components: [ aux_ac ]
#refresh: 0s
substitutions:
devicename: test_local_minimal
upper_devicename: Test AUX
esphome:
name: $devicename
platform: ESP8266
board: esp12e
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_pass
reboot_timeout: 0s
ap:
ssid: $upper_devicename Fallback Hotspot
password: !secret wifi_ap_pass
logger:
level: DEBUG
baud_rate: 0
api:
password: !secret api_pass
reboot_timeout: 0s
ota:
password: !secret ota_pass
uart:
id: ac_uart_bus
tx_pin: GPIO1
rx_pin: GPIO3
baud_rate: 4800
data_bits: 8
parity: EVEN
stop_bits: 1
climate:
- platform: aux_ac
name: $upper_devicename