1-st post-AI review

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-05-01 23:28:13 +03:00
parent 04d709a1e8
commit 47c2fd8a74
3 changed files with 120 additions and 69 deletions

View File

@@ -59,7 +59,8 @@ const ch_type ch_type_P[] PROGMEM =
"ELEVATOR", // 19 // "ELEVATOR", // 19 //
"COUNTER", // 20 //Generic counter "COUNTER", // 20 //Generic counter
"HUM", // 21 //Humidifier "HUM", // 21 //Humidifier
"MERCURY" // 22 //Mercury energy meter/RS485 interface "MERCURY", // 22 //Mercury energy meter/RS485 interface
"SPRINKLR" // 23 //Sprinkler controller
}; };
#define ch_typeNum sizeof(ch_type_P)/sizeof(ch_type) #define ch_typeNum sizeof(ch_type_P)/sizeof(ch_type)

View File

@@ -14,7 +14,6 @@ bool out_sprinkler::getConfig()
gatesObj = NULL; gatesObj = NULL;
vinPin = drenPin = pumpPin = -1; vinPin = drenPin = pumpPin = -1;
wMaxPin = wMinPin = fbDrenPin = fbPumpPin = wCtrPin = -1; wMaxPin = wMinPin = fbDrenPin = fbPumpPin = wCtrPin = -1;
lastWctrState = false;
if (!item || !item->itemArg) return false; if (!item || !item->itemArg) return false;
@@ -51,6 +50,13 @@ static bool isValidControlPin(short pin)
return (pin >= 0 && pin < PINS_COUNT && !isProtectedPin(pin)); return (pin >= 0 && pin < PINS_COUNT && !isProtectedPin(pin));
} }
void out_sprinkler::publishBooleanStateIfChanged(const char * subItem, bool state, uint32_t flag, uint32_t & lastState)
{
if (state == (bool) (lastState & flag)) return;
if (state) lastState |= flag ; else lastState &= ~flag;
publishBooleanState(subItem, state);
}
void out_sprinkler::setOutput(short pin, bool value) void out_sprinkler::setOutput(short pin, bool value)
{ {
if (!isValidControlPin(pin)) return; if (!isValidControlPin(pin)) return;
@@ -89,17 +95,34 @@ int out_sprinkler::Setup()
getCreateObject(gatesObj, "@state", (long)SP_UNKNOWN); getCreateObject(gatesObj, "@state", (long)SP_UNKNOWN);
getCreateObject(gatesObj, "@timer", (long)0); getCreateObject(gatesObj, "@timer", (long)0);
getCreateObject(gatesObj, "@flowTimer", (long)0); getCreateObject(gatesObj, "@flowTimer", (long)0);
getCreateObject(gatesObj, "@wCtrLast", (long)0);
if (wCtrPin >= 0 && wCtrPin < PINS_COUNT) pinMode(wCtrPin, INPUT); uint16_t lastVals = 0;
if (wMaxPin >= 0 && wMaxPin < PINS_COUNT) pinMode(wMaxPin, INPUT); if (wCtrPin >= 0 && wCtrPin < PINS_COUNT)
if (wMinPin >= 0 && wMinPin < PINS_COUNT) pinMode(wMinPin, INPUT); {
if (fbDrenPin >= 0 && fbDrenPin < PINS_COUNT) pinMode(fbDrenPin, INPUT); pinMode(wCtrPin, INPUT);
if (fbPumpPin >= 0 && fbPumpPin < PINS_COUNT) pinMode(fbPumpPin, INPUT); lastVals |= (getPinVal(wCtrPin) ? LASTWCTRLSTATE : 0);
lastVals |= (getPinVal(wCtrPin) ? LASTWCTRLSTATE_ALL : 0);
}
if (wMaxPin >= 0 && wMaxPin < PINS_COUNT) {
pinMode(wMaxPin, INPUT);
lastVals |= (publishBooleanState("$wMax", getPinVal(wMaxPin)) ? LASTWMAXSTATE : 0);
}
if (wMinPin >= 0 && wMinPin < PINS_COUNT) {
pinMode(wMinPin, INPUT);
lastVals |= (publishBooleanState("$wMin", getPinVal(wMinPin)) ? LASTWMINSTATE : 0);
}
if (fbDrenPin >= 0 && fbDrenPin < PINS_COUNT) {
pinMode(fbDrenPin, INPUT);
lastVals |= (publishBooleanState("$fbDren", getPinVal(fbDrenPin)) ? LASTFBDRENSTATE : 0);
}
if (fbPumpPin >= 0 && fbPumpPin < PINS_COUNT) {
pinMode(fbPumpPin, INPUT);
lastVals |= (publishBooleanState("$fbPump", getPinVal(fbPumpPin)) ? LASTFBPUMPSTATE : 0);
}
lastWctrState = (wCtrPin >= 0) ? getPinVal(wCtrPin) : false; setValToJson(gatesObj, "@lastVals", (long)lastVals);
item->setExt(millisNZ()); //item->setExt(millisNZ());
setStatus(CST_INITIALIZED); setStatus(CST_INITIALIZED);
notifyState(SP_UNKNOWN); notifyState(SP_UNKNOWN);
return 1; return 1;
@@ -117,6 +140,7 @@ int out_sprinkler::Stop()
return 1; return 1;
} }
/*
int out_sprinkler::Status() int out_sprinkler::Status()
{ {
if (!item || !gatesObj) return 0; if (!item || !gatesObj) return 0;
@@ -126,16 +150,17 @@ int out_sprinkler::Status()
bool fbDren = (fbDrenPin >= 0) ? getPinVal(fbDrenPin) : false; bool fbDren = (fbDrenPin >= 0) ? getPinVal(fbDrenPin) : false;
bool fbPump = (fbPumpPin >= 0) ? getPinVal(fbPumpPin) : false; bool fbPump = (fbPumpPin >= 0) ? getPinVal(fbPumpPin) : false;
publishBooleanState("$wMax", wMax); publishBooleanStateIfChanged("$wMax", wMax, lastWMaxState);
publishBooleanState("$wMin", wMin); publishBooleanStateIfChanged("$wMin", wMin, lastWMinState);
publishBooleanState("$fbDren", fbDren); publishBooleanStateIfChanged("$fbDren", fbDren, lastFbDrenState);
publishBooleanState("$fbPump", fbPump); publishBooleanStateIfChanged("$fbPump", fbPump, lastFbPumpState);
int state = getIntFromJson(gatesObj, "@state", SP_UNKNOWN); int state = getIntFromJson(gatesObj, "@state", SP_UNKNOWN);
publishNumericState("$state", state); publishNumericState("$state", state);
return 1; return 1;
} }
*/
bool out_sprinkler::isFreeze() bool out_sprinkler::isFreeze()
{ {
@@ -203,8 +228,7 @@ void out_sprinkler::turnOffValves()
void out_sprinkler::notifyState(short state) void out_sprinkler::notifyState(short state)
{ {
if (!gatesObj) return; if (!gatesObj) return;
aJsonObject * stateObj = getCreateObject(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
if (stateObj) stateObj->valueint = state;
publishNumericState("$state", state); publishNumericState("$state", state);
} }
@@ -306,10 +330,22 @@ void out_sprinkler::updateZoneValue(aJsonObject * zone, long value)
item->SendStatusImmediate(itemCmd().Int(current).setSuffix(S_VAL), FLAG_PARAMETERS, zone->name); item->SendStatusImmediate(itemCmd().Int(current).setSuffix(S_VAL), FLAG_PARAMETERS, zone->name);
} }
void out_sprinkler::publishBooleanState(const char * subItem, bool state) void out_sprinkler::updateCounterValue()
{ {
if (!item) return; int value = 1;
if (!gatesObj) return;
long current = getIntFromJson(gatesObj, "@wCtr", 0);
current += value;
setValToJson(gatesObj, "wCtr", current);
item->SendStatusImmediate(itemCmd().Int(current).setSuffix(S_SET), FLAG_PARAMETERS);
}
bool out_sprinkler::publishBooleanState(const char * subItem, bool state)
{
if (!item) return state;
item->SendStatusImmediate(itemCmd().Cmd(state ? CMD_ON : CMD_OFF).setSuffix(S_CMD), FLAG_COMMAND, (char *)subItem); item->SendStatusImmediate(itemCmd().Cmd(state ? CMD_ON : CMD_OFF).setSuffix(S_CMD), FLAG_COMMAND, (char *)subItem);
return state;
} }
void out_sprinkler::publishNumericState(const char * subItem, long value) void out_sprinkler::publishNumericState(const char * subItem, long value)
@@ -322,20 +358,36 @@ int out_sprinkler::Poll(short cause)
{ {
if (!item || !gatesObj) return 0; if (!item || !gatesObj) return 0;
bool freeze = isFreeze(); bool freeze = isFreeze();
bool wMax = (wMaxPin >= 0) ? getPinVal(wMaxPin) : false; bool wMax = (wMaxPin >= 0) ? getPinVal(wMaxPin) : false;
bool wMin = (wMinPin >= 0) ? getPinVal(wMinPin) : false; bool wMin = (wMinPin >= 0) ? getPinVal(wMinPin) : false;
bool fbDren = (fbDrenPin >= 0) ? getPinVal(fbDrenPin) : false; bool fbDren = (fbDrenPin >= 0) ? getPinVal(fbDrenPin) : false;
bool fbPump = (fbPumpPin >= 0) ? getPinVal(fbPumpPin) : false; bool fbPump = (fbPumpPin >= 0) ? getPinVal(fbPumpPin) : false;
publishBooleanState("$wMax", wMax); uint32_t lastVals = getIntFromJson(gatesObj, "@lastVals", 0);
publishBooleanState("$wMin", wMin);
publishBooleanState("$fbDren", fbDren); publishBooleanStateIfChanged("$wMax", wMax, LASTWMAXSTATE, lastVals);
publishBooleanState("$fbPump", fbPump); publishBooleanStateIfChanged("$wMin", wMin, LASTWMINSTATE, lastVals);
publishBooleanStateIfChanged("$fbDren", fbDren, LASTFBDRENSTATE, lastVals);
publishBooleanStateIfChanged("$fbPump", fbPump, LASTFBPUMPSTATE, lastVals);
uint32_t now = millisNZ(); uint32_t now = millisNZ();
int state = getIntFromJson(gatesObj, "@state", SP_UNKNOWN); int state = getIntFromJson(gatesObj, "@state", SP_UNKNOWN);
uint32_t timer = (uint32_t)getIntFromJson(gatesObj, "@timer", 0); uint32_t timer = (uint32_t)getIntFromJson(gatesObj, "@timer", 0);
bool lastWctrlState = lastVals & LASTWCTRLSTATE;
bool lastWctrlStateAll = lastVals & LASTWCTRLSTATE_ALL;
if (wCtrPin >= 0)
{
bool curr = getPinVal(wCtrPin);
if (curr && !lastWctrlStateAll)
{
updateCounterValue();
}
if (curr) lastVals |= LASTWCTRLSTATE_ALL; else lastVals &= ~LASTWCTRLSTATE_ALL;
}
setValToJson(gatesObj, "@lastVals", (long)lastVals);
if (freeze) if (freeze)
{ {
@@ -352,14 +404,14 @@ int out_sprinkler::Poll(short cause)
if (wMax) if (wMax)
{ {
state = SP_FULL; state = SP_FULL;
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
notifyState(state); notifyState(state);
} }
else else
{ {
state = SP_DREN_ON; state = SP_DREN_ON;
getCreateObject(gatesObj, "@timer", (long)now)->valueint = now; setValToJson(gatesObj, "@timer", (long)now);
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_DREN_ON); shutdown(SP_DREN_ON);
} }
break; break;
@@ -368,14 +420,14 @@ int out_sprinkler::Poll(short cause)
if (fbDren) if (fbDren)
{ {
state = SP_DREN_OPERATE; state = SP_DREN_OPERATE;
getCreateObject(gatesObj, "@timer", (long)now)->valueint = now; setValToJson(gatesObj, "@timer", (long)now);
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_DREN_OPERATE); shutdown(SP_DREN_OPERATE);
} }
else if (isTimeOver(timer, now, DRENAGE_TIME)) else if (isTimeOver(timer, now, DRENAGE_ON_TIME))
{ {
state = SP_DREN_EMPTY; state = SP_DREN_EMPTY;
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_DREN_EMPTY); shutdown(SP_DREN_EMPTY);
} }
break; break;
@@ -384,19 +436,19 @@ int out_sprinkler::Poll(short cause)
if (!fbDren) if (!fbDren)
{ {
state = SP_DREN_EMPTY; state = SP_DREN_EMPTY;
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_DREN_EMPTY); shutdown(SP_DREN_EMPTY);
} }
else if (wMax) else if (wMax)
{ {
state = SP_FULL; state = SP_FULL;
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FULL); shutdown(SP_FULL);
} }
else if (isTimeOver(timer, now, 1200000UL)) else if (isTimeOver(timer, now, 1200000UL))
{ {
state = SP_FAULT_DREN; state = SP_FAULT_DREN;
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FAULT_DREN); shutdown(SP_FAULT_DREN);
} }
break; break;
@@ -405,14 +457,14 @@ int out_sprinkler::Poll(short cause)
if (wMax) if (wMax)
{ {
state = SP_FULL; state = SP_FULL;
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FULL); shutdown(SP_FULL);
} }
else if (item->getCmd() == CMD_ON) else if (item->getCmd() == CMD_ON)
{ {
state = SP_VIN; state = SP_VIN;
getCreateObject(gatesObj, "@timer", (long)now)->valueint = now; setValToJson(gatesObj, "@timer", (long)now);
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_VIN); shutdown(SP_VIN);
} }
break; break;
@@ -421,20 +473,20 @@ int out_sprinkler::Poll(short cause)
if (fbDren) if (fbDren)
{ {
state = SP_DREN_OPERATE; state = SP_DREN_OPERATE;
getCreateObject(gatesObj, "@timer", (long)now)->valueint = now; setValToJson(gatesObj, "@timer", (long)now);
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_DREN_OPERATE); shutdown(SP_DREN_OPERATE);
} }
else if (wMax) else if (wMax)
{ {
state = SP_FULL; state = SP_FULL;
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FULL); shutdown(SP_FULL);
} }
else if (isTimeOver(timer, now, 1200000UL)) else if (isTimeOver(timer, now, VIN_MAX_TIME))
{ {
state = SP_FAULT_VIN; state = SP_FAULT_VIN;
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FAULT_VIN); shutdown(SP_FAULT_VIN);
} }
break; break;
@@ -443,8 +495,8 @@ int out_sprinkler::Poll(short cause)
if (!wMax) if (!wMax)
{ {
state = SP_DREN_ON; state = SP_DREN_ON;
getCreateObject(gatesObj, "@timer", (long)now)->valueint = now; setValToJson(gatesObj, "@timer", (long)now);
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_DREN_ON); shutdown(SP_DREN_ON);
} }
break; break;
@@ -453,7 +505,7 @@ int out_sprinkler::Poll(short cause)
if (wMax) if (wMax)
{ {
state = SP_FULL; state = SP_FULL;
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FULL); shutdown(SP_FULL);
} }
break; break;
@@ -462,7 +514,7 @@ int out_sprinkler::Poll(short cause)
if (wMax) if (wMax)
{ {
state = SP_FULL; state = SP_FULL;
getCreateObject(gatesObj, "@state", (long)state)->valueint = state; setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FULL); shutdown(SP_FULL);
} }
break; break;
@@ -493,17 +545,18 @@ int out_sprinkler::Poll(short cause)
setZoneActive(currentZone, true); setZoneActive(currentZone, true);
short zonePin = getIntFromJson(currentZone, "pin", -1); short zonePin = getIntFromJson(currentZone, "pin", -1);
setOutput(zonePin, true); setOutput(zonePin, true);
getCreateObject(gatesObj, "@flowTimer", (long)now)->valueint = now; setValToJson(gatesObj, "@flowTimer", (long)now);
} }
if (wCtrPin >= 0) if (wCtrPin >= 0)
{ {
bool curr = getPinVal(wCtrPin); bool curr = getPinVal(wCtrPin);
if (curr && !lastWctrState) if (curr && !lastWctrlState)
{ {
updateZoneValue(currentZone, 1); updateZoneValue(currentZone, 1);
} }
lastWctrState = curr; if (curr) lastVals |= LASTWCTRLSTATE; else lastVals &= ~LASTWCTRLSTATE;
setValToJson(gatesObj, "@lastVals", (long)lastVals);
} }
else else
{ {
@@ -511,17 +564,16 @@ int out_sprinkler::Poll(short cause)
if (isTimeOver(flowTimer, now, 1000UL)) if (isTimeOver(flowTimer, now, 1000UL))
{ {
updateZoneValue(currentZone, 1); updateZoneValue(currentZone, 1);
getCreateObject(gatesObj, "@flowTimer", (long)now)->valueint = now; setValToJson(gatesObj, "@flowTimer", (long)now);
} }
} }
long setVal2 = getIntFromJson(currentZone, "set", 0);
long valVal2 = getIntFromJson(currentZone, "val", 0); if (setVal > 0 && valVal >= setVal)
if (setVal2 > 0 && valVal2 >= setVal2)
{ {
setOutput(getIntFromJson(currentZone, "pin", -1), false); setOutput(getIntFromJson(currentZone, "pin", -1), false);
setZoneActive(currentZone, false); setZoneActive(currentZone, false);
setValToJson(currentZone, "cmd", (long)CMD_OFF); //////setValToJson(currentZone, "cmd", (long)CMD_OFF);
item->SendStatusImmediate(itemCmd().Cmd(CMD_OFF).setSuffix(S_CMD), FLAG_COMMAND, currentZone->name); item->SendStatusImmediate(itemCmd().Cmd(CMD_OFF).setSuffix(S_CMD), FLAG_COMMAND, currentZone->name);
currentZone = findNextZone(); currentZone = findNextZone();
} }
@@ -657,16 +709,7 @@ int out_sprinkler::Ctrl(itemCmd cmd, char* subItem, bool toExecute, bool authori
if (toExecute) if (toExecute)
{ {
long value = cmd.getInt(); long value = cmd.getInt();
if (value < 0) setValToJson(gatesObj, "@wCtr", value);
{
item->setFlag(FLAG_FREEZED);
item->SendStatus(FLAG_FLAGS);
}
else if (isFreeze())
{
item->clearFlag(FLAG_FREEZED);
item->SendStatus(FLAG_FLAGS);
}
} }
return 1; return 1;
@@ -690,7 +733,6 @@ int out_sprinkler::Ctrl(itemCmd cmd, char* subItem, bool toExecute, bool authori
default: default:
break; break;
} }
return 0; return 0;
} }

View File

@@ -6,8 +6,15 @@
#include <abstractout.h> #include <abstractout.h>
#include <item.h> #include <item.h>
#define DRENAGE_TIME 10000 #define DRENAGE_ON_TIME 10000
#define VIN_MAX_TIME 1200000UL
#define LASTWCTRLSTATE 1
#define LASTWCTRLSTATE_ALL 2
#define LASTWMAXSTATE 4
#define LASTWMINSTATE 8
#define LASTFBDRENSTATE 16
#define LASTFBPUMPSTATE 32
enum sprinklerState { enum sprinklerState {
SP_UNKNOWN = 0, SP_UNKNOWN = 0,
@@ -26,12 +33,11 @@ public:
//out_sprinkler(){ /*NO getConfig() here due Poll() optimization*/ }; //out_sprinkler(){ /*NO getConfig() here due Poll() optimization*/ };
bool getConfig(); bool getConfig();
void link(Item * _item){abstractOut::link(_item); if (_item) getConfig();};
int Setup() override; int Setup() override;
int Poll(short cause) override; int Poll(short cause) override;
int Stop() override; int Stop() override;
int Status() override; //int Status() override;
int getChanType() override; int getChanType() override;
int Ctrl(itemCmd cmd, char* subItem=NULL, bool toExecute=true, bool authorized = false) override; int Ctrl(itemCmd cmd, char* subItem=NULL, bool toExecute=true, bool authorized = false) override;
@@ -39,7 +45,7 @@ protected:
aJsonObject * gatesObj; aJsonObject * gatesObj;
short vinPin, drenPin, pumpPin; short vinPin, drenPin, pumpPin;
short wMaxPin, wMinPin, fbDrenPin, fbPumpPin, wCtrPin; short wMaxPin, wMinPin, fbDrenPin, fbPumpPin, wCtrPin;
bool lastWctrState;
void pump(bool state); void pump(bool state);
void setOutput(short pin, bool value); void setOutput(short pin, bool value);
@@ -50,10 +56,12 @@ protected:
aJsonObject * findNextZone(); aJsonObject * findNextZone();
void setZoneActive(aJsonObject * zone, bool active); void setZoneActive(aJsonObject * zone, bool active);
void updateZoneValue(aJsonObject * zone, long value); void updateZoneValue(aJsonObject * zone, long value);
void publishBooleanState(const char * subItem, bool state); bool publishBooleanState(const char * subItem, bool state);
void publishNumericState(const char * subItem, long value); void publishNumericState(const char * subItem, long value);
void publishBooleanStateIfChanged(const char * subItem, bool state, uint32_t flag, uint32_t & lastState);
bool isFreeze(); bool isFreeze();
void notifyState(short state); void notifyState(short state);
int shutdown(sprinklerState nextState); int shutdown(sprinklerState nextState);
void updateCounterValue();
}; };
#endif #endif