Multi AC/vent - released. Sprinkler - alpha for testing

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-05-05 22:08:07 +03:00
parent 47c2fd8a74
commit 5cb9c87135
9 changed files with 288 additions and 128 deletions

View File

@@ -43,3 +43,4 @@
-D ROTARYENCODER -D ROTARYENCODER
-D CANDRV -D CANDRV
-D THERMO_OVERHEAT_CELSIUS=44. -D THERMO_OVERHEAT_CELSIUS=44.
-D SPRINKLER_ENABLE

View File

@@ -28,7 +28,7 @@ int abstractCh::publishTopic(const char* topic, float value, const char* subtopi
return publishTopic(topic, valstr,subtopic); return publishTopic(topic, valstr,subtopic);
}; };
int abstractCh::publishTopic(const char* topic, const char * value, const char* subtopic) int abstractCh::publishTopic(const char* topic, const char * value, const char* subtopic, const char* suffix)
{ {
#if not defined (NOIP) #if not defined (NOIP)
char addrstr[MQTT_TOPIC_LENGTH]; char addrstr[MQTT_TOPIC_LENGTH];
@@ -38,6 +38,10 @@ int abstractCh::publishTopic(const char* topic, const char * value, const char*
strncpy(addrstr,topic,sizeof(addrstr)); strncpy(addrstr,topic,sizeof(addrstr));
if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,topic); if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,topic);
strncat(addrstr,subtopic,sizeof(addrstr)-1); strncat(addrstr,subtopic,sizeof(addrstr)-1);
if (suffix)
{
strncat(addrstr,suffix,sizeof(addrstr)-1);
}
if (mqttClient.connected() && lanStatus == OPERATION && !ethernetIdleCount) if (mqttClient.connected() && lanStatus == OPERATION && !ethernetIdleCount)
{ {
mqttClient.publish(addrstr, value, true); mqttClient.publish(addrstr, value, true);

View File

@@ -21,6 +21,6 @@ public:
protected: protected:
int publishTopic(const char* topic, long value, const char* subtopic = NULL); int publishTopic(const char* topic, long value, const char* subtopic = NULL);
int publishTopic(const char* topic, float value, const char* subtopic = NULL ); int publishTopic(const char* topic, float value, const char* subtopic = NULL );
int publishTopic(const char* topic, const char * value, const char* subtopic = NULL); int publishTopic(const char* topic, const char * value, const char* subtopic = NULL, const char* suffix = NULL);
}; };

View File

@@ -2066,6 +2066,9 @@ int Item::SendStatus(long sendFlags, char * subItem) {
case S_FAN: case S_FAN:
strncat_P(addrstr, suffix_P[S_FAN], sizeof(addrstr)-1); strncat_P(addrstr, suffix_P[S_FAN], sizeof(addrstr)-1);
break; break;
case S_VAL:
strncat_P(addrstr, suffix_P[S_VAL], sizeof(addrstr)-1);
break;
default: default:
strncat_P(addrstr, suffix_P[S_SET], sizeof(addrstr)-1); strncat_P(addrstr, suffix_P[S_SET], sizeof(addrstr)-1);
} }

View File

@@ -194,7 +194,7 @@ int out_Multivent::isActive()
if (i->name && *i->name) if (i->name && *i->name)
{ {
int preHaltcmd = getIntFromJson(i,"@preHaltcmd",CMD_OFF); int preHaltcmd = getIntFromJson(i,"@preHaltcmd",CMD_OFF);
if (preHaltcmd) //setPassiveMode(i, false); if (preHaltcmd && (preHaltcmd != CMD_OFF)) //setPassiveMode(i, false);
fanCtrl(itemCmd().Cmd(preHaltcmd).setSuffix(S_CMD),i->name,true); fanCtrl(itemCmd().Cmd(preHaltcmd).setSuffix(S_CMD),i->name,true);
setValToJson(i,"@preHaltcmd",0); //reset preHaltcmd in any case setValToJson(i,"@preHaltcmd",0); //reset preHaltcmd in any case
} }
@@ -711,7 +711,7 @@ while (i)
case S_CMD: case S_CMD:
if (cmd.isCommand()) if (cmd.isCommand())
{ {
bool checkMinFanLevel = false;
if (cmd.getCmd() == CMD_ON) if (cmd.getCmd() == CMD_ON)
{ {
if (getFlag(i,FLAG_FREEZED)) {debugSerial<<F("VENT: zone frozen")<<endl; return -2;} if (getFlag(i,FLAG_FREEZED)) {debugSerial<<F("VENT: zone frozen")<<endl; return -2;}
@@ -729,6 +729,7 @@ while (i)
switch (cmd.getCmd()) switch (cmd.getCmd())
{ {
case CMD_ON: case CMD_ON:
checkMinFanLevel = true;
break; break;
case CMD_OFF: case CMD_OFF:
if (getFlag(i,FLAG_FREEZED)) {debugSerial<<F("VENT: zone frozen")<<endl; return -2;} if (getFlag(i,FLAG_FREEZED)) {debugSerial<<F("VENT: zone frozen")<<endl; return -2;}
@@ -773,6 +774,7 @@ while (i)
sendFlags |= FLAG_COMMAND; sendFlags |= FLAG_COMMAND;
cmdObj->valueint = cmd.getCmd(); cmdObj->valueint = cmd.getCmd();
setPassiveMode(i,false); setPassiveMode(i,false);
checkMinFanLevel = true;
break; break;
case CMD_HEAT: case CMD_HEAT:
@@ -783,6 +785,7 @@ while (i)
sendFlags |= FLAG_COMMAND; sendFlags |= FLAG_COMMAND;
cmdObj->valueint = cmd.getCmd(); cmdObj->valueint = cmd.getCmd();
setPassiveMode(i,false); setPassiveMode(i,false);
checkMinFanLevel = true;
break; break;
case CMD_FAN: case CMD_FAN:
@@ -795,10 +798,11 @@ while (i)
sendFlags |= FLAG_COMMAND; sendFlags |= FLAG_COMMAND;
cmdObj->valueint = cmd.getCmd(); cmdObj->valueint = cmd.getCmd();
setPassiveMode(i,false); setPassiveMode(i,false);
checkMinFanLevel = true;
break; break;
//todo - halt-rest-xon-xoff //todo - halt-rest-xon-xoff
} }
if (isNotRetainingStatus() && (cmdObj->valueint == CMD_ON) && (fanObj->valueint<20)) if (isNotRetainingStatus() && checkMinFanLevel && (fanObj->valueint<20))
{ {
fanObj->valueint=30; fanObj->valueint=30;
cmd.Percents255(30); cmd.Percents255(30);
@@ -961,7 +965,7 @@ bool out_Multivent::pidEnabled(aJsonObject* pidObj)
if (!(acCmd == CMD_OFF && lastFan == 0)) if (!(acCmd == CMD_OFF && lastFan == 0))
{ {
debugSerial<<"VENT: AC MODE changed manually from "<<lastCmd<<" to "<<acCmd<<endl; debugSerial<<"VENT: AC MODE changed manually from "<<lastCmd<<" to "<<acCmd<<endl;
//TODO!
switch (acCmd) switch (acCmd)
{ {
case CMD_OFF: case CMD_OFF:
@@ -971,6 +975,12 @@ bool out_Multivent::pidEnabled(aJsonObject* pidObj)
restoreAllzones(); restoreAllzones();
break; break;
} }
aJsonObject * execObj = aJson.getObjectItem(acObj, "onextcmd");
if (execObj)
{
executeCommand(execObj,-1,itemCmd().Cmd(acCmd).setSuffix(S_CMD).setArgType(0).doReverseMapping(aJson.getObjectItem(execObj, "map")));
}
} }
setValToJson(acObj,"@lastCmd",acCmd); setValToJson(acObj,"@lastCmd",acCmd);
setValToJson(acObj,"@lastFan",-1); setValToJson(acObj,"@lastFan",-1);
@@ -1004,6 +1014,11 @@ bool out_Multivent::pidEnabled(aJsonObject* pidObj)
if (lastSet && (acSet != lastSet)) { if (lastSet && (acSet != lastSet)) {
debugSerial<<"VENT: AC SET changed manually from "<<lastSet<<" to "<<acSet<<endl; debugSerial<<"VENT: AC SET changed manually from "<<lastSet<<" to "<<acSet<<endl;
aJsonObject * execObj = aJson.getObjectItem(acObj, "onextcmd");
if (execObj)
{
executeCommand(execObj,-1,itemCmd().Int(acSet).setSuffix(S_SET).doReverseMapping(aJson.getObjectItem(execObj, "map")));
}
setValToJson(acObj,"@lastSet",acSet); setValToJson(acObj,"@lastSet",acSet);
return;} return;}

View File

@@ -12,8 +12,8 @@
bool out_sprinkler::getConfig() bool out_sprinkler::getConfig()
{ {
gatesObj = NULL; gatesObj = NULL;
vinPin = drenPin = pumpPin = -1; vinPin = drenPin = pumpPin = PINS_COUNT;
wMaxPin = wMinPin = fbDrenPin = fbPumpPin = wCtrPin = -1; wMaxPin = wMinPin = fbDrenPin = fbPumpPin = wCtrPin = PINS_COUNT;
if (!item || !item->itemArg) return false; if (!item || !item->itemArg) return false;
@@ -33,21 +33,21 @@ bool out_sprinkler::getConfig()
aJsonObject * rootCfg = aJson.getObjectItem(gatesObj, ""); aJsonObject * rootCfg = aJson.getObjectItem(gatesObj, "");
if (!rootCfg) rootCfg = gatesObj; if (!rootCfg) rootCfg = gatesObj;
vinPin = getIntFromJson(rootCfg, "vIn", -1); vinPin = getIntFromJson(rootCfg, "vIn", PINS_COUNT);
drenPin = getIntFromJson(rootCfg, "rDren", -1); drenPin = getIntFromJson(rootCfg, "rDren", PINS_COUNT);
pumpPin = getIntFromJson(rootCfg, "rPump", -1); pumpPin = getIntFromJson(rootCfg, "rPump", PINS_COUNT);
wMaxPin = getIntFromJson(rootCfg, "wMax", -1); wMaxPin = getIntFromJson(rootCfg, "wMax", PINS_COUNT);
wMinPin = getIntFromJson(rootCfg, "wMin", -1); wMinPin = getIntFromJson(rootCfg, "wMin", PINS_COUNT);
fbDrenPin = getIntFromJson(rootCfg, "fbDren", -1); fbDrenPin = getIntFromJson(rootCfg, "fbDren", PINS_COUNT);
fbPumpPin = getIntFromJson(rootCfg, "fbPump", -1); fbPumpPin = getIntFromJson(rootCfg, "fbPump", PINS_COUNT);
wCtrPin = getIntFromJson(rootCfg, "wCtr", -1); wCtrPin = getIntFromJson(rootCfg, "wCtr", PINS_COUNT);
return true; return true;
} }
static bool isValidControlPin(short pin) static bool isValidControlPin(short pin)
{ {
return (pin >= 0 && pin < PINS_COUNT && !isProtectedPin(pin)); return (abs(pin) < PINS_COUNT && !isProtectedPin(abs(pin)));
} }
void out_sprinkler::publishBooleanStateIfChanged(const char * subItem, bool state, uint32_t flag, uint32_t & lastState) void out_sprinkler::publishBooleanStateIfChanged(const char * subItem, bool state, uint32_t flag, uint32_t & lastState)
@@ -59,8 +59,7 @@ void out_sprinkler::publishBooleanStateIfChanged(const char * subItem, bool stat
void out_sprinkler::setOutput(short pin, bool value) void out_sprinkler::setOutput(short pin, bool value)
{ {
if (!isValidControlPin(pin)) return; writeOutPin(pin, value ? HIGH : LOW);
digitalWrite(pin, value ? HIGH : LOW);
} }
int out_sprinkler::Setup() int out_sprinkler::Setup()
@@ -73,17 +72,19 @@ int out_sprinkler::Setup()
return 0; return 0;
} }
if (isValidControlPin(vinPin)) { pinMode(vinPin, OUTPUT); digitalWrite(vinPin, LOW); } if (isValidControlPin(vinPin)) { pinMode(vinPin, OUTPUT); writeOutPin(vinPin, LOW); }
if (isValidControlPin(drenPin)) { pinMode(drenPin, OUTPUT); digitalWrite(drenPin, LOW); } if (isValidControlPin(drenPin)) { pinMode(drenPin, OUTPUT); writeOutPin(drenPin, LOW); }
if (isValidControlPin(pumpPin)) { pinMode(pumpPin, OUTPUT); digitalWrite(pumpPin, LOW); } if (isValidControlPin(pumpPin)) { pinMode(pumpPin, OUTPUT); writeOutPin(pumpPin, LOW); }
debugSerial << F("SPRINKLER: ")<<"vIN=" << vinPin << " dren=" << drenPin << " pump=" << pumpPin << endl;
aJsonObject * zone = gatesObj->child; aJsonObject * zone = gatesObj->child;
while (zone) while (zone)
{ {
if (zone->name && *zone->name && zone->type == aJson_Object) if (zone->name && *zone->name && zone->type == aJson_Object)
{ {
short pin = getIntFromJson(zone, "pin", -1); short pin = getIntFromJson(zone, "pin", PINS_COUNT);
if (isValidControlPin(pin)) { pinMode(pin, OUTPUT); digitalWrite(pin, LOW); } if (isValidControlPin(pin)) { pinMode(pin, OUTPUT); writeOutPin(pin, LOW); }
getCreateObject(zone, "cmd", (long)CMD_OFF); getCreateObject(zone, "cmd", (long)CMD_OFF);
getCreateObject(zone, "val", (long)0); getCreateObject(zone, "val", (long)0);
getCreateObject(zone, "set", (long)0); getCreateObject(zone, "set", (long)0);
@@ -96,28 +97,29 @@ int out_sprinkler::Setup()
getCreateObject(gatesObj, "@timer", (long)0); getCreateObject(gatesObj, "@timer", (long)0);
getCreateObject(gatesObj, "@flowTimer", (long)0); getCreateObject(gatesObj, "@flowTimer", (long)0);
debugSerial << F("SPRINKLER: ") << " wMax=" << wMaxPin << " wMin=" << wMinPin << " fbDren=" << fbDrenPin << " fbPump=" << fbPumpPin << " wCtr=" << wCtrPin << endl;
uint16_t lastVals = 0; uint16_t lastVals = 0;
if (wCtrPin >= 0 && wCtrPin < PINS_COUNT) if (wCtrPin != PINS_COUNT)
{ {
pinMode(wCtrPin, INPUT); setupInPin(wCtrPin);
lastVals |= (getPinVal(wCtrPin) ? LASTWCTRLSTATE : 0); lastVals |= (readInPin(wCtrPin) ? LASTWCTRLSTATE : 0);
lastVals |= (getPinVal(wCtrPin) ? LASTWCTRLSTATE_ALL : 0); lastVals |= (readInPin(wCtrPin) ? LASTWCTRLSTATE_ALL : 0);
} }
if (wMaxPin >= 0 && wMaxPin < PINS_COUNT) { if (wMaxPin != PINS_COUNT) {
pinMode(wMaxPin, INPUT); setupInPin(wMaxPin);
lastVals |= (publishBooleanState("$wMax", getPinVal(wMaxPin)) ? LASTWMAXSTATE : 0); lastVals |= (publishBooleanState("/$wMax", readInPin(wMaxPin)) ? LASTWMAXSTATE : 0);
} }
if (wMinPin >= 0 && wMinPin < PINS_COUNT) { if (wMinPin != PINS_COUNT) {
pinMode(wMinPin, INPUT); setupInPin(wMinPin);
lastVals |= (publishBooleanState("$wMin", getPinVal(wMinPin)) ? LASTWMINSTATE : 0); lastVals |= (publishBooleanState("/$wMin", readInPin(wMinPin)) ? LASTWMINSTATE : 0);
} }
if (fbDrenPin >= 0 && fbDrenPin < PINS_COUNT) { if (fbDrenPin != PINS_COUNT) {
pinMode(fbDrenPin, INPUT); setupInPin(fbDrenPin);
lastVals |= (publishBooleanState("$fbDren", getPinVal(fbDrenPin)) ? LASTFBDRENSTATE : 0); lastVals |= (publishBooleanState("/$fbDren", readInPin(fbDrenPin)) ? LASTFBDRENSTATE : 0);
} }
if (fbPumpPin >= 0 && fbPumpPin < PINS_COUNT) { if (fbPumpPin != PINS_COUNT) {
pinMode(fbPumpPin, INPUT); setupInPin(fbPumpPin);
lastVals |= (publishBooleanState("$fbPump", getPinVal(fbPumpPin)) ? LASTFBPUMPSTATE : 0); lastVals |= (publishBooleanState("/$fbPump", readInPin(fbPumpPin)) ? LASTFBPUMPSTATE : 0);
} }
setValToJson(gatesObj, "@lastVals", (long)lastVals); setValToJson(gatesObj, "@lastVals", (long)lastVals);
@@ -133,39 +135,18 @@ int out_sprinkler::Stop()
debugSerial << F("SPRINKLER: stop") << endl; debugSerial << F("SPRINKLER: stop") << endl;
turnOffAllZones(); turnOffAllZones();
pump(false); pump(false);
dren(false);
setOutput(vinPin, false); setOutput(vinPin, false);
setOutput(drenPin, false);
setOutput(pumpPin, false);
setStatus(CST_UNKNOWN); setStatus(CST_UNKNOWN);
return 1; return 1;
} }
/*
int out_sprinkler::Status()
{
if (!item || !gatesObj) return 0;
bool wMax = (wMaxPin >= 0) ? getPinVal(wMaxPin) : false;
bool wMin = (wMinPin >= 0) ? getPinVal(wMinPin) : false;
bool fbDren = (fbDrenPin >= 0) ? getPinVal(fbDrenPin) : false;
bool fbPump = (fbPumpPin >= 0) ? getPinVal(fbPumpPin) : false;
publishBooleanStateIfChanged("$wMax", wMax, lastWMaxState);
publishBooleanStateIfChanged("$wMin", wMin, lastWMinState);
publishBooleanStateIfChanged("$fbDren", fbDren, lastFbDrenState);
publishBooleanStateIfChanged("$fbPump", fbPump, lastFbPumpState);
int state = getIntFromJson(gatesObj, "@state", SP_UNKNOWN);
publishNumericState("$state", state);
return 1;
}
*/
bool out_sprinkler::isFreeze() bool out_sprinkler::isFreeze()
{ {
if (!item) return false; if (!item) return false;
return ((item->getFlag(FLAG_FREEZED) & FLAG_FREEZED) == FLAG_FREEZED); return (item->getFlag(FLAG_FREEZED));
} }
bool out_sprinkler::isNeedPump(bool steelNeed) bool out_sprinkler::isNeedPump(bool steelNeed)
@@ -195,8 +176,27 @@ bool out_sprinkler::isNeedPump(bool steelNeed)
void out_sprinkler::pump(bool state) void out_sprinkler::pump(bool state)
{ {
if (!isValidControlPin(pumpPin)) return; if (!isValidControlPin(pumpPin)) return;
uint32_t lastVals = getIntFromJson (gatesObj, "@lastVals", 0);
setOutput(pumpPin, state); setOutput(pumpPin, state);
publishBooleanState("$rPump", state); if (state != (bool)(lastVals & LASTPUMPSTATE))
{
if(state) lastVals |= LASTPUMPSTATE; else lastVals &= ~LASTPUMPSTATE;
setValToJson(gatesObj, "@lastVals", (long)lastVals);
publishBooleanState("/$rPump", state);
}
}
void out_sprinkler::dren(bool state)
{
if (!isValidControlPin(drenPin)) return;
uint32_t lastVals = getIntFromJson (gatesObj, "@lastVals", 0);
setOutput(drenPin, state);
if (state != (bool)(lastVals & LASTDRENSTATE))
{
if(state) lastVals |= LASTDRENSTATE; else lastVals &= ~LASTDRENSTATE;
setValToJson(gatesObj, "@lastVals", (long)lastVals);
publishBooleanState("/$rDren", state);
}
} }
void out_sprinkler::turnOffAllZones() void out_sprinkler::turnOffAllZones()
@@ -207,7 +207,7 @@ void out_sprinkler::turnOffAllZones()
{ {
if (zone->name && *zone->name && zone->type == aJson_Object) if (zone->name && *zone->name && zone->type == aJson_Object)
{ {
short pin = getIntFromJson(zone, "pin", -1); short pin = getIntFromJson(zone, "pin", PINS_COUNT);
setOutput(pin, false); setOutput(pin, false);
if (getIntFromJson(zone, "@active", 0)) if (getIntFromJson(zone, "@active", 0))
{ {
@@ -225,12 +225,78 @@ void out_sprinkler::turnOffValves()
setOutput(drenPin, false); setOutput(drenPin, false);
} }
//void out_sprinkler::notifyState(short state)
//{
// if (!gatesObj) return;
// setValToJson(gatesObj, "@state", (long)state);
// publishNumericState("$state", state);
//}
void out_sprinkler::notifyState(short state) void out_sprinkler::notifyState(short state)
{ {
char val[16];
long fault = 0;
if (!gatesObj) return; if (!gatesObj) return;
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
publishNumericState("$state", state);
aJsonObject *faultObj = aJson.getArrayItem(item->itemArg, 3);
switch (state) {
case SP_OFF:
strcpy(val,"OFF");
break;
case SP_DREN_ON:
strcpy(val,"DREN_ON");
break;
case SP_DREN_OPERATE:
strcpy(val,"DREN_OPERATE");
break;
case SP_DREN_EMPTY:
strcpy(val,"DREN_EMPTY");
break;
case SP_VIN:
strcpy(val,"VIN");
break;
case SP_FULL:
strcpy(val,"FULL");
break;
case SP_FAULT_VIN:
strcpy(val,"FAULT_VIN");
fault = 1;
break;
case SP_FAULT_DREN:
strcpy(val,"FAULT_DREN");
fault = 2;
break;
default:
strcpy(val,"UNKNOWN");
break;
} }
//if (fault) strcpy(val,"FAULT");
if (faultObj)
{
executeCommand(faultObj,-1,itemCmd().Int((int32_t) fault));
}
else publishTopic(item->itemArr->name,fault,"/$fault");
publishTopic(item->itemArr->name,val,"/$state");
}
int out_sprinkler::shutdown(sprinklerState nextState) int out_sprinkler::shutdown(sprinklerState nextState)
{ {
@@ -268,8 +334,8 @@ int out_sprinkler::shutdown(sprinklerState nextState)
break; break;
} }
publishBooleanState("$rDren", nextState == SP_DREN_ON || nextState == SP_DREN_OPERATE); publishBooleanState("/$rDren", nextState == SP_DREN_ON || nextState == SP_DREN_OPERATE);
publishBooleanState("$vIN", nextState == SP_VIN); publishBooleanState("/$vIN", nextState == SP_VIN);
notifyState(nextState); notifyState(nextState);
return 1; return 1;
} }
@@ -311,14 +377,17 @@ inline aJsonObject * out_sprinkler::findNextZone()
return NULL; return NULL;
} }
/*
*/
void out_sprinkler::setZoneActive(aJsonObject * zone, bool active) void out_sprinkler::setZoneActive(aJsonObject * zone, bool active)
{ {
if (!zone) return; if (!zone) return;
setValToJson(zone, "@active", (long)(active ? 1 : 0)); setValToJson(zone, "@active", (long)(active ? 1 : 0));
char subItem[48]; char subItem[48];
snprintf(subItem, sizeof(subItem), "%s/$state", zone->name); snprintf(subItem, sizeof(subItem), "/%s/$state", zone->name);
item->SendStatusImmediate(itemCmd().Cmd(active ? CMD_ON : CMD_OFF).setSuffix(S_CMD), FLAG_COMMAND, subItem); publishTopic(item->itemArr->name, active ? "ON": "OFF", subItem);
} }
void out_sprinkler::updateZoneValue(aJsonObject * zone, long value) void out_sprinkler::updateZoneValue(aJsonObject * zone, long value)
@@ -336,7 +405,7 @@ void out_sprinkler::updateCounterValue()
if (!gatesObj) return; if (!gatesObj) return;
long current = getIntFromJson(gatesObj, "@wCtr", 0); long current = getIntFromJson(gatesObj, "@wCtr", 0);
current += value; current += value;
setValToJson(gatesObj, "wCtr", current); setValToJson(gatesObj, "@wCtr", current);
item->SendStatusImmediate(itemCmd().Int(current).setSuffix(S_SET), FLAG_PARAMETERS); item->SendStatusImmediate(itemCmd().Int(current).setSuffix(S_SET), FLAG_PARAMETERS);
} }
@@ -344,15 +413,11 @@ void out_sprinkler::updateCounterValue()
bool out_sprinkler::publishBooleanState(const char * subItem, bool state) bool out_sprinkler::publishBooleanState(const char * subItem, bool state)
{ {
if (!item) return state; if (!item) return state;
item->SendStatusImmediate(itemCmd().Cmd(state ? CMD_ON : CMD_OFF).setSuffix(S_CMD), FLAG_COMMAND, (char *)subItem);
publishTopic(item->itemArr->name,state ? "ON": "OFF", subItem);
return state; return state;
} }
void out_sprinkler::publishNumericState(const char * subItem, long value)
{
if (!item) return;
item->SendStatusImmediate(itemCmd().Int(value).setSuffix(S_SET), FLAG_PARAMETERS, (char *)subItem);
}
int out_sprinkler::Poll(short cause) int out_sprinkler::Poll(short cause)
{ {
@@ -360,17 +425,17 @@ int out_sprinkler::Poll(short cause)
bool freeze = isFreeze(); bool freeze = isFreeze();
bool wMax = (wMaxPin >= 0) ? getPinVal(wMaxPin) : false; bool wMax = (wMaxPin != PINS_COUNT) ? readInPin(wMaxPin) : false;
bool wMin = (wMinPin >= 0) ? getPinVal(wMinPin) : false; bool wMin = (wMinPin != PINS_COUNT) ? readInPin(wMinPin) : false;
bool fbDren = (fbDrenPin >= 0) ? getPinVal(fbDrenPin) : false; bool fbDren = (fbDrenPin != PINS_COUNT) ? readInPin(fbDrenPin) : false;
bool fbPump = (fbPumpPin >= 0) ? getPinVal(fbPumpPin) : false; bool fbPump = (fbPumpPin != PINS_COUNT) ? readInPin(fbPumpPin) : false;
uint32_t lastVals = getIntFromJson(gatesObj, "@lastVals", 0); uint32_t lastVals = getIntFromJson(gatesObj, "@lastVals", 0);
publishBooleanStateIfChanged("$wMax", wMax, LASTWMAXSTATE, lastVals); publishBooleanStateIfChanged("/$wMax", wMax, LASTWMAXSTATE, lastVals);
publishBooleanStateIfChanged("$wMin", wMin, LASTWMINSTATE, lastVals); publishBooleanStateIfChanged("/$wMin", wMin, LASTWMINSTATE, lastVals);
publishBooleanStateIfChanged("$fbDren", fbDren, LASTFBDRENSTATE, lastVals); publishBooleanStateIfChanged("/$fbDren", fbDren, LASTFBDRENSTATE, lastVals);
publishBooleanStateIfChanged("$fbPump", fbPump, LASTFBPUMPSTATE, 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);
@@ -378,9 +443,9 @@ int out_sprinkler::Poll(short cause)
bool lastWctrlState = lastVals & LASTWCTRLSTATE; bool lastWctrlState = lastVals & LASTWCTRLSTATE;
bool lastWctrlStateAll = lastVals & LASTWCTRLSTATE_ALL; bool lastWctrlStateAll = lastVals & LASTWCTRLSTATE_ALL;
if (wCtrPin >= 0) if (wCtrPin != PINS_COUNT)
{ {
bool curr = getPinVal(wCtrPin); bool curr = readInPin(wCtrPin);
if (curr && !lastWctrlStateAll) if (curr && !lastWctrlStateAll)
{ {
updateCounterValue(); updateCounterValue();
@@ -520,7 +585,7 @@ int out_sprinkler::Poll(short cause)
break; break;
} }
bool tankReady = (state == SP_FULL || wMax); bool tankReady = (state == SP_FULL || wMax || wMin || fbPump);
bool needPump = false; bool needPump = false;
aJsonObject * currentZone = NULL; aJsonObject * currentZone = NULL;
@@ -543,14 +608,14 @@ int out_sprinkler::Poll(short cause)
{ {
turnOffAllZones(); turnOffAllZones();
setZoneActive(currentZone, true); setZoneActive(currentZone, true);
short zonePin = getIntFromJson(currentZone, "pin", -1); short zonePin = getIntFromJson(currentZone, "pin", PINS_COUNT);
setOutput(zonePin, true); setOutput(zonePin, true);
setValToJson(gatesObj, "@flowTimer", (long)now); setValToJson(gatesObj, "@flowTimer", (long)now);
} }
if (wCtrPin >= 0) if (wCtrPin != PINS_COUNT)
{ {
bool curr = getPinVal(wCtrPin); bool curr = readInPin(wCtrPin);
if (curr && !lastWctrlState) if (curr && !lastWctrlState)
{ {
updateZoneValue(currentZone, 1); updateZoneValue(currentZone, 1);
@@ -571,10 +636,10 @@ int out_sprinkler::Poll(short cause)
if (setVal > 0 && valVal >= setVal) if (setVal > 0 && valVal >= setVal)
{ {
setOutput(getIntFromJson(currentZone, "pin", -1), false); setOutput(getIntFromJson(currentZone, "pin", PINS_COUNT), 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();
} }
@@ -610,30 +675,38 @@ int out_sprinkler::Ctrl(itemCmd cmd, char* subItem, bool toExecute, bool authori
{ {
if (!item || !gatesObj) return 0; if (!item || !gatesObj) return 0;
int suffixCode = cmd.isCommand() ? S_CMD : cmd.getSuffix(); int suffixCode = cmd.isCommand() ? S_CMD : cmd.getSuffix();
debugSerial << "SPRINKLER: CTRL " << subItem << " "<< "Execute:"<< toExecute << " "; cmd.debugOut();
bool sendStatus = isNotRetainingStatus();
if (subItem && *subItem) if (subItem && *subItem)
{ {
aJsonObject * zone = getZone(subItem); aJsonObject * zone = getZone(subItem);
if (!zone) return 0; if (!zone) return 0;
///// FOR ZONES
switch (suffixCode) switch (suffixCode)
{ {
case S_SET: case S_SET:
if (toExecute) // if (toExecute)
{ {
long value = cmd.getInt(); long value = cmd.getInt();
setValToJson(zone, "set", value); setValToJson(zone, "set", value);
if (sendStatus)
{
item->SendStatusImmediate(itemCmd().Int(value).setSuffix(S_SET), FLAG_PARAMETERS, subItem); item->SendStatusImmediate(itemCmd().Int(value).setSuffix(S_SET), FLAG_PARAMETERS, subItem);
} }
}
return 1; return 1;
case S_VAL: case S_VAL:
if (toExecute) // if (toExecute)
{ {
long value = cmd.getInt(); long value = cmd.getInt();
setValToJson(zone, "val", value); setValToJson(zone, "val", value);
if (sendStatus)
{
item->SendStatusImmediate(itemCmd().Int(value).setSuffix(S_VAL), FLAG_PARAMETERS, subItem); item->SendStatusImmediate(itemCmd().Int(value).setSuffix(S_VAL), FLAG_PARAMETERS, subItem);
} }
}
return 1; return 1;
case S_CMD: case S_CMD:
@@ -641,27 +714,28 @@ int out_sprinkler::Ctrl(itemCmd cmd, char* subItem, bool toExecute, bool authori
switch (cmd.getCmd()) switch (cmd.getCmd())
{ {
case CMD_ON: case CMD_ON:
if (toExecute)
{
setValToJson(zone, "cmd", (long)CMD_ON); setValToJson(zone, "cmd", (long)CMD_ON);
if (sendStatus)
{
item->SendStatusImmediate(itemCmd().Cmd(CMD_ON).setSuffix(S_CMD), FLAG_COMMAND, subItem); item->SendStatusImmediate(itemCmd().Cmd(CMD_ON).setSuffix(S_CMD), FLAG_COMMAND, subItem);
} }
return 1; return 1;
case CMD_OFF: case CMD_OFF:
if (toExecute)
{
setValToJson(zone, "cmd", (long)CMD_OFF); setValToJson(zone, "cmd", (long)CMD_OFF);
setZoneActive(zone, false); setZoneActive(zone, false);
setOutput(getIntFromJson(zone, "pin", -1), false); setOutput(getIntFromJson(zone, "pin", PINS_COUNT), false);
if (sendStatus)
{
item->SendStatusImmediate(itemCmd().Cmd(CMD_OFF).setSuffix(S_CMD), FLAG_COMMAND, subItem); item->SendStatusImmediate(itemCmd().Cmd(CMD_OFF).setSuffix(S_CMD), FLAG_COMMAND, subItem);
} }
return 1; return 1;
case CMD_RESET: case CMD_RESET:
if (toExecute)
{
setValToJson(zone, "val", (long)0); setValToJson(zone, "val", (long)0);
if (sendStatus)
{
item->SendStatusImmediate(itemCmd().Int(0).setSuffix(S_VAL), FLAG_PARAMETERS, subItem); item->SendStatusImmediate(itemCmd().Int(0).setSuffix(S_VAL), FLAG_PARAMETERS, subItem);
} }
return 1; return 1;
@@ -671,7 +745,7 @@ int out_sprinkler::Ctrl(itemCmd cmd, char* subItem, bool toExecute, bool authori
} }
} }
} }
/// FOR SPRINKLER CONTROLLER
switch (suffixCode) switch (suffixCode)
{ {
case S_CMD: case S_CMD:
@@ -683,6 +757,7 @@ int out_sprinkler::Ctrl(itemCmd cmd, char* subItem, bool toExecute, bool authori
case CMD_OFF: case CMD_OFF:
turnOffAllZones(); turnOffAllZones();
pump(false); pump(false);
//dren(false);
return 1; return 1;
case CMD_RESET: case CMD_RESET:
@@ -693,8 +768,11 @@ int out_sprinkler::Ctrl(itemCmd cmd, char* subItem, bool toExecute, bool authori
if (zone->name && *zone->name && zone->type == aJson_Object) if (zone->name && *zone->name && zone->type == aJson_Object)
{ {
setValToJson(zone, "val", (long)0); setValToJson(zone, "val", (long)0);
if (sendStatus)
{
item->SendStatusImmediate(itemCmd().Int(0).setSuffix(S_VAL), FLAG_PARAMETERS, zone->name); item->SendStatusImmediate(itemCmd().Int(0).setSuffix(S_VAL), FLAG_PARAMETERS, zone->name);
} }
}
zone = zone->next; zone = zone->next;
} }
} }
@@ -706,39 +784,44 @@ int out_sprinkler::Ctrl(itemCmd cmd, char* subItem, bool toExecute, bool authori
break; break;
case S_SET: case S_SET:
if (toExecute)
{ {
debugSerial << F("SPRINKLER: set wCtr to ") << cmd.getInt() << endl;
long value = cmd.getInt(); long value = cmd.getInt();
setValToJson(gatesObj, "@wCtr", value); setValToJson(gatesObj, "@wCtr", value);
if (sendStatus)
{
item->SendStatusImmediate(itemCmd().Int(0).setSuffix(S_SET), FLAG_PARAMETERS);
} }
return 1; return 1;
}
case S_VAL: case S_VAL:
if (toExecute)
{ {
debugSerial << F("SPRINKLER: ext temperature: ") << cmd.getInt() << endl;
long value = cmd.getInt(); long value = cmd.getInt();
if (value < 0) if (value < 0)
{ {
item->setFlag(FLAG_FREEZED); item->setFlag(FLAG_FREEZED);
item->SendStatus(FLAG_FLAGS); item->SendStatus(FLAG_FLAGS);
} }
else if (isFreeze()) // else if (isFreeze())
{ // {
item->clearFlag(FLAG_FREEZED); // item->clearFlag(FLAG_FREEZED);
item->SendStatus(FLAG_FLAGS); // item->SendStatus(FLAG_FLAGS);
} // }
}
return 1;
default: return 1;
break; }
// default:
// break;
} }
return 0; return 0;
} }
int out_sprinkler::getChanType() int out_sprinkler::getChanType()
{ {
return CH_RELAY; return CH_COUNTER;
} }
#endif // SPRINKLER_ENABLE #endif // SPRINKLER_ENABLE

View File

@@ -15,6 +15,8 @@
#define LASTWMINSTATE 8 #define LASTWMINSTATE 8
#define LASTFBDRENSTATE 16 #define LASTFBDRENSTATE 16
#define LASTFBPUMPSTATE 32 #define LASTFBPUMPSTATE 32
#define LASTPUMPSTATE 64
#define LASTDRENSTATE 128
enum sprinklerState { enum sprinklerState {
SP_UNKNOWN = 0, SP_UNKNOWN = 0,
@@ -48,6 +50,7 @@ protected:
void pump(bool state); void pump(bool state);
void dren(bool state);
void setOutput(short pin, bool value); void setOutput(short pin, bool value);
bool isNeedPump(bool steelNeed=false); bool isNeedPump(bool steelNeed=false);
void turnOffValves(); void turnOffValves();

View File

@@ -1136,5 +1136,54 @@ return NULL;
} }
void setupInPin(short pin)
{
if (abs(pin)>=PINS_COUNT)
{
debugSerial<<F("Attempt to setup non existing pin: ")<<pin<<endl;
return;
}
//debugSerial<<F("Setup pin: ")<<pin<<endl;
if (pin<0)
pinMode(-pin, INPUT_PULLUP);
else
pinMode(pin, INPUT);
}
bool readInPin(short pin)
{
if (abs(pin)>=PINS_COUNT)
{
debugSerial<<F("Attempt to read non existing pin: ")<<pin<<endl;
return false;
}
if (pin<0)
return (digitalRead(-pin)==LOW);
else
return (digitalRead(pin)==HIGH);
}
void writeOutPin(short pin, bool val)
{
if(isProtectedPin(abs(pin)))
{
debugSerial<<F("Attempt to write protected pin: ")<<pin<<endl;
return;
}
if (abs(pin)>=PINS_COUNT)
{
debugSerial<<F("Attempt to write non existing pin: ")<<pin<<endl;
return;
}
if (pin<0)
digitalWrite(-pin, val?LOW:HIGH);
else
digitalWrite(pin, val?HIGH:LOW);
}
#pragma message(VAR_NAME_VALUE(debugSerial)) #pragma message(VAR_NAME_VALUE(debugSerial))
#pragma message(VAR_NAME_VALUE(SERIAL_BAUD)) #pragma message(VAR_NAME_VALUE(SERIAL_BAUD))

View File

@@ -91,7 +91,9 @@ bool checkToken(char * token, char * data);
long getIntFromJson(aJsonObject * a, const char * name, int i,long def); long getIntFromJson(aJsonObject * a, const char * name, int i,long def);
float getFloatFromJson(aJsonObject * a, const char * name, int i, float def); float getFloatFromJson(aJsonObject * a, const char * name, int i, float def);
void setupInPin(short pin);
bool readInPin(short pin);
void writeOutPin(short pin, bool val);
// Get object from array, create if absent and return pointer to object // Get object from array, create if absent and return pointer to object
template<typename Type> template<typename Type>