diff --git a/lighthub/abstractch.cpp b/lighthub/abstractch.cpp index 7c45b55..48f3bf8 100644 --- a/lighthub/abstractch.cpp +++ b/lighthub/abstractch.cpp @@ -8,21 +8,21 @@ extern lan_status lanStatus; extern PubSubClient mqttClient; -int abstractCh::publishTopic(char* topic, long value, char* subtopic) +int abstractCh::publishTopic(const char* topic, long value, const char* subtopic) { char valstr[16]; printUlongValueToStr(valstr, value); return publishTopic(topic, valstr,subtopic); }; -int abstractCh::publishTopic(char* topic, float value, char* subtopic) +int abstractCh::publishTopic(const char* topic, float value, const char* subtopic) { char valstr[16]; printFloatValueToStr(value, valstr); return publishTopic(topic, valstr,subtopic); }; -int abstractCh::publishTopic(char* topic, char * value, char* subtopic) +int abstractCh::publishTopic(const char* topic, const char * value, const char* subtopic) { char addrstr[MQTT_TOPIC_LENGTH]; diff --git a/lighthub/abstractch.h b/lighthub/abstractch.h index ed7efae..6c923ed 100644 --- a/lighthub/abstractch.h +++ b/lighthub/abstractch.h @@ -10,14 +10,14 @@ public: virtual ~abstractCh(){}; virtual int Poll() = 0; virtual int Setup() =0; //Should initialize hardware and reserve resources - virtual int Anounce () {}; - virtual int Stop() {}; //Should free resources + virtual int Anounce () {return 0;}; + virtual int Stop() {return 0;}; //Should free resources virtual int Status() {return CST_UNKNOWN;} protected: -virtual int publishTopic(char* topic, long value, char* subtopic = NULL); -virtual int publishTopic(char* topic, float value, char* subtopic = NULL ); -virtual int publishTopic(char* topic, char * value, char* subtopic = NULL); +virtual int publishTopic(const char* topic, long value, const char* subtopic = NULL); +virtual int publishTopic(const char* topic, float value, const char* subtopic = NULL ); +virtual int publishTopic(const char* topic, const char * value, const char* subtopic = NULL); //friend Input; }; diff --git a/lighthub/abstractin.cpp b/lighthub/abstractin.cpp index 3ec1e5d..8956bbb 100644 --- a/lighthub/abstractin.cpp +++ b/lighthub/abstractin.cpp @@ -10,21 +10,21 @@ extern lan_status lanStatus; extern PubSubClient mqttClient; -int abstractIn::publish(long value, char* subtopic) +int abstractIn::publish(long value, const char* subtopic) { char valstr[16]; printUlongValueToStr(valstr, value); return publish(valstr,subtopic); }; -int abstractIn::publish(float value, char* subtopic) +int abstractIn::publish(float value, const char* subtopic) { char valstr[16]; printFloatValueToStr(value, valstr); return publish(valstr,subtopic); }; -int abstractIn::publish(char * value, char* subtopic) +int abstractIn::publish(char * value, const char* subtopic) { char addrstr[MQTT_TOPIC_LENGTH]; if (in) diff --git a/lighthub/abstractin.h b/lighthub/abstractin.h index cb857c6..87f3748 100644 --- a/lighthub/abstractin.h +++ b/lighthub/abstractin.h @@ -9,8 +9,8 @@ public: protected: Input * in; -int publish(long value, char* subtopic = NULL); -int publish(float value, char* subtopic = NULL ); -int publish(char * value, char* subtopic = NULL); +int publish(long value, const char* subtopic = NULL); +int publish(float value, const char* subtopic = NULL ); +int publish(char * value, const char* subtopic = NULL); friend Input; }; diff --git a/lighthub/inputs.cpp b/lighthub/inputs.cpp index 15f7af5..5626e56 100644 --- a/lighthub/inputs.cpp +++ b/lighthub/inputs.cpp @@ -188,6 +188,7 @@ switch (cause) { #endif } } + return 0; } #ifndef COUNTER_DISABLE @@ -226,7 +227,7 @@ void Input::counterPoll() { char addrstr[MQTT_TOPIC_LENGTH]; strncpy(addrstr,emit->valuestring,sizeof(addrstr)); if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,emit->valuestring); - sprintf(valstr, "%d", counterValue); + sprintf(valstr, "%ld", counterValue); if (mqttClient.connected() && !ethernetIdleCount) mqttClient.publish(addrstr, valstr); setNextPollTime(millis() + DHT_POLL_DELAY_DEFAULT); diff --git a/lighthub/item.cpp b/lighthub/item.cpp index 09fa61c..bafdffc 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -34,6 +34,7 @@ e-mail anklimov@gmail.com #include #include "modules/out_spiled.h" +#include "modules/out_ac.h" //Commands const char ON_P[] PROGMEM = "ON"; @@ -48,11 +49,11 @@ const char DECREASE_P[] PROGMEM = "DECREASE"; const char TRUE_P[] PROGMEM = "TRUE"; const char FALSE_P[] PROGMEM = "FALSE"; -const char HEAT_P[] PROGMEM = "HEAT"; -const char COOL_P[] PROGMEM = "COOL"; -const char AUTO_P[] PROGMEM = "AUTO"; -const char FAN_ONLY_P[] PROGMEM = "FAN_ONLY"; -const char DRY_P[] PROGMEM = "DRY"; +char HEAT_P[] PROGMEM = "HEAT"; +char COOL_P[] PROGMEM = "COOL"; +char AUTO_P[] PROGMEM = "AUTO"; +char FAN_ONLY_P[] PROGMEM = "FAN_ONLY"; +char DRY_P[] PROGMEM = "DRY"; // SubTopics const char SET_P[] PROGMEM = "set"; @@ -81,7 +82,7 @@ static unsigned long lastctrl = 0; static aJsonObject *lastobj = NULL; int txt2cmd(char *payload) { - int cmd = -1; + int cmd = CMD_UNKNOWN; // Check for command if (*payload == '-' || (*payload >= '0' && *payload <= '9')) cmd = CMD_NUM; @@ -115,16 +116,16 @@ int txt2subItem(char *payload) { // Check for command if (strcmp_P(payload, SET_P) == 0) cmd = S_SET; else if (strcmp_P(payload, CMD_P) == 0) cmd = S_CMD; -// else if (strcmp_P(payload, MODE_P) == 0) cmd = S_MODE; + else if (strcmp_P(payload, MODE_P) == 0) cmd = S_MODE; else if (strcmp_P(payload, HSV_P) == 0) cmd = S_HSV; else if (strcmp_P(payload, RGB_P) == 0) cmd = S_RGB; - else if (strcmp_P(payload, FAN_P) == 0) cmd = S_FAN; + else if (strcmp_P(payload, FAN_P) == 0) cmd = S_FAN; /* UnUsed now else if (strcmp_P(payload, SETPOINT_P) == 0) cmd = S_SETPOINT; else if (strcmp_P(payload, TEMP_P) == 0) cmd = S_TEMP; else if (strcmp_P(payload, POWER_P) == 0) cmd = S_POWER; else if (strcmp_P(payload, VOL_P) == 0) cmd = S_VOL; - else if (strcmp_P(payload, HEAT_P) == 0) cmd = S_HEAT; */ + */ return cmd; } @@ -152,7 +153,14 @@ void Item::Parse() { #ifndef SPILED_DISABLE case CH_SPILED: driver = new out_SPILed (this); -// debugSerial<itemArr->name, "ON","/fresh"); + else publishTopic(item->itemArr->name, "OFF","/fresh"); + + ///////////////////////////////// + if (lock_rem == 0x80){ + publishTopic(item->itemArr->name, "ON","/lock"); + } + if (lock_rem == 0x00){ + publishTopic(item->itemArr->name, "OFF","/lock"); + } + ///////////////////////////////// + /* + if (power == 0x01 || power == 0x11){ + publishTopic(item->itemArr->name,"Power", "on"); + } + if (power == 0x00 || power == 0x10){ + publishTopic(item->itemArr->name,"Power", "off"); + } + */ + + Serial.print ("Power="); + Serial.println(power); + + if (power & 0x08) + publishTopic(item->itemArr->name, "ON", "/quiet"); + else publishTopic(item->itemArr->name, "OFF" , "/quiet"); + + + if (power == 3 || power == 2) + publishTopic(item->itemArr->name, "on","/compressor"); + else + publishTopic(item->itemArr->name, "off","/compressor"); + + + publishTopic(item->itemArr->name, (long) swing,"/swing"); + publishTopic(item->itemArr->name, (long) fan_spd,"/fan"); + + ///////////////////////////////// +/* + if (swing == 0x00){ + publishTopic(item->itemArr->name, "off","swing"); + } + if (swing == 0x01){ + publishTopic(item->itemArr->name, "ud","swing"); + } + if (swing == 0x02){ + publishTopic(item->itemArr->name, "lr","swing"); + } + if (swing == 0x03){ + publishTopic(item->itemArr->name, "all","swing"); + } + ///////////////////////////////// + if (fan_spd == 0x00){ + publishTopic(item->itemArr->name, "max","fan"); + } + if (fan_spd == 0x01){ + publishTopic(item->itemArr->name, "mid","fan"); + } + if (fan_spd == 0x02){ + publishTopic(item->itemArr->name, "min","fan"); + } + if (fan_spd == 0x03){ + publishTopic(item->itemArr->name, "auto","fan"); + } + */ + ///////////////////////////////// + + publishTopic(item->itemArr->name,(long)set_tmp,"/set"); + publishTopic(item->itemArr->name, (long)cur_tmp, "/temp"); + //////////////////////////////////// + s_mode[0]='\0'; + + if (mode == 0x00){ + strcpy_P(s_mode,AUTO_P); + } + else if (mode == 0x01){ + strcpy_P(s_mode,COOL_P); + } + else if (mode == 0x02){ + strcpy_P(s_mode,HEAT_P); + } + else if (mode == 0x03){ + strcpy_P(s_mode,FAN_ONLY_P); + } + else if (mode == 0x04){ + strcpy_P(s_mode,DRY_P); + } + + publishTopic(item->itemArr->name, (long) mode, "/mode"); + + if (power & 0x01) + publishTopic(item->itemArr->name, s_mode,"/cmd"); + + else publishTopic(item->itemArr->name, "OFF","/cmd"); + + String raw_str; + char raw[75]; + for (int i=0; i < 37; i++){ + if (data[i] < 10){ + raw_str += "0"; + raw_str += String(data[i], HEX); + } else { + raw_str += String(data[i], HEX); + } + } + raw_str.toUpperCase(); + raw_str.toCharArray(raw,75); + publishTopic(item->itemArr->name, raw,"/raw"); + Serial.println(raw); + +/////////////////////////////////// +} + +byte getCRC(byte req[], size_t size){ + byte crc = 0; + for (int i=2; i < size; i++){ + crc += req[i]; + } + return crc; +} + +void SendData(byte req[], size_t size){ + AC_Serial.write(req, size - 1); + AC_Serial.write(getCRC(req, size-1)); + AC_Serial.flush(); +} + +inline unsigned char toHex( char ch ){ + return ( ( ch >= 'A' ) ? ( ch - 'A' + 0xA ) : ( ch - '0' ) ) & 0x0F; +} + + + +int out_AC::Setup() +{ +Serial.println("AC Init"); +AC_Serial.begin(9600); +driverStatus = CST_INITIALIZED; +return 1; +} + +int out_AC::Stop() +{ +Serial.println("AC De-Init"); + +driverStatus = CST_UNKNOWN; +return 1; +} + +int out_AC::Status() +{ +return driverStatus; +} + +int out_AC::isActive() +{ +return (power & 1); +} + +int out_AC::Poll() +{ + //debugSerial<<"."; + +long now = millis(); + if (now - prevPolling > INTERVAL_AC_POLLING) { + prevPolling = now; + Serial.println ("Polling"); + SendData(qstn, sizeof(qstn)/sizeof(byte)); //Опрос кондиционера + } +delay(100); + if(AC_Serial.available() > 0){ + AC_Serial.readBytes(data, 37); + while(AC_Serial.available()){ + delay(2); + AC_Serial.read(); + } + if (data[36] != inCheck){ + inCheck = data[36]; + InsertData(data, 37); + } + } +return 1; +}; + +int out_AC::Ctrl(short cmd, short n, int * Parameters, boolean send, int suffixCode, char* subItem) +{ + // 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, RAW_P) == 0) suffixCode = S_RAW; + + data[B_POWER] = power; + // debugSerial<= 0 && set_tmp <= 30) + { + data[B_SET_TMP] = set_tmp; + } + break; + + case S_CMD: + switch (cmd) + { + case CMD_ON: + data[B_POWER] |= 1; + SendData(on, sizeof(on)/sizeof(byte)); + return 1; + break; + case CMD_OFF: + case CMD_HALT: + data[B_POWER] = 0; + SendData(off, sizeof(off)/sizeof(byte)); + return 1; + break; + case CMD_AUTO: + data[B_MODE] = 0; + data[B_POWER] |= 1; + break; + case CMD_COOL: + data[B_MODE] = 1; + data[B_POWER] |= 1; + break; + case CMD_HEAT: + data[B_MODE] = 2; + data[B_POWER] |= 1; + break; + case CMD_DRY: + data[B_MODE] = 4; + data[B_POWER] |= 1; + break; + case CMD_FAN: + data[B_MODE] = 3; + data[B_POWER] |= 1; + break; + case CMD_UNKNOWN: + return -1; + break; + } + break; + + case S_FAN: + data[B_FAN_SPD] = Parameters[0]; + break; + + case S_MODE: + data[B_MODE] = Parameters[0]; + break; + + case S_LOCK: + switch (cmd) + { + case CMD_ON: + data[B_LOCK_REM] = 80; + break; + case CMD_OFF: + data[B_LOCK_REM] = 0; + break; + } + break; + + case S_SWING: + data[B_SWING] = Parameters[0]; + break; + + case S_QUIET: + switch (cmd) + { + case CMD_ON: + data[B_POWER] |= 8; + break; + case CMD_OFF: + data[B_POWER] &= ~8; + break; + } + + + break; + + case S_RAW: + /* + { + char buf[75]; + char hexbyte[3] = {0}; + strPayload.toCharArray(buf, 75); + int octets[sizeof(buf) / 2] ; + for (int i=0; i < 76; i += 2){ + hexbyte[0] = buf[i] ; + hexbyte[1] = buf[i+1] ; + data[i/2] = (toHex(hexbyte[0]) << 4) | toHex(hexbyte[1]); + + + + AC_Serial.write(data, 37); + AC_Serial.flush(); + + publishTopic("RAW", buf); + } + */ + + break; + + case S_NOTFOUND: + return -1; + + } + +/* + ////////// + if (strTopic == "/myhome/in/Conditioner/Fan_Speed"){ + if (strPayload == "max"){ + data[B_FAN_SPD] = 0; + } + if (strPayload == "mid"){ + data[B_FAN_SPD] = 1; + } + if (strPayload == "min"){ + data[B_FAN_SPD] = 2; + } + if (strPayload == "auto"){ + data[B_FAN_SPD] = 3; + } + } + //////// + if (strTopic == "/myhome/in/Conditioner/Swing"){ + if (strPayload == "off"){ + data[B_SWING] = 0; + } + if (strPayload == "ud"){ + data[B_SWING] = 1; + } + if (strPayload == "lr"){ + data[B_SWING] = 2; + } + if (strPayload == "all"){ + data[B_SWING] = 3; + } + } + //////// + if (strTopic == "/myhome/in/Conditioner/Lock_Remote"){ + if (strPayload == "true"){ + data[B_LOCK_REM] = 80; + } + if (strPayload == "false"){ + data[B_LOCK_REM] = 0; + } + } + //////// + if (strTopic == "/myhome/in/Conditioner/Power"){ + if (strPayload == "off" || strPayload == "false" || strPayload == "0"){ + SendData(off, sizeof(off)/sizeof(byte)); + return; + } + if (strPayload == "on" || strPayload == "true" || strPayload == "1"){ + SendData(on, sizeof(on)/sizeof(byte)); + return; + } + if (strPayload == "quiet"){ + data[B_POWER] = 9; + } + } + */ + //////// + //if (strTopic == "/myhome/in/Conditioner/RAW") + + data[B_CMD] = 0; + data[9] = 1; + data[10] = 77; + data[11] = 95; + SendData(data, sizeof(data)/sizeof(byte)); + return 1; +} + + + +#endif diff --git a/lighthub/modules/out_ac.h b/lighthub/modules/out_ac.h new file mode 100644 index 0000000..9d1d123 --- /dev/null +++ b/lighthub/modules/out_ac.h @@ -0,0 +1,37 @@ + +#pragma once +#ifndef AC_DISABLE +#include + +#define LEN_B 37 +#define B_CUR_TMP 13 //Текущая температура +#define B_CMD 17 // 00-команда 7F-ответ ??? +#define B_MODE 23 //04 - DRY, 01 - cool, 02 - heat, 00 - smart 03 - вентиляция +#define B_FAN_SPD 25 //Скорость 02 - min, 01 - mid, 00 - max, 03 - auto +#define B_SWING 27 //01 - верхний и нижний предел вкл. 00 - выкл. 02 - левый/правый вкл. 03 - оба вкл +#define B_LOCK_REM 28 //80 блокировка вкл. 00 - выкл +#define B_POWER 29 //on/off 01 - on, 00 - off (10, 11)-Компрессор??? 09 - QUIET +#define B_FRESH 31 //fresh 00 - off, 01 - on +#define B_SET_TMP 35 //Установленная температура + +#define S_LOCK S_ADDITIONAL+1 +#define S_QUIET S_ADDITIONAL+2 +#define S_SWING S_ADDITIONAL+3 +#define S_RAW S_ADDITIONAL+4 + +extern void modbusIdle(void) ; +class out_AC : public abstractOut { +public: + + out_AC(Item * _item):abstractOut(_item){}; + int Setup() override; + int Poll() override; + int Stop() override; + int Status() override; + int isActive() override; + int Ctrl(short cmd, short n=0, int * Parameters=NULL, boolean send=true, int suffixCode=0, char* subItem=NULL) override; + +protected: + void InsertData(byte data[], size_t size); +}; +#endif