diff --git a/documentation/core/channel_types_reference.md b/documentation/core/channel_types_reference.md index 39df77d..364e7c5 100644 --- a/documentation/core/channel_types_reference.md +++ b/documentation/core/channel_types_reference.md @@ -129,7 +129,7 @@ ```json "ac_main": [10, 1] // номер порта serial (0-3) // подканалы: fan (LOW/MEDIUM/HIGH), set (16-40), temp, cmd -// также доступны подканалы lock/swing/queit/raw (/mode — число, текстовые режимы — в /cmd) +// также доступны подканалы lock/swing/quiet/raw (/mode — число, текстовые режимы — в /cmd) ``` ### CH_SPILED (11) - SPI LED лента diff --git a/documentation/core/modules_description.md b/documentation/core/modules_description.md index 6268ec2..bf61a5c 100644 --- a/documentation/core/modules_description.md +++ b/documentation/core/modules_description.md @@ -162,7 +162,7 @@ | `/mode` | число (B_MODE) | Режим | | `/lock` | ON/OFF | Блокировка пульта | | `/swing` | ON/OFF | Качание жалюзей | -| `/queit` | ON/OFF | Тихий режим (опечатка в прошивке! Статус публикуется в `/quiet`) | +| `/quiet` | ON/OFF | Тихий режим (legacy «queit» принимается; статус публикуется в `/quiet`) | | `/raw` | - | Сырой кадр протокола | --- diff --git a/documentation/core/mqtt_quick_reference.md b/documentation/core/mqtt_quick_reference.md index b4b1f8d..66abbec 100644 --- a/documentation/core/mqtt_quick_reference.md +++ b/documentation/core/mqtt_quick_reference.md @@ -129,8 +129,8 @@ mosquitto_pub -h 192.168.1.100 -t "myhome/in/ac_main/fan" -m "HIGH" # Направление воздуха (ON, OFF) mosquitto_pub -h 192.168.1.100 -t "myhome/in/ac_main/swing" -m "ON" -# Тихий режим (входной subitem «queit» — опечатка в прошивке; статус — /quiet) -mosquitto_pub -h 192.168.1.100 -t "myhome/in/ac_main/queit" -m "ON" +# Тихий режим (legacy «queit» также принимается; статус — /quiet) +mosquitto_pub -h 192.168.1.100 -t "myhome/in/ac_main/quiet" -m "ON" # Блокировка ПДУ mosquitto_pub -h 192.168.1.100 -t "myhome/in/ac_main/lock" -m "ON" diff --git a/documentation/core/suffixes_reference.md b/documentation/core/suffixes_reference.md index dceaa4e..d13002e 100644 --- a/documentation/core/suffixes_reference.md +++ b/documentation/core/suffixes_reference.md @@ -77,7 +77,7 @@ myhome/in/rgb_light → 240,100,200 | `/fan` | ✅ | ✅ | Скорость вентилятора | LOW, MEDIUM, HIGH, OFF или число | | `/lock` | ✅ | ✅ | Блокировка ПДУ | ON, OFF | | `/swing` | ✅ | ✅ | Направление воздушного потока | ON, OFF | -| `/quiet` | ✅ | ✅ | Режим "тихой работы". Входной subitem — «queit» (опечатка в прошивке); статус публикуется в `/quiet` | ON, OFF | +| `/quiet` | ✅ | ✅ | Режим "тихой работы". Входной subitem — `/quiet` (legacy «queit» принимается); статус публикуется в `/quiet` | ON, OFF | **Примеры**: ``` @@ -93,8 +93,8 @@ myhome/in/ac_main/set → 22 # Максимальная скорость вентилятора myhome/in/ac_main/fan → HIGH -# Включить тихий режим (входной subitem «queit» — опечатка в прошивке) -myhome/in/ac_main/queit → ON +# Включить тихий режим (legacy «queit» также принимается) +myhome/in/ac_main/quiet → ON ``` **Логика срабатывания AC**: @@ -237,7 +237,7 @@ myhome/in/ac/HEAT/set → 25 | 7 | CH_GROUP | `/cmd`, `/set`, `/hue`, `/sat`, `/HSV` | Группа каналов | | 8 | CH_VCTEMP | — | Регулятор Vacon (PID) | | 9 | CH_VC | — | Привод Vacon (Modbus) | -| 10 | CH_AC (Haier) | `/cmd`, `/set` (16-40), `/mode` (0-4), `/fan`, `/lock`, `/swing`, `/queit` (статус `/quiet`), `/temp`, `/raw` | Кондиционер | +| 10 | CH_AC (Haier) | `/cmd`, `/set` (16-40), `/mode` (0-4), `/fan`, `/lock`, `/swing`, `/quiet` (legacy `queit`), `/temp`, `/raw` | Кондиционер | | 11 | CH_SPILED | `/cmd`, `/set`, `/hue`, `/sat`, `/HSV` + subitem-пиксели 10-20 | Адресуемая LED лента | | 12 | CH_MOTOR | `/cmd`, `/set` | Сервопривод | | 13 | CH_PID | `/cmd`, `/set`, `/val` (вход сенсора), `/ctrl` | PID регулятор, теплые полы | @@ -430,7 +430,7 @@ myhome/s_out/rgb_lamp/cmd → ON /fan → HIGH Максимальная скорость вентилятора /lock → ON Заблокировать ПДУ (только кондиционер) /swing → ON Включить направление воздуха -/queit → ON Тихий режим (опечатка в прошивке; статус — /quiet) +/quiet → ON Тихий режим (legacy «queit» принимается; статус — /quiet) ``` --- diff --git a/lighthub/modules/out_ac.cpp b/lighthub/modules/out_ac.cpp index fab4fcb..76404a8 100644 --- a/lighthub/modules/out_ac.cpp +++ b/lighthub/modules/out_ac.cpp @@ -35,7 +35,8 @@ byte lock[] = {255,255,10,0,0,0,0,0,1,3,0,0,14}; // Блокировка пул //Extended subItem set const char LOCK_P[] PROGMEM = "lock"; -const char QUIET_P[] PROGMEM = "queit"; +const char QUIET_P[] PROGMEM = "quiet"; +const char QUIET_LEGACY_P[] PROGMEM = "queit"; // legacy typo, kept for backward compatibility const char SWING_P[] PROGMEM = "swing"; const char RAW_P[] PROGMEM = "raw"; @@ -503,7 +504,7 @@ int out_AC::Ctrl(itemCmd cmd, char* subItem , bool toExecute, bool authorized) // Some additional Subitems if (strcmp_P(subItem, LOCK_P) == 0) suffixCode = S_LOCK; else if (strcmp_P(subItem, SWING_P) == 0) suffixCode = S_SWING; - else if (strcmp_P(subItem, QUIET_P) == 0) suffixCode = S_QUIET; + else if (strcmp_P(subItem, QUIET_P) == 0 || strcmp_P(subItem, QUIET_LEGACY_P) == 0) suffixCode = S_QUIET; else if (strcmp_P(subItem, RAW_P) == 0) suffixCode = S_RAW; if (cmd.isCommand() && !suffixCode && !subItem) suffixCode=S_CMD; //if some known command find, but w/o correct suffix - got it diff --git a/lighthub/modules/out_ac.h b/lighthub/modules/out_ac.h index 1535d34..a39d817 100644 --- a/lighthub/modules/out_ac.h +++ b/lighthub/modules/out_ac.h @@ -5,6 +5,7 @@ #include #include "itemCmd.h" +/** @brief Byte length of the AC status frame. */ #define LEN_B 37 #define B_CUR_TMP 13 //Текущая температура #define B_CMD 17 // 00-команда 7F-ответ ??? @@ -16,6 +17,7 @@ #define B_FRESH 31 //fresh 00 - off, 01 - on #define B_SET_TMP 35 //Установленная температура +/** Additional suffix codes (beyond the standard suffix_P table). */ #define S_LOCK S_ADDITIONAL+1 #define S_QUIET S_ADDITIONAL+2 #define S_SWING S_ADDITIONAL+3 @@ -23,6 +25,13 @@ extern void modbusIdle(void) ; +/** + * @brief Persistent per-item state of an AC channel, stored in the config tree. + * + * Holds the last 37-byte status frame received from the AC, decoded power + * and mode bytes, the last frame CRC value (inCheck, used to detect + * updates) and a timestamp of the last transmission. + */ class acPersistent : public chPersistent { public: byte data[37]; @@ -32,19 +41,52 @@ public: uint32_t timestamp; }; +/** + * @brief Air conditioner driver (Haier IR-over-UART protocol), channel type CH_AC = 10. + * + * Talks to a Haier AC over UART at 9600 baud using 13-byte request frames + * and 37-byte status frames (frame check = sum of bytes). Periodically + * polls the AC unit and applies control commands. + * + * JSON config (itemArg): [portNum(0-3), callbacksObj] + * - portNum: 0 = default port (Serial3, or USB-CDC Serial), 1..3 = Serial1..Serial3; + * - callbacksObj (optional): object with keys "fan", "set", "cmd", "temp" + * holding execution objects invoked on every polled status update. + * + * Ctrl commands: + * - /set 16-40 - set temperature; + * - /cmd - AUTO / HEAT / COOL / FAN_ONLY / DRY, plus ON / OFF; + * - /fan - LOW / MEDIUM / HIGH / AUTO / OFF, or a 0-255 value; + * - /mode - raw mode code; + * - subitems: "lock" ON/OFF, "swing" ON/OFF, "quiet" ON/OFF (legacy + * "queit" accepted for backward compatibility), "raw". + * + * Published status topics: /set, /temp, /mode, /cmd, /fan, /fresh, /lock, + * /quiet, /compressor, /swing. + */ class out_AC : public abstractOut { public: + /** @brief Default constructor; binds nothing until link() is called. */ out_AC():store(NULL),portNum(0),ACSerial(NULL){}; + /** @brief Links the channel item, attaches persistent storage and reads the config. */ void link(Item * _item){abstractOut::link(_item); if (_item) {store = (acPersistent *) item->getPersistent(); getConfig();} else store = NULL;}; + /** @brief Reads itemArg and selects the UART port (0-3) for the AC line. */ void getConfig(); + /** @brief Initializes persistent storage and starts the UART at 9600 baud. */ int Setup() override; + /** @brief Polls the AC every 5 s, parses the 37-byte status frame and publishes the status topics. */ int Poll(short cause) override; + /** @brief Releases the persistent storage and marks the channel as unknown. */ int Stop() override; + /** @brief Returns 1 if the AC power bit is set, 0 otherwise. */ int isActive() override; + /** @brief Returns CH_THERMO (5). */ int getChanType() override; // int getDefaultStorageType(){return ST_FLOAT_CELSIUS;}; + /** @brief Applies a control command: /set, /cmd, /fan, /mode, and lock/swing/quiet/raw subitems (see class doc). */ int Ctrl(itemCmd cmd, char* subItem=NULL, bool toExecute=true, bool authorized = false) override; + /** @brief Invokes the named callback object ("fan"/"set"/"cmd"/"temp") from itemArg with a polled value. */ void SubmitParameters(const char * name, itemCmd value); protected: