Sprinkler module released

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-05-22 22:44:36 +03:00
parent 641b314218
commit 985d058c50
3 changed files with 202 additions and 50 deletions

View File

@@ -28,13 +28,13 @@ INIT | true | OFF | выключить клапана
OFF | vMax && !FREEZE | FULL | выключить vIN, rDren| OFF | vMax && !FREEZE | FULL | выключить vIN, rDren|
OFF | ! vMax && !FREEZE | DREN\_ON|включить rDren| OFF | ! vMax && !FREEZE | DREN\_ON|включить rDren|
DREN\_ON|fbDren (насос дренажа реально работает)|DREN\_OPERATE| DREN\_ON|fbDren (насос дренажа реально работает)|DREN\_OPERATE|
DREN\_ON|таймаут 10 сек|DREN\_EMPTY| DREN\_ON|таймаут 10 сек|DREN\_EMPTY| насос так и не заработал - видимо в колодце пусто
DREN\_EMPTY|включен цикл полива и бак не полон|VIN|включить клапан vIN для набора бака из водопровода| DREN\_EMPTY|включен цикл полива и бак не полон|VIN|включить клапан vIN для набора бака из водопровода|
DREN\_OPERATE|fbDren (насос дренажа более не работает)|DREN\_EMPTY|| DREN\_OPERATE| ! fbDren (насос дренажа более не работает)|DREN\_EMPTY||
VIN|fbDren|DREN\_OPERATE|вылючить клапан vIN для набора бака из водопровода| VIN|fbDren|DREN\_OPERATE|вылючить клапан vIN для набора бака из водопровода - заработал дренажный насос|
VIN, DREN\_OPERATE|vMax|FULL | выключить vIN, rDren| VIN, DREN\_OPERATE|vMax|FULL | выключить vIN, rDren - бак полон|
VIN|таймаут 1200 сек | FAULT\_VIN| выключить vIN| VIN|таймаут 1200 сек | FAULT\_VIN| выключить vIN - бак так и не наполнился|
DREN\_OPERATE|таймаут 1200 сек |FAULT_DREN|| DREN\_OPERATE|таймаут 2000 сек |FAULT_DREN|выключить rDren - не смотря на продолжительную работу насоса бак не наполнен|
@@ -59,7 +59,8 @@ DREN\_OPERATE|таймаут 1200 сек |FAULT_DREN||
}, },
"nord":{"pin":6,"set":60,"cmd":1}, "nord":{"pin":6,"set":60,"cmd":1},
"south":{"pin":7,"set":100,"cmd":1}, "south":{"pin":7,"set":100,"cmd":1},
"trees":{"pin":10,"set":60,"cmd":2} "trees":{"pin":10,"set":60,"cmd":2},
"outlets:{}
}] }]
} }
@@ -79,15 +80,19 @@ DREN\_OPERATE|таймаут 1200 сек |FAULT_DREN||
Контроллер должен передать это значение в выходной топик ```root/name/s_out/sprinkrer/garden/set``` и оно будет восстановлено при перезагрузке контроллера Контроллер должен передать это значение в выходной топик ```root/name/s_out/sprinkrer/garden/set``` и оно будет восстановлено при перезагрузке контроллера
отработанный обьем воды или время будет сохраняться в параметре "val" каждой зоны (параметр будет автоматически увеличиваться при работе зоны, передаваться в соответствующий зоне топик для мониторинга и восстановления в случае перезагрузки контроллера) отработанный обьем воды или время будет сохраняться в параметре "val" каждой зоны (параметр будет автоматически увеличиваться при работе зоны, передаваться в соответствующий зоне топик для мониторинга и восстановления в случае перезагрузки контроллера)
**Пример топика:** ```root/s_out/sprinkler/garden/val``` **Пример топика:** ```root/s_out/sprinkler/garden/val```
Когда данный параметр достигнет значения, заданного в параметре "set" контроллер завершит полив данной зоны и перейдет к следующей. Когда данный параметр достигнет значения (или времени), заданного в параметре "set" контроллер завершит полив данной зоны и перейдет к следующей.
Важно: если set=0 (по умолчанию) то время работы зоны не лимитируется. Если такая зона включена - система полива не будет отключаться после окончания полива прочих зон и насос не будет обесточиваться. Это удобно, если в системе полива есть водяная розетка для подключения поливочного шланга, которая всегда должна находиться под давлением. Такую зону конфигурируйте последней в списке.
Для сброса счетчиков можно использовать как непосредственную установку значения параметра "val" для каждой зоны так и команду RESET, отправленную в нужную зону или в объект sprinkler через суффикс /cmd. Для сброса счетчиков можно использовать как непосредственную установку значения параметра "val" для каждой зоны так и команду RESET, отправленную в нужную зону или в объект sprinkler через суффикс /cmd.
В последнем случае, контроллер итерационно сбросит счетчики в значение 0 для каждой зоны полива. В последнем случае, контроллер итерационно сбросит счетчики в значение 0 для каждой зоны полива.
А также, отключит систему полива, чтобы программа не стартовала в момент сброса счетчиков (например, в полночь)
**Пример:** ```root/name/sprinkler/cmd -> RESET``` **Пример:** ```root/name/sprinkler/cmd -> RESET```
@@ -178,4 +183,128 @@ root/s_out/sprinkler/garden/cmd - ON или OFF - признак включен
root/s_out/sprinkler/garden/$state - ON или OFF - признак того что зона поливается в настоящее время root/s_out/sprinkler/garden/$state - ON или OFF - признак того что зона поливается в настоящее время
root/s_out/sprinkler/garden/val - текущее время или обьем полива данной зоны root/s_out/sprinkler/garden/val - текущее время или обьем полива данной зоны
```
### Пример конфигурации Home Assistant
```
sensor:
- name: "Полив бак Макс"
state_topic: "root/s_out/sprinkler/$wMax"
- name: "Полив бак Мin"
state_topic: "root/s_out/sprinkler/$wMin"
- name: "Полив водопровод"
state_topic: "root/s_out/sprinkler/$vIN"
- name: "Полив дренаж вкл"
state_topic: "root/s_out/sprinkler/$rDren"
- name: "Полив дренаж качает"
state_topic: "root/s_out/sprinkler/$fbDren"
- name: "Полив насос вкл"
state_topic: "root/s_out/sprinkler/$rPump"
- name: "Полив насос качает"
state_topic: "root/s_out/sprinkler/$fbPump"
- name: "Полив состояние"
state_topic: "root/s_out/sprinkler/$state"
- name: "Полив ошибка"
state_topic: "root/s_out/sprinkler/$fault"
- name: "Полив юг выполнено"
state_topic: "root/s_out/sprinkler/south/val"
- name: "Полив север выполнено"
state_topic: "root/s_out/sprinkler/nord/val"
- name: "Полив капельный выполнено"
state_topic: "root/s_out/sprinkler/trees/val"
- name: "Полив блокировки"
state_topic: "root/s_out/sprinkler/ctrl"
switch:
- name: "Полив"
state_topic: "root/s_out/sprinkler/cmd"
command_topic: "root/air/sprinkler/cmd"
availability_topic: "root/air/$state"
payload_available: "ready"
payload_not_available: "disconnected"
- name: "Полив север"
state_topic: "root/s_out/sprinkler/nord/cmd"
command_topic: "root/air/sprinkler/nord/cmd"
availability_topic: "root/air/$state"
payload_available: "ready"
payload_not_available: "disconnected"
- name: "Полив юг"
state_topic: "root/s_out/sprinkler/south/cmd"
command_topic: "root/air/sprinkler/south/cmd"
availability_topic: "root/air/$state"
payload_available: "ready"
payload_not_available: "disconnected"
- name: "Полив капельный"
state_topic: "root/s_out/sprinkler/trees/cmd"
command_topic: "root/air/sprinkler/trees/cmd"
availability_topic: "root/air/$state"
payload_available: "ready"
payload_not_available: "disconnected"
- name: "Полив розетки"
state_topic: "root/s_out/sprinkler/outlets/cmd"
command_topic: "root/air/sprinkler/outlets/cmd"
availability_topic: "root/air/$state"
payload_available: "ready"
payload_not_available: "disconnected"
button:
- name: "Полив сброс"
command_topic: "root/air/sprinkler/cmd"
payload_press: "RESET"
- name: "Полив блокировка"
command_topic: "root/air/sprinkler/cmd"
payload_press: "FREEZE"
- name: "Полив разблокировка"
command_topic: "root/air/sprinkler/cmd"
payload_press: "UNFREEZE"
- name: "Полив разрешить"
command_topic: "root/air/sprinkler/cmd"
payload_press: "ENABLE"
- name: "Полив запретить"
command_topic: "root/air/sprinkler/cmd"
payload_press: "DISABLE"
number:
- name: "Полив юг"
state_topic: "root/s_out/sprinkler/south/set"
command_topic: "root/air/sprinkler/south/set"
min: 0
max: 6000
- name: "Полив север"
state_topic: "root/s_out/sprinkler/nord/set"
command_topic: "root/air/sprinkler/nord/set"
min: 0
max: 6000
- name: "Полив капельный"
state_topic: "root/s_out/sprinkler/trees/set"
command_topic: "root/air/sprinkler/trees/set"
min: 0
max: 6000
``` ```

View File

@@ -99,7 +99,7 @@ int out_sprinkler::Setup()
debugSerial << F("SPRINKLER: ") << " wMax=" << wMaxPin << " wMin=" << wMinPin << " fbDren=" << fbDrenPin << " fbPump=" << fbPumpPin << " wCtr=" << wCtrPin << endl; debugSerial << F("SPRINKLER: ") << " wMax=" << wMaxPin << " wMin=" << wMinPin << " fbDren=" << fbDrenPin << " fbPump=" << fbPumpPin << " wCtr=" << wCtrPin << endl;
uint16_t lastVals = 0; uint16_t lastVals = 0;
if (wCtrPin != PINS_COUNT) if (abs(wCtrPin) < PINS_COUNT)
{ {
setupInPin(wCtrPin); setupInPin(wCtrPin);
lastVals |= (readInPin(wCtrPin) ? LASTWCTRLSTATE : 0); lastVals |= (readInPin(wCtrPin) ? LASTWCTRLSTATE : 0);
@@ -165,7 +165,7 @@ bool out_sprinkler::isNeedPump(bool steelNeed)
{ {
long setVal = getIntFromJson(zone, "set", 0); long setVal = getIntFromJson(zone, "set", 0);
long valVal = getIntFromJson(zone, "val", 0); long valVal = getIntFromJson(zone, "val", 0);
if (valVal < setVal) return true; if (!setVal || (valVal < setVal)) return true;
} }
} }
zone = zone->next; zone = zone->next;
@@ -199,6 +199,20 @@ void out_sprinkler::dren(bool state)
} }
} }
void out_sprinkler::vin(bool state)
{
if (!isValidControlPin(vinPin)) return;
uint32_t lastVals = getIntFromJson (gatesObj, "@lastVals", 0);
setOutput(vinPin, state);
if (state != (bool)(lastVals & LASTVINSTATE))
{
if(state) lastVals |= LASTVINSTATE; else lastVals &= ~LASTVINSTATE;
setValToJson(gatesObj, "@lastVals", (long)lastVals);
publishBooleanState("/$rVIN", state);
}
}
void out_sprinkler::turnOffAllZones() void out_sprinkler::turnOffAllZones()
{ {
if (!gatesObj) return; if (!gatesObj) return;
@@ -208,7 +222,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", PINS_COUNT); short pin = getIntFromJson(zone, "pin", PINS_COUNT);
setOutput(pin, false); if (isValidControlPin(pin)) setOutput(pin, false);
if (getIntFromJson(zone, "@active", 0)) if (getIntFromJson(zone, "@active", 0))
{ {
setZoneActive(zone, false); setZoneActive(zone, false);
@@ -241,8 +255,9 @@ long fault = 0;
if (!gatesObj) return; if (!gatesObj) return;
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
aJsonObject * rootCfg = aJson.getObjectItem(gatesObj, "");
aJsonObject *faultObj = aJson.getArrayItem(item->itemArg, 3); if (!rootCfg) rootCfg = gatesObj;
aJsonObject * faultObj = aJson.getObjectItem(rootCfg, "onFault");
switch (state) { switch (state) {
case SP_OFF: case SP_OFF:
@@ -298,7 +313,7 @@ publishTopic(item->itemArr->name,val,"/$state");
int out_sprinkler::shutdown(sprinklerState nextState) int out_sprinkler::moveToState(sprinklerState nextState)
{ {
if (!gatesObj) return 0; if (!gatesObj) return 0;
@@ -306,36 +321,36 @@ int out_sprinkler::shutdown(sprinklerState nextState)
{ {
case SP_OFF: case SP_OFF:
case SP_FULL: case SP_FULL:
setOutput(drenPin, false); dren(false);
setOutput(vinPin, false); vin(false);
break; break;
case SP_DREN_ON: case SP_DREN_ON:
case SP_DREN_OPERATE: case SP_DREN_OPERATE:
setOutput(drenPin, true); dren(true);
setOutput(vinPin, false); vin(false);
break; break;
case SP_VIN: case SP_VIN:
setOutput(vinPin, true); vin(true);
setOutput(drenPin, false); //setOutput(drenPin, false);
break; break;
case SP_DREN_EMPTY: case SP_DREN_EMPTY:
setOutput(drenPin, false); //setOutput(drenPin, false);
setOutput(vinPin, false); vin(false);
break; break;
case SP_FAULT_VIN: case SP_FAULT_VIN:
setOutput(vinPin, false); vin(false);
break; break;
case SP_FAULT_DREN: case SP_FAULT_DREN:
setOutput(drenPin, false); dren(false);
break; break;
case SP_UNKNOWN: case SP_UNKNOWN:
setOutput(drenPin, false); dren(false);
setOutput(vinPin, false); vin(false);
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;
} }
@@ -370,7 +385,7 @@ inline aJsonObject * out_sprinkler::findNextZone()
int cmd = getIntFromJson(zone, "cmd", CMD_OFF); int cmd = getIntFromJson(zone, "cmd", CMD_OFF);
long setVal = getIntFromJson(zone, "set", 0); long setVal = getIntFromJson(zone, "set", 0);
long valVal = getIntFromJson(zone, "val", 0); long valVal = getIntFromJson(zone, "val", 0);
if (cmd == CMD_ON && valVal < setVal) return zone; if (cmd == CMD_ON && (!setVal || valVal < setVal)) return zone;
} }
zone = zone->next; zone = zone->next;
} }
@@ -443,7 +458,7 @@ 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 != PINS_COUNT) if (abs(wCtrPin) < PINS_COUNT)
{ {
bool curr = readInPin(wCtrPin); bool curr = readInPin(wCtrPin);
if (curr && !lastWctrlStateAll) if (curr && !lastWctrlStateAll)
@@ -456,7 +471,7 @@ int out_sprinkler::Poll(short cause)
if (freeze) if (freeze)
{ {
shutdown(SP_OFF); moveToState(SP_OFF);
turnOffValves(); turnOffValves();
pump(false); pump(false);
return 0; return 0;
@@ -477,7 +492,7 @@ int out_sprinkler::Poll(short cause)
state = SP_DREN_ON; state = SP_DREN_ON;
setValToJson(gatesObj, "@timer", (long)now); setValToJson(gatesObj, "@timer", (long)now);
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_DREN_ON); moveToState(SP_DREN_ON);
} }
break; break;
@@ -487,13 +502,13 @@ int out_sprinkler::Poll(short cause)
state = SP_DREN_OPERATE; state = SP_DREN_OPERATE;
setValToJson(gatesObj, "@timer", (long)now); setValToJson(gatesObj, "@timer", (long)now);
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_DREN_OPERATE); moveToState(SP_DREN_OPERATE);
} }
else if (isTimeOver(timer, now, DRENAGE_ON_TIME)) else if (isTimeOver(timer, now, DRENAGE_ON_TIME))
{ {
state = SP_DREN_EMPTY; state = SP_DREN_EMPTY;
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_DREN_EMPTY); moveToState(SP_DREN_EMPTY);
} }
break; break;
@@ -502,19 +517,19 @@ int out_sprinkler::Poll(short cause)
{ {
state = SP_DREN_EMPTY; state = SP_DREN_EMPTY;
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_DREN_EMPTY); moveToState(SP_DREN_EMPTY);
} }
else if (wMax) else if (wMax)
{ {
state = SP_FULL; state = SP_FULL;
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FULL); moveToState(SP_FULL);
} }
else if (isTimeOver(timer, now, 1200000UL)) else if (isTimeOver(timer, now, DRENAGE_MAX_TIME))
{ {
state = SP_FAULT_DREN; state = SP_FAULT_DREN;
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FAULT_DREN); moveToState(SP_FAULT_DREN);
} }
break; break;
@@ -523,14 +538,14 @@ int out_sprinkler::Poll(short cause)
{ {
state = SP_FULL; state = SP_FULL;
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FULL); moveToState(SP_FULL);
} }
else if (item->getCmd() == CMD_ON) else if (item->getCmd() == CMD_ON)
{ {
state = SP_VIN; state = SP_VIN;
setValToJson(gatesObj, "@timer", (long)now); setValToJson(gatesObj, "@timer", (long)now);
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_VIN); moveToState(SP_VIN);
} }
break; break;
@@ -540,19 +555,19 @@ int out_sprinkler::Poll(short cause)
state = SP_DREN_OPERATE; state = SP_DREN_OPERATE;
setValToJson(gatesObj, "@timer", (long)now); setValToJson(gatesObj, "@timer", (long)now);
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_DREN_OPERATE); moveToState(SP_DREN_OPERATE);
} }
else if (wMax) else if (wMax)
{ {
state = SP_FULL; state = SP_FULL;
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FULL); moveToState(SP_FULL);
} }
else if (isTimeOver(timer, now, VIN_MAX_TIME)) else if (isTimeOver(timer, now, VIN_MAX_TIME))
{ {
state = SP_FAULT_VIN; state = SP_FAULT_VIN;
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FAULT_VIN); moveToState(SP_FAULT_VIN);
} }
break; break;
@@ -562,7 +577,7 @@ int out_sprinkler::Poll(short cause)
state = SP_DREN_ON; state = SP_DREN_ON;
setValToJson(gatesObj, "@timer", (long)now); setValToJson(gatesObj, "@timer", (long)now);
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_DREN_ON); moveToState(SP_DREN_ON);
} }
break; break;
@@ -571,7 +586,7 @@ int out_sprinkler::Poll(short cause)
{ {
state = SP_FULL; state = SP_FULL;
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FULL); moveToState(SP_FULL);
} }
break; break;
@@ -580,7 +595,7 @@ int out_sprinkler::Poll(short cause)
{ {
state = SP_FULL; state = SP_FULL;
setValToJson(gatesObj, "@state", (long)state); setValToJson(gatesObj, "@state", (long)state);
shutdown(SP_FULL); moveToState(SP_FULL);
} }
break; break;
} }
@@ -609,11 +624,11 @@ int out_sprinkler::Poll(short cause)
turnOffAllZones(); turnOffAllZones();
setZoneActive(currentZone, true); setZoneActive(currentZone, true);
short zonePin = getIntFromJson(currentZone, "pin", PINS_COUNT); short zonePin = getIntFromJson(currentZone, "pin", PINS_COUNT);
setOutput(zonePin, true); if (isValidControlPin(zonePin)) setOutput(zonePin, true);
setValToJson(gatesObj, "@flowTimer", (long)now); setValToJson(gatesObj, "@flowTimer", (long)now);
} }
if (wCtrPin != PINS_COUNT) if (abs(wCtrPin) < PINS_COUNT)
{ {
bool curr = readInPin(wCtrPin); bool curr = readInPin(wCtrPin);
if (curr && !lastWctrlState) if (curr && !lastWctrlState)
@@ -636,7 +651,9 @@ int out_sprinkler::Poll(short cause)
if (setVal > 0 && valVal >= setVal) if (setVal > 0 && valVal >= setVal)
{ {
setOutput(getIntFromJson(currentZone, "pin", PINS_COUNT), false); short zonePin = getIntFromJson(currentZone, "pin", PINS_COUNT);
if (isValidControlPin(zonePin)) setOutput(zonePin, 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);
@@ -775,6 +792,9 @@ int out_sprinkler::Ctrl(itemCmd cmd, char* subItem, bool toExecute, bool authori
} }
zone = zone->next; zone = zone->next;
} }
turnOffAllZones();
pump(false);
item->Off();
} }
return 1; return 1;

View File

@@ -8,6 +8,7 @@
#define DRENAGE_ON_TIME 10000 #define DRENAGE_ON_TIME 10000
#define VIN_MAX_TIME 1200000UL #define VIN_MAX_TIME 1200000UL
#define DRENAGE_MAX_TIME 2000000UL
#define LASTWCTRLSTATE 1 #define LASTWCTRLSTATE 1
#define LASTWCTRLSTATE_ALL 2 #define LASTWCTRLSTATE_ALL 2
@@ -17,6 +18,7 @@
#define LASTFBPUMPSTATE 32 #define LASTFBPUMPSTATE 32
#define LASTPUMPSTATE 64 #define LASTPUMPSTATE 64
#define LASTDRENSTATE 128 #define LASTDRENSTATE 128
#define LASTVINSTATE 256
enum sprinklerState { enum sprinklerState {
SP_UNKNOWN = 0, SP_UNKNOWN = 0,
@@ -51,6 +53,7 @@ protected:
void pump(bool state); void pump(bool state);
void dren(bool state); void dren(bool state);
void vin(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();
@@ -64,7 +67,7 @@ protected:
void publishBooleanStateIfChanged(const char * subItem, bool state, uint32_t flag, uint32_t & lastState); 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 moveToState(sprinklerState nextState);
void updateCounterValue(); void updateCounterValue();
}; };
#endif #endif