From b888f1a521891713633ae324dd8b95130cd6f499 Mon Sep 17 00:00:00 2001 From: "anklimov@gmail.com" Date: Sat, 7 Mar 2026 23:19:46 +0300 Subject: [PATCH] Multi-AC reworking, Mbus fix, RESET command for PID --- lighthub/itemCmd.cpp | 5 + lighthub/itemCmd.h | 4 +- lighthub/modules/out_modbus.cpp | 41 ++-- lighthub/modules/out_modbus.h | 7 +- lighthub/modules/out_multivent.cpp | 322 ++++++++++++++++++++--------- lighthub/modules/out_multivent.h | 9 +- lighthub/modules/out_pid.cpp | 6 +- 7 files changed, 284 insertions(+), 110 deletions(-) diff --git a/lighthub/itemCmd.cpp b/lighthub/itemCmd.cpp index 5717fa3..49f8763 100644 --- a/lighthub/itemCmd.cpp +++ b/lighthub/itemCmd.cpp @@ -1141,6 +1141,11 @@ itemCmd itemCmd::Cmd(uint8_t i) return *this; } +itemCmd itemCmd::Cmd(itemCmd i) + { + cmd.cmdCode=i.cmd.cmdCode; + return *this; + } uint8_t itemCmd::getSuffix() { diff --git a/lighthub/itemCmd.h b/lighthub/itemCmd.h index 207eefa..4238b61 100644 --- a/lighthub/itemCmd.h +++ b/lighthub/itemCmd.h @@ -29,7 +29,7 @@ const cmdstr commands_P[] PROGMEM = "ENABLE","DISABLE","UNFREEZE","FREEZE", "AUTO","FAN_ONLY", "HIGH","MEDIUM","LOW","HEAT_COOL", -"HEAT","COOL","DRY","RGB","HSV" +"HEAT","COOL","DRY","RGB","HSV","RESET" }; #define commandsNum sizeof(commands_P)/sizeof(cmdstr) @@ -94,6 +94,7 @@ const ch_type ch_type_P[] PROGMEM = #define CMD_RGB 0x17 #define CMD_HSV 0x18 +#define CMD_RESET 0x19 #define CMD_MASK 0xffUL #define FLAG_MASK 0x00ffff00UL @@ -236,6 +237,7 @@ public: itemCmd Tens(int32_t i); itemCmd Tens_raw(int32_t i); itemCmd Cmd(uint8_t i); + itemCmd Cmd(itemCmd i); itemCmd HSV(uint16_t h, uint8_t s, uint8_t v); itemCmd HSV255(uint16_t h, uint8_t s, uint8_t v); itemCmd HS(uint16_t h, uint8_t s); diff --git a/lighthub/modules/out_modbus.cpp b/lighthub/modules/out_modbus.cpp index 37fba57..187f154 100644 --- a/lighthub/modules/out_modbus.cpp +++ b/lighthub/modules/out_modbus.cpp @@ -196,7 +196,7 @@ bool out_Modbus::getConfig() if (store->parameters) { // Creating for parameters where prefetch required - debugSerial<parameters->child; while (i) { @@ -208,7 +208,7 @@ bool out_Modbus::getConfig() i=i->next; } - debugSerial<parameters->child; // Creating for parameters used in references from another parameters while (i) @@ -229,7 +229,7 @@ bool out_Modbus::getConfig() } i=i->next; } - debugSerial<itemArg, 2); if (itemParametersObj) @@ -286,7 +286,7 @@ int out_Modbus::createLastMeasured(aJsonObject * execObj) lastMeasured = aJson.getObjectItem(markObj,"@S"); if (!lastMeasured) return false; - lastMeasured->subtype |= MB_VALUE_OUTDATED; + lastMeasured->subtype |= LM_VALUE_EMPTY; return true; } @@ -316,6 +316,20 @@ if (lastMeasured && lastMeasured->type == aJson_Int) return lastMeasured; return NULL; } +void out_Modbus::setLastMeasured(aJsonObject * lastMeasured, int val) +{ + //aJsonObject *lastMeasured = getLastMeasured (execObj); + if (lastMeasured) + { + lastMeasured->valueint = val; + //lastMeasured->subtype&=~LM_VALUE_OUTDATED; + //lastMeasured->subtype&=~LM_VALUE_EMPTY; + lastMeasured->subtype = 0; + + } + +} + /** * @brief Инициализирует канал Modbus и загружает конфигурацию. * @return 1 при успехе, 0 при ошибке. @@ -503,7 +517,7 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin mappedParam.Int((uint32_t)param); } - traceSerial << F("MBUSD: got ")<name<name<type==aJson_Array || mapObj->type==aJson_Object)) { @@ -587,11 +601,11 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin if (nestedMapObj && (nestedMapObj->type==aJson_Array || nestedMapObj->type==aJson_Object)) mappedParam=mappedParam.doReverseMapping(nestedMapObj); traceSerial << F("MBUSD: NestedMapped:")<subtype & MB_VALUE_OUTDATED)) + if (!(lastMeasured->subtype & LM_VALUE_OUTDATED)) { executeWithoutCheck=true; submitRecurrentOut=true; - lastMeasured->subtype|= MB_VALUE_OUTDATED; + lastMeasured->subtype|= LM_VALUE_OUTDATED; } } @@ -627,22 +641,21 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin aJsonObject *lastMeasured = getLastMeasured(execObj); if (lastMeasured) { - if (lastMeasured->valueint == param) + if (lastMeasured->valueint == param && !(lastMeasured->subtype & LM_VALUE_EMPTY)) { //if recurrent call but value was readed before - if (!doExecution && !(lastMeasured->subtype & MB_VALUE_OUTDATED)) + if (!doExecution && !(lastMeasured->subtype & LM_VALUE_OUTDATED)) { *submitParam=true; //never used - lastMeasured->subtype|=MB_VALUE_OUTDATED; + lastMeasured->subtype|=LM_VALUE_OUTDATED; return mappedParam; } *submitParam=false; //supress repeating execution for same val } else { - lastMeasured->valueint=param; traceSerial<<"MBUS: Stored "<name<subtype&=~MB_VALUE_OUTDATED; + setLastMeasured(lastMeasured,param); } } // } @@ -898,7 +911,7 @@ if (prefetchObj && (prefetchObj->type == aJson_Boolean) && prefetchObj->valueboo debugSerial<valueint<valueint<type == aJson_Int) && lastMeasured && (lastMeasured->type == aJson_Int)) lastMeasured->valueint = outValue->valueint; +if ((res ==0) && (outValue->type == aJson_Int) && lastMeasured && (lastMeasured->type == aJson_Int)) setLastMeasured(lastMeasured,outValue->valueint); return ( res == 0); @@ -1116,7 +1129,7 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object) { if (lastMeasured) { - if (lastMeasured->valueint == Value && !(lastMeasured->subtype & MB_VALUE_OUTDATED)) + if (lastMeasured->valueint == Value && !(lastMeasured->subtype)) { debugSerial<<"MBUS: Value2send equal retrieved"<valueint = (long int) new PID (&valObj->valuefloat, &poObj->valuefloat, &setObj->valuefloat, kP, kI, kD, direction); - ((PID*) pidObj->valueint)->SetMode (AUTOMATIC); + //((PID*) pidObj->valueint)->SetMode (AUTOMATIC); ((PID*) pidObj->valueint)->SetSampleTime(dT*1000.0); debugSerial << F ("VENT: PID P=")<valueint) { PID * p = (PID *) pidObj->valueint; + if ((execCmd == CMD_HEAT || execCmd == CMD_COOL) && p->GetMode() == AUTOMATIC) pidActive = true; + + switch (actualMode) + { //if air hot or cold - uses temp PID and block control by /fan + case CMD_HEAT: + p->SetMode(AUTOMATIC); + p->SetControllerDirection(DIRECT); + break; + case CMD_COOL: + p->SetMode(AUTOMATIC); + p->SetControllerDirection(REVERSE); + break; + default: + if (passiveMode || execCmd == CMD_AUTO || execCmd ==CMD_OFF) p->SetMode(MANUAL); + } + if (p->Compute()) { + aJsonObject * poObj = aJson.getObjectItem(i,"po"); if (poObj && poObj->type == aJson_Float) { @@ -232,61 +247,48 @@ int out_Multivent::Poll(short cause) <<" P:"<GetKp()<<" I:"<GetKi()<<" D:"<GetKd()<<((p->GetDirection())?" Rev ":" Dir ")<<((p->GetMode())?"A":"M"); debugSerial<name,true,true); + else + fanCtrl(itemCmd().Percents255(poObj->valuefloat).setSuffix(S_FAN),i->name,true,true); + + balance+=poObj->valuefloat; + pidComputed = true; + + break; + case CMD_COOL: + if (actualCmd==CMD_HEAT) //close + fanCtrl(itemCmd().Percents255(0).setSuffix(S_FAN),i->name,true,true); + else + fanCtrl(itemCmd().Percents255(poObj->valuefloat).setSuffix(S_FAN),i->name,true,true); + + balance-=poObj->valuefloat; + pidComputed = true; + break; + + default: switch (actualMode) { case CMD_HEAT: - ((PID *) pidObj->valueint)->SetControllerDirection(DIRECT); - debugSerial<itemArr->name<<"/"<name<valuefloat <valuefloat).setSuffix(S_FAN),i->name,true); - if (poObj->valuefloat == 0.0 && autoRequested) {autoRequested = false; debugSerial<<"Vent: no more heat needed for "<name<itemArr->name<<"/"<name<valuefloat <valuefloat).setSuffix(S_FAN),i->name,true,true); break; case CMD_COOL: - ((PID *) pidObj->valueint)->SetControllerDirection(REVERSE); - debugSerial<itemArr->name<<"/"<name<valuefloat << F(" set REVERSE mode")<valuefloat).setSuffix(S_FAN),i->name,true); - if (poObj->valuefloat == 0.0 && autoRequested) {autoRequested = false; debugSerial<<"Vent: no more cool needed for "<name<itemArr->name<<"/"<name<valuefloat <valuefloat).setSuffix(S_FAN),i->name,true,true); break; - //case CMD_FAN: //no more hot or cold air - //if (autoRequested) debugSerial<<"VENT: Cancel automode request"<valueint)->SetMode(MANUAL); } } - else switch (execCmd) - { - case CMD_HEAT: - ((PID *) pidObj->valueint)->SetControllerDirection(DIRECT); - debugSerial<itemArr->name<<"/"<name<valuefloat).setSuffix(S_FAN),i->name); - //else? - - balance+=poObj->valuefloat; - break; - case CMD_COOL: - //case CMD_FAN: // if PIB using for vent - //case CMD_ON: // AC temp unknown - assuming that PID used for vent - ((PID *) pidObj->valueint)->SetControllerDirection(REVERSE); - debugSerial<itemArr->name<<"/"<name<valuefloat).setSuffix(S_FAN),i->name); - //else ? - balance-=poObj->valuefloat; - break; - // if FAN_ONLY (AC report room temp regularry) - not use internal PID - let be on external control via /fan - case CMD_FAN: - // vent requested but air temp hot or cold - if (actualCmd == CMD_HEAT || actualCmd == CMD_COOL) - { - Ctrl(itemCmd().Percents255(0).setSuffix(S_FAN),i->name); - Ctrl(itemCmd().Cmd(CMD_FREEZE),i->name); - } - else Ctrl(itemCmd().Cmd(CMD_UNFREEZE),i->name); - } - } } } @@ -294,31 +296,30 @@ int out_Multivent::Poll(short cause) } i=i->next; }//while - if (balance) debugSerial<boostTreshold) sendACcmd (CMD_HEAT); - else if (-balance>boostTreshold) sendACcmd (CMD_COOL); - else if (autoRequested) sendACcmd(CMD_AUTO); - else if (ventRequested) sendACcmd(CMD_FAN); - // else sendACcmd (CMD_OFF); + if (balance>boostTreshold) setBoost(itemCmd().Cmd(CMD_HEAT).Int(30).setSuffix(S_SET)); + else if (-balance>boostTreshold) setBoost(itemCmd().Cmd(CMD_COOL).Int(18).setSuffix(S_SET)); + else + { + pidActive = false; + } + } + + if (!pidActive) + + { + resetBoost(); + if (autoRequested) sendACcmd(itemCmd().Cmd(CMD_AUTO)); + else if (ventRequested) sendACcmd(itemCmd().Cmd(CMD_FAN)); + } + return 1; }; -int out_Multivent::sendACcmd (int cmd) -{ - if (!acObj) return 0; - int lastCmd = getIntFromJson(acObj,"@lastCmd"); - int acCmd = getIntFromJson(acObj,"mode"); - if (lastCmd && (acCmd != lastCmd)) { - //debugSerial<<"VENT: AC MODE changed manually to "<getCmd()<child; // Pass 1 - calculate summ air value, max value etc @@ -511,7 +532,20 @@ while (i) case S_FAN: if (getFlag(i,FLAG_FREEZED)) {debugSerial<valueint == CMD_OFF && turnbyfan) @@ -550,9 +584,9 @@ while (i) case S_CMD: if (cmd.isCommand()) { - switch (cmd.getCmd()) + + if (cmd.getCmd() == CMD_ON) { - case CMD_ON: if (getFlag(i,FLAG_FREEZED)) {debugSerial<valueint != CMD_OFF && cmdObj->valueint != CMD_HALT) break; cmd.Percents255(fanObj->valueint); @@ -563,6 +597,11 @@ while (i) debugSerial<<"VENT: Turning ON. cmd:"<valueint<valueint); setPassiveMode(i,false); + } + + switch (cmd.getCmd()) + { + case CMD_ON: break; case CMD_OFF: if (getFlag(i,FLAG_FREEZED)) {debugSerial<valueint = CMD_OFF; + enablePid(pidObj,false); break; + /* case CMD_ENABLE: if (pidObj && pidObj->valueint) ((PID *) pidObj->valueint)->SetMode(AUTOMATIC); sendFlags |= FLAG_FLAGS; @@ -585,6 +626,7 @@ while (i) sendFlags |= FLAG_FLAGS; setPassiveMode(i,false); break; + */ case CMD_FREEZE: setFlag(i,FLAG_FREEZED); @@ -594,12 +636,27 @@ while (i) clearFlag(i,FLAG_FREEZED); return 1; - case CMD_AUTO: - case CMD_HEATCOOL: case CMD_COOL: - case CMD_HEAT: - case CMD_FAN: case CMD_DRY: + enablePid(pidObj,true,REVERSE); + sendFlags |= FLAG_COMMAND; + cmdObj->valueint = cmd.getCmd(); + setPassiveMode(i,false); + break; + + case CMD_HEAT: + enablePid(pidObj,true,DIRECT); + case CMD_HEATCOOL: + enablePid(pidObj,true); + + sendFlags |= FLAG_COMMAND; + cmdObj->valueint = cmd.getCmd(); + setPassiveMode(i,false); + break; + + case CMD_FAN: + case CMD_AUTO: + enablePid(pidObj,false); sendFlags |= FLAG_COMMAND; cmdObj->valueint = cmd.getCmd(); setPassiveMode(i,false); @@ -614,8 +671,6 @@ while (i) } } break; - - case S_SET: if (cmd.isValue()) { @@ -638,14 +693,14 @@ while (i) } //switch if (isNotRetainingStatus()) //Send status separately for cmd, param, flags { - if (sendFlags & FLAG_COMMAND) item->SendStatusImmediate(cmd.setSuffix(S_CMD),FLAG_COMMAND,i->name); + if (sendFlags & FLAG_COMMAND) item->SendStatusImmediate(itemCmd().Cmd(cmd).setSuffix(S_CMD),FLAG_COMMAND,i->name); if (sendFlags & FLAG_PARAMETERS ) item->SendStatusImmediate(cmd,FLAG_PARAMETERS,i->name); if (sendFlags & FLAG_FLAGS) item->SendStatusImmediate(cmd,FLAG_FLAGS,i->name); } if (cascadeObj) { - if (sendFlags & FLAG_COMMAND) SubmitParameters(cascadeObj,"cmd",cmd.setSuffix(S_CMD).setArgType(0),true); + if (sendFlags & FLAG_COMMAND) SubmitParameters(cascadeObj,"cmd",itemCmd().Cmd(cmd).setSuffix(S_CMD).setArgType(0),true); if (sendFlags & FLAG_PARAMETERS) switch (cmd.getSuffix()) { @@ -732,4 +787,87 @@ while (i) return 1; } +void out_Multivent::enablePid(aJsonObject* pidObj, int enable, int direction ) + { + if (pidObj && pidObj->valueint) + { + ((PID *) pidObj->valueint)->SetMode(enable); + if (direction != -1) ((PID *) pidObj->valueint)->SetControllerDirection(direction); + } + } + + +bool out_Multivent::pidEnabled(aJsonObject* pidObj) + { + return ((pidObj && pidObj->valueint) && (((PID *) pidObj->valueint)->GetMode() ==AUTOMATIC)); + } + + int out_Multivent::sendACcmd (itemCmd cmd) +{ + if (!acObj) return 0; + int lastCmd = getIntFromJson(acObj,"@lastCmd"); + int acCmd = getIntFromJson(acObj,"mode"); + + //if (lastCmd && (acCmd != lastCmd)) { + // //debugSerial<<"VENT: AC MODE changed manually to "<getCmd()<itemArr->name,val,"/$state"); +} + #endif diff --git a/lighthub/modules/out_multivent.h b/lighthub/modules/out_multivent.h index 0d7ed01..9913d17 100644 --- a/lighthub/modules/out_multivent.h +++ b/lighthub/modules/out_multivent.h @@ -25,11 +25,18 @@ public: int fanCtrl(itemCmd cmd, char* subItem=NULL, bool toExecute=true, bool force = false); protected: void getConfig(); - int sendACcmd (int cmd); + int sendACcmd (itemCmd cmd); void setPassiveMode(aJsonObject* zone, bool mode); uint32_t getFlag (aJsonObject* zone, uint32_t flag); void setFlag (aJsonObject* zone, uint32_t flag); void clearFlag (aJsonObject* zone, uint32_t flag); + void enablePid(aJsonObject* zone, int enable, int direction = -1); + bool pidEnabled(aJsonObject* pidObj); + void setBoost(itemCmd); + void resetBoost(); + void notifyState(itemCmd state); + + aJsonObject * gatesObj; aJsonObject * acObj; //float acTemp; diff --git a/lighthub/modules/out_pid.cpp b/lighthub/modules/out_pid.cpp index 0bf234a..fbbe04c 100644 --- a/lighthub/modules/out_pid.cpp +++ b/lighthub/modules/out_pid.cpp @@ -377,7 +377,11 @@ case S_CTRL: executeCommand(oCmd,-1,value); return 1; } */ - + case CMD_RESET: + store->pid->Initialize(); + debugSerial<