Automata locsolórendszer

Tartalom:

  • Kertlocsolás kialakítása, szivattyú elhelyezés, csövezés, mágnesszelepes vezérlés
  • Rendszerterv, 5 locsolóprogrammal, locsolási időpontokkal, tanuló mód, 10 vezérelhető locsolókör
  • Relés vezérlés manuális módban, Arduino MEGA vezérlés automata módban
  • Vízkifogyás érzékelése, locsolóprogram folytatása
  • Rádiós távvezérlővel és nyomógombbal slag (autómosás) indítás, locsolóprogram megszakítása és folytatása
  • Teljes forráskód
  • Relés vezérlés és Arduino vezérlés áramkör szimulátoros állományai, kipróbálhatóság szimulátorban

Mint említettem a STARduino bevezető oldalán, ezt a weboldalt saját magam is használom. Gyorsan és bárhonnan, tetszőleges eszközről elérhetem az információkat. Ezért jobb, mint egy Word dokumentum. Így most is kihasználom a lehetőséget, és egy olyan munka leírása került az oldalra, ami még nincs készen. Sőt! Várhatóan hónapok múlva, esetleg egy-két év múlva lesz olyan ez a szerkezet mint amit megálmodtam, és ezt sem akartam megvárni a publikálással. Annak, aki automata locsolórendszer építésre adja a fejét, már ennyi is hasznos lehet, ezért folyamatosan frissítem a leírást, ahogyan haladok előre. Már most kiderülhet a leírásokból, hogy milyen apró problémákba lehet ütközni egy ennyire egyszerűnek tűnő szerkezet építése közben is. Igyekszem alaposan átgondolni minden eshetőséget és szituációt, hogy ne akkor szembesüljek a problémákkal, amikor elkészültem. Ezt a szerkezetet igazából már kb. 5 éve tervezgetem, gondolatban gyűjtöttem az információkat, hogyan is lenne komfortos a működés. Már van némi elképzelésem arról, hogy az Apolló űrhajót miért tervezte és építette több ezer mérnök közel egy évtizeden keresztül.
Még csak a tervezést fejeztem be, és most kezdődik a hardver megépítése, amihez a weboldalról használom az eddig elkészült dokumentációt.

Néhány információ szükséges a kiépített locsolórendszerről, hogy érthető legyen, mi miért készült a rendszerben.

Kiépítés leglényegesebb elemei:

  1. Kertünkben egy gyűrűs kútba leeresztett Pedrollo szivattyú üzemel, ami évek óta a kútban van, még soha nem kellett felhúzni. A szivattyú rendelkezik egy úszó kapcsolóval, ami kikapcsolja a motort (megszakítja a 230V hálózatot), ha a vízszint a motor beömlő nyilasa közelébe csökken. Ha növekszik a vízszint (kb. 50cm növekedés) újra bekapcsol. A kút lényegében egy nagy gödör, ami jó esetben tele van vízzel. Megtelt állapotban kb. 1.5m a vízmagasság a gödör alja és maximális vízszint között. A vizet a szivattyú 20-30 perc alatt teljesen kiszívja a gödörből, és kb. 1-2 óra alatt újra megtelik vízzel, ami az oldalsó talajrétegekből szivárog a gödörbe. Még soha nem tudtam megmérni, de egy teljes leszívással kb. 500-1000liter vizet lehet kinyerni. Ez szárazságban egy teljes kertlocsoláshoz éppen elegendő.
  2. A kútból a szivattyú egy sima locsolócsőben tolja fel a vizet kb. 8 méter mélységből. Ez a cső két irányba ágazik el.
    a.) Az egyik irány egy 24V váltófeszültségű solenoidon (mágnesszelepen) keresztül közvetlenül egy „magas nyomású” hálózatba kerül. Ha a solenoidot bekapcsoljuk (24V-ot kapcsolunk rá), akkor a víz a kertben több ponton elhelyezett vízcsatlakozókhoz áramlik, és ezzel a hálózattal lehet slaggal (szépen magyarosan „tömlővel”) locsolni.
    b.) A másik irányban szintén egy solenoid található, azt követi egy kimosható szűrő, ami a vízben található szennyeződések eltávolítására szolgál, valamint egy rugós elven működő nyomáscsökkentő, ami kb. 1.5 bar nyomást állít be. A szivattyú 3-4 bar nyomást állít elő, de ezt még soha nem mértem meg, csak becslés. A nyomáscsökkentőre azért van szükség, mert a locsolást csepegtető csövekkel és locsoló gombákkal oldottam meg, és ezek többé kevésbé egyenletes és alacsonyabb víznyomást igényelnek. Egy kép a kútban látható berendezésekről:
  • Az alacsony nyomású vízvezeték körbe fut a kerten és több ponton függőlegesen kiemelkedik egy csőcsonk, amire 24Volt egyenárammal működő mágneskapcsolók kerültek. Míg a kútban elhelyezett mágneskapcsolók sok vizet engednek át magukon, nagyon drágák (kb. 8000Ft db-ja). Ezek a mágneskapcsolók válójában mosógépekhez gyártott mágneskapcsolók, jóval kevesebb, de azért elegendő vizet engednek át magukon (néhány liter percenként). Viszont sokkal olcsóbbak, kb. 1000Ft-ba kerültek kínai testvéreinknél.

Sajnos a szelepekhez beszerelt vezeték hossza elérte 200 métert, így többe került, mint a locsoló rendszer összes műanyagcsöve. Erre nem számítottam, mert elég kicsi a kertünk. A mágneskapcsolókból 10db-ra volt szükségem, mert a kert sajnos nem locsolható egyszerre. Ugyan a terület csak kb. 50-70nm, a szükséges csepegtető csövek, szalagok hossza és locsológombák együttes száma olyan nagy, amit a szivattyú nem bír ellátni vízzel egyszerre. Ráadásul a csepegtető szalagok más nyomást igényelnek, mint a locsoló gombák, így a csepegtető csöveknek további 0.6 bar-os nyomáscsökkentőket szereltem be. Ha leesik nyomás, mert sok fogyasztót kapcsolok a szivattyúra, akkor az nem azt eredményezi, hogy minden lyukon lassabban folyik a víz, hanem egyes lukakon egyáltalán nem folyik, másokon meg igen! Így sajnos csak szakaszonként lehet locsolni elegendően magas nyomással. Bezzeg az elektronikában nincsenek ilyen problémák. Az ellenállás az ellenállás, a feszültség meg feszültség, Kirchoff törvényei mindig működnek. Láthatóan a víz világa alacsonyabb rendű, butább világ, nem tiszteli a törvényeket 😊. De nem baj, mi vagyunk az okosabbak, átverjük, csak ez sokba kerül, és egy számítógép vezérelt locsolórendszer létrehozása szükséges hozzá!

A feladat:

Kb. 20-40 ezer forintért nagyon profi locsolás vezérlők kaphatók. Sok mágnes szelepet vezérelnek, sok időprogramot megjegyeznek, talán a drágábbak még New York-ból is indíthatók mobiltelefonról, de egyik sem tudta azt az egyszerű dolgot, amire nekem szükségem volt. Nem voltak képesek külön vezérelni a nagy és a csökkentett nyomású hálózatot (slag és csepegtető), nem kapcsolták be a szivattyút, csak a szelepeket vezérelték, és a legfejlettebbek is csak 8 mágnesszelepet vezérletek. Egy ilyen vezérlővel házi vízműben kellett volna gondolkodnom, vagy csak vezetékes vízzel tudok locsolni. Azt már meg sem említem, hogy ami nekem fontos volt, hogy rádiós távvezérlővel külön ki be kapcsolhassam a locsoló slagot, ha autót mosok, azt egyik sem tudta. Persze lehetséges, hogy nem találtam meg a megfelelő típust. Kb. 50 ezer forintos nagyságrendű készülékeknél hagytam abba a további keresést. Ennyibe került a szivattyú nélkül az összes cső, locsoló gomba, idomok szerelvények szerszámok stb. Ennyit már igazán nem akartam egy automata öntöző vezérlőre költeni. Tanulság: speciális igényekhez nem lehet berendezést venni, magadnak kell megcsinálni.

Ezek alapján a következők az elvárások:

  • Rádiós vezérlővel lehessen a slag-ot külön ki és bekapcsolni. Kertlocsolásnál vegye figyelembe, ha közben a slag használat miatt kiesett idő, ettől ne kapjanak kevesebb vizet az ágyások (folytassa a locsoló programot). Ez azt jelenti, hogy legyen prioritása a slag-nak! Ha autót akarok mosni, addig állítsa le a kertlocsolást, a kettő nem megy egyszerre.
  • Tíz mágneskapcsolót vezéreljen egyszerre, plusz a két fő mágnesszelepet, melyek kertlocsolás vagy slag irányba kapcsolják a vizet. Kapcsolja be a szivattyút amikor szükség van rá, és kapcsolja ki, ha végzett!
  • Ha a kútból kifogy a víz, és leáll a szivattyú, helyezze a locsolást „pause” állapotba, kacsolja le a feszültséget a mágneskapcsolókról, mert 5W teljesítmény az áramló víz hűtése nélkül esetleg tönkre teheti azokat.
  • Lehessen több időpontot beállítani a locsolás elkezdéséhez. Öt időpontot határoztam meg, bár a gyakorlatban nekem kettő is elégnek tűnik. Akkor is többre lehet szükség, ha egyes növényeket lényegesen ritkábban kell locsolni, pl. kétnaponta. Ezért az időpontok között legyen megadható a hét adott napja is mint kezdő időpont.
  • Lehessen több locsoló programot tárolni. Sorban meg lehessen adni, hogy mennyi ideig locsoljuk a paradicsomot, paprikát, zöldséget stb. Mindnek más a vízigénye. Több programra azért is szükség van, mert pl. a paradicsomot minden nap kell locsolni, a málnabokroknak elég hetente egy locsolás stb. Nyilván az időprogramokhoz beállítható, hogy melyik locsolási programot indítja el. Összesen öt locsoló program tárolásának lehetőségét elégnek tartottam.
  • Legyen tanuló üzemmód. Ez azt jelenti, hogy elindítom a locsolást, kiálok az ágyások szélére, és szemmel megállapítom mikor elég. Odaballagok a vezérlőhöz lekapcsolom az éppen locsolt ágyásokat és másikat állítok be. Újra várakozok, hogy mikor elég, megint átállítom a mágnesszelepeket és így tovább. Jegyezze meg, mikor mit, és mennyi ideig locsoltam. Megjegyzem, ilyen üzemmód sem volt az általam megismert méregdrága luxus locsoló vezérlőkben.
  • Nyilván lehessen nyomógombokról is programozni, meglévő programot módosítani stb.
  • Bónusz elvárás, hogy vegye figyelembe, ha eső esett, sokat sütött a nap és fújt a szél, és ezeknek megfelelő vizet engedjen az ágyásokra. Hát ez nem fog elsőre menni! Az eső mérés, szélsebesség mérés már megoldott, megvannak a szükséges szenzorok, de itt még tapasztalatot kell gyűjteni. Nincsenek viszony számaim, hogy x mm eső hány perc locsolásnak felel meg az ágyásokban stb. Így kísérletezgetés kezdődik, ha elkészül a rendszer. Szerintem ennek „belövése” két nyár. Első körben megelégszem azzal, ha a fenti elvárások teljesülnek.

 Rendszerterv:

Az idei évben már központi helyről kézzel kapcsolgattam a mágnesszelepeket. Ehhez készült egy műanyag doboz, beleszereltem a kapcsolókat és a fontosabb vezetékeket. Ezt a műanyag dobozt a kúthoz közeli „kisház”-nak becézett szerszámoskamra szerű épületben helyeztem el. Ebben az épületben van áram, jelenleg is innen lehet bekapcsolni a szivattyút, illetve van hozzá egy 10A-es biztosíték. A mágnesszelepeknek egy 24V-os 4A-es nyomtató tápegység ad feszültséget. Úgy tervezem, hogy a teljes berendezésnek ez lesz a tápegysége, DC-DC konverterekkel csinálok majd 5V-ot az Arduino-nak. Minden más 24V-ról fog működni (relék LED-ek stb.) Így néz ki a műanyag doboz, amibe tervezem beépíteni az elektronikus vezérlést is:

Ezt a dobozt fogom tovább farigcsálni, lyukasztgatni, és ebből valami ehhez hasonló szerkezet fog kialakulni (miközben írtam a rendszertervet, fokozatosan rakosgattam a ledeket, nyomógombokat a tervezett helyükre):

Fő üzemmódok:

SLAG BE/KI működés. Ez nem egy megkülönböztetett üzemmód, hanem két magas prioritású nyomógomb a panelen, melyek minden állapotban működnek. Nem kell hozzájuk a vezérlő működése sem, relék kapcsolgatásával zajlanak az átkapcsolások. Ha manuális beállítással locsolás zajlik (az alsó választó kapcsolókkal direktben, KÉZI működéssel locsolunk), akkor azt a SLAG BE nyomógomb megnyomása, vagy a távirányító megfelelő gombjának megnyomása megszakítja, és a slag-ot használhatjuk pl. autómosásra. Automatikus locsolást is ugyanígy megszakítja a slag használat. A SLAG KI nyomógomb megnyomásával (illetve távitányitó KI gombjának megnyomásával) véget és a slag használat, minden visszakapcsol a megelőző feladatra, tehát zajlik tovább a kézi locsolás, vagy folytatódik a félbehagyott időzített automata locsolási program.

Kézi működés. Ebben a működési módban manuálisan állíthatjuk be a szelep vezérlő kapcsolókat.
A működés választó kapcsolót „KÉZI” állásba kell tenni, azaz lefele kell kapcsolni a váltókapcsolót a kezelő panel közepén. A szelepek vezérlését ekkor a szelepekhez rendelt kapcsolók veszik át. A mágneskapcsolók vezérléséhez semmilyen program vagy elektronika nem kell, pusztán a kapcsolók és néhány relé végzi a feladatokat. Ez egyfajta vész üzemmód, ha az Arduino bedöglene. Ha a mikrovezérlő nem működik, akkor is megy az öntözés, mert a kézi szelep kapcsolók kapcsolják a szelepeket, és ha egyetlen egy is be van kapcsolva, akkor beindul a motor, és a csepegtető csőrendszerhez rendelt fő solenoid a kútban. A motor beindítását bármelyik szelep vezérlő kapcsoló bekapcsolása vagy a SLAG BE nyomógomb megnyomása kiváltja. Ha nincs bekapcsolva egyetlen szelep sem, illetve a slag-ot sem akarjuk használni, akkor a szivattyú is áll. A fő solenoidok (csepegtető és slag választó mágnesszelepek) vezérlését is automatikusan relékkel akarom megoldani, tehát ha a szelepvezérlők valamelyikét bekapcsolom, akkor kinyit a csepegtető fő szelep, ha slag-ot kapcsolom be akkor kinyit a slag fő szelep. Ha a motor áll, akkor a fő szelepek sem kapnak feszültséget, mert azok táplálását egy 24V-os trafó végzi, ami a szivattyúval együtt kap áramot.
Ez az üzemmód azért lesz kialakítva, mert nem bízok meg annyira az elkészülő berendezésben, hogy kockáztassam a növények locsolását egy esetleges meghibásodás, vagy üzemzavar esetén. Ez biztosan működni fog minden pillanatban, hiszen nincs benne semmilyen vezérlő elektronika, vagy szoftver. Egy mechanikus kapcsolóban már meg kell bíznom! Másik ok, hogy ha velem valami történik és a berendezés elromlik, nem lesz ember a földön, aki megjavítja. Legalább ez az üzemmód működni fog.

Automata működés: Ebben a működési módban az Arduino-ra írt program vezérli a locsolást. Az automata locsoláshoz természetesen be kell valahogyan állítani a locsolási programot és be kell állítani az automatikus elindulások időpontjait.
A működés választó kapcsolót „AUTOMATA” üzemmódba kell kapcsolni ahhoz, hogy automatikus locsolási funkciókat tudjunk használni. A szelepek vezérlését ekkor a mikrovezérlő veszi át. Az átkapcsolás pillanatában a mikrovezérlő alap állapotba kerül, vagyis egyetlen szelepet sem kapcsol be, a motor áll. Ha esetleg a KÉZI vezérlésnél járt a motor, akkor azonnal leáll. Az Automata üzemmódnak 4 fő állapota lehetséges, ezt a „MÓD választó” nyomógombbal lehet beállítani, ha ciklikusan nyomogatjuk, a négy LED valamelyike fog világítani a kijelző mellett:

  • TANULÓ
  • SZERKESZTŐ
  • IDŐZÍTŐ
  • LOCSOLÁS

AUTOMATA müködésre kapcsoláskor automatikusan a LOCSLÁS üzemmód lesz az aktív. 10 perc után, ha semmilyen nyomógombhoz nem nyúlunk szintén automatikusan a LOCSOLÁS mód aktivizálódik. Ez az automatikus átkapcsolás akkor is megtörténik, ha éppen a slag-ot használjuk (lásd később). Ennek oka, hogyha van beállított program, akkor az biztosan elinduljon, így nem lehet olyan állapotban felejteni a locsolásvezérlőt, hogy nem locsol. Ha KÉZI működési módban van a locsoló berendezés, akkor a MÓD választóval csak a SZERKESZTŐ és az IDŐZÍTÉS módokba lehet kapcsolni, a TANULÓ és a LOCSOLÁS mód értelemszerűen nem működik.

Automata működés üzemmódjai

TANULÓ mód. Ebben az üzemmódban megtaníthatjuk a locsoló berendezésünket egy locsolási programra. Gyakorlatilag ez egy öntanuló mód, aminek során megjegyzi az egyik locsolás lezajlását.
A vezérlő panelen a TANULÓ feliratú LED világit. A kijelző első sorában az éppen aktuális program tároló neve látható. 5 db program tároló áll rendelkezésre, ezek elnevezése LP1-LP5 (LP=Locsoló Program). Ekkor a VÁLASZT gombbal lehet sorban léptetni az felső sorban látható feliratot LP1 és LP5 között ciklikusan (LP5 után LP1 következik). Közben kijelzi az adott programtárolóban található locsolási program hosszát, az érintett szelepeket, melyek egy 0-9 közötti számmal rendelkeznek). Pl:
LP1
38p=>0___4_6___

Itt a program ideje után a sorszámok 0-9 közötti számok, melyek helyett szóköz látható az adott karakter pozícióban, ha az a kapcsoló (szelep) nincs abban az időszakban bekapcsolva. Ezek a tárolt locsolási adatok a tanulás elindításával törlődni fognak, amint a START gombot megnyomjuk. Ekkor ugyanis a program méri az időt, és ha változtatunk valamelyik kapcsoló állapotán, akkor azt megjegyzi.

START gomb megnyomásával elindul a szivattyú, de ehhez legalább egy szelep kapcsolónak is bekapcsolt állapotban kell lennie. Ha jár a szivattyú akkor zajlik ez eltelt idő mérése, közben figyeli a vezérlő a manuális kapcsolók állapotát. A vezérlő a szelep kapcsolók állapotától függően vezérli a szelepeket. Ha kifogy a víz és a szivattyú leáll (vagy ha egyetlen szelep vezérlő sincs bekapcsolva), akkor a program rögzítés is megáll, ha a szivattyú újra beindul, akkor folytatódik az időmérés. Amikor megy a locsolás, méri az időt, és minden olyan ponton amikor változtatunk a kapcsolók állapotán, megjegyzi az eltelt időt, és az új kapcsoló állapotot. Maximum 10 időpont lehet egy programon belül. A szelepvezérlő kapcsolását mindig akkor jegyzi meg, amikor egy kapcsolgatást követően újra megnyomjuk a START gombot. Erre azért van szükség, mert enélkül minden egyes kapcsoló átállítás elhasználna egy időpontot, miközben feltehetőleg egyszerre sok kapcsoló átállítása zajlik. A START megnyomásától kezdően a kijelzőn a program neve és s „RÖGZITES” felirat látható a felső sorban, és alatta az eddigi rögzítések száma, és az utolsó rögzítés óta eltelt idő, és a teljes eddigi programhossz. pl:
LP1 RÖGZITÉS
6/5p15 (45p)

Ha még nem használtuk el a 10 tároló helyet, de nincs szükség további program rögzítésre, akkor a START gomb többszöri megnyomásával kell az összes programhelyre rögzíteni az utolsó szelep állapotot. Ha elhasználtuk a 10 időpontot, akkor a START következő megnyomásakor eltűnik a „RÖGZITES” felirat a program neve mellől az első sorban, és újra a program teljes hossza és az érintett szelepek száma látható. Azonban egy 2 másodperc időre a „RÖGZ.VÉGE” felirat látható miközben nem érzékeli a START lenyomását a program, ezzel akadályozzuk meg, hogy véletlenül újra elinduljon a rögzítés a 11. START megnyomására. A program adatainak a tárolása a belső EEPROM-ba történik. A locsolási időtartam rögzítése 1/4-ed perces lépésekben történik, tehát az időmérés felbontása 15 másodperc (eltelt 15 másodpercet rögzít egy egységnek, tehát az első 15 másodpercen belül újból megnyomott START az 0 másodperc időtartam). A memória helyen tárolt idő tárolása 1 byte-on történik, így összesen 255 x 15 másodperc lehet egy program lépés teljes időtartama (63perc 45 másodperc). Ha a START gombot véletlenül kétszer is megnyomjuk, annak semmilyen következménye nincs, hiszen nem változik a szelepek állapota, azonban egy memória helyet elhasználunk.

SZERKESZTŐ mód. Ebben az üzemmódban szerkeszthetjük a locsolóprogramokat. Ezek a programok az Arduino EEPROM memóriájában találhatók, és az ott található adatokat tudjuk módosítani.
A vezérlő panelen a „SZERKESZTÉS” LED világít. A VÁLASZT gombbal választani kell a rendelkezésre álló program tárolók közül egyet (Léptet körbe-körbe LP1-től LP5-ig és megállunk azon, amit változtatni szeretnénk). Közben kijelzi az éppen aktuális locsolási program hosszát, az érintett szelepeket. A START megnyomására megjelenik az LPx felirat mögött a memóriahely száma, alatta az ott tárolt locsolási idő hossz, és a bekapcsolt szelepek állapota számokkal (ha nincs bekapcsolva akkor szóköz). Pl.:
LP1 – 1
3p=>0_____6___

Az időt 15 másodperces lépésekben a NÖVEL illetve CSÖKKENT nyomógombok nyomkodásával lehet növelni illetve csökkenteni. A lehetséges maximális időtartam 63perc 45 másodperc. Ha egy programlépést szeretnénk törölni, akkor állítsuk az időtartamot 0p0-ra. Locsoláskor azt a lépést a vezérlő ki fogja hagyni (0 ideig locsol). A szelepek programban tárolt állapotát nem változtatja meg az adott szelephez rendelt kapcsoló mindaddig, amíg ahhoz hozzá nem nyúlunk. Tehát ha a kijelzőn egy szelep kikapcsolt állapotban van, miközben a kapcsolón bekapcsolt állapot található, akkor a kapcsolót először ki kell kapcsolni, majd újra be, és ennek hatására lesz a programban a szelep bekapcsolva. Vagyis itt a kapcsoló állapot változtatásával lehet elérni az adott szelep programozott állapotának változtatását. Ha nem tetszik amit látunk, kapcsolgassuk a szelepvezérlő kapcsolót a kívánt állapot eléréséig. Ha a START gomb újbóli megnyomásáig nem nyúlunk a szelep vezérlő kapcsolókhoz, akkor a program lépésben eredetileg tárolt állapot nem is változik meg, függetlenül attól, hogy is állnak a szelepvezérlő kapcsolók. A START gomb megnyomásakor az LPX felirat mögött növekszik a memória hely száma. Ha a START nyomkodásával az összes memória helyet végig léptetük, az utolsó megnyomása után két másodpercig a SZERK.TÁROL felirat látható a program neve mellett. Ekkor történik meg a változtatásaink tárolása. Amikor ez eltűnt a START gombbal újra kezdhető az adott program szerkesztése. A VÁLASZT gomb azonnal megnyomható ebben a két másodperces időszakban is, mert ennek hatására a következő programra lép, és törli a program név mögötti feliratot. Ha egy program szerkesztése közben meggondoltuk magunkat és mégis el akarjuk dobni az addigi változtatásainkat, akkor a VÁLASZT gombot kell megnyomni a START helyett, a kijelzőn a következő program neve jelenik meg, és nem történik tárolás. Ha egy programot szeretnénk végig nézni, akkor a START gombot kell 10x megnyomni, és ezzel végig léptetjük az összes program helyet, és látjuk a kijelzőn az egyes lépések időtartamát és az érintett szelepek állapotát. Ha semmin nem változtattunk (sem időtartamon, sem szelepek állapotán) akkor a tárolás elmarad, vagyis nem jelenik meg két másodpercre a SZERK.TAROL felirat.

IDŐZÍTŐ mód. Ebben az üzemmódban tudjuk beállítani az automatikus locsolás indítások időpontját és megadhatjuk, hogy az adott időpontban melyik locsoló program induljon el a lehetséges öt közül. Ebben az üzemmódban lehetséges beépített belső óra beállítása is.
A vezérlő panelen az IDŐZÍTÉS feliratú LED világít. A VÁLASZT gombbal választhatunk az IP1-IP5 időzítő programok közül, valamint 6. állapotként beállíthatjuk az órát. Összesen 5 időpontot lehet beállítani IP0-től IP5-ig (IP=Idő Program). Minden időpontban az adott locsoló program elindítása következik be. Kivéve, ha az eső, szél és napsütés  érzékelőkből érkező adatok indokolják, hogy ne locsoljunk. Ennek algoritmusa később kerül kialakításra, most még nem foglalkozok ezzel a kérdéssel. A VÁLASZT gombbal válasszuk ki a szükséges időprogram nevet, és a kijelzőn a beállított időpont látható. Pl.:
IP1 LP2
07:00 nap:1234567

A kijelzőn az látható ekkor, hogy az IP1 időzítő programban az LP2 locsoló program lesz elindítva 7 órakor a hét minden napján. Alapértelmezett időpont (ha még soha nem állítottuk be) a reggel 7 óra és a hét minden napja, és az időponthoz nincs locsoló program rendelve. Ekkor a START gombot megnyomva léptethetjük a locsoló program kiválasztását LP1-LP5 között, illetve van egy hatodik állapot is, amikor TÖRÖLVE felirat jelenik meg. Ez az alapértelmezett, ha egy időprogramot még soha nem állítottunk be. Ez azt jelenti, hogy nem használjuk az időprogramot időzítésre. A NÖVEL és CSÖKKENT gombokkal tudjuk beállítani az időprogram kezdő időpontját. Lehet az adott nyomógombbal egyesével nyomkodva fel és leszámoltatni a perceket, vagy az adott nyomógombot folyamatosan nyomva kell tartani, és az idő percenkénti bontásban gyorsan számol felfelé, vagy lefelé. Öt másodperc nyomva tartás után a perc felgyorsul, hogy gyorsabban lehessen a szükséges időponthoz érni. Ha ekkor túlszaladunk az időponton, akkor a másik gombbal vissza lehet menni a szükséges időpontra.
A START gombot hosszan nyomva tartva átválthatunk a hét napjainak megadására. Ezt a hét adott napjának villogása jelzi. Először az „1”-es villog, és a NÖVEL vagy CSÖKKENT gombbal lehet szóközre vagy az 1-es kijelzésére váltani. A szóköz az adott nap kihagyását jelzi. Ha ekkor megnyomjuk a START gombot, a „2”-es kezd villogni, ha ezt beállítottuk a 3-as, és így tovább. A 7-es után tárolódnak a nap beállítások, és visszaáll az alaphelyzet. Ekkor a NÖVEL vagy CSÖKKENT gomb újra az időpontot állítja. Ha egy adott napot szóközre állítottunk a nap számjegye helyett, akkor azon a napon a leprogramozott locsolási program nem fog elindulni. A hét a hétfővel kezdődik, tehát az 1 a hétfő, a 7 a vasárnap.

A hatodik állapot az IP1-IP5 időprogramok után az óra beállítás. Ekkor a dátumot és az időpontot jelzi ki a felső sorban. Ha ekkor megnyomjuk a START gombot, akkor először az évet, aztán a hónapot, aztán a napot, hét napját, órát és percet jelzi ki az alsó sorban, és a NÖVEL illetve CSÖKKENT nyomógombokkal lehet az adott adatot változtatni. A megváltoztatott adat beállítása az órában azonnal megtörténik, tehát a felső sorban látjuk is az új eredményt. A perc beállítása után megnyomott START törli az alsó sort (kész vagyunk), de újbóli lenyomása előről kezdi a beállítást a fentiek szerint.

LOCSOLÓ mód. Ebben az üzemmódban automatikusan működik a locsolás. A beállított időpontban a beállított locsolóprogramot indítja el. Lehetőség van azonban a locsolási programok időzítés nélküli azonnali elindítására is.
A vezérlő panelen a LOCSOLÓ feliratú LED világít. A kijelzőn általában a következő locsolás várható időpontja és a locsolási program száma látható. Pl.:
IP1 07:00 LP2
38p=>0___4_6___

Az alsó sorban a program teljes végrehajtási ideje látható, valamint a programban érintett szelepek sorszáma. Amikor a program elindul, akkor az alsó sor tartalma átvált az éppen végrehajtott lépés sorszám és hátralévő idejének kijelzésére.

Ha éppen nem zajlik locsolás, akkor a VÁLASZT gombbal manuálisan kiválaszthatók az előre programozott locsoló programok, illetve beállítható a következő időzített locsolás időpontjának kijelzése. A kiválasztás léptetéssel történik körbe-körbe (LP1-LP5, következő időzített időpont kijelzés), LP1-LP5 esetén a START gombbal indul a locsolási program végrehajtása, a következő időzített locsolási program időpontjának kijelzése esetén a START gombnak nincs hatása. Ha manuálisan indítunk egy locsoló programot, és közben elérkezik egy időzített locsolás, akkor az időzített locsolás kimarad. Ha az időzítés időpontjában éppen a slag-ot használjuk, pl. autót mosunk, akkor a program elindul, és azonnal szüneteltetett állapotba kerül. Ha vége a slag használatnak, akkor a program végrehajtás folytatódik (elindul).
Ha éppen egy időzített vagy manuálisan elindított locsolás zajlik, akkor a kijelzőn az locsoló program adatai láthatók:
IP1 07:00 LP2
3=>5p  (25p)

Az alsó sorban a program éppen végrehajtott lépésének sorszáma és a lépésből hátralévő idő látható (zárójelben a programból hátralévő teljes idő). A szelep kapcsolók mellett elhelyezett LED-ek jelzik, hogy éppen melyik van használatban. A VÁLASZT gomb ekkor nem reagál megnyomásokra. Ha egy időzített vagy éppen manuálisan elindított locsolási program közben a START gombot nyomjuk meg, akkor a következő locsolási lépésre lép a végrehajtás az aktuális további időtartama kimarad. Így néhány START lenyomással a program utolsó lépése után a locsolás befejeződik, és a kijelzőn a következő időzített locsolás időpontja lesz látható. Ha a víz kifogyott, vagy a slag használat miatt szünetel a program végrehajtása. Ekkor a „vízkifogyás” feliratú LED, vagy a „slag használat” LED világít. A kijelző továbbra is a locsolás állapotát mutatja.

Ha egy locsolási program lezajlott, a kijelzőn a következő időzített locsolás időpontja látható. Ha a VÁLASZT gombbal ellépünk erről a kijelzésről, akkor 10 perc eltetltével automatikusan visszaáll a következő időzítés kijelzésének állapotába a kijelző. Ha a VÁLASZT gombbal kiválasztunk egy locsoló programot, de nem indítjuk el a START gombbal, és közben elérkezik egy időzített locsolás időpontja, akkor az el fog indulni, függetlenül attól, hogy a kijelzőn mi látható.
Futó automata locsolás közben nem lehet az üzemmódot TANULÓ, SZERKESZTŐ vagy IDŐZITÉS módra kapcsolni, mert a MÓD választó nyomógomb nem működik. Ha erre mégis szükség van, akkor a START gombbal az előbbiekben leírtak szerint gyorsan befejezhető a locsoló program, és ekkor lehet üzemmódot váltani. Locsolás közben ugyanígy a VÁLASZT gomb sem működik.

Úgy tervezem, hogy a következő főbb részegységekből fogom felépíteni a berendezést:

  1. Központi szelep kapcsoló és kézi üzemmód vezérlő relés áramkör (a műanyag dobozban kap helyet a kisházunkban).
  2. Arduino-val megvalósított szelep vezérlő panel, és kijelző, és a programozáshoz működtetéshez szükséges nyomógombok Iez is a műanyag dobozban a kisházban).
  3. Szivattyú kapcsoló és fő solenoid kapcsolós relés áramkör (a kútban a szivattyú hálózati csatlakoztatására szolgáló konnektor melletti villanyszerelő dobozban).
  4. Slag be/ki távvezérlő kapcsoló és annak vevő berendezése (a kisház oldalán a falon a jobb vételi körülmények miatt).
  5. Vízkifogyás (szivattyú leállás) áram érzékelő (a szivattyú biztosíték dobozában).

Az egyes részegységeket egyenként terveztem meg. A valóságban természetesen sokat gondolkodtam azon, hogyan is épüljön fel a teljes szerkezet, de a rendszerterv működésről szóló leírását, amit már az előzőekben ismertettem, ténylegesen az első lépésben találtam ki. Eldöntöttem, hogy mit szeretnék elérni, és le is írtam. Ez fontos lépés egy ilyen összetett berendezésnél, mert különben minden nap más ötletem támad, és soha nem kezdem el a tényleges építést. Kitaláltam hát mit szeretnék, és rögzítettem az elvárásokat.

Jöhet a tényleges áramkör tervezés, és a legvégén a programozás. Nagyon nagy segítségre volt a tervező munkában a SimulIDE nevű áramkör tervező program. Szép áttekinthető áramköröket lehet vele megrajzolni. Ment volna tollal és papírral is, de így ki is tudtam próbálni a végeredményt. A központi szelep kapcsoló és vezérlő relés logikával kezdtem. Ennek az áramkörnek Arduino nélkül kell tudnia manuálisan bekapcsolni a mágnesszelepeket, nyomógombokkal vezérelni a slag ki és bekapcsolását, közben az ágyásokról lekapcsolni a víznyomást. Ugyanakkor később tudnia kell ugyanazt elvégezni az Arduino felől kapott vezérlőjelekkel is. Próbáltam először értelmes részekre bontani a tervezett áramkört:

  1. Mágneskapcsolók vezérlése kapcsolókról, és Arduino kimenetről

Ezt az áramkört a SumilIDE szimulátorban szerkesztettem (itt találsz róla leírást), a futtatható, kipróbálható szimulátor állomány innen töltehtő le: Letöltés

Ez egy nagyon egyszerű áramkör. A mágnesszelepet egy relé-vel helyettesítettem, mert tényleges vízkapcsoló mágnesrelé nincs a szimulátor alkatrészjegyzékében. Ha futtatom a szimulátort, akkor a relé kontaktusainak behúzásán látom, hogy folyik a víz vagy nem! A mágnesszeleppel párhuzamosan raktam záró irányban egy diódát, ami a relé kikapcsolásakor keletkező feszültség impulzust vezeti el. Ez minden relé esetében kötelező. Párhuzamosan került a mágnesszeleppel egy LED soros áramkorlátozó ellenállással. A végleges panelen ez a LED fogja visszajelezni, hogy működik a mágnesszelep és locsoljuk az ágyást. Amikor a berendezésen a KÉZI/AUTOMATA váltó kapcsoló KÉZI állásban van, akkor valójában az áramkörben látható „Kézi/Automata váltó kapcsoló” nevű kapcsoló kerül bekapcsolásra. A kapcsoló másik áramköre az Arduino-nak ad jelzést, hogy KÉZI üzemmód van, ne kapcsolgassa a szelepeket. Ekkor a mágnesszelepek váltó kapcsolóinak bekapcsolása GND-re húzza a mágnesszelep másik pontját és a szelepeken áram folyik át és kinyitnak. Tehát a Kézi/Automata váltó kapcsoló, egy közös kapcsoló, 10 ugyanilyen áramkör közös kapcsolója. Amikor az Arduino vezérli a mágnesszelepet, akkor ez a kapcsoló kikapcsolt állapotban lesz, egyetlen mágnesszelep sem kaphat GND-t a saját kézi szelepkapcsolóján keresztül. Ekkor az Arduino egy FET-nek a bemenetére fog 5V feszültséget kapcsolni. Nekem a fiókban éppen  IRLZ34N típusú FET található, ez kb. 200mA áramot fog kapcsolni, így hűtés sem kell neki.

  • Slag be/ki kapcsolás, fő szolenoid-ok vezérlése:

Ezt az áramkört is a SumilIDE szimulátorban szerkesztettem (itt találsz róla leírást), a futtatható, kipróbálható szimulátor állomány innen töltehtő le: Letöltés Sajnos a szimulátor furcsaságokat is produkál, a slag KI nyomógomb megnyomása után időnként 4-5 másodperc, mire a Slag BE relé elenged. Ezt nem tudom miért csinálja!

Ez már kicsit bonyolultabb áramkör. Itt a relék tényleg relék. Sokat gondolkodtam, hogyan is oldjam meg a locsolás vezérlőt, mit vállaljon magára az Arduino program, és mit oldjak meg relékkel és kapcsolókkal. Egyrészt szempont volt az, hogy ha az Arduino áramkör tönkremegy (pl. villámcsapás, vagy megeszi egy dobozba költöző pók stb.) akkor is legalább manuálisan működjön a rendszer. Másrészt félek tőle, hogy a teljes berendezés nem készül el nyárig, amikor már locsolni kell. Így szempont az is, hogy már az első fázis mutasson valamilyen működési jelenséget. Ha még nem automatikus a locsolás, az nem baj, de legyen locsolás. Ezen indokok alapján az alap működést Arduino nélkül szeretném megoldani. A mágnesszelepek vezérlése egyszerű, lényegében már kész is. Viszont az alap működés része a slag be és kikapcsolása is. Ehhez viszont már relé fog kelleni, mert ez a „legalapabb” eszköz egyetlen bit tárolására. Ezt csinálja a fenti áramkör. Ha megnyomom a „Slag BE” gombot, meghúz a „Slag BE” relé, és saját magának ad GND-t, így ha elengedem a nyomógombot, akkor is meghúzva marad a relé, működteti a nagynyomású vízrendszert ellátó fő solenoidot. Ez a relé viszont egy másik relé kontaktusán keresztül ad magának GND-t, így ha azt a relét is meghúzom, az megszakítja a kontaktust, és a relé elenged. Vagyis töröljük a bit-et. Ez a Slag KI nyomógomb és relé feladata. Általában a reléken egy meghúzásra záródó kontaktus van, ami egy másik kontaktust is tartalmaz, ami meghúzáskor elenged. Így ezt a relét pont fordítva kell bekötni, meghúzáskor nem zárja az áramkört, hanem megszakítja. A relék elektronikus jellel is vezérelhetők, az most éppen nem az Arduino lesz, hanem egy rádiós távvezérlő kimenetei. Ezen a távvezérlőn négy nyomógomb van, és ennek megfelelően négy kimenet. Ebből az egyik nyomógom a bekapcsolásra, a másik a kikapcsolásra fog szolgálni.

Nem fog a központi egységhez tartozni a szivattyút és a fő solenoidokat vezérlő két relé. Ezeket egyéb praktikus  és történelmi okok miatt a kút tetején a szivattyú bekötésnél fogom elhelyezni egy vízmentesen zárható villanyszerelő dobozban. Itt kap még helyet egy 230V/24V trafó, amit a párhuzamosan fogok kötni a szivattyúval. Ha megy a szivattyú, akkor valamelyik fő szolenoid biztosan 24V feszültséget fog kapni. Így néz ki az áramkör:

Ezt az áramkört is a SumilIDE szimulátorban szerkesztettem (itt találsz róla leírást), a futtatható, kipróbálható szimulátor állomány innen töltehtő le: Letöltés

AZ áramkört nem tudtam teljesen megépíteni a szimulátorban, mert nincs a szimulátorban trafó, és villanymotor sem, ráadásul a 230V váltóáramot sem kezeli. Így az áramkör jobb oldala csak rajz, nem működik. A lényeg talán látható. Magyarázatot igényel a „Solenoid választó” kapcsoló, és a „M.szelep kapcs. x” nevű kapcsolók és a diódák. Itt már átgondoltam előre, hogy mi fog történni. A központi panelen amikor egy szelep vezérlőt bekapcsolok (vagy bekapcsol a FET, lásd első áramkör), akkor a mágnesszelep GND pontra kerülő kivezetésének föld potenciálját fogom kihasználni a szivattyút bekapcsoló relé vezérléséhez. Ezt jelképezik a rajzban található kapcsolók, a valóságban nem lesznek ott. Kell azonban minden kapcsoló után egy dióda, különben bármelyiket is bekapcsolom, bekapcsolna az összes mágnesszelep. Ugyanígy fog működni a solenoid választó relé is. Ennek a relének ugyanaz a pont fog GND-t adni, mint ami a központi vezérlő panelen az 1 bites tároló relének (lásd előző kapcsolás). Ide is kell egy dióda, de azt elfelejtettem berajzolni.

És végezetül lássuk egyben a teljes relés vezérlő áramkört:

Ezt az áramkört is a SumilIDE szimulátorban szerkesztettem (itt találsz róla leírást), a futtatható, kipróbálható szimulátor állomány innen töltehtő le: Letöltés

Bár semmi hasonlóságot nem mutat az előző kapcsolásokkal, de ténylegesen azokból épül fel. Csak három mágnesszelep vezérlést rajzoltam be, mert 10 már nagyon sok munka lett volna. A szimulációhoz, áramkör kipróbáláshoz három is elég. Egy mágnesszelep vezérlést be is kapcsoltam a szimulátorban, hogy világítson egy LED. Az a kis piros pötty balra középen. A szivattyú és solenoid vezérlő reléket követő áramkört sem ugyanúgy rajzoltam meg, LED-ekkel helyettesítettem a szivattyút és a solenoidokat, hogy a szimulátorban könnyen ellenőrizhessem a működést. Még egy eltérés van, amit az előző áramkörök nem tartalmaztak, ez pedig a motor leállást érzékelő áramkör megoldása. A szivattyú a biztosíték táblából kapja egy hosszú vezetéken keresztül a 230V-os feszültséget. Ennek a vezetéknek a vége a kútban végződik, itt van a szivattyú vezérlő relé. Ha a szivattyú megy, akkor áram folyik a vezetékben, ha nem megy, akkor nincs benne áram, csak feszültség. Ez úgy lehetséges, hogy a relé közben meg van húzva, mert szerinte a szivattyúnak menni kéne, de a víz kifogyott és a szivattyú önhatalmúlag leállította magát. Ekkor azonban a vezetékében nem folyik áram, és ezt lehet érzékelni. Ezért vettem az alábbi áramkört:

Ez funkciója szerint egy túláram érzékelő. A potméterrel beállítható egy áram küszöb, ami felett a relé meghúz, és riaszt. Nálam olyan alacsonyra lesz állítva az áram küszöb, hogy a működő szivattyú meghúzza a relét. A bekötése nagyon egyszerű, adni kell neki tápfeszt (pl. 5V) és a kis fekete lyukas „izén” át kell vezetni a szivattyú tápfesz vezetékének egyik drótját. A biztosíték dobozban pont el fog férni, és sok méter kábelt sem kell építenem az udvaron a kisháztól a kútig. Ha a szivattyú vesz fel áramot, akkor a relé meghúz, ha éppen nem működik, akkor a relé nem húz meg. Kész a vizkifogyás érzékelés! A rajzon az „Áramérzékelő relé” ezt a relét jelenti, és a működés ellenőrzéséhez ezt feszültség bekapcsolással működtethetővé tettem. Sajna ez a relé pont fordítva működik, mint nekem kellene, mert akkor van meghúzva, amikor megy a motor. Szerencsére záró és nyitó kontaktusa is van, nyilván a elengedéskor a záródót fogom használni. Ekkor egy-egy diódán keresztül GND-re húzza a „Slag leállító relé”-t és a „Locsolás leállító relé”-t. Ezek elveszik a 24V tápfeszt minden más áramkörtől, így leáll a slag illetve a locsolás is, ha éppen működne. Amikor a vízszint újra megnő és a szivattyú beindul a relé meghúz, és újra 24V-ot kapnak az áramkörök és folytatódik a locsolás. A slag az nem folytatódik, mert az egy bites tárolónk tápfesz híján törlődött, de ez most pont jó, mert nem szeretném, ha váratlanul beindulna a slag. Persze mindez csak akkor tud így lezajlani, ha a szivattyú közben a vezérlő relén keresztül kap feszültséget, hogy beindulhasson ha nőtt a vízszint. Tehát ezt a relét közvetlenül a 24V-ra kellett kötni, nem szüntetheti meg a saját tápfeszét. Sajnos ilyenkor az egyik solenoid is tápot kap, de úgy tapasztaltam nem melegszenek. Ha ez gondot okoz, akkor két áramkörös relét fogok tenni a szivattyú vezérléshez, és a 24V-ot is megszakítom erre az időre. Arra vigyázni kell közben, hogy a motort beindító jelzés elegendően hosszú legyen ahhoz, hogy ennek a relének legyen ideje meghúzni, különben soha nem fog a rendszer beindulni. A locsoló résznél ez adott, hiszen folyamatosan van jel, vagy átbillentettük a megfelelő kapcsolót, vagy az Arduino folyamatos vezérlő jelet ad a megfelelő MOS-FET-nek. A slag kapcsolásakor lehet ebből probléma, mert amikor megnyomjuk a slag be gombot, nem szabad addig elengedni, amíg a motor el nem indul és a kifogyás jelző relé meg nem húz. Majd kiderül a gyakorlatban, hogy ez mennyi idő, de szerintem nem fogom tudni olyan gyorsan elengedni a gombot, hogy ne kapcsoljon be!
A „Slag leállító relé” és a „Locsolás leállító relé” meghúzása azért diódákon keresztül megy, mert a locsolás leállító relét egyedül kell meghúzni akkor, amikor éppen locsolunk, és bekapcsoljuk a slag-ot! Kicsit zavaros, de nem sikerült egyszerűbban megfogalmaznom!

Most következnek a szorgos téli hétköznapok, megépítem a központi panelt a kis műanyag dobozba. Mindent a lecsavarozható előlapra fogok szerelni, és a külső irányokba menő vezetékeket csatlakozókkal látom el. Ha mindez készen van, akkor már elvileg manuálisan lehet locsolni, de ami fontosabb, hogy az előlap egyben a program fejlesztő is lesz. Deszka modellen nem tudok ennyi kapcsolót, nyomógombot összerakni, így az előlapra épített Arduino-val, LCD kijelzővel és nyomógombokkal fogok programot fejleszteni. Az Arduino nano kivezetésszáma kevés, mert kell 10 bemenet és 10 kimenet minimum, és már ez is több mint a rendelkezésre álló kivezetések száma. Így már beszereztem egy Arduino Mega alaplapot. Ha jól emlékszem több mint ötven kivezetése van. Ezt fogom ráépíteni az előlapra a kijelző mögé, és ezen fogom folytatni a munkát, ha eddig eljutottam. Még annyit kell magyarázatként megadnom, hogy a mágnesszelep kapcsolók két áramkörösek, egyik áramkör a mágnes szelepeket kapcsolja, a másik az Arduino bemeneteket fogja vezérelni!

Közben eltelt egy kis idő, március eleje van, és az unalmas téli hónapokban sikerült kicsit előre haladni. Elkészült a locsoló vezérlő panel. Ráépítettem a szükséges nyomóhombokat, ledeket, LCD kijelzőt és az Arduino Mega Pro alaplapot. Így néz ki az előlap:

Kicsit színes és ízléstelen a színvilág! Azonban a sokféle színes led-nek és színes nyomógombnak szántam szerepet. Beszélgettem egyszer egy pilótával. Elmesélte, hogy azért szereti jobban a Boeing gépeket, mert minden nyomógombnak, kapcsolónak más az alakja, a kijelző lámpáknak más a színe. Nem lehet összekeverni, ha vészhelyzetben kapkodsz. Oda sem kell nézni a nyomógombra, érzi melyiket fogta meg. A jelzőfényeket meg a szeme sarkából is felismeri és megkülönbözteti. Az Airbus gépeken katonás (németes) rendben sorakoznak a gombok, ott kicsit könnyebb mellé nyúlni. Íme vizuálisan is amiről beszélek:

A bal oldal a Boeing 737 műszerfala kiterítve, a jobb oldal az Airbusz A320 műszerfala. Amerikai kontra német logika. Egyébként mindkettő jó!
Mint olvashatjátok, remek magyarázatot találtam az ízléstelen csiricsáré vezérlőpultomra!

Viszont hasonlít arra, amit a rendszertervben rajzoltam. Még nincsnek feliratok és rajta felejtettem a mágnesszelep vezérlők mellé ragasztott fehér szikszalagokat, amikre a múlt évi ágyás-beosztást feliratoztam. Primitív, de egyszerű módszer a minden évben változó feliratok eltüntetésére. Lekapargatom a fehér szikszalagot, és egy üreset ragasztok, erre alkoholos filccel felírom az ágyásba vetett növények nevét. A sorszámokat meg kell változtatnom, mert a kijelzőn nem lehetnek kétjegyű mágnesszelep sorszámok. Így az ágyások sorszáma 0-tól fog indulni, és 9-ig tart majd. Ez azt jelenti, hogy megint el kell lopnom feleségem körömlakk lemosóját. Csak meg ne tudja!

Megtörtént a hátlapon a vezérlő logika összehuzalozása. Egy művészi alkotás lett a végén:

Az Apolló űrhajó egyik paneljének láttam a fotóját, hasonlóan nézett ki. Mondhatnám, hogy onnan vettem a kivitelezési ötleteket, de nem, minden hasonlóság a véletlen műve.

Viszont az áramkörök működnek. A relés logika szuper. Váltogatja a slag ki-be üzemmódokat, közben kikapcsolnak a locsoló mágnesszelepek. Mindent leállít a víz kifogyás stb. Arduino Mega alaplapot akár ki is vehetem (foglalatokba tettem óvatosságból), a relés és kapcsolgatós logika már most képes a manuális locsolás vezérlésére, és a slag használatára locsolás közben. A rádiós távvezérlőt is ráköthetném, ehhez már most ott vannak csatlakozók a panelen (négy kék reléről lehet felismerni). A rádiós távvezérlő vevője egyébként pár méterre a kisházon kívül lesz, mert ott valószínűleg jobb lesz a vétel. Innen egy egy vezeték pár fog bemenni a panelen található csatlakozókhoz, amik a FET gate kivezetésén keresztül kapcsolják a slag ki és bekapcsoló reléket. Most egy 5V-os vezérlő jellel próbáltam ki a működést.

Persze vannak hibák is. Elfelejtettem, hogy a víz kifogyásról, illetve a slag bekapcsolásáról az Arduino programnak is tudnia kell, hiszen addig amig ezek valamelyike éppen igaz, le kell állítani az időmérést. Parasztos megoldást találtam ki! Mindkét eseményre található egy-egy led. Igaz, ezek 24V-os tápfeszről világítanak, amikor kell, és GND-t kapnak egy-egy relén vagy FET-en keresztül, amikor kell. Hát egy megfelelően méretezett ellenállás osztó fogja „levenni” róluk a jelet! Így nem kell mindent elölről kezdeni.

Már leellenőriztem minden ki és bemenetet az Arduino Mega panelen, tényleg mindent vezérel és érzékel. A mágneskapcsolókhoz rendelt led-ek világítanak, amikor az Arduino kimenet a váltókapcsoló helyett a FET-et kapcsolja be. Így a program futása közvetlenül ellenőrizhető. Még az egészet beépítem egy cipősdobozba, nehogy programozás közben leszakítsak egy vezetéket. Belepusztulnék, ha még egyszer valamit ki kellene keresnem ebben a káoszban. Sajnos a programozás hetekig fog tartani, és minden este el kell rakni az egész cuccot, mert kicsi a lakásunk. Ezért az elővigyázatosság!


Ismét eltelt egy hónap, és majdnem készen vagyok a programmal. Minden működik, amit szerettem volna megvalósítani. Mivel az Arduino Mega Pro-ban van memória dögivel, mindenféle extra funkciókat is beépítettem. Pulzálva villognak a led-ek szerkesztés alatt stb. Találtam egy piezo buzzert, így most még hanghatásokat is beépítek (még nincs benne). A forráskód csaknem tökéletes. Kommentezni még sok helyen kell, de már közzé tehető:

/***********************************
 * Vezeték bekötéek MEGA PRO kivezetésekhez:
 * D20 SDA
 * D21 SCL
 * D22-D31 mágnesszelep vezérlés (FET-ek gate-jára van kötve, 24V-ot kapcsolja a FET)
 *    D22 -0. szelep
 *    ...
 *    D31 -9. szelep
 * D34-D43 mágnesszelep vezérlő kapcsolók állapotának beolvasása (kapcsolók egyik áramköre direktben a FET-et vezérli
 *         a másik az Arduino Mega Pro itt részletezett bemenetét húzza le 0-ra bekepcsolt állapotban.
 *    D34 - 0. szelep kapcsoló állapota
 *    ...
 *    D43 - 9. szelep kapcsoló állapota
 * Kijelző panel mód led vezérlő kimenetek
 *    D44 Zöld led - Locsolás
 *    D45 kék led - Időzítés
 *    D46 sárga led - Szerkesztő
 *    D47 piros led - Tanuló
 * Működtető nyomógombok
 *    D33 váltókapcsoló kézi/automata választó
 *    D32 fehér nyomógomb - üzemmód választó
 *    D48 fekete nyomógomb - Növel
 *    D49 fekete nyomógomb - Csökkent
 *    D50 sárga nyomógomb - Választ
 *    D51 fekete nyomógomb - Start
 *    D52 slag bekapcsolás érzékelő bemenet 0-slag be, 1-slag ki
 *    D53 vizkifogyás érzékelő bemenet 0-vizkifogysad, 1-szivattyú működik, van víz
 * EEPROM memória térkép   
 *    Az időzítő memória területen tárolom a beállított időpontok és a hét napjainak aktivitását. Utóbbiaknál az egyszerűség kedvéért 
 *    Egy byte-on tárolom, hogy aznap kell laocsolni vagy sem. Elég lenne az összesre egy bit, de így egyszerűbb és követhetőbb lesz a program,
 *    nem kell bit műveleteket végezni. Memória van bőven. Az aktív jelzés azt mutatja, hogy használatban van-e az időzítő (0 esetén nincs).
 *    Ha egy adott nap tároló celája 0, akkor az adott napon nem kell locsolni, ha 1, akkor igen.
 *    A 0. címen kezdődik a 1-es időzítés tároló, a 10. címen az 2-es, 20. címen 3-as, 30. címen a 4-es tároló, 40. címen a 5-ös tároló.
 *    Az egyes memória cellák címei:
 *    IP1 időzítő adatok, (0)Aktív (1)óra, (2)perc, (3)hétfő, (4)kedd, (5)szerda, (6)csütörtök, (7)péntek, (8)szombat, (9)vasárnap
 *    IP2 időzítő adatok, (10)Aktív (11)óra, (12)perc, (13)hétfő, (14)kedd, (15)szerda, (16)csütörtök, (17)péntek, (18)szombat, (19)vasárnap
*     IP3 időzítő adatok, (20)Aktív (21)óra, (22)perc, (23)hétfő, (24)kedd, (25)szerda, (26)csütörtök, (27)péntek, (28)szombat, (29)vasárnap
*     IP4 időzítő adatok, (30)Aktív (31)óra, (32)perc, (33)hétfő, (34)kedd, (35)szerda, (36)csütörtök, (37)péntek, (38)szombat, (39)vasárnap
*     IP5 időzítő adatok, (40)Aktív (41)óra, (42)perc, (43)hétfő, (44)kedd, (45)szerda, (46)csütörtök, (47)péntek, (48)szombat, (49)vasárnap
*     Locsoló programok számai: (50) IP1, (51) IP2, (52) IP3, (53) IP4, (54) IP5 Így egyszerűbb volt tárolni, mert memória címek kiszámításához nem kellett bonyolult algoritmus
*    
 *    Locsolóprogramok tárolására szolgáló adatmező kezdőcímei locsolási programonként:
 *    LP1 locsolóprogram adatok kezdő címe (100)
 *    LP2 locsolóprogram adatok kezdő címe (300)
 *    LP3 locsolóprogram adatok kezdő címe (500)
 *    LP4 locsolóprogram adatok kezdő címe (700)
 *    LP5 locsolóprogram adatok kezdő címe (900)
 *    Egy locsolóprogram adatainak sorrendja (a kezdő cím felel meg a 0-nak):
 *    (0) - 1. időzített locsolási lépés 0. szelep állapota
 *    (1) - 2. időzített locsolási lépés 0. szelep állapota
 *     ...
 *    (9) - 9. időzített locsolási lépés 0. szelep állapota
 *    (10) - 1. időzített locsolási lépés 1. szelep állapota
 *    (11) - 2. időzített locsolási lépés 1. szelep állapota
 *     ...
 *    (19) - 9. időzített locsolási lépés 1. szelep állapota
 *    ...
 *    ...
 *    (90) - 1. időzített locsolási lépés 9. szelep állapota
 *    (91) - 2. időzített locsolási lépés 9. szelep állapota
 *     ...
 *    (99) - 9. időzített locsolási lépés 9. szelep állapota
 *    
 *    Az időzített locsolási programok egyes lépéseinek végrehajtási idejei (1000)-től kezdődnek:
 *    A megadott cimeket 1000-hez kell hozzáadni a memóriacím kiszámításához.
 *    LP1 locsolási program:
 *    (0) - 0. időzített locsolási lépés vegrahajtási ideje (0-255) 15 másodperc felbontásban
 *    (1) - 1. időzített locsolási lépés vegrahajtási ideje (0-255) 15 másodperc felbontásban
 *    ...
 *    (9) - 9. időzített locsolási lépés vegrahajtási ideje (0-255) 15 másodperc felbontásban
 *    LP2 locsolási program:
 *    (10) - 0. időzített locsolási lépés vegrahajtási ideje (0-255) 15 másodperc felbontásban
 *    (11) - 1. időzített locsolási lépés vegrahajtási ideje (0-255) 15 másodperc felbontásban
 *    ...
 *    (19) - 9. időzített locsolási lépés vegrahajtási ideje (0-255) 15 másodperc felbontásban
 *    ...
 *    ...
 *    LP5 locsolási program:
 *    (40) - 0. időzített locsolási lépés vegrahajtási ideje (0-255) 15 másodperc felbontásban
 *    (41) - 1. időzített locsolási lépés vegrahajtási ideje (0-255) 15 másodperc felbontásban
 *    ...
 *    (49) - 9. időzített locsolási lépés vegrahajtási ideje (0-255) 15 másodperc felbontásban
 */
 
#include <EEPROM.h>  //belső EEPROM programkönyvtára
#include <Wire.h>    //I2C library 
#include <LiquidCrystal_I2C.h>  //I2C LCD kezelő könyvtár
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  //LCD paraméterek megadása

//elemes óra modul kezelő függvény inicializálása és az időméréssel, időpont mehatározással kapcsolatos változók, segéd változók
 #include <DS3231.h>   
 DS3231 Clock;
 bool Century=false;
 bool h12=true;
 bool PM;
 byte ev=0;
 byte ho=0;
 byte nap=0;
 byte hetnapja=0;
 byte ora=0;
 byte perc=0;
 int int_perc;           //az összegzett idő számításakor kell, mert a program ideje több is lehet mint 255 perc
 byte masodperc=0;
 String str_tmp;         // segéd változó az időpontok kiírásához és egyéb stringbe összeszerkeszett információkhoz
 byte kov_ora_tmp=0;     // a soron következő idoprogram meghatározásához kell
 byte kov_perc_tmp=0;    // a soron következő idoprogram meghatározásához kell
 byte prog_ora_tmp=0;    // az eeprom-ból ebbe olvasom át az adott locsolási program időpobtját
 byte prog_perc_tmp=0;   // az eeprom-ból ebbe olvasom át az adott locsolási program időpobtját
 bool van_ma_locsolas=0; // annak jelzésére, hogy az adott napon van-e locsolás
 byte kov_idoprogram=0;  // a soronkövetkező időprogram száma
 byte kov_lp_program=0;  // a soronkövetkező locsolóprogram számát tárolom benne
 long kijelzo_kikapcs_ido_tmp=millis(); //egy perc tétlenség után lekapcsoljuk a kijelzőt, ehhez szükséges segéd változó


//nyomógombok kezeléséhez szükséges globális segéd változók multi_button() függvényhez, ami 5 nyomógombot kezel
 byte bemenet_allapot[]={1,1,1,1,1};        // bemenet pillanatnyi állapota (prellmenetes állapotaban kerül beállításra), 
                                            // mivel most lefutó él az aktív, ezt alapértelmezetten 1-re kell állítani       
 int kimenet_allapot[]={3,0,0,0,0};         // kimete állapota, ez a függvény által visszaadott érték, ami 0,1,1-255 értékeket vehet fel
                                            // 0-kikapcsolt állapotot ad vissza, 1-bekapcsolt állapotot ad vissza, 
                                            // 1-255 amikor számlált állapotot ad vissza (setup=3)
                                            // a mod választó gombon (0-as csatorna) az alepértelmezett a 3. állapot, vagyis a locsolás lesz alapértelmezett állapot
 byte bemenet_elozo_allapot[]={1,1,1,1,1};  // bemenet előző állapota segéd változó, amivel felderíthetjük a 
                                            // fel vagy lefutó álét a prellmentes nyomógomb állapotváltozásnak
 byte prell_tmp[]={0,0,0,0,0};              // bemenet prell figyeléshez segéd változó  
 long prell_time[]={0,0,0,0,0};             // bemenet prellmentesítéshez az első kontaktus időpontja      

//nyomógombok állapotának tárolásához használt változók (multi_buttom() ezeket a változókat tölti fel értékkel a loop minden ciklusába, vagy a meghívott függvények ciklusaiban) 
 byte mod_num=0;                     // a mód választó nyomógomb állapota, 0-3-ig vehet fel értékeket
 byte elozo_allapot_mod_num=0;       // a mod_num változó előző állapota, azért kell, hogy csak változáskor változtassuk a működési módot
 byte valaszt_num=0;                 // a valasztó nyomógomb állapota, 0-5-ig vagy 0-4-ig vehet fel értékeket a különböző üzemmódokban
 byte elozo_allapot_valaszt_num=0;   // valszt_num változó előző állapota, azért kell, hogy kimutathassuk, ha változik az értéke
 byte start_num=0;                   // a start nyomógomb állapota, különböző funkciókban különböző értékeket vehet fel
 byte elozo_allapot_start_num=0;     // a start_num változó előző állapota, azért kell, hogy kimutathassuk, ha változik az értéke
 byte novel_num=0;                   // az SW_NOVEL nyomógomb állapota (lenyomva=1, vagy nincs lenyomva=0)
 byte elozo_allapot_novel_num=0;     // a novel_num változó előző állapota, azért kell, hogy kimutathassuk, ha változik az értéke
 byte csokkent_num=0;                // az SW_CSOKKENT nyomógomb állapota (lenyomva=1, vagy nincs lenyomva=0)
 byte elozo_allapot_csokkent_num=0;  // a csokkent_num változó előző állapota, azért kell, hogy kimutathassuk, ha változik az értéke

//globális segéd változók
  byte aktiv; 
  byte hetfo;
  byte kedd;
  byte szerda;
  byte csutortok;
  byte pentek;
  byte szombat;
  byte vasarnap;
  byte lp_program;  
  byte hetnapja_tmp; //ebbe olvasom atmenetileg az eeprom-ból, hogy az adott napra van-e programozva locsolás
  int ossz_ido; //egy locsolási program teljes végrehajtási idejének számításához

//mágnesszelep állapotok a locsolóprogramokba
  bool szelep0[]={0,0,0,0,0,0,0,0,0,0};
  bool szelep1[]={0,0,0,0,0,0,0,0,0,0};
  bool szelep2[]={0,0,0,0,0,0,0,0,0,0};
  bool szelep3[]={0,0,0,0,0,0,0,0,0,0};
  bool szelep4[]={0,0,0,0,0,0,0,0,0,0};
  bool szelep5[]={0,0,0,0,0,0,0,0,0,0};
  bool szelep6[]={0,0,0,0,0,0,0,0,0,0};
  bool szelep7[]={0,0,0,0,0,0,0,0,0,0};
  bool szelep8[]={0,0,0,0,0,0,0,0,0,0};
  bool szelep9[]={0,0,0,0,0,0,0,0,0,0};
  bool szelepo[]={0,0,0,0,0,0,0,0,0,0};  //az összes szelep összegzésére az érintett szelepek kiírásához
  int lp_ido[]={0,0,0,0,0,0,0,0,0,0};    //egyes locsolási lépések időtartama 15 másodperces felbontásban, 
                                         //int kell legyen, mert a változtatás közben negatív értéket is használok, 
                                         //tárolva viszont csak byte típusban lesz 0 és 255 között
  byte lp_ido_tmp;                       //csak a beolvasáshoz és kiíráshoz, mivel a memóriában int típusban dolgozok, tárolásban már byte
  long lp_fut_ido_tmp=millis();          //15 másodpercenként ellenőrizni kell, hogy van-e indítandó locsolóprogram

//konstansok létrehozása
//Mágnesszelep vezérlő váltókapcsolók állapotának figyeléséhez
  const byte SW_0=34;
  const byte SW_1=35;
  const byte SW_2=36;
  const byte SW_3=37;
  const byte SW_4=38;
  const byte SW_5=39;
  const byte SW_6=40;
  const byte SW_7=41;
  const byte SW_8=42;
  const byte SW_9=43;
  byte sw_bemenet[]={34,35,36,37,38,39,40,41,42,43};
//Mágnesszelep vezárlő kimenetek
  const byte OUT_0=22;
  const byte OUT_1=23;
  const byte OUT_2=24;
  const byte OUT_3=25;
  const byte OUT_4=26;
  const byte OUT_5=27;
  const byte OUT_6=28;
  const byte OUT_7=29;
  const byte OUT_8=30;
  const byte OUT_9=31;
//üzemmód és programozó nyomógombok fogyeléséhez
  const byte SW_KEZI=33;   //kiolvasva a bemenetet 0 esetén kézi üzemmód, 1 esetén automata üzemmód
  const byte SW_MOD=32;
  const byte SW_VALSZT=50;
  const byte SW_START=51;
  const byte SW_NOVEL=48;
  const byte SW_CSOKKENT=49;
  const byte SLAG_ERZEKELO=52;
  const byte VIZKIFOGYAS_ERZEKELO=53;
//kijelzőn található négy üzemmód visszejlző led
  const byte LED_LOCSOLAS=44;
  const byte LED_IDOZITES=45;
  const byte LED_SZERKESZTO=46;
  const byte LED_TANULO=47;

void setup() {
//  Serial.begin(9600);
  
  //ki és bemnetek konfigurálása
  for (byte i=22;i<32;i++) {pinMode(i,OUTPUT);digitalWrite(i,LOW);}   //mágnesszelep vezélő kimenetek
  for (byte i=32;i<44;i++) {pinMode(i,INPUT);digitalWrite(i,HIGH);}   //Mágnesszelep váltógombok állapot lekérdező bemneteinek beállítása
  pinMode(SW_VALSZT,INPUT);digitalWrite(SW_VALSZT,HIGH);
  pinMode(SW_START,INPUT);digitalWrite(SW_START,HIGH);
  pinMode(SW_NOVEL,INPUT);digitalWrite(SW_NOVEL,HIGH);
  pinMode(SW_CSOKKENT,INPUT);digitalWrite(SW_CSOKKENT,HIGH);
  pinMode(SW_KEZI,INPUT);digitalWrite(SW_KEZI,HIGH);
  pinMode(SW_MOD,INPUT);digitalWrite(SW_MOD,HIGH);
  for (byte i=48;i<52;i++) {pinMode(i,INPUT);digitalWrite(i,HIGH);}   //vezérlő nyomógombok bemeneteinek beállítása (Növel, Csökkent, Választ, START)
  for (byte i=44;i<48;i++) {pinMode(i,OUTPUT);digitalWrite(i,LOW);}   //kijelző led-ek kimeneteinek beállítása
  pinMode(52,INPUT);digitalWrite(52,HIGH);                            //slag használat érzéklő bemenet
  pinMode(53,INPUT);digitalWrite(53,HIGH);                            //vizkifogyás jelzés érzékelő bemenet

  lcd.begin(16,2);              //LCD inicializálása
  lcd_print_hu(""); //saját kerakterek betöltése a kijelző memóriájába
  lcd.clear();
  //ékezetes karakterek kiírása a kijelzőre
  lcd.backlight();              //háttérvilágítás bekapcsolása

  if (digitalRead(SW_MOD)==0) {   //bekapcsoláskor folyamtosan nyomtuk a mod nyomógombot, ezért EEPROM törlés következik
                                  //minden tárolt időzítő időpontot és beállítást kitörlünk,és alapértelmezettre állítunk
    lcd.setCursor(0,0);lcd.print("Teljes torles!");
    for (byte i=0;i<50;i++) {EEPROM.put(i,0);}
    // óra beállítása alapértelmezett 7 órára
    EEPROM.put(1,7);EEPROM.put(11,7);EEPROM.put(21,7);EEPROM.put(31,7);EEPROM.put(41,7);
    // locsolóprogram beállítás alapértelmezett 1-re minden időzítőhoz 
    EEPROM.put(50,1);EEPROM.put(51,1);EEPROM.put(52,1);EEPROM.put(53,1);EEPROM.put(54,1);
    //szelep állapotok 10 állapot 10 szelep 5 locsolóprogram
    for (int i=100;i<600;i++) {EEPROM.put(i,0);}
    for (int i=1000;i<1050;i++) {EEPROM.put(i,0);}
    EEPROM.put(102,1);  //demo egy szelephez
    EEPROM.put(1000,10);  //demo időhöz 150 sec= 2 perc 30másodprec
    delay(2000);
  }
}

void loop() {
  
  //60 sec tétlenség után kikapcsoljuk a kijelző háttérvilágítást, és bekényszerítjük a locsolási időpontra várakozásra
  if (millis()>kijelzo_kikapcs_ido_tmp+60000) {   
    lcd.noBacklight();   //csak a következő időzítéskor fog lekapcsolni, mert a üzemmód megváltoztatása újra felkapcsolja, de a következőnél már nem változik a üzemmód.
    digitalWrite(LED_TANULO,LOW);
    digitalWrite(LED_SZERKESZTO,LOW);
    digitalWrite(LED_IDOZITES,LOW);
    kimenet_allapot[0]=3;     //az 0-as csatornán az SW_MOD kapcsoló van,ennek kimenetét a locsolás állapotba kényszerítjük
    kimenet_allapot[1]=0;     //az 1-es csatornán a SW_VALSZT kapcsoló van, ennek kimenetét 0-ba kényszerítjük, ami a következő locsolási időpontra várakozás
  }  
  mod_num=multi_button(0,2,SW_MOD,1,1,3);   //az SW_MOD nyomógombot figyeljuk, megnyomásra növeljük mod_num változóba értékét, 3 felett ujra 0
                                            //a loop()-ban legelősször alapértelmezetten 3 ennek a kapcsolónak az állapota (locsolás)
                                            //paraméterek jelentése:0. csatorna, számláló mód, bemenet száma, lefutóél, növekedés, max érték
  if (elozo_allapot_mod_num!=mod_num){
    lcd.backlight();                        // a háttérvilágítás bekapcsolása mert megnyomtuk a SW_MOD gombot (változott a mod_num értéke
    kijelzo_kikapcs_ido_tmp=millis();       //megjegyezzük a pillanatnyi időt, hogy 60-sec múlva kikapcsolhassuk a háttérvilágítást
    elozo_allapot_valaszt_num=99;           //ahhoz, hogy az SW_VALSZT gomb megnyomása nélkül is kijelezhessük a 0 értékhez tartozó feliratokat, generálunk egy eltérést
    kimenet_allapot[1]=0;                   //az SW_VALASZT nyomógomb alapállapotát 0-ra állítjuk, hogy a különböző üzemmódokban mindíg az első elemet mutassa  
  }   
  elozo_allapot_mod_num=mod_num;            //előző állapot rögzítése, hogy az előző if észre vegye a változást

  //kézi üzemmeódra váltás figyelése, és kézi üzemmódban kényszerítjük az időzítés beállítás üzemmódot (csak az lehetséges)
  //és minden szelepet kikapcsolunk, mert csak a kézi kapcsolók fogják beállítani
  if ((digitalRead(SW_KEZI)==0 and mod_num==0) or (digitalRead(SW_KEZI)==0 and mod_num==1) or (digitalRead(SW_KEZI)==0 and mod_num==3)) {
    digitalWrite(LED_TANULO,LOW);
    digitalWrite(LED_SZERKESZTO,LOW);
    digitalWrite(LED_LOCSOLAS,LOW);
    //kézi üzemmódban azösszes szelepet kikapcsoljuk, csak a kézi billenőkapcsolók vezérelnek
    digitalWrite(OUT_0,LOW);      
    digitalWrite(OUT_1,LOW);      
    digitalWrite(OUT_2,LOW);      
    digitalWrite(OUT_3,LOW);      
    digitalWrite(OUT_4,LOW);      
    digitalWrite(OUT_5,LOW);      
    digitalWrite(OUT_6,LOW);      
    digitalWrite(OUT_7,LOW);      
    digitalWrite(OUT_8,LOW);      
    digitalWrite(OUT_9,LOW); 
    //bekényszerítjük az időzítés üzemmódba, mert időt is indítási időt közben is állíthat, ez az egyetlen menüpont, aminél
    //a kézi kapcsolókat semmire nem használjuk
    mod_num=2;
    kimenet_allapot[0]=2;         
  }

  //A mod_num pillanatnyi állapotától függően beállítjuk a kijelzőt, és figyeljük a többi nyomógombot
  switch (mod_num) {
      case 0:
       /**************************************************************************************************  
        *   Tanuló mód, kiválaszthatja az 5 locsolási program egyikét, és elindíthatja a tanuló módot    *                                                                                
        *   ami rögzíti a kézi szelep kapcsolók állapotát inden egyes START nyomógomb lenyomáskor.       *
        *   Összesen 10 lépést tud rögzíteni az eltelt idővel és a bekapcsolot kézi kapcsoló állapotokkal*
        **************************************************************************************************/
        digitalWrite(LED_LOCSOLAS,LOW);                     //A locsolás led-et lakpcsoljuk
        digitalWrite(LED_TANULO,HIGH);                      //A tanulás led-et felkapcsoljuk a kiválasztott üzemmódnak megfelelően
        valaszt_num=multi_button(1,2,SW_VALSZT,1,1,4);      //az SW_VALASZT nyomógombot figyeljuk, megnyomásra növeljük mod_num változóba értékét, 5 felett ujra 0
                                                            //paraméterek jelentése: 1 csatorna, számláló mód, bemenet száma, lefutóél, növekedés, max érték
        start_num=multi_button(2,0,SW_START,1,0,0);         //az SW_START nyomógombot figyeljuk, megnyomásra fogjuk elkezdeni a rögzítést 
                                                            //paraméterek jelentése: 2 csatorna, megnyomás érzékelő mód, bemenet száma, lefutóél, nem használt, nem használt

        // Csak a SW_VALASZT megnyomásakor (változásakor) olvassuk ki az eeprom-ból a locsoló program adatait, és kiírjuk a képernyőre a kiolvasott adatokat
        // Ez a feltétel akkor is igaz, ha az SW_MOD-ot nyomtuk meg, mert akkor az előző állapotot 99-re állítjuk, hogy egyszer üzemmód váltáskor is belemenjen                                                    
        // Ez a feltétel akkor is igaz, ha a tanulas_start() függvényből térünk vissza, mert akkor is 99-re állítjuk az állapotot, hogy frissítsük a képernyőt a betanult adatokkal                                               
        if (elozo_allapot_valaszt_num!=valaszt_num){        
          if (elozo_allapot_valaszt_num!=valaszt_num) {     //megnyomta az SW_VALASZT gombot
            lcd.backlight();                                //bekapcsoljuk a kijelző háttérvilágítást
            kijelzo_kikapcs_ido_tmp=millis();               //elindítjuk a 60sec-es várakozást a kijelző kikapcsolásáig
          } 
          //a kiválasztott locsolóprogram szelep állapotának beolvasása az eeprom-ból
          for (int i=0;i<10;i++) {
            EEPROM.get((valaszt_num)*100+100+i,szelep0[i]);
            EEPROM.get((valaszt_num)*100+110+i,szelep1[i]);
            EEPROM.get((valaszt_num)*100+120+i,szelep2[i]);
            EEPROM.get((valaszt_num)*100+130+i,szelep3[i]);
            EEPROM.get((valaszt_num)*100+140+i,szelep4[i]);
            EEPROM.get((valaszt_num)*100+150+i,szelep5[i]);
            EEPROM.get((valaszt_num)*100+160+i,szelep6[i]);
            EEPROM.get((valaszt_num)*100+170+i,szelep7[i]);
            EEPROM.get((valaszt_num)*100+180+i,szelep8[i]);
            EEPROM.get((valaszt_num)*100+190+i,szelep9[i]);
            EEPROM.get((valaszt_num)*10+1000+i,lp_ido_tmp);  //a tárolt érték byte típusú, ezért átmeneti változóba töltöm
            lp_ido[i]=(int) lp_ido_tmp;  //a memóriában már int típussal dolgozok, mert a beállításnál kell a -1-et is figyelnem lefele léptetéskor
          }
          //A locsolóprogramban érintett szelepek meghatározása. Ez csak a kijelzőre történő kiíráshoz kell
          //Ami egyszer is be van kapcsolva a teljes program alatt, azt a szelepo[] változóban megjelöljük
          for (int i=0;i<10;i++) {szelepo[i]=0;}   //töröljük az összes bitet
          for (int i=0;i<10;i++) {
            if (szelep0[i]) {szelepo[0]=1;}
            if (szelep1[i]) {szelepo[1]=1;}
            if (szelep2[i]) {szelepo[2]=1;}
            if (szelep3[i]) {szelepo[3]=1;}
            if (szelep4[i]) {szelepo[4]=1;}
            if (szelep5[i]) {szelepo[5]=1;}
            if (szelep6[i]) {szelepo[6]=1;}
            if (szelep7[i]) {szelepo[7]=1;}
            if (szelep8[i]) {szelepo[8]=1;}
            if (szelep9[i]) {szelepo[9]=1;}
          }
          
          //összes működési idő kiszámítása és megjelenítése a kijelzőn 15 másodperces bontásban (perc, másodperc)
          ossz_ido=0;
          for (byte i=0;i<10;i++) {ossz_ido=ossz_ido+lp_ido[i];}
          ossz_ido=ossz_ido*15; //ez a teljes végrehajtási idő másodpercben
          lcd.clear();
          str_tmp="";
          int_perc=ossz_ido/60;
          if (int_perc>99) {     //ha a működési idő nagyobb mint 100perc, akkor óra perc pontossággal írjuk ki az időzítési időt, hogy elférjen minden adat a képernyőn
            ora=int_perc/60;
            perc=int_perc-ora*60;
            str_tmp=String(ora)+"o"+String(perc)+"p";
          }
          else {                 //kevesebb mint 100 perc a működési idő, perc másodperc pontossággal írjuk ki
            masodperc=ossz_ido-(int_perc*60);
            if (int_perc==0) {str_tmp=str_tmp+"00:";}
            else {
              if (int_perc<10) {str_tmp=str_tmp+"0"+String(int_perc)+":";;}
              else {str_tmp=String(int_perc)+":"; }
            }
            if (masodperc==0) {str_tmp=str_tmp+"00";} else {str_tmp=str_tmp+String(masodperc);}
          }
          //működő szelepek kijelzése sorszámmal, program alatt nem működő szelepeket "-" jelzi
          lcd.setCursor(0,1);lcd.print(str_tmp);
          for (byte i=0;i<10;i++) {
            lcd.setCursor(6+i,1);
            if (szelepo[i]==1) {lcd.print(i);}
            else {lcd.print("-");}
          }
          
          //A valaszt_num értékétől függően kiírjuk, hogy melyik locsoló program van érvényben
          switch (valaszt_num) {
            case 0:
              //LP1 tanuló mód felirat ékezetesen
              lcd.setCursor(0,0);lcd_print_hu("LP1 tanuló mód");  
              break;
            case 1:
              //LP2 tanuló mód felirat ékezetesen
              lcd.setCursor(0,0);lcd_print_hu("LP2 tanuló mód"); 
              break;
            case 2:
              //LP3 tanuló mód felirat ékezetesen
              lcd.setCursor(0,0);lcd_print_hu("LP3 tanuló mód");
              break;
            case 3:
              //LP4 tanuló mód felirat ékezetesen
              lcd.setCursor(0,0);lcd_print_hu("LP4 tanuló mód");
              break;
            case 4:
              //LP5 tanuló mód felirat ékezetesen
              lcd.setCursor(0,0);lcd_print_hu("LP5 tanuló mód");
              break;
          }
          
        } 
        elozo_allapot_valaszt_num=valaszt_num;        //ez teszi lehetővé, hogy legközelebb csak a valaszt_num változásakor kerüljünk be a locslóprogram kiválasztásba

        //csak akkor indítunk rögzítést, ha megnyomtuk az SW-START gombot, annak változását figyeljük
        if (elozo_allapot_start_num!=start_num) {       
          switch (valaszt_num) {
            case 0:
              tanulas_start(0);             //meghívjuk a locsoló program rögzítését végző függvényt (SW_MOD és SW_VALASZT gombokat abban már nem fogjuk figyelni)
              kimenet_allapot[1]=0;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 0-ra, hogy újra az LP1 időprogram beállítás legyen a képernyőn
              break;
            case 1:
              tanulas_start(1);             //meghívjuk a locsoló program rögzítését végző függvényt (SW_MOD és SW_VALASZT gombokat abban már nem fogjuk figyelni)
              kimenet_allapot[1]=1;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 1-re, hogy újra az LP2 időprogram beállítás legyen a képernyőn
              break;
            case 2:
              tanulas_start(2);             //meghívjuk a locsoló program rögzítését végző függvényt (SW_MOD és SW_VALASZT gombokat abban már nem fogjuk figyelni)
              kimenet_allapot[1]=2;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 2-re, hogy újra az LP3 időprogram beállítás legyen a képernyőn
              break;
            case 3:
              tanulas_start(3);             //meghívjuk a locsoló program rögzítését végző függvényt (SW_MOD és SW_VALASZT gombokat abban már nem fogjuk figyelni)
              kimenet_allapot[1]=3;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 3-re, hogy újra az LP4 időprogram beállítás legyen a képernyőn
              break;
            case 4:
              tanulas_start(4);             //meghívjuk a locsoló program rögzítését végző függvényt (SW_MOD és SW_VALASZT gombokat abban már nem fogjuk figyelni)
              kimenet_allapot[1]=4;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 4-re, hogy újra az IP5 időprogram beállítás legyen a képernyőn
              break;
          }
          start_num=0;                  //különben az előző állapot a jelenlegi 10-et veszi fel, és végtelen ciklus alakul ki, mert a következő ciklusban is bemegy
                                        //az idozites_beallitas() függvénybe, ami viszont azonnal ki is lép start_num=10-el.
          elozo_allapot_valaszt_num=99; //hogy ki is írja a képernyőre az IP1 beállítás üzenetet
          bemenet_allapot[2]=1;         //azért, hogy a tanulómódból visszatérve biztosan ne tekintse úgy, hogy a start gomb le vol nyomva, 
                                        //alapjelyzetbe állítjuk a 2. csatornat a multi_button változóival 
          bemenet_elozo_allapot[2]=1;  
          prell_tmp[2]=0;                
          kijelzo_kikapcs_ido_tmp=millis();  //innen indzul az egy perc időzítés, ami kikapcsolja a képernyőt és locsoló módba kényszeríti az üzemmódot
        }
        elozo_allapot_start_num=start_num;
        break;
      case 1:
       /***************************************************************************************************  
        *   Locsoló program szerkesztő mód. Ebben a részben az SW_VALASZT nyomógombbal kiválasztunk egy   *                                                               
        *   locsoló programot, az SW_START-al váltjuk annak lépéseit, és az SW_NOVEL és SW_CSOKKENT-el    *
        *   beállíthatjuk a lépés végrehajtási idejét, a manuális szelep kapcsolókkal pedig a szelep      * 
        *   be vagy kikapcsolt állapotát lehet ki és bekapcsolni. Azért, hogy a szelep állapota ne rontsa *
        *   el a programlépés már tárolt értékét, a szelep kapcsolók változásakor állítjuk csak az        *
        *   állapotot. Így végig lehet menni a lépéseken változtatás nélkül, és csak megnézni a szelepek  *
        *   leprogramozott állapotát.                                                                     *
        ***************************************************************************************************/
        digitalWrite(LED_TANULO,LOW);                      //kikapvsoljuk a tanuló mód led jelzését
        digitalWrite(LED_SZERKESZTO,HIGH);                 //bekapcsoljuk a szerkesztés mód led jelzését
        valaszt_num=multi_button(1,2,SW_VALSZT,1,1,4);     //az SW_VALASZT nyomógombot figyeljuk, megnyomásra növeljük mod_num változóba értékét, 4 felett ujra 0
                                                           //paraméterek jelentése:1 csatorna, számláló mód, bemenet száma, lefutóél, növekedés, max érték
        start_num=multi_button(2,0,SW_START,1,0,0);        //az SW_START nyomógombot figyeljuk, megnyomásra fogunk belemenni az egyes locsolóprogram szerkesztésbe 
                                                           //2 csatorna, megnyomás érzékelő mód, bemenet száma, lefutóél, nem használt, nem használt

        // Csak a SW_VALASZT megnyomásakor (változásakor) olvassuk ki az eeprom-ból a locsoló program adatait, és kiírjuk a képernyőre a kiolvasott adatokat
        // Ez a feltétel akkor is igaz, ha az SW_MOD-ot nyomtuk meg, mert akkor az előző állapotot 99-re állítjuk, hogy egyszer üzemmód váltáskor is belemenjen                                                    
        // Ez a feltétel akkor is igaz, ha a tanulas_start() függvényből térünk vissza, mert akkor is 99-re állítjuk az állapotot, hogy frissítsük a képernyőt a betanult adatokkal                                               
        if (elozo_allapot_valaszt_num!=valaszt_num){       
          lcd.backlight();kijelzo_kikapcs_ido_tmp=millis();
        
          //a kiválasztott locsolóprogram szelep állapotának beolvasása az eeprom-ból
          for (int i=0;i<10;i++) {
            EEPROM.get(valaszt_num*100+100+i,szelep0[i]);
            EEPROM.get(valaszt_num*100+110+i,szelep1[i]);
            EEPROM.get(valaszt_num*100+120+i,szelep2[i]);
            EEPROM.get(valaszt_num*100+130+i,szelep3[i]);
            EEPROM.get(valaszt_num*100+140+i,szelep4[i]);
            EEPROM.get(valaszt_num*100+150+i,szelep5[i]);
            EEPROM.get(valaszt_num*100+160+i,szelep6[i]);
            EEPROM.get(valaszt_num*100+170+i,szelep7[i]);
            EEPROM.get(valaszt_num*100+180+i,szelep8[i]);
            EEPROM.get(valaszt_num*100+190+i,szelep9[i]);
            EEPROM.get(valaszt_num*10+1000+i,lp_ido_tmp);  //a tárolt érték byte típusú, ezért átmeneti változóba töltöm
            lp_ido[i]=(int) lp_ido_tmp;  //a memóriában már int típussal dolgozok, mert a beállításnál kell a -1-et is figyelnem lefele léptetéskor
          }
          
          //a locsolóprogramban érintett szelepek meghatározása.
          //ami egyszer is be van kapcsolva a teljes program alatt, azt a szelepo[] változóban megjelöljük
          for (int i=0;i<10;i++) {szelepo[i]=0;}
          for (int i=0;i<10;i++) {
             if (szelep0[i]) {szelepo[0]=1;}
             if (szelep1[i]) {szelepo[1]=1;}
             if (szelep2[i]) {szelepo[2]=1;}
             if (szelep3[i]) {szelepo[3]=1;}
             if (szelep4[i]) {szelepo[4]=1;}
             if (szelep5[i]) {szelepo[5]=1;}
             if (szelep6[i]) {szelepo[6]=1;}
             if (szelep7[i]) {szelepo[7]=1;}
             if (szelep8[i]) {szelepo[8]=1;}
             if (szelep9[i]) {szelepo[9]=1;}
          }
          
          //összes működési idő kiszámítása és megjelenítése a kijelzőn 15 másodperces bontásban (perc, másodperc)
          ossz_ido=0;
          for (byte i=0;i<10;i++) {ossz_ido=ossz_ido+lp_ido[i];}
          ossz_ido=ossz_ido*15; //ez a teljes végrehajtási idő másodpercben
          lcd.clear();
          str_tmp="";
          int_perc=ossz_ido/60;
          if (int_perc>99) {
            ora=int_perc/60;
            perc=int_perc-ora*60;
            str_tmp=String(ora)+"o"+String(perc)+"p";
          }
          else {
            masodperc=ossz_ido-(int_perc*60);
            if (int_perc==0) {str_tmp=str_tmp+"00:";}
            else {
              if (int_perc<10) {str_tmp=str_tmp+"0"+String(int_perc)+":";;}
              else {str_tmp=String(int_perc)+":"; }
            }
            if (masodperc==0) {str_tmp=str_tmp+"00";} else {str_tmp=str_tmp+String(masodperc);}
          }
          //működő szelepek kijelzése sorszámmal, program alatt nem működő szelepeket "-" jelzi
          lcd.setCursor(0,1);lcd.print(str_tmp);
          for (byte i=0;i<10;i++) {
            lcd.setCursor(6+i,1);
            if (szelepo[i]==1) {lcd.print(i);}
            else {lcd.print("-");}
          }
          
          //kiírjuk a képernyőre az SW_VALASZT által kiválasztott locsolóprogram számát (amit szerkeszteni fogunk az SW_START megnyomásakor)
          switch (valaszt_num) {
            case 0:
              lcd.setCursor(0,0);lcd_print_hu("LP1 szerkesztés");
              break;
            case 1:
              lcd.setCursor(0,0);lcd_print_hu("LP2 szerkesztés");
              break;
            case 2:
              lcd.setCursor(0,0);lcd_print_hu("LP3 szerkesztés");
              break;
            case 3:
              lcd.setCursor(0,0);lcd_print_hu("LP4 szerkesztés");
              break;
            case 4:
              lcd.setCursor(0,0);lcd_print_hu("LP5 szerkesztés");
              break;
          }
          
        } 
        elozo_allapot_valaszt_num=valaszt_num;

        // ha megnyomtuk az SW_START gombot, locsolóprogramot kell szerkeszteni, ezért meghívjuk
        // lp_prog_szerkesztes() függvényt a locsolóprogram sorszámával.
        // A konkrét locsolóprogram szerkesztést az lp_prog_szerkesztes() függvény végzi el,
        // amíg ez fut a loop()-ba nem kerülünk vissza, csak ha ennek végrehajtása befejeződött!
        if (elozo_allapot_start_num!=start_num) {
          switch (valaszt_num) {
            case 0:
              lp_prog_szerkesztes(0);       //meghívjuk a locsoló program szerkesztését végző függvényt (SW_MOD és SW_VALASZT gombokat abban már nem fogjuk figyelni)
              kimenet_allapot[1]=0;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 0-ra, hogy újra az LP1 időprogram beállítás legyen a képernyőn
              break;
            case 1:
              lp_prog_szerkesztes(1);       //meghívjuk a locsoló program szerkesztését végző függvényt (SW_MOD és SW_VALASZT gombokat abban már nem fogjuk figyelni)
              kimenet_allapot[1]=1;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 1-re, hogy újra az IP2 időprogram beállítás legyen a képernyőn
              break;
            case 2:
              lp_prog_szerkesztes(2);       //meghívjuk a locsoló program szerkesztését végző függvényt (SW_MOD és SW_VALASZT gombokat abban már nem fogjuk figyelni)
              kimenet_allapot[1]=2;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 2-re, hogy újra az IP3 időprogram beállítás legyen a képernyőn
              break;
            case 3:
              lp_prog_szerkesztes(3);       //meghívjuk a locsoló program szerkesztését végző függvényt (SW_MOD és SW_VALASZT gombokat abban már nem fogjuk figyelni)
              kimenet_allapot[1]=3;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 3-re, hogy újra az IP4 időprogram beállítás legyen a képernyőn
              break;
            case 4:
              lp_prog_szerkesztes(4);       //meghívjuk a locsoló program szerkesztését végző függvényt (SW_MOD és SW_VALASZT gombokat abban már nem fogjuk figyelni)
              kimenet_allapot[1]=4;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 4-re, hogy újra az IP5 időprogram beállítás legyen a képernyőn
              break;
          }
          start_num=0;                      //különben az előző állapot a jelenlegi 10-et veszi fel, és végtelen ciklus alakul ki, mert a következő ciklusban is bemegy
                                            //az idozites_beallitas() függvénybe, ami viszont azonnal ki is lép start_num=10-el.
          elozo_allapot_valaszt_num=99;     //hogy ki is írja a képernyőre az "IPX szerkesztés" üzenetet
          bemenet_allapot[2]=1;             //azért, hogy a kézi indításból visszatérve biztosan ne tekintse úgy, hogy a start gomb le vol nyomva, alapjelyzetbe állítjuk a 2. csatornat a multi_buttom változóival 
          bemenet_elozo_allapot[2]=1;       //a multi_buttom belső változója, ezt is be kell állítani, hogy ne érzékelje a start gombot lenyomottnak
        }
        elozo_allapot_start_num=start_num;
        break;
      case 2:
       /***********************************************************************************************************  
        *   Időzítés beállítás és óra beállítás. Ebben a részben az SW_VALSZT gombbal kiválasztunk egy időzítési  *                                                          
        *   tárolót (IP1-IP5), és beállíthatjuk, hogy milyen időpontban, melyik locsolóprogram induljon el.       *
        *   Nem csak időpont, hanem a hét napja is beállítható, amikor az időpontban induljon a program.          *
        *   Az időzítés inaktíválható és aktíválható, hogy ne csak a hét napjaival lehessen kikapcsolni a         *
        *   locsolóprogram indítást, ha nem akarjuk, hogy az adott időzíttés működjön.                            *
        *   A hatodik állapotban az órát lehet beállítani.                                                        *
        ***********************************************************************************************************/
        digitalWrite(LED_SZERKESZTO,LOW);                   //szerkesztő mód led kikapcsolása
        digitalWrite(LED_IDOZITES,HIGH);                    //időzítés led bekapcsolása
        valaszt_num=multi_button(1,2,SW_VALSZT,1,1,5);      //az SW_VALASZT nyomógombot figyeljuk, megnyomásra növeljük mod_num változóba értékét, 5 felett ujra 0
                                                            //paraméterek jelentése:1 csatorna, számláló mód, bemenet száma, lefutóél, növekedés, max érték
        start_num=multi_button(2,0,SW_START,1,0,0);         //az SW_START nyomógombot figyeljuk, megnyomásra fogunk belemenni az egyes időprogramok vagy az órabeállításba 
                                                            //paraméterek jelentése:2 csatorna, megnyomás érzékelő mód, bemenet száma, lefutóél, nem használt, nem használt

        // Csak a SW_VALASZT megnyomásakor (változásakor) olvassuk ki az eeprom-ból a időprogram adatait, és kiírjuk a képernyőre a kiolvasott adatokat
        // Ez a feltétel akkor is igaz, ha az SW_MOD-ot nyomtuk meg, mert akkor az előző állapotot 99-re állítjuk, hogy egyszer üzemmód váltáskor is belemenjen                                                    
        // Ez a feltétel akkor is igaz, ha a tanulas_start() függvényből térünk vissza, mert akkor is 99-re állítjuk az állapotot, hogy frissítsük a képernyőt a betanult adatokkal                                               
        if (elozo_allapot_valaszt_num!=valaszt_num){        
          lcd.backlight();kijelzo_kikapcs_ido_tmp=millis(); //ha menyomtuk a nyomógombot, akkor bekapcsola világítás, és elindul az egy perc időzítése
          
          //az időprogramok beállított értékeinek kijelzée a második sorban
          if (valaszt_num<5) {                       //az 5. állapotban az órát állítjuk, akkor annak adatait jelezzük ki,most az időzítési program adatait
            EEPROM.get(valaszt_num*10+0,aktiv);      //az időzítési program aktív vagy inaktív állapotának kiolvasása 
            lcd.clear();
            if (aktiv==0) {                          //csak kakor olvassuk ki az időzítési program adatait, ha aktív jelenleg
              lcd.setCursor(0,1);lcd.print("Nincs bekapcs.");
            }
            else {                                   //aktív az időzítési program, tehát kellenek az adatok
              EEPROM.get(valaszt_num+50,lp_program);
              EEPROM.get(valaszt_num*10+1,ora);
              EEPROM.get(valaszt_num*10+2,perc);
              EEPROM.get(valaszt_num*10+3,hetfo);
              EEPROM.get(valaszt_num*10+4,kedd);
              EEPROM.get(valaszt_num*10+5,szerda);
              EEPROM.get(valaszt_num*10+6,csutortok);
              EEPROM.get(valaszt_num*10+7,pentek);
              EEPROM.get(valaszt_num*10+8,szombat);
              EEPROM.get(valaszt_num*10+9,vasarnap);
              if (ora<10) {str_tmp="0"+String(ora)+":";}
              else {str_tmp=String(ora)+":";}
              if (perc==0) {str_tmp=str_tmp+"00";}
              else {
                if (perc<10) {str_tmp=str_tmp+"0";}
                str_tmp=str_tmp+String(perc); 
              }    
              lcd.setCursor(0,1);lcd.print(str_tmp);lcd.print("  -------   ");   //het napjainak kiírása. AMikor egy adott nap aktvív, akkor kiírjuk a nap számát, egyébként "-"
              if (hetfo==1){lcd.setCursor(7,1);lcd.print("1");}
              if (kedd==1){lcd.setCursor(8,1);lcd.print("2");}
              if (szerda==1){lcd.setCursor(9,1);lcd.print("3");}
              if (csutortok==1){lcd.setCursor(10,1);lcd.print("4");}
              if (pentek==1){lcd.setCursor(11,1);lcd.print("5");}
              if (szombat==1){lcd.setCursor(12,1);lcd.print("6");}
              if (vasarnap==1){lcd.setCursor(13,1);lcd.print("7");}
            }
          }
          if (valaszt_num==5) {        //az óra adatait írjuk ki
            ev=Clock.getYear();ho=Clock.getMonth(Century);nap=Clock.getDate();ora=Clock.getHour(h12,PM);perc=Clock.getMinute();hetnapja=Clock.getDoW(); 
            str_tmp=String(ev)+"/";     
            if (ho<10) {str_tmp=str_tmp+"0"+String(ho)+"/";} else {str_tmp=str_tmp+String(ho)+"/";}
            if (nap<10) {str_tmp=str_tmp+"0"+String(nap)+" ";} else {str_tmp=str_tmp+String(nap)+" ";}
            if (ora<10) {str_tmp=str_tmp+"0"+String(ora)+":";} else {str_tmp=str_tmp+String(ora)+":";}
            if (perc<10) {str_tmp=str_tmp+"0"+String(perc);} else {str_tmp=str_tmp+String(perc);}
            lcd.clear();
            lcd.setCursor(0,1);lcd.print(str_tmp);
          }
          
          switch (valaszt_num) {     //a kiválasztott időprogram számának vagy az óraállítás kiírása az első sorba
            case 0:
              lcd.setCursor(0,0);lcd_print_hu("IP1 időz.       ");
              if (aktiv==1) {lcd.setCursor(9,0);lcd.print(":LP");lcd.print(lp_program);}
              break;
            case 1:
              lcd.setCursor(0,0);lcd_print_hu("IP2 időz.       ");
              if (aktiv==1) {lcd.setCursor(9,0);lcd.print(":LP");lcd.print(lp_program);}
              break;
            case 2:
              lcd.setCursor(0,0);lcd_print_hu("IP3 időz.       ");
              if (aktiv==1) {lcd.setCursor(9,0);lcd.print(":LP");lcd.print(lp_program);}
              break;
            case 3:
              lcd.setCursor(0,0);lcd_print_hu("IP4 időz.       ");
              if (aktiv==1) {lcd.setCursor(9,0);lcd.print(":LP");lcd.print(lp_program);}
              break;
            case 4:
              lcd.setCursor(0,0);lcd_print_hu("IP5 időz.       ");
              if (aktiv==1) {lcd.setCursor(9,0);lcd.print(":LP");lcd.print(lp_program);}
              break;
            case 5:
              lcd.setCursor(0,0);lcd_print_hu("óra beallitás   ");
              break;
          }
          
        } 
        elozo_allapot_valaszt_num=valaszt_num;   //azért, hogy legközelebb már ne írja ki az adatokat, hiszen nem történt gombnyomás (SW_VALASZT)

        // megnyomtuk az SW_START gombot, időprogramot kell állítani, vagy órát beállítani, ezért meghívjuk
        // idozitas_beallitas() függvényt az időzítés program sorszámával.
        // A konkrét időprogram beállítást az idozitas_beallitas() függvény végzi el,
        //amíg az fut a loop()-ba nem kerülünk vissza, csak ha annak végrehajtása befejeződött!
        if (elozo_allapot_start_num!=start_num) {
          switch (valaszt_num) {
            case 0:
              idozites_beallitas(0);        //meghívjuk az idozítés beállítást elvégző függvényt a kiválasztott időzítő program indexével
              kimenet_allapot[1]=0;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 0-re, hogy újra az IP1 időprogram beállítás legyen a képernyőn
              break;
            case 1:
              idozites_beallitas(1);        //meghívjuk az idozítés beállítást elvégző függvényt a kiválasztott időzítő program indexével
              kimenet_allapot[1]=1;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 1-re, hogy újra az IP2 időprogram beállítás legyen a képernyőn
              break;
            case 2:
              idozites_beallitas(2);        //meghívjuk az idozítés beállítást elvégző függvényt a kiválasztott időzítő program indexével
              kimenet_allapot[1]=2;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 2-re, hogy újra az IP3 időprogram beállítás legyen a képernyőn
              break;
            case 3:
              idozites_beallitas(3);        //meghívjuk az idozítés beállítást elvégző függvényt a kiválasztott időzítő program indexével
              kimenet_allapot[1]=3;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 3-re, hogy újra az IP4 időprogram beállítás legyen a képernyőn
              break;
            case 4:
              idozites_beallitas(4);        //meghívjuk az idozítés beállítást elvégző függvényt a kiválasztott időzítő program indexével
              kimenet_allapot[1]=4;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 4-re, hogy újra az IP5 időprogram beállítás legyen a képernyőn
              break;
            case 5:
             ora_beallitas();               //meghívjuk az óra beállítást elvégző függvényt 
              kimenet_allapot[1]=5;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 5-re, hogy újra az óraállítás legyen a képernyőn
              kimenet_allapot[2]=0;         //az SW_START gomb kimenetének állapotát vissza kell állítani 0-re, mert most ujra normál kétállapotú nyomógombként fogjuk használni, aminek alapértéke 0
              start_num=0;                  //a start_num állapotát is 0-ra kell írni, különben újra belemegy az óraállításba. mert a következő ciklusban is bemegy
                                            //az idozites_beallitas() függvénybe, ami viszont azonnal ki is lép start_num=10-el.
              break;
          }
          elozo_allapot_valaszt_num=99; //hogy ki is írja a képernyőre az "IPX időz. LPX" üzenetet
          bemenet_allapot[2]=1;         //azért, hogy a kézi indításból visszatérve biztosan ne tekintse úgy, hogy a start gomb le vol nyomva, alapjelyzetbe állítjuk a 2. csatornat a multi_buttom változóival 
          bemenet_elozo_allapot[2]=1;   //a multi_buttom belső változója, ezt is be kell állítani, hogy ne érzékelje a start gombot lenyomottnak
        }
        elozo_allapot_start_num=start_num;     //hogy újbóli SW_START lenyomásig már ne menjen be mégeyszer a fenti if-be
        break;
      case 3:
       /**********************************************************************************************************
        *   Locsoló üzemmód. Ebben a részben el lehet indítani manuálisan a beprogramozott locsoló programokat,  *                                                                      
        *   illetve figyeli a soron következő időprogramot és automatikusan is elindtja a locsolást, ha          *
        *   elérkezik az időprogramban beállított időpont. Csak az aktív időprogramokat figyeli.                 *
        *   Ebben az üzemmódba egy perc elteltével mindenképpen bekényszerítjük a programot, akkor is            *
        *   ha valamilyen beállítást félbehagytunk. Ezzel biztosítjuk, hogy időzített program ne maradhasson     *
        *   ki.                                                                                                  *
        **********************************************************************************************************/
        digitalWrite(LED_IDOZITES,LOW);      //időzítés led kikapcsolása
        //digitalWrite(LED_LOCSOLAS,HIGH);   //locsolás led bekapcsolása
        analogWrite(LED_LOCSOLAS,50);        //nagyon fényesen világít a zöld led. Már 500ohm körüli soros ellenállás van benne, de sokkal jobban ragyog, mint a többi, és vakít a kijelző melett
        valaszt_num=multi_button(1,2,SW_VALSZT,1,1,5);     //az SW_VALASZT nyomógombot figyeljuk, megnyomásra növeljük mod_num változóba értékét, 5 felett ujra 0
                                                           //paraméterek jelentése: 1 csatorna, számláló mód, bemenet száma, lefutóél, növekedés, max érték
        start_num=multi_button(2,0,SW_START,1,0,0);        //az SW_START nyomógombot figyeljuk, megnyomásra fogunk belemenni az egyes locsolóprogram szerkesztésbe 
                                                           //paraméterek jelentése: 2 csatorna, megnyomás érzékelő mód, bemenet száma, lefutóél, nem használt, nem használt

                                                           
        // Csak a SW_VALASZT megnyomásakor (változásakor) olvassuk ki az eeprom-ból a locsolóprogram adatait, és kiírjuk a képernyőre a kiolvasott adatokat
        // Ez a feltétel akkor is igaz, ha az SW_MOD-ot nyomtuk meg, mert akkor az előző állapotot 99-re állítjuk, hogy egyszer üzemmód váltáskor is belemenjen                                                    
        // Ez a feltétel akkor is igaz, ha a lp_locsolas_start() függvényből térünk vissza, mert akkor is 99-re állítjuk az állapotot, hogy frissítsük a képernyőn a soron következő locsolás adatait
        // Ez a feltétel 15 másodpercenként ismét igaz, ekkor valaszt_num=0, így meghatározzuk a soron következő automatikus locsolási időpontot, és ha elértük, akkor el is indítjuk                                  
        if (elozo_allapot_valaszt_num!=valaszt_num or millis()>lp_fut_ido_tmp+15000){     //csak a SW_VALASZT megnyomásakor csináljuk az alábbiakat, illetve amikor az SW_MOD-ot megnyomjuk, mert akkor az előző állapot 99
                                                                                          //valamint 15 másodpercenként is belemegyünk, mert meg kell határozni a következő locsolási időpontot, és
                                                                                          //ha az egyenlő a pillanatnyi idővel, akkor el is kell inditani a locsolást
          lp_fut_ido_tmp=millis();         
          if (elozo_allapot_valaszt_num!=valaszt_num) {lcd.backlight();kijelzo_kikapcs_ido_tmp=millis();} //csak akkor kapcsoljuk be a kijelzőt, ha nyomógombot nyomott
          if (valaszt_num>0) {             //a választ gombbal választottunk egy locsoló programot, így annak adatait beolvassuk az epromból, és kiírjuk a kijelzőre
                                           //a valszt_num=0 esetén a következő időpont figyelés volt érvényben, tehát automatikus indításban várakoztunk
            //a kiválasztott locsolóprogram szelep állapotának beolvasása az eeprom-ból
            for (int i=0;i<10;i++) {
              EEPROM.get((valaszt_num-1)*100+100+i,szelep0[i]);
              EEPROM.get((valaszt_num-1)*100+110+i,szelep1[i]);
              EEPROM.get((valaszt_num-1)*100+120+i,szelep2[i]);
              EEPROM.get((valaszt_num-1)*100+130+i,szelep3[i]);
              EEPROM.get((valaszt_num-1)*100+140+i,szelep4[i]);
              EEPROM.get((valaszt_num-1)*100+150+i,szelep5[i]);
              EEPROM.get((valaszt_num-1)*100+160+i,szelep6[i]);
              EEPROM.get((valaszt_num-1)*100+170+i,szelep7[i]);
              EEPROM.get((valaszt_num-1)*100+180+i,szelep8[i]);
              EEPROM.get((valaszt_num-1)*100+190+i,szelep9[i]);
              EEPROM.get((valaszt_num-1)*10+1000+i,lp_ido_tmp);  //a tárolt érték byte típusú, ezért átmeneti változóba töltöm
              lp_ido[i]=(int) lp_ido_tmp;  //a memóriában már int típussal dolgozok, mert a beállításnál kell a -1-et is figyelnem lefele léptetéskor
            }
            //a locsolóprogramban érintett szelepek meghatározása.
            //ami egyszer is be van kapcsolva a teljes program alatt, azt a szelepo[] változóban megjelöljük
            for (int i=0;i<10;i++) {szelepo[i]=0;}
            for (int i=0;i<10;i++) {
              if (szelep0[i]) {szelepo[0]=1;}
              if (szelep1[i]) {szelepo[1]=1;}
              if (szelep2[i]) {szelepo[2]=1;}
              if (szelep3[i]) {szelepo[3]=1;}
              if (szelep4[i]) {szelepo[4]=1;}
              if (szelep5[i]) {szelepo[5]=1;}
              if (szelep6[i]) {szelepo[6]=1;}
              if (szelep7[i]) {szelepo[7]=1;}
              if (szelep8[i]) {szelepo[8]=1;}
              if (szelep9[i]) {szelepo[9]=1;}
            }
            //összes működési idő kiszámítása és megjelenítése a kijelzőn 15 másodperces bontásban (perc, másodperc)
            ossz_ido=0;
            for (byte i=0;i<10;i++) {ossz_ido=ossz_ido+lp_ido[i];}
            ossz_ido=ossz_ido*15;         //ez a teljes végrehajtási idő másodpercben
            lcd.clear();
            str_tmp="";
            int_perc=ossz_ido/60;
            if (int_perc>99) {
              ora=int_perc/60;
              perc=int_perc-ora*60;
              str_tmp=String(ora)+"o"+String(perc)+"p";
            }
            else {
              masodperc=ossz_ido-(int_perc*60);
              if (int_perc==0) {str_tmp=str_tmp+"00:";}
              else {
                if (int_perc<10) {str_tmp=str_tmp+"0"+String(int_perc)+":";;}
                else {str_tmp=String(int_perc)+":"; }
              }
              if (masodperc==0) {str_tmp=str_tmp+"00";} else {str_tmp=str_tmp+String(masodperc);}
            }
            //működő szelepek kijelzése sorszámmal, program alatt nem működő szelepeket "-" jelzi
            lcd.setCursor(0,1);lcd.print(str_tmp);
            for (byte i=0;i<10;i++) {
              lcd.setCursor(6+i,1);
              if (szelepo[i]==1) {lcd.print(i);}
              else {lcd.print("-");}
            }
          }
          
          //**************************az aktuálisan következő időprogram kijelzésére váltottunk*******************************
          //******ebbe az állapotba egy perc után bekényszerítjük, ha esetleg más állapotban hagyta a választ gombbal*********
          else {      
            ora=Clock.getHour(h12,PM);   //aktuális időpont
            perc=Clock.getMinute();      //aktuális időpont
            hetnapja=Clock.getDoW();     //aktuális hét napja
            kov_ora_tmp=23;              //a maximumra vesszük, ha valamelyik program órája kisebb, akkor annak értékét fogja felvenni, így gyüjtjük ki a legközelebbi időpontot
            kov_perc_tmp=59;             //ezt is a maximumra állítjuk
            van_ma_locsolas=0;           //ha találunk mai napra előírt locsolást, ami a pillanatnyi időpontnál későbbi, akkor 1-re állítjuk majd
            kov_idoprogram=0;            //a soron következő idoprogram sorszámát fogjuk beleírni (ha van a mai napon következő időprogram, amit végre kell hajtani)
            for (byte i=0;i<5;i++) {     //az időprogramok átnézése, hogy van-e az adott napra locslási program beállítva
              EEPROM.get(i*10,aktiv);
              if (aktiv==1) {            //az időprogram aktív, megnézhetjük, hogy van-e az adott napra időpont
                EEPROM.get(i*10+hetnapja+2,hetnapja_tmp);  //hétfő a 3,13,23 stb.-vel kezdődő címektől kezdődik, ami hetnapja+2 címentalálható, így pl. ha most csütörtök van, az 
                                                           //az 4+2=6, így minden időprogramnál a 6, 16, 26, 36, 46 címeken kell nézni, hogy aznap az időprogram előír-e locsolást
                if (hetnapja_tmp==1) {                     //az adott napon az adott időprogramban van beállítva időpont, kiolvassuk az idopontot
                  EEPROM.get(i*10+1,prog_ora_tmp);         //kiolvassuk az időprogramban előírt időpont ora-ját
                  EEPROM.get(i*10+2,prog_perc_tmp);        //kiolvassuk az időprogramban előírt időpont percét
                  if (ora==prog_ora_tmp) {                 //A program időpontjának órája megeggyezik az aktuális időpont órájával, jó lehet
                    if (perc<=prog_perc_tmp) {             //A program időpontjának perce nagyobb mint az aktuális időpont perce, ez lehet a soron következő időpont
                      van_ma_locsolas=1;                   //ez későbbi időpontra előírt locsolás, bár még nem biztos, hogy a soronkövetkező, de ma már biztosan kell locsolni
                      if (kov_ora_tmp==prog_ora_tmp) {     //Találtunk egyet, aminek az órája azonos az eddigi legközelebbi időponttal, ez lehet a legközelebbi időpont is
                        if (kov_perc_tmp>=prog_perc_tmp) { //a perc is közelebb van, tehát ez az eddigi legközelebbi időpont
                          kov_ora_tmp=prog_ora_tmp;        //megjegyezzük ennek az időprogramnak az előírt óráját, hátha ez lesz a legközelebbi időpont
                          kov_perc_tmp=prog_perc_tmp;      //megjegyezzük ennek az időprogramnak az előírt percét, hátha ez lesz a legközelebbi időpont
                          kov_idoprogram=i;                //megjegyezzük az időprogram sorszámát, hátha ez lesz a legközelebbi időpont
                          EEPROM.get(i+50,kov_lp_program); //a locsoló program számának kiolvasása
                        }
                      }
                      if (kov_ora_tmp>prog_ora_tmp) {      //ez biztosan közelebbi időpont, mint az eddigi legközelebbi
                        kov_ora_tmp=prog_ora_tmp;          //megjegyezzük ennek az időprogramnak az előírt óráját, hátha ez lesz a legközelebbi időpont
                        kov_perc_tmp=prog_perc_tmp;        //megjegyezzük ennek az időprogramnak az előírt percét, hátha ez lesz a legközelebbi időpont
                        kov_idoprogram=i;                  //megjegyezzük az időprogram sorszámát, hátha ez lesz a legközelebbi időpont
                        EEPROM.get(i+50,kov_lp_program);   //a locsoló program számának kiolvasása
                      } 
                    }
                  }
                  if (ora<prog_ora_tmp) {                  //A program időpontjának órája nagyobb mint az aktuális időpont órája, ez lehet a soron következő időpont
                    van_ma_locsolas=1;
                    if (kov_ora_tmp==prog_ora_tmp) {       //Találtunk egyet, aminek az órája azonos az eddigi legközelebbi időponttal, ez lehet a legközelebbi időpont is
                      if (kov_perc_tmp>=prog_perc_tmp) {   //a perc is közelebb van, tehát ez az eddigi legközelebbi időpont
                        kov_ora_tmp=prog_ora_tmp;          //megjegyezzük ennek az időprogramnak az előírt óráját, hátha ez lesz a legközelebbi időpont
                        kov_perc_tmp=prog_perc_tmp;        //megjegyezzük ennek az időprogramnak az előírt percét, hátha ez lesz a legközelebbi időpont
                        kov_idoprogram=i;                  //megjegyezzük az időprogram sorszámát, hátha ez lesz a legközelebbi időpont
                        EEPROM.get(i+50,kov_lp_program);   //a locsoló program számának kiolvasása
                      }
                    }
                    if (kov_ora_tmp>prog_ora_tmp) {        //ez biztosan közelebbi időpont, mint az eddigi legközelebbi
                      kov_ora_tmp=prog_ora_tmp;            //megjegyezzük ennek az időprogramnak az előírt óráját, hátha ez lesz a legközelebbi időpont
                      kov_perc_tmp=prog_perc_tmp;          //megjegyezzük ennek az időprogramnak az előírt percét, hátha ez lesz a legközelebbi időpont
                      kov_idoprogram=i;                    //megjegyezzük az időprogram sorszámát, hátha ez lesz a legközelebbi időpont
                      EEPROM.get(i+50,kov_lp_program);     //a locsoló program számának kiolvasása
                    } 
                  }
                }
              }
            }
            if (van_ma_locsolas==1) {     //az előző részben kiderült, hogy van ma locsolás, összehasonlítjuk az időpontot és locsolást indítunk, ha elérkezett
              lcd.setCursor(0,1);lcd.print("                ");
              lcd.setCursor(8,0);lcd.print("IP"+String(kov_idoprogram+1)+" LP"+String(kov_lp_program)+" ");
              str_tmp="";
              str_tmp=String(kov_ora_tmp)+":";
              if (kov_perc_tmp<10) {str_tmp=str_tmp+"0";}
              str_tmp=str_tmp+String(kov_perc_tmp);
              str_tmp=str_tmp+" ("+String(ora)+":";
              if (perc<10) {str_tmp=str_tmp+"0";}
              str_tmp=str_tmp+String(perc)+")";
              lcd.setCursor(0,1);lcd.print(str_tmp);
              if (ora==kov_ora_tmp and perc==kov_perc_tmp) {   //ha megeggyezik a következő locsolás időpontja az aktuális időponttal, akkor locsolunk
                lp_locsolas_start(kov_lp_program-1);           //ez 15 másodpercenként elindítja a locsolást, ha annak végrehajtási ideje kevesebb mint 15 sec, de ez nem valószínű
                                                               //így ezzel a lehetséges működési zavarral nem foglalkoztam. Remélhetőleg nem lesz olyan locsoló program
                                                               //leprogramozva, ami egy percnél rövidebb. A konkrét locsolás vezérlést az lp_locsolas_start() függvény végzi el,
                                                               //amíg az fut a loop()-ba nem kerülünk vissza, csak ha annak végrehajtása befejeződött!
              }
            }
            else {       // ma már nincs locsolási időpont
              lcd.setCursor(8,0);lcd_print_hu("nincs ma ");
              lcd.setCursor(0,1);lcd_print_hu("már locsolás!  ");
            }
          }
          switch (valaszt_num) {    //a kiválasztott locsolási program számának vagy a soronkövetkező automatikus locsolás adatainak a kiírása
            case 0:
              lcd.setCursor(0,0);lcd.print("Aut.ind:");
              break;
            case 1:
              lcd.setCursor(0,0);lcd_print_hu("LP1 kézi inditás");
              break;
            case 2:
              lcd.setCursor(0,0);lcd_print_hu("LP2 kézi inditás");
              break;
            case 3:
              lcd.setCursor(0,0);lcd_print_hu("LP3 kézi inditás");
              break;
            case 4:
              lcd.setCursor(0,0);lcd_print_hu("LP4 kézi inditás");
              break;
            case 5:
              lcd.setCursor(0,0);lcd_print_hu("LP5 kézi inditás");
              break;
          }
        } 

        //amennyiben az SW_VALASZT gombbal beállítottunk egy locsoló programot, és az SW_START gombot megnyomtuk, akkor itt fogjuk meghívni a locsolást
        //végző lp_locsolas_start() függvényt a locsoló program sorszámával. A konkrét locsolás vezérlést az lp_locsolas_start() függvény végzi el,
        //amíg az fut a loop()-ba nem kerülünk vissza, csak ha annak végrehajtása befejeződött!
        elozo_allapot_valaszt_num=valaszt_num;
        if (elozo_allapot_start_num!=start_num) {
          switch (valaszt_num) {
            case 1:
              lp_locsolas_start(0);         //meghívjuk a locsolást elvégző függvényt a kiválasztott időzítő program indexével
              kimenet_allapot[1]=1;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 1-ra, hogy újra az LP1 időprogram beállítás legyen a képernyőn
              break;
            case 2:
              lp_locsolas_start(1);         //meghívjuk a locsolást elvégző függvényt a kiválasztott időzítő program indexével
              kimenet_allapot[1]=2;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 2-re, hogy újra az IP2 időprogram beállítás legyen a képernyőn
              break;
            case 3:
              lp_locsolas_start(2);         //meghívjuk a locsolást elvégző függvényt a kiválasztott időzítő program indexével
              kimenet_allapot[1]=3;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 3-re, hogy újra az IP3 időprogram beállítás legyen a képernyőn
              break;
            case 4:
              lp_locsolas_start(3);         //meghívjuk a locsolást elvégző függvényt a kiválasztott időzítő program indexével
              kimenet_allapot[1]=4;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 4-re, hogy újra az IP4 időprogram beállítás legyen a képernyőn
              break;
            case 5:
              lp_locsolas_start(4);         //meghívjuk a locsolást elvégző függvényt a kiválasztott időzítő program indexével
              kimenet_allapot[1]=5;         //az SW_VALSZT gomb kimenetének állapotát vissza kell állítani 5-re, hogy újra az IP5 időprogram beállítás legyen a képernyőn
              break;
          }
          start_num=0;                  //különben az előző állapot a jelenlegi 10-et veszi fel, és végtelen ciklus alakul ki, mert a következő ciklusban is bemegy
                                        //az idozites_beallitas() függvénybe, ami viszont azonnal ki is lép start_num=10-el.
          elozo_allapot_valaszt_num=99; //hogy ki is írja a képernyőre az IP1 beállítás üzenetet
          bemenet_allapot[2]=1;        //azért, hogy a kézi indításból visszatérve biztosan ne tekintse úgy, hogy a start gomb le vol nyomva, alapjelyzetbe állítjuk a 2. csatornat a multi_buttom változóival 
          bemenet_elozo_allapot[2]=1;  
          prell_tmp[2]=0;                

        }
        elozo_allapot_start_num=start_num;
        break;
    }
}

void tanulas_start(byte lp_program_num) {
/*****************************************************************************************************************************************
 * Ez a függvény végzi a tanulás funkció alatt a szelepek állapotának és az eltelt időnek a rögzítését. Akkor hívjuk meg ezt a függvényt *
 * a loop()-ból, amikor az SW_VALASZT-al kiválasztott locsoló program esetén megnyomjuk az SW_START gombot. Ekkor elindul ez a függvény. *
 * Figyelmeztető felirat után várakozik a legelső programlépésben működő szelepek váltó kapcsolóinak beállítására, majd meg kell nyomni  *
 * újra az SW_START gombot. ettől kezdve méri az időt egy következő SW_START megnyomásáig, amikor is azt tárolja. Az időmérés alatt      *
 * bármikor át lehet állítani a szelepeket, a következő SW_START megnyomása az éppen akkor aktuális állapotot rögzíti. Összesen 10 lépés *
 * adatait tárolja. Egy lépés maximális ideje 63 perc, he eddig nem nyúlunk a SW_START gombhoz, akkor automatikusan a következő lépést   *
 * kezdi el mérni. Ha 15 másodpercnél kevesebb idő telik el a lépés mérésekor, akkor 0 időt rögzít, a locsolás ezt a lpést ki fogja      *
 * hagyni. Így lehet a szükségtelen lépéseket kihyagyni, ha egy locsolás kevesebb mint 10 lépésből is megvalósítható.                    *
 * Rögzítés közben villog a tanulás led.                                                                                                 *
 * Ha kifogy a víz, vagy elindítják a slag használatát, akkor szünetel az időmérés, áll a program rögzítése. Ha lesz víz, vagy           *
 * befelyeződik a slag hasznáat, akkor a rögzítés folytatódik.                                                                           *
 * Bemenő paraméter annak a locsoló program tárolóhelynek a száma, amire a locsoló programot rögzíteni kell!                             *
 *****************************************************************************************************************************************/
bool szunet_vege=0;           //ha szünetel a locsolás, akkor ez jelzi 1-el a szünetben, hogy amikor vége, be kell kapcsolni a szelepeket az aktuális állapotba
bool szunet_kiiras=1;         //1-el jelzi, hogy ki kell írni a szünetre vonatkozó tájékoztató feliratot, kiírás után 0-ra állítjuk, hogy a szünetben ne irogassa állandóan
long ido_tmp=millis(); 
long villog_ido_tmp=millis(); //másodperces cilusidőbel villogtatni fogjuk a tanulás led-et, ehhez segédváltozó
bool villog_vilagit=0;        //a led villogáshoz tárolja, hogy éppen világít vagy sem
bool ido_tulcsordulas=0;      //annak jelzésére, ha egy lépés időzítése során meghaladtuk az egy lépés maximális idejét (kényszerített lépésszám növeléshez)
int akt_ido_szamlalo=0;       //ebben tároljuk a lépés idejét. Másodpercenként növeljük az értékét. Maximális értéke 3825, ennél az értéknél nulázzuk, és következő lépésre váltunk
byte akt_lepes=0;             //az mutatja, hogy a 10-ből hányadik lpésnél járunk 0-tól 9-ig változik az értéke, de az utolsó lépénél 10-re vált, de ekkor már kapcsoló 
                              //szelep állapotot nem rögzítünk, csak a 9. lépés idejét. A kijelzőre 1-től 10-ig írjuk ki.
elozo_allapot_start_num=1;    //hogy biztosan belemenjen egyszer a szelepállításban SW_START megnyomás nélkül, hiszen amikor elindul a folyamat nyomva lesz az SW-START (ezzel indul)

if (digitalRead(SLAG_ERZEKELO)==0) {  //a tanulóprogram elindulásakor éppen slagot használunk, így nem indítható el
  lcd.clear();lcd.setCursor(0,0);lcd_print_hu("SLAG használat! ");
  lcd.setCursor(0,1);lcd_print_hu("Tanulás megsz.! ");
  delay(2000);
  return;
}

if (digitalRead(VIZKIFOGYAS_ERZEKELO)==0) {  //a locsolóprogram elindulásakor éppen ki van fogyva a víz, de a programot elindítottuk, mert ez tanulás közben is előfordulhat
  lcd.clear();lcd.setCursor(0,0);lcd_print_hu(" Vizkifogyás!   ");
  lcd.setCursor(0,1);lcd.print("Tanul. elindult!");
  delay(2000);
}


do {  //várakozás az SW_START elengedésére, hiszen nyomva van, amikor meghívjuk ezt a függvényt
} while (digitalRead(SW_START)==0);  //megvárjuk, amíg elengedi a START gombot
delay(100); //kis várakozás, hogy vége legyen a prell_nek, ha van

//kijelző háttérvilágítás bekapcsolása és figyelmeztető felirat, hogy állítsa be az első lpés kapcsolóit, és nyomja le a START gombot.
lcd.backlight();
lcd.clear();
lcd.setCursor(0,0);lcd_print_hu("Kapcsoló állitás");
lcd.setCursor(0,1);lcd_print_hu("   és START!    ");

do {  //megvárjuk, hogy megnomja a START gombot, ezzel indul a 0. lépés kapcsolóinak rögzítése. Itt elvileg akármeddig várhatnánk,
      //de ezt a várakozási időt egy percben korlátozzuk, ha addig nem történik semmi, akkor kilépünk a függvényből.
      
  if (digitalRead(SW_KEZI)==0) {return;}  //ha közben átkapcsoljuk kézi üzemmódba, akkor mindent meg kell szakítani,
                                          //kilépünk a függvényből és a főciklus lekapcsolja az esetleg vezérelt szelepeket

  if (millis()>ido_tmp+60000) {return;}  //ha nem nyomjuk meg a start-ot egy percen belül, akkor visszatérünk, 
                                         //így nem ragadhatunk egy olyan állapotban, ami nem tteszi lehetővé locsolás elindítását

  //bekapcsoljuk a szelepeketn ha valamelyik szelep kapcsolót átkapcsolja, már folyik a víz ha valamit bekapcsol
  if (digitalRead(SW_0)==0) {digitalWrite(OUT_0,HIGH);} else {digitalWrite(OUT_0,LOW);} 
  if (digitalRead(SW_1)==0) {digitalWrite(OUT_1,HIGH);} else {digitalWrite(OUT_1,LOW);} 
  if (digitalRead(SW_2)==0) {digitalWrite(OUT_2,HIGH);} else {digitalWrite(OUT_2,LOW);} 
  if (digitalRead(SW_3)==0) {digitalWrite(OUT_3,HIGH);} else {digitalWrite(OUT_3,LOW);} 
  if (digitalRead(SW_4)==0) {digitalWrite(OUT_4,HIGH);} else {digitalWrite(OUT_4,LOW);} 
  if (digitalRead(SW_5)==0) {digitalWrite(OUT_5,HIGH);} else {digitalWrite(OUT_5,LOW);} 
  if (digitalRead(SW_6)==0) {digitalWrite(OUT_6,HIGH);} else {digitalWrite(OUT_6,LOW);} 
  if (digitalRead(SW_7)==0) {digitalWrite(OUT_7,HIGH);} else {digitalWrite(OUT_7,LOW);} 
  if (digitalRead(SW_8)==0) {digitalWrite(OUT_8,HIGH);} else {digitalWrite(OUT_8,LOW);} 
  if (digitalRead(SW_9)==0) {digitalWrite(OUT_9,HIGH);} else {digitalWrite(OUT_9,LOW);} 
} while (digitalRead(SW_START)==1);  //megvártuk, amíg megnyomta a START gombot
delay(100); //kis várakozás, hogy vége legyen a prell_nek, ha van

//indul a 0. lépés mérése
lcd.setCursor(0,0);lcd.print(akt_lepes+1);lcd_print_hu(".lépés        ");  //egy-el nagyobb lépésszámot írunk ki, hogy 1-10 között legyen a lépésszám
lcd.setCursor(0,1);lcd_print_hu("beáll. és START");

do {                                 //megvárjuk, amíg elengedi a START gombot
} while (digitalRead(SW_START)==0);  
delay(100);                          //kis várakozás, hogy vége legyen a prell_nek, ha van

//ez vot a 0. lépés indulása, tároljuk az aktuális szelep állásokat
szelep0[akt_lepes]=!digitalRead(SW_0);
szelep1[akt_lepes]=!digitalRead(SW_1);
szelep2[akt_lepes]=!digitalRead(SW_2);
szelep3[akt_lepes]=!digitalRead(SW_3);
szelep4[akt_lepes]=!digitalRead(SW_4);
szelep5[akt_lepes]=!digitalRead(SW_5);
szelep6[akt_lepes]=!digitalRead(SW_6);
szelep7[akt_lepes]=!digitalRead(SW_7);
szelep8[akt_lepes]=!digitalRead(SW_8);
szelep9[akt_lepes]=!digitalRead(SW_9);

//ebben a fő ciklusban fogjuk végezni az összes tevékenységet. Akkor lépünk ki belőle, ha a 10. lépés
//rögzítése is megtörtént. A 10. lépésig biztosan eljutunk egyszer, mert 63 percenként SW_START
//megnyomása nélkül is vesszük a következő lépést.
do  {
  if (digitalRead(SW_KEZI)==0) {return;}  //ha közben átkapcsoljuk kézi üzemmódba, akkor mindent meg kell szakítani,
                                          //kilépünk a függvényből és a főciklus lekapcsolja az esetleg vezérelt szelepeket

  if (digitalRead(SLAG_ERZEKELO)==0 or digitalRead(VIZKIFOGYAS_ERZEKELO)==0) {    //ha közben slag-ot használunk, vagy kifogy a víz, szüneteltetni kell az időmérést
    delay(100);  //ez a bemenet egy relével kapcsolt jelet érzékel, lehet prell, ezért várunk egy kicsit, hogy következő ciklusban biztosan egy stabil állapotot találjunk
    //amíg szünetel a locsolás, lekapcsoljuk a szelepeket
    digitalWrite(OUT_0,LOW);      
    digitalWrite(OUT_1,LOW);      
    digitalWrite(OUT_2,LOW);      
    digitalWrite(OUT_3,LOW);      
    digitalWrite(OUT_4,LOW);      
    digitalWrite(OUT_5,LOW);      
    digitalWrite(OUT_6,LOW);      
    digitalWrite(OUT_7,LOW);      
    digitalWrite(OUT_8,LOW);      
    digitalWrite(OUT_9,LOW); 
    szunet_vege=1;  //ezzel jelezzük, ha egy szünet történt, és újra be kell kapcsolni a szelepeket a folytatáskor az aktuális programlépésnek megfelelően
    if (szunet_kiiras==1) {
      szunet_kiiras=0;  //nem kell többször kiirni a szünet alatt
      if (digitalRead(SLAG_ERZEKELO)==0) {lcd.clear();lcd.setCursor(0,0);lcd_print_hu(" SLAG használat ");}
      if (digitalRead(VIZKIFOGYAS_ERZEKELO)==0) {lcd.clear();lcd.setCursor(0,0);lcd.print("A viz kifogyott!");}
      lcd.setCursor(0,1);lcd_print_hu(" Tanulás aktiv! ");
    }
  }
  else {  //nincs vizkifogyas és slag használat sem, mehet a tanuló program vegrahajtasa
    if (szunet_vege==1) { //szünet után egyszer be kell kapcsolni a szelepeket az aktuális állapotba
      if (digitalRead(SW_0)==0) {digitalWrite(OUT_0,HIGH);} else {digitalWrite(OUT_0,LOW);} 
      if (digitalRead(SW_1)==0) {digitalWrite(OUT_1,HIGH);} else {digitalWrite(OUT_1,LOW);} 
      if (digitalRead(SW_2)==0) {digitalWrite(OUT_2,HIGH);} else {digitalWrite(OUT_2,LOW);} 
      if (digitalRead(SW_3)==0) {digitalWrite(OUT_3,HIGH);} else {digitalWrite(OUT_3,LOW);} 
      if (digitalRead(SW_4)==0) {digitalWrite(OUT_4,HIGH);} else {digitalWrite(OUT_4,LOW);} 
      if (digitalRead(SW_5)==0) {digitalWrite(OUT_5,HIGH);} else {digitalWrite(OUT_5,LOW);} 
      if (digitalRead(SW_6)==0) {digitalWrite(OUT_6,HIGH);} else {digitalWrite(OUT_6,LOW);} 
      if (digitalRead(SW_7)==0) {digitalWrite(OUT_7,HIGH);} else {digitalWrite(OUT_7,LOW);} 
      if (digitalRead(SW_8)==0) {digitalWrite(OUT_8,HIGH);} else {digitalWrite(OUT_8,LOW);} 
      if (digitalRead(SW_9)==0) {digitalWrite(OUT_9,HIGH);} else {digitalWrite(OUT_9,LOW);} 
      szunet_vege=0; //ha szunet után bekapcsoltuk a szelepeket, akkor már nem kell többször
      szunet_kiiras=1;  //a következő szünetnél (ha lesz), ki fogjuk írni egyszer a tájékoztató szüzenetet
      //ujra ki kell írni a képernyőre a tanulási állapotokat
      lcd.clear();
      lcd.setCursor(0,0);lcd.print(akt_lepes+1);lcd_print_hu(".lépés        "); //egy-el nagyobb lépésszámot írunk ki, hogy 1-10 között legyen a lépésszám
      lcd.setCursor(0,1);lcd_print_hu("beáll. és START");
    }
    start_num=multi_button(3,0,SW_START,1,0,0);     //az SW_START nyomógombot figyeljuk, megnyomásakor egyet ad vissza
    //lemásoljuk a kijelző ledekre és a szelepekre a kapcsolók állapotát, szelepeken folyik a víz, ha be vannak kapcsolva
    if (digitalRead(SW_0)==0) {digitalWrite(OUT_0,HIGH);} else {digitalWrite(OUT_0,LOW);} 
    if (digitalRead(SW_1)==0) {digitalWrite(OUT_1,HIGH);} else {digitalWrite(OUT_1,LOW);} 
    if (digitalRead(SW_2)==0) {digitalWrite(OUT_2,HIGH);} else {digitalWrite(OUT_2,LOW);} 
    if (digitalRead(SW_3)==0) {digitalWrite(OUT_3,HIGH);} else {digitalWrite(OUT_3,LOW);} 
    if (digitalRead(SW_4)==0) {digitalWrite(OUT_4,HIGH);} else {digitalWrite(OUT_4,LOW);} 
    if (digitalRead(SW_5)==0) {digitalWrite(OUT_5,HIGH);} else {digitalWrite(OUT_5,LOW);} 
    if (digitalRead(SW_6)==0) {digitalWrite(OUT_6,HIGH);} else {digitalWrite(OUT_6,LOW);} 
    if (digitalRead(SW_7)==0) {digitalWrite(OUT_7,HIGH);} else {digitalWrite(OUT_7,LOW);} 
    if (digitalRead(SW_8)==0) {digitalWrite(OUT_8,HIGH);} else {digitalWrite(OUT_8,LOW);} 
    if (digitalRead(SW_9)==0) {digitalWrite(OUT_9,HIGH);} else {digitalWrite(OUT_9,LOW);} 
    if ((elozo_allapot_start_num!=start_num and start_num==1) or ido_tulcsordulas==1) { //ha megnyomtam a start gombot, vagy változik a kimenetének állapota, mert letelt a maximális ido, akkor veszem a következő lépést
      ido_tulcsordulas=0;                                                               //következő esetben is jelezze az idő tulcsordulást, illetve nem menjen be rögtön ebbe a feltételbe
        
      // letároljuk a kacsolók aktuális állapotát, és ha nem a 0. lépésről van szó, akkor az előző lépéshez az eltelt időt
      akt_lepes++;                              //ez a második vagy azt követő start lenyomás, tároljuk az éppen aktuális értékeket
      if (akt_lepes<10) {                       //a ciklusba 10.-re is belemegy, de akkor már csak az időt kell tárolni
        szelep0[akt_lepes]=!digitalRead(SW_0);
        szelep1[akt_lepes]=!digitalRead(SW_1);
        szelep2[akt_lepes]=!digitalRead(SW_2);
        szelep3[akt_lepes]=!digitalRead(SW_3);
        szelep4[akt_lepes]=!digitalRead(SW_4);
        szelep5[akt_lepes]=!digitalRead(SW_5);
        szelep6[akt_lepes]=!digitalRead(SW_6);
        szelep7[akt_lepes]=!digitalRead(SW_7);
        szelep8[akt_lepes]=!digitalRead(SW_8);
        szelep9[akt_lepes]=!digitalRead(SW_9);
      }
      if (akt_lepes>0) {                         //mindíg az alőző lépés tárolójához kell tárolni az eltelt időt, ezért a 0.lépéshez nem kell
        lp_ido[akt_lepes-1]=akt_ido_szamlalo/15;
      }
      akt_ido_szamlalo=0;                        //elkezdjük az aktuális lépés idejének mérését
      lcd.setCursor(0,0);lcd.print(akt_lepes+1);lcd_print_hu(".lépés        "); //egy-el nagyobb lépésszámot írunk ki, hogy 1-10 között legyen a lépésszám
      lcd.setCursor(0,1);lcd_print_hu("beáll. és START");
    }
    elozo_allapot_start_num=start_num;
    if (millis()>ido_tmp+1000) {                //egy másodpercenként növeljük az idő számlálót, és frissítjük a kijelzőn a végrehajtási időt
      ido_tmp=millis();
      akt_ido_szamlalo++;
      if (akt_ido_szamlalo>3825) {              //3825 másodpercnél nem lehet hosszabb egy lépés időzítése (kb 63 perc)
        ido_tulcsordulas=1;
      }
      //Kiírjuk a kijelzőre, hogy hol tartunk a lépésben
      perc=(akt_ido_szamlalo)/60;
      masodperc=(akt_ido_szamlalo)-((int)perc*60);
      str_tmp="";
      if (perc==0) {str_tmp=str_tmp+"00:";}
      else {
        if (perc<10) {str_tmp=str_tmp+"0"+String(perc)+":";;}
        else {str_tmp=String(perc)+":"; }
      }
      if (masodperc==0) {str_tmp=str_tmp+"00";}
      else {
        if (masodperc<10) {str_tmp=str_tmp+"0"+String(masodperc);}
        else {str_tmp=str_tmp+String(masodperc);}
      }
      lcd.setCursor(9,0);lcd.print("(");lcd.print(str_tmp);lcd.print(")");
    }
  }
  
  //fél másodpercenként fel, vagy le kapcsoljuk a tanulás led-et, ezzel jelezzük, hogy rögzítés van folyamatban
  if (millis()>villog_ido_tmp+500) {   
    villog_ido_tmp=millis();    
    if (villog_vilagit==0) {digitalWrite(LED_TANULO,HIGH);villog_vilagit=1;}
    else {digitalWrite(LED_TANULO,LOW);villog_vilagit=0;}
  }
  
} while (akt_lepes<10);  //főciklus vége a 10. lépés után

digitalWrite(LED_TANULO,LOW); //biztosan folyamatosan világítson a tanulás led, amikor vége a rögzítésnek

//szelepek leállítása, locsolás vége
digitalWrite(OUT_0,LOW);      
digitalWrite(OUT_1,LOW);      
digitalWrite(OUT_2,LOW);      
digitalWrite(OUT_3,LOW);      
digitalWrite(OUT_4,LOW);      
digitalWrite(OUT_5,LOW);      
digitalWrite(OUT_6,LOW);      
digitalWrite(OUT_7,LOW);      
digitalWrite(OUT_8,LOW);      
digitalWrite(OUT_9,LOW); 

//a rögzített adatok eeprom-ba írása
for (byte i=0;i<10;i++) {
  lp_ido_tmp=(byte) lp_ido[i];   //a memóriában int típussal dolgozok, mert a beállításnál kell a -1-et is figyelnem lefele léptetéskor, ezért byte-ra kell konvertálni
  EEPROM.put(lp_program_num*10+1000+i,lp_ido_tmp);  //a tárolt érték byte típusú, ezért átmeneti változóból írom, hogy az eeprom.put jó típussal írjon
  EEPROM.put(lp_program_num*100+100+i,szelep0[i]);
  EEPROM.put(lp_program_num*100+110+i,szelep1[i]);
  EEPROM.put(lp_program_num*100+120+i,szelep2[i]);
  EEPROM.put(lp_program_num*100+130+i,szelep3[i]);
  EEPROM.put(lp_program_num*100+140+i,szelep4[i]);
  EEPROM.put(lp_program_num*100+150+i,szelep5[i]);
  EEPROM.put(lp_program_num*100+160+i,szelep6[i]);
  EEPROM.put(lp_program_num*100+170+i,szelep7[i]);
  EEPROM.put(lp_program_num*100+180+i,szelep8[i]);
  EEPROM.put(lp_program_num*100+190+i,szelep9[i]);
}
kijelzo_kikapcs_ido_tmp=millis();   //hogy ne váltson azonnal automata locsolás figyelésbe, hátha egy következő programot is be akarunk tanítani  
lcd.clear();
lcd.setCursor(0,0);lcd_print_hu("Locsoló program");
lcd.setCursor(0,1);lcd_print_hu("rögzités vége! ");
delay(2000);
}

void lp_locsolas_start(byte lp_program_num) {
/**************************************************************************************************************************************************
 * Ez a függvény végzi el egy manuálisan, vagy automatikusan (időzítve) elindított locsoló program végrehajtását. Paraméterként megkapja a        * 
 * Locsoló programszámát. Ha a START gomb éppen nyomva van a függvény meghívásakor, az azt jelenti, hogy mauálisan indult a program, hiszen       *
 * időzített indításnál nem nyomjuk le a START gombot. Locsolás közben mérjük az időt, és ha elértük az aktuális locsolóprogram lépés vegrehajtási*
 * idejét, akkor a következő lépésre lépünk. Közben figyeljük a vizkifogyást és a slag használatot. Ha valamelyik bekövetkezik, akkor             *
 * szüneteltetjük a locsoló programot. Ha újra van víz, vagy vége a slag használatnak, akkor folytatjuk.                                          *
 * A locsoló program végrehajtása közben lépésenként frissítjük a kijelzőt, kijelezzük a lépésből hátralévő időt másodperces bontásban.           *
 * A locsolás led-et folyamatosan villogtatjuk.                                                                                                   *
 **************************************************************************************************************************************************/
bool szunet_vege=0;             //ha szünetel a locsolás, akkor ez jelzi 1-el a szünetben, hogy amikor vége, be kell kapcsolni a szelepeket az aktuális állapotba
bool szunet_kiiras=1;           //1-el jelzi, hogy ki kell írni a szünetre vonatkozó tájékoztató feliratot, kiírás után 0-ra állítjuk, hogy a szünetben ne irogassa állandóan
long lepes_ido_tmp=millis();    //a lepes végrehajtási idejének méréséhez használt segéd változó, másodperces időzítéshez használjuk
long villog_ido_tmp=millis();   //másodperces cilusidőbel villogtatni fogjuk a locsolás led-et, ehhez segédváltozó
bool villog_vilagit=0;          //a led villogáshoz tárolja, hogy éppen világít vagy sem
int akt_ido_szamlalo=0;         //ebbe a változóba olvassuk be az eeprom-ból az adott lépés időtartamát. 15-el szorozzuk az eeprom-ból kiolvasott értéket, hogy másodpercben legyen a végrehajtási idő
byte akt_lepes=0;               //az aktuálisan végrehajtott lépés sorszáma
bool kov_lepes=1;               //ez a változó jelzi, ha letelt az aktuális lépés időzitétt ideje, és jöhet a következő lépés
bool man_inditas=0;             //ebben a tárolóban jegyezzük meg, ha manuálisan indítottuk a locsoló programot. A kijelzőre más feliratok kerülnek, ha manuális indítás volt.
elozo_allapot_start_num=0;      //mivel az SW_START lenyomásával ki lehet hagyni lépéseket a végrehajtás során, ezzel biztosítjuk, hogy az első lépést nehogy lenyomott
                                //SW_START-nak azonosítsa és kihagyja a lépést

if (digitalRead(SW_START)==0) {man_inditas=1;} //éppen nyomva a START gomb, tehát mauális indítás volt, és nem automatikus

//megvárjuk, míg elengedi az SW_START nyomógombot. Erre azért van szükség, mert a START gombbal kihagyhatók lépések, ezért elengedett start-al kell indulnia a programnak
do {
} while (digitalRead(SW_START)==0);  //megvárjuk, amíg elengedi a START gombot
delay(100); //kis várakozás, hogy vége legyen a prell_nek, ha van

if (digitalRead(SLAG_ERZEKELO)==0) {  //a locsolóprogram elindulásakor éppen slagot használunk, de a programot elindítottuk, mert különben nem lenne időzített locsolás
                                      //küldünk egy figyelmeztető üzenetet
  lcd.clear();lcd.setCursor(0,0);lcd_print_hu("SLAG használat! ");
  lcd.setCursor(0,1);lcd.print("Prog. elindult! ");
  delay(2000);
}
  
if (digitalRead(VIZKIFOGYAS_ERZEKELO)==0) {  //a locsolóprogram elindulásakor éppen ki van fogyva a víz, de a programot elindítottuk, mert különben nem lenne időzített locsolás
                                             //küldünk egy figyelmeztető üzenetet
  lcd.clear();lcd.setCursor(0,0);lcd_print_hu(" Vizkifogyás!   ");
  lcd.setCursor(0,1);lcd.print("Prog. elindult! ");
  delay(2000);
}

//tömbökbe töltjük a locsoló program egyes lépéseinek szelep állapotait és a lépések végrehajtási idejét
for (int i=0;i<10;i++) {
  EEPROM.get(lp_program_num*100+100+i,szelep0[i]);
  EEPROM.get(lp_program_num*100+110+i,szelep1[i]);
  EEPROM.get(lp_program_num*100+120+i,szelep2[i]);
  EEPROM.get(lp_program_num*100+130+i,szelep3[i]);
  EEPROM.get(lp_program_num*100+140+i,szelep4[i]);
  EEPROM.get(lp_program_num*100+150+i,szelep5[i]);
  EEPROM.get(lp_program_num*100+160+i,szelep6[i]);
  EEPROM.get(lp_program_num*100+170+i,szelep7[i]);
  EEPROM.get(lp_program_num*100+180+i,szelep8[i]);
  EEPROM.get(lp_program_num*100+190+i,szelep9[i]);
  EEPROM.get(lp_program_num*10+1000+i,lp_ido_tmp);  //a tárolt érték byte típusú, ezért átmeneti változóba töltöm
  lp_ido[i]=(int) lp_ido_tmp;                       //a memóriában már int típussal dolgozok, mert a beállításnál kell a -1-et is figyelnem lefele léptetéskor
}

//bekapcsoljuk a háttér vélágítást, és kiírjuk az elindított losoló program számát. Ha nem manuális indítás volt, akkor az időprogram számát is.
lcd.backlight();
lcd.clear();
lcd.setCursor(0,0);lcd_print_hu("Locsolás ");
if (man_inditas==1) {  //amikor elindul a fuggvény, nyomva volt a start gomb, tehát kézi locsolási program indítás van
  lcd.setCursor(9,0);lcd.print("MAN.LP"+String(lp_program_num+1));
  lcd.setCursor(0,1);lcd_print_hu(" Kézi inditás!  ");
  delay(2000);
}
else {
  lcd.setCursor(9,0);lcd.print("IP"+String(kov_idoprogram+1)+" LP"+String(lp_program_num+1));
  lcd.setCursor(0,1);lcd_print_hu("Időzit. inditás!");
  delay(2000);
}

// Ez itt a főciklus, amiben az összes feladatot elvégezzük. Figyeljük a manuális kapcsolót, a slag használatot 
// és a vízkifogyást. Ha menet közben lenyomjuk az SW_START gombot, akkor a locsolóprogram idejének letelte előtt
// átkapcsolunk a következő lépésre. Ha egy lépés ideje 0, akkor azt kihagyjuk. Ha letelt a lépés ideje, akkor 
// jön a következő lépés.
do  {
  if (digitalRead(SW_KEZI)==0) {return;}  //ha közben átkapcsoljuk kézi üzemmódba, akkor mindent meg kell szakítani,
                                          //kilépünk a függvényből és a főciklus lekapcsolja az esetleg vezérelt szelepeket

  if (digitalRead(SLAG_ERZEKELO)==0 or digitalRead(VIZKIFOGYAS_ERZEKELO)==0) {    //ha közben slag-ot használunk, vagy kifogy a víz, szüneteltetni kell a számlálást
    delay(100);  //ez a bemenet egy relével kapcsolt jelet érzékel, lehet prell, ezért várunk egy kicsit, hogy következő ciklusban biztosan egy stabil állapotot találjunk
    //amíg szünetel a locsolás, lekapcsoljuk a szelepeket
    digitalWrite(OUT_0,LOW);      
    digitalWrite(OUT_1,LOW);      
    digitalWrite(OUT_2,LOW);      
    digitalWrite(OUT_3,LOW);      
    digitalWrite(OUT_4,LOW);      
    digitalWrite(OUT_5,LOW);      
    digitalWrite(OUT_6,LOW);      
    digitalWrite(OUT_7,LOW);      
    digitalWrite(OUT_8,LOW);      
    digitalWrite(OUT_9,LOW); 
    szunet_vege=1;  //ezzel jelezzük, ha egy szünet történt, és újra be kell kapcsolni a szelepeket a folytatáskor az aktuális programlépésnek megfelelően
    if (szunet_kiiras==1) {
      szunet_kiiras=0;  //nem kell többször kiirni a szünet alatt
      if (digitalRead(SLAG_ERZEKELO)==0) {lcd.clear();lcd.setCursor(0,0);lcd_print_hu(" SLAG használat ");}
      if (digitalRead(VIZKIFOGYAS_ERZEKELO)==0) {lcd.clear();lcd.setCursor(0,0);lcd.print("A viz kifogyott!");}
      lcd.setCursor(0,1);lcd.print("Locs.prog aktiv!");
    }
  }
  else { //nincs vizkifogyas és slag használat sem, mehet a locsoló program vegrahajtasa
    if (szunet_vege==1) { //szünet után egyszer be kell kapcsolni a szelepeket az aktuális állapotba
      digitalWrite(OUT_0,szelep0[akt_lepes]);      
      digitalWrite(OUT_1,szelep1[akt_lepes]);      
      digitalWrite(OUT_2,szelep2[akt_lepes]);      
      digitalWrite(OUT_3,szelep3[akt_lepes]);      
      digitalWrite(OUT_4,szelep4[akt_lepes]);      
      digitalWrite(OUT_5,szelep5[akt_lepes]);      
      digitalWrite(OUT_6,szelep6[akt_lepes]);      
      digitalWrite(OUT_7,szelep7[akt_lepes]);      
      digitalWrite(OUT_8,szelep8[akt_lepes]);      
      digitalWrite(OUT_9,szelep9[akt_lepes]);  
      szunet_vege=0; //ha szunet után bekapcsoltuk a szelepeket, akkor már nem kell többször
      szunet_kiiras=1;  //a következő szünetnél (ha lesz), ki fogjuk írni egyszer a tájékoztató szüzenetet
      //ujra ki kell írni a képernyőre a locsolási állapotokat
      lcd.clear();
      lcd.setCursor(0,0);lcd_print_hu("Locsolás ");
      if (man_inditas==1) {  //amikor elindul a fuggvény, nyomva volt a start gomb, tehát kézi locsolási program indítás van
        lcd.setCursor(9,0);lcd.print("MAN.LP"+String(lp_program_num+1));
        lcd.setCursor(0,1);lcd_print_hu(" Kézi inditás!  ");
      }
      else {
        lcd.setCursor(9,0);lcd.print("IP"+String(kov_idoprogram+1)+" LP"+String(lp_program_num+1));
        lcd.setCursor(0,1);lcd_print_hu("Időzit. inditás!");
      }
      lcd.setCursor(0,1);lcd.print(akt_lepes+1);lcd_print_hu(".lépés        ");
    }
    start_num=multi_button(3,0,SW_START,1,0,0);     //az SW_START nyomógombot figyeljuk, megnyomásakor egyet ad vissza
    if ((elozo_allapot_start_num!=start_num and start_num==1) or kov_lepes==1) { //ha megnyomtam a start gombot, vagy változik a kemenetének állapota, mert letelt az ido, akkor veszem a következő lépést
      if (akt_lepes<10) {
        lcd.setCursor(0,1);lcd.print(akt_lepes+1);lcd_print_hu(".lépés        ");
        akt_ido_szamlalo=lp_ido[akt_lepes]*15; //bemásoljuk az aktuális lépés idejének számláló értékét (másodpercben), ezt fogjuk másodpercenként csökkenteni
        if (akt_ido_szamlalo>0) { //csak akkor vezéreljük a szelepeket, ha a lépés végrehajtási ideje nagyobb min 0, ha kihagyunk egy lépést a 0 idő miatt, akkor ne állítgassuk a szelepeket fölöslegesen
          digitalWrite(OUT_0,szelep0[akt_lepes]);      
          digitalWrite(OUT_1,szelep1[akt_lepes]);      
          digitalWrite(OUT_2,szelep2[akt_lepes]);      
          digitalWrite(OUT_3,szelep3[akt_lepes]);      
          digitalWrite(OUT_4,szelep4[akt_lepes]);      
          digitalWrite(OUT_5,szelep5[akt_lepes]);      
          digitalWrite(OUT_6,szelep6[akt_lepes]);      
          digitalWrite(OUT_7,szelep7[akt_lepes]);      
          digitalWrite(OUT_8,szelep8[akt_lepes]);      
          digitalWrite(OUT_9,szelep9[akt_lepes]);  
        }
        kov_lepes=0; //majd a ciusban lévő időzítés figyelés fogja 1-re állítani, ha letelt a lépés időzítése, és akkor ujra bejön ebbe az if-be
      }
      else {   //ez már a 10. lépés, ami nem programlépés, csak a szelepeket kapcsolja ki, és kilép a cilusból
        digitalWrite(OUT_0,LOW);      
        digitalWrite(OUT_1,LOW);      
        digitalWrite(OUT_2,LOW);      
        digitalWrite(OUT_3,LOW);      
        digitalWrite(OUT_4,LOW);      
        digitalWrite(OUT_5,LOW);      
        digitalWrite(OUT_6,LOW);      
        digitalWrite(OUT_7,LOW);      
        digitalWrite(OUT_8,LOW);      
        digitalWrite(OUT_9,LOW); 
        akt_ido_szamlalo=0; 
      }
      akt_lepes++;  
      lepes_ido_tmp=millis();   //a 1 másodperces időzítés innen induljon akkor is, ha a start gombot nyomtuk meg, és ezzel kihagytunk eg lépést
      delay(100);   //pici várakozás,mert néha kettőt is lépett egy gombnyomásra (prell???)
    }  
    elozo_allapot_start_num=start_num;
    if (akt_ido_szamlalo==0) {kov_lepes=1;} //letelt az idő, jöhet a következő lépés
    if (millis()>lepes_ido_tmp+1000) {
      lepes_ido_tmp=millis();
      akt_ido_szamlalo--;
      perc=(akt_ido_szamlalo)/60;
      masodperc=(akt_ido_szamlalo)-((int)perc*60);
      str_tmp="";
      if (perc==0) {str_tmp=str_tmp+"00:";}
      else {
        if (perc<10) {str_tmp=str_tmp+"0"+String(perc)+":";;}
        else {str_tmp=String(perc)+":"; }
      }
      if (masodperc==0) {str_tmp=str_tmp+"00";}
      else {
        if (masodperc<10) {str_tmp=str_tmp+"0"+String(masodperc);}
        else {str_tmp=str_tmp+String(masodperc);}
      }
      lcd.setCursor(9,1);lcd.print("(");lcd.print(str_tmp);lcd.print(")");
    }
  }
  if (millis()>villog_ido_tmp+500) {   //fél másodpercenként fel, vagy le kapcsoljuk a locsolás led-et, ezzel jelezzük, hogy rögzítés van folyamatban
    villog_ido_tmp=millis();    
    if (villog_vilagit==0) {digitalWrite(LED_LOCSOLAS,HIGH);villog_vilagit=1;}
    else {digitalWrite(LED_LOCSOLAS,LOW);villog_vilagit=0;}
  }
} while (akt_lepes<11);  //fő ciklus vége, ha mint a 10 lépést végrehajtottuk

digitalWrite(LED_LOCSOLAS,LOW); //biztosan folyamatosan világítson a locsolás led, amikor vége a rögzítésnek
lcd.clear();
lcd.setCursor(0,0);lcd_print_hu("Locsolás vége!");
delay(2000);
}


void lp_prog_szerkesztes(byte lp_program_num) {
/**********************************************************************************************************************************
 * Ebben a függvényben tudjuk egy kiválasztott locsolóprogram adatait szerkeszteni. AZ SW_SATRT nyomkodásával végig lépkedhetünk  *
 * mind a 10 locsolóprogram lépésen, és egyenként beállíthatjuk a végrahajtási időta növel illetve csökkent nyomógombokkal,
 * valamint a szelep kapcsolók változtatásával beállíthatjuk azt, hogy az adott lépésben legyen-e bakapcsolva az adott szelep, 
 * vagy sem. Ha semmihez nem nyúlunk, csak nyomkodjuk a START gombot, akkor úgy lépkedünk végig a lépéseken, hogy semmin nem 
 * változtatunk. Ez szolgál a locsolóprogram tartalmának megtekintésére. Ezért szükséges, hogy a szelep kapcsolók éppen aktuális
 * állapotátától függetlenül semmi nem változzon a programban. Ha egy szelepkapcsoló állapotát a programlépésben meg akarunk 
 * változtatni, akkor lehetséges, hogy elősször át kell billenteni, és vissza ahhoz, hogy változzon az állapot. 
 * A szelep kapcsolók állapota az adott program lépésben a sorszámukkal, vagy egy "-" jellel ábrázolt. Ha a sorszámot látjuk
 * akkor be van kapcsolva az adott lépésben, ha a - jelet látjuk, akkor nincs. Ha a kijelzőn az adott szelep kapcsolónál egy 
 * - jelet látunk (nincs bekapcsolva) és a szerkesztésben a szelep kapcsoló éppen bekapcsolt állapotba van billentve, 
 * akkor elősször ki kapcsolt állapotba kell billeneteni, és az újbóli bekapcsolt állapotba billentéskor fog a kijelzőn megjelenni
 * a szelep kapcsoló sorszáma, ami azt jelzi, hogy az adott lépésben be lesz kapcsolva.
 * *********************************************************************************************************************************/
long ido_tmp=millis();                          //ha szerkesztés közben 5 percig semmilyen nyomógombot nem nyomunk meg, akkor kilépünk a szerkesztésből. Ennek az időnek a méréséhez kell ez a változó
long pulzal_ido_tmp=millis();                   //fél másodperces cilusidőbel pulzal az szerkesztés led a szerkesztes alatt, ehhez segédváltozó, 
                                                //10millisec-eneként fogunk fényerőt változtatni 25 lépésben (10 fel, 10 le)
byte pulzal_fenyero=255;                        //a led pulzáláshoz tárolja az aktuális fényerőt (5-255 közötti), alapértelmezetten maximum
bool pulzal_irany=0;                            //a pulzálás iránya (növekszik=1, vagy csökken=0), maximum az alapértelmezett, így első lépésben csökkenteni fogunk
bool sw_allapot_tmp;                            //a szelep kapcsolók állapot változásának megállapításához ebbe olvassuk be az éppen vizsgált szelep kapcsoló állapotát
bool elozo_allapot_sw[]={0,0,0,0,0,0,0,0,0,0};  //a szelep kapcsolók állapot változásának megállípításához szükséges segéd változó
for (byte i=0;i<10;i++) {elozo_allapot_sw[i]=digitalRead(sw_bemenet[i]);}  //tároljuk, hogy most éppen hogy állnak a szelep kapcsolók
long sw_figy_ido=millis();                      //100millisec-enként vizsgáljuk, hogy átkapcsolta-e a szelep kapcsolók valamelyikét, ehhez segédváltozó
long ism_ido_tmp=millis();                      //ha folyamatosan nyomv tartja a csökkent vagy növel gombok valamelyikét, akkor 200millisec-enként növeljük vagy csökkentjük a 
                                                //végrehajtási időt. Ennek időzítéséhez használt segéd változó
kimenet_allapot[2]=-1;                          //a függvény meghívásakor már megnyomtuk az SW_START gombot, ezért az rögtön 1 lenne az első érték, de nekem 0 kell
elozo_allapot_start_num=99;                     //mert rögtön megnyomás nélkül az locsolóprogram program első programlépésébe kell bemenni, és egy megnyomás már volt a függvény meghívása előtt
do  {
    if (digitalRead(SW_KEZI)==0) {return;}  //ha közben átkapcsoljuk kézi üzemmódba, akkor mindent meg kell szakítani,
                                            //kilépünk a függvényből és a főciklus lekapcsolja az esetleg vezérelt szelepeket

    start_num=multi_button(2,2,SW_START,0,1,11);     //az SW_START nyomógombot figyeljuk, megnyomásakor megjelennek sorban programlépések 0-tól 9-ig
                                                         //a tizedik megnyomás tárolja a beállított idő és szelep állás értékeket az eepromban 
                                                         
         //2 csatorna, számláló mód, bemenet száma, lefutóél, nem használt, növekedés 1, max érték 10
    novel_num=multi_button(3,0,SW_NOVEL,1,0,0);
        //3. csatorna, megnyomás érzékelő mód, bemenet száma, lefutóél, nem használt, nem használt, nem használt
    csokkent_num=multi_button(4,0,SW_CSOKKENT,1,0,0);
        //4. csatorna, megnyomás érzékelő mód, bemenet száma, lefutóél, nem használt, nem használt, nem használt
    if (millis()>ido_tmp+300000) {kijelzo_kikapcs_ido_tmp=millis();return;}  //ha öt percig nem nyomja meg a startot vagy csökkent vagy novel gombokat, akkor kilépünk a szerkesztésből
                                          //Igy nem ragadhatunk véletlenül olyan állapotban, hogy ne indulhasson el, egy időzített locsolás
                                          //a kijelző kikapcsolási időzítőt is ujra indítjuk, hogy csak egy perc múlva menjen a főmenüből a locsolás időzítés várakozásba
    if (elozo_allapot_start_num!=start_num and start_num!=255) {            //csak akkor csinálunk valamit, ha változik a start_num értéke
                                                                            //amikor meghívjuk a függvényt, épp nyomva van aa start, így a startnum értékét 255-re kell
                                                                            //allítani ahhoz, hogy 0 is legyen az érték a következő megnyomáskor. Így viszont a 255-öt
                                                                            //ki kell zárni a megjelenítésből, mert az rossz eredményt jelez ki egy pillanatra, amit aztán
                                                                            //a következő ciklus felül ír, de így a kijelzőn villan a szám, valamint eltolódott számjegyek
                                                                            //miatt megjelenhet egy szám a szókoz helett
        lcd.backlight();kijelzo_kikapcs_ido_tmp=millis();  //bekapcsoljuk a háttérvilágítást, és megjegyezzük az időt, hogy 60sec múlva kikapcsolhassuk a loop()-ban
        ido_tmp=millis();   //megnyomtak a start gombot, újraindul a kilépési időzítés
        str_tmp="LP"+String(lp_program_num+1)+" "+String(start_num+1);
        lcd.setCursor(0,0);lcd.print(str_tmp);lcd_print_hu(". lépés   ");
        //programlépés idejének kiszámítása és kiírása
        perc=(lp_ido[start_num]*15)/60;
        masodperc=(lp_ido[start_num]*15)-((int)perc*60);
        str_tmp="";
        if (perc==0) {str_tmp=str_tmp+"00:";}
        else {
          if (perc<10) {str_tmp=str_tmp+"0"+String(perc)+":";;}
          else {str_tmp=String(perc)+":"; }
        }
        if (masodperc==0) {str_tmp=str_tmp+"00";}
        else {str_tmp=str_tmp+String(masodperc);}
        lcd.setCursor(0,1);lcd.print(str_tmp);
        //működő szelepek kijelzése sorszámmal, program alatt nem működő szelepeket "-" jelzi
        lcd.setCursor(6,1);if (szelep0[start_num]==1) {lcd.print(0);} else {lcd.print("-");}
        lcd.setCursor(7,1);if (szelep1[start_num]==1) {lcd.print(1);} else {lcd.print("-");}
        lcd.setCursor(8,1);if (szelep2[start_num]==1) {lcd.print(2);} else {lcd.print("-");}
        lcd.setCursor(9,1);if (szelep3[start_num]==1) {lcd.print(3);} else {lcd.print("-");}
        lcd.setCursor(10,1);if (szelep4[start_num]==1) {lcd.print(4);} else {lcd.print("-");}
        lcd.setCursor(11,1);if (szelep5[start_num]==1) {lcd.print(5);} else {lcd.print("-");}
        lcd.setCursor(12,1);if (szelep6[start_num]==1) {lcd.print(6);} else {lcd.print("-");}
        lcd.setCursor(13,1);if (szelep7[start_num]==1) {lcd.print(7);} else {lcd.print("-");}
        lcd.setCursor(14,1);if (szelep8[start_num]==1) {lcd.print(8);} else {lcd.print("-");}
        lcd.setCursor(15,1);if (szelep9[start_num]==1) {lcd.print(9);} else {lcd.print("-");}
      }
      elozo_allapot_start_num=start_num;
    
      //a növel illetve csökkent nyomógombok figyelése és változásukkor, vagy időzítés letelésekor automatikusan az idő növelése és csökkentése
      if (millis()>ism_ido_tmp+200 and novel_num==1) {elozo_allapot_novel_num=0;}  //ha nyomjuk a novel gombot akkor 200msec mulva mindenképpen számol egyet
      if (millis()>ism_ido_tmp+200 and csokkent_num==1) {elozo_allapot_csokkent_num=0;}  //ha nyomjuk a novel gombot akkor 200msec mulva mindenképpen számol egyet
      if (elozo_allapot_novel_num==0 and novel_num==1 or elozo_allapot_csokkent_num==0 and csokkent_num==1) {            //csak akkor csinálunk valamit, ha változik a novel_num vagy csokkent_num értéke és éppen megnyomtuk a gombot
        lcd.backlight();kijelzo_kikapcs_ido_tmp=millis();  //bekapcsoljuk a háttérvilágítást, és megjegyezzük az időt, hogy 60sec múlva kikapcsolhassuk a loop()-ban
        ido_tmp=millis();  //megnyomtak a novel vagy csokket gombot, újraindul a kilépési időzítés
        if (novel_num==1) {lp_ido[start_num]=lp_ido[start_num]+1;if (lp_ido[start_num]>255) {lp_ido[start_num]=0;}}
        if (csokkent_num==1) {lp_ido[start_num]=lp_ido[start_num]-1;if (lp_ido[start_num]==-1) {lp_ido[start_num]=255;}}
        //kiírás a képernyőre 15 másodperces bontásban
        perc=(lp_ido[start_num]*15)/60;
        masodperc=(lp_ido[start_num]*15)-((int)perc*60);
        str_tmp="";
        if (perc==0) {str_tmp=str_tmp+"00:";}
        else {
          if (perc<10) {str_tmp=str_tmp+"0"+String(perc)+":";;}
          else {str_tmp=String(perc)+":"; }
        }
       if (masodperc==0) {str_tmp=str_tmp+"00";}
        else {str_tmp=str_tmp+String(masodperc);}
        lcd.setCursor(0,1);lcd.print(str_tmp);
        ism_ido_tmp=millis(); //azért, hogy 300msec múlva számoljunk egyet, ha nyomjuk a gombot
      }
      elozo_allapot_novel_num=novel_num;
      elozo_allapot_csokkent_num=csokkent_num;

      //100msec után megnézzük a váltókapcsolók állapotát, ha valamelyik változik, és ellentétes értékre, mint az éppen tárolt állapot
      //akkor átállítjuk a szelep állapotát a program lépésben
      if (millis()>sw_figy_ido+100) {  
        for (byte i=0;i<10;i++) {  
          sw_allapot_tmp=digitalRead(sw_bemenet[i]);
          if (elozo_allapot_sw[i]!=sw_allapot_tmp) {
            switch (i) {
              case 0:
                if (szelep0[start_num]==0 and sw_allapot_tmp==0) {szelep0[start_num]=1;lcd.setCursor(6,1);lcd.print(0);}
                if (szelep0[start_num]==1 and sw_allapot_tmp==1) {szelep0[start_num]=0;lcd.setCursor(6,1);lcd.print("-");}
                break;
              case 1:
                if (szelep1[start_num]==0 and sw_allapot_tmp==0) {szelep1[start_num]=1;lcd.setCursor(7,1);lcd.print(1);}
                if (szelep1[start_num]==1 and sw_allapot_tmp==1) {szelep1[start_num]=0;lcd.setCursor(7,1);lcd.print("-");}
                break;
              case 2:
                if (szelep2[start_num]==0 and sw_allapot_tmp==0) {szelep2[start_num]=1;lcd.setCursor(8,1);lcd.print(2);}
                if (szelep2[start_num]==1 and sw_allapot_tmp==1) {szelep2[start_num]=0;lcd.setCursor(8,1);lcd.print("-");}
                break;
              case 3:
                if (szelep3[start_num]==0 and sw_allapot_tmp==0) {szelep3[start_num]=1;lcd.setCursor(9,1);lcd.print(3);}
                if (szelep3[start_num]==1 and sw_allapot_tmp==1) {szelep3[start_num]=0;lcd.setCursor(9,1);lcd.print("-");}
                break;
              case 4:
                if (szelep4[start_num]==0 and sw_allapot_tmp==0) {szelep4[start_num]=1;lcd.setCursor(10,1);lcd.print(4);}
                if (szelep4[start_num]==1 and sw_allapot_tmp==1) {szelep4[start_num]=0;lcd.setCursor(10,1);lcd.print("-");}
                break;
              case 5:
                if (szelep5[start_num]==0 and sw_allapot_tmp==0) {szelep5[start_num]=1;lcd.setCursor(11,1);lcd.print(5);}
                if (szelep5[start_num]==1 and sw_allapot_tmp==1) {szelep5[start_num]=0;lcd.setCursor(11,1);lcd.print("-");}
                break;
              case 6:
                if (szelep6[start_num]==0 and sw_allapot_tmp==0) {szelep6[start_num]=1;lcd.setCursor(12,1);lcd.print(6);}
                if (szelep6[start_num]==1 and sw_allapot_tmp==1) {szelep6[start_num]=0;lcd.setCursor(12,1);lcd.print("-");}
                break;
              case 7:
                if (szelep7[start_num]==0 and sw_allapot_tmp==0) {szelep7[start_num]=1;lcd.setCursor(13,1);lcd.print(7);}
                if (szelep7[start_num]==1 and sw_allapot_tmp==1) {szelep7[start_num]=0;lcd.setCursor(13,1);lcd.print("-");}
                break;
              case 8:
                if (szelep8[start_num]==0 and sw_allapot_tmp==0) {szelep8[start_num]=1;lcd.setCursor(14,1);lcd.print(8);}
                if (szelep8[start_num]==1 and sw_allapot_tmp==1) {szelep8[start_num]=0;lcd.setCursor(14,1);lcd.print("-");}
                break;
              case 9:
                if (szelep9[start_num]==0 and sw_allapot_tmp==0) {szelep9[start_num]=1;lcd.setCursor(15,1);lcd.print(9);}
                if (szelep9[start_num]==1 and sw_allapot_tmp==1) {szelep9[start_num]=0;lcd.setCursor(15,1);lcd.print("-");}
                break;
            }
            elozo_allapot_sw[i]=sw_allapot_tmp;
          }
        }
      }
    if (millis()>pulzal_ido_tmp+10) {   //10msec-enként növeljük vagy csökkentjük a szerkesztés led fényerejét, ezzel jelezzük, hogy szerkesztés van folyamatban 5-ről indul a fényerő
      pulzal_ido_tmp=millis();  
      if (pulzal_irany==1) {pulzal_fenyero=pulzal_fenyero+10;}
      else {pulzal_fenyero=pulzal_fenyero-10;}
      analogWrite(LED_SZERKESZTO,pulzal_fenyero);
      if (pulzal_fenyero==5) {pulzal_irany=1;}    //elértük a minimumot, növelni fogunk
      if (pulzal_fenyero==255) {pulzal_irany=0;}   //elértük a maximum fényerőt, csökkenteni fogunk
    }
  } while (start_num<10 or start_num==255);

  //EEPROM írás beállítása
  for (byte i=0;i<10;i++) {
    lp_ido_tmp=(byte) lp_ido[i];   //a memóriában int típussal dolgozok, mert a beállításnál kell a -1-et is figyelnem lefele léptetéskor, ezért byte-ra kell konvertálni
    EEPROM.put(lp_program_num*10+1000+i,lp_ido_tmp);  //a tárolt érték byte típusú, ezért átmeneti változóból írom, hogy az eeprom.put jó típussal írjon
    EEPROM.put(lp_program_num*100+100+i,szelep0[i]);
    EEPROM.put(lp_program_num*100+110+i,szelep1[i]);
    EEPROM.put(lp_program_num*100+120+i,szelep2[i]);
    EEPROM.put(lp_program_num*100+130+i,szelep3[i]);
    EEPROM.put(lp_program_num*100+140+i,szelep4[i]);
    EEPROM.put(lp_program_num*100+150+i,szelep5[i]);
    EEPROM.put(lp_program_num*100+160+i,szelep6[i]);
    EEPROM.put(lp_program_num*100+170+i,szelep7[i]);
    EEPROM.put(lp_program_num*100+180+i,szelep8[i]);
    EEPROM.put(lp_program_num*100+190+i,szelep9[i]);
  }
  lcd.clear();
  str_tmp="LP"+String(lp_program_num+1);
  lcd.setCursor(2,0);lcd.print(str_tmp);lcd_print_hu(" beállitás ");
  lcd.setCursor(0,1);lcd_print_hu("     vége!      ");
  delay(2000);
  lcd.clear();
}

void idozites_beallitas(byte idozito_num) {
 /**************************************************************************************************************************
  * Amikor megnyomja az SW_START gombot, kiolvassuk változókba az időzítőhöz tárolt értékeket az EEPROM-ból változókba, 
  * majd megjelenik az időzítő aktivitás értéke, amit a növel és csökkent gombokkal is be lehet állítani aktívra, 
  * vagy inaktívra. Ha inaktív, akkor a következő start megnyomás kiugrik, a további állítási lépések kimaradnak. 
  * Az inaktiv érték beíródik az EEPROM-ba.
  * Ha aktívon hagytuk, a következő megnyomáskor megjelenik óra értéke, amit a növel és csökkent gombokkal tud változtatni. 
  * Ez után jön a perc beállítás, aztán a hét napjai sorban. A vasárnap beállítását követő SW-SATRT megnyomással tárolódnak 
  * az értékek az EEPROM-ban.
  ***************************************************************************************************************************/
  bool kilep=0;
  long ism_ido_tmp=millis();
  long ido_tmp=millis();   //ezzel időzítem, hogy egy perc tétlenségnél visszakényszerítsük abba az állapotba, ahol vátakozik a következő automata locsolás elindulására
  long pulzal_ido_tmp=millis(); //fél másodperces cilusidőbel pulzal az idozítés led a szerkesztes alatt, ehhez segédváltozó, 
                                //10millisec-eneként fogunk fényerőt változtatni 25 lépésben (10 fel, 10 le)
  byte pulzal_fenyero=255;      //a led pulzáláshoz tárolja az aktuális fényerőt (5-255 közötti), alapértelmezetten maximum
  bool pulzal_irany=0;          //a pulzálás iránya (növekszik=1, vagy csökken=0), maximum az alapértelmezett, így első lépésben csökkenteni fogunk
  bool sw_allapot_tmp;
  EEPROM.get(idozito_num*10+0,aktiv);
  EEPROM.get(idozito_num*10+1,ora);
  EEPROM.get(idozito_num*10+2,perc);
  EEPROM.get(idozito_num*10+3,hetfo);
  EEPROM.get(idozito_num*10+4,kedd);
  EEPROM.get(idozito_num*10+5,szerda);
  EEPROM.get(idozito_num*10+6,csutortok);
  EEPROM.get(idozito_num*10+7,pentek);
  EEPROM.get(idozito_num*10+8,szombat);
  EEPROM.get(idozito_num*10+9,vasarnap);
  EEPROM.get(idozito_num+50,lp_program);
  kimenet_allapot[2]=-1; //a függvény meghívásakor már megnyomtuk, ezért az év beállítást kihagyná,mivel amikor a függvény meghívódik, még nyomva a gomb
  elozo_allapot_start_num=99;  //mert rögtön megnyomás nélkül az év beállításba kell bemenni, és egy megnyomás már volt a függvény meghívása előtt
  do  {
    start_num=multi_button(2,2,SW_START,1,1,11);     //az SW_START nyomógombot figyeljuk, megnyomásakor megjelenik sorban az időpont óra, perc , hét napjai
                                                         //start_num=0 aktív/inaktív, 1 időpont óra, 2 időpont perc, 3 hétfő, 4 kedd, 5 szerda, 6 csütörtök, 7 péntek, 8 szombat, 9 vasárnap
                                                         //a tizedikk megnyomás tárolja a beállított értékeket az eepromban 
         //2 csatorna, számláló mód, bemenet száma, lefutóél, nem használt, növekedés 1, max érték 10
    novel_num=multi_button(3,0,SW_NOVEL,1,0,0);
        //3. csatorna, megnyomás érzékelő mód, bemenet száma, lefutóél, nem használt, nem használt, nem használt
    csokkent_num=multi_button(4,0,SW_CSOKKENT,1,0,0);
        //4. csatorna, megnyomás érzékelő mód, bemenet száma, lefutóél, nem használt, nem használt, nem használt
    if (millis()>ido_tmp+60000) {kijelzo_kikapcs_ido_tmp=millis();return;} //ha félbehagyja a beállítást, akkor egy perc után kilépünk a beállításból
    if (elozo_allapot_start_num!=start_num) {            //csak akkor csinálunk valamit, ha változik a start_num értéke
      ido_tmp=millis();    //megnyomta a start gombot, tehát folyik a beállítás, ujra indítjuk az egy perces időzítést
      lcd.backlight();kijelzo_kikapcs_ido_tmp=millis();  //bekapcsoljuk a háttérvilágítást, és megjegyezzük az időt, hogy 60sec múlva kikapcsolhassuk a loop()-ban
      lcd.setCursor(0,1);lcd.print("                ");
      str_tmp="IP"+String(idozito_num+1);
      switch (start_num) {
        case 0:
          lcd.setCursor(0,0);lcd.print(str_tmp);lcd_print_hu(" időzitő:    ");
          lcd.setCursor(0,1);
          if (aktiv==1) {lcd.print("BEKAPCSOLVA     ");} 
          else {lcd.print("KIKAPCSOLVA     ");} 
          break;
        case 1:
          if (aktiv==1) {
            lcd.setCursor(0,0);lcd.print(str_tmp);lcd.print(" Locs.prog:  ");
            lcd.setCursor(0,1);lcd.print("LP: ");lcd.print(lp_program);
          }
          else {kilep=1;}
          break;
        case 2:
          lcd.setCursor(0,0);lcd.print(str_tmp);lcd_print_hu(" ind.időpont:");
          lcd.setCursor(0,1);lcd_print_hu("óra:");lcd.print(ora);
          break;
        case 3:
          lcd.setCursor(0,0);lcd.print(str_tmp);lcd_print_hu(" ind.időpont:");
          lcd.setCursor(0,1);lcd.print("Perc:");lcd.print(perc);
          break;
        case 4:
          lcd.setCursor(0,0);lcd.print(str_tmp);lcd_print_hu(" működ.nap:  ");
          lcd.setCursor(0,1);lcd_print_hu("Hetfő:");
          if (hetfo==1) {lcd.print("IGEN  ");} else {lcd.print("NEM  ");} 
          break;
        case 5:
          lcd.setCursor(0,0);lcd.print(str_tmp);lcd_print_hu(" működ.nap:  ");
          lcd.setCursor(0,1);lcd.print("Kedd:");
          if (kedd==1) {lcd.print("IGEN  ");} else {lcd.print("NEM  ");} 
          break;
        case 6:
          lcd.setCursor(0,0);lcd.print(str_tmp);lcd_print_hu(" működ.nap:  ");
          lcd.setCursor(0,1);lcd.print("Szerda:");
          if (szerda==1) {lcd.print("IGEN  ");} else {lcd.print("NEM  ");} 
          break;
        case 7:
          lcd.setCursor(0,0);lcd.print(str_tmp);lcd_print_hu(" működ.nap:  ");
          lcd.setCursor(0,1);lcd_print_hu("Csütörtök:");
          if (csutortok==1) {lcd.print("IGEN  ");} else {lcd.print("NEM  ");} 
          break;
        case 8:
          lcd.setCursor(0,0);lcd.print(str_tmp);lcd_print_hu(" működ.nap:  ");
          lcd.setCursor(0,1);lcd_print_hu("Péntek:");
          if (pentek==1) {lcd.print("IGEN  ");} else {lcd.print("NEM  ");} 
          break;
        case 9:
          lcd.setCursor(0,0);lcd.print(str_tmp);lcd_print_hu(" működ.nap:  ");
          lcd.setCursor(0,1);lcd.print("Szombat:");
          if (szombat==1) {lcd.print("IGEN  ");} else {lcd.print("NEM  ");} 
          break;
        case 10:
          lcd.setCursor(0,0);lcd.print(str_tmp);lcd_print_hu(" működ.nap:  ");
          lcd.setCursor(0,1);lcd_print_hu("Vasánap:");
          if (vasarnap==1) {lcd.print("IGEN  ");} else {lcd.print("NEM  ");} 
          break;
        case 11:
          kilep=1;
          break;
      }
    }
    elozo_allapot_start_num=start_num;
    if (millis()>ism_ido_tmp+300 and novel_num==1) {elozo_allapot_novel_num=0;}  //ha nyomjuk a novel gombot akkor 500msec mulva mindenképpen számol egyet
    if (millis()>ism_ido_tmp+300 and csokkent_num==1) {elozo_allapot_csokkent_num=0;}  //ha nyomjuk a novel gombot akkor 500msec mulva mindenképpen számol egyet
    if (elozo_allapot_novel_num==0 and novel_num==1 or elozo_allapot_csokkent_num==0 and csokkent_num==1) {            //csak akkor csinálunk valamit, ha változik a novel_num vagy csokkent_num értéke és éppen megnyomtuk a gombot
       ido_tmp=millis();    //megnyomta a növel vagy csökkent gombot, tehát folyik a beállítás, ujra indítjuk az egy perces időzítést
       lcd.backlight();kijelzo_kikapcs_ido_tmp=millis();  //bekapcsoljuk a háttérvilágítást, és megjegyezzük az időt, hogy 60sec múlva kikapcsolhassuk a loop()-ban
       switch (start_num) {
        case 0:
          lcd.setCursor(0,1);
          if (novel_num==1 or csokkent_num==1) {if (aktiv==0) {aktiv=1;lcd.print("BEKAPCSOLVA  ");} 
          else {aktiv=0;lcd.print("KIKAPCSOLVA  ");}}
          break;
        case 1:
          if (novel_num==1) {lp_program=lp_program+1;if (lp_program>5) {lp_program=1;}}
          if (csokkent_num==1) {lp_program=lp_program-1;if (lp_program==0) {lp_program=5;}}
          lcd.setCursor(4,1);lcd.print(lp_program);lcd.print("          ");
          break;
        case 2:
          if (novel_num==1) {ora=ora+1;if (ora>23) {ora=0;}}
          if (csokkent_num==1) {ora=ora-1;if (ora==255) {ora=23;}}
          lcd.setCursor(4,1);lcd.print(ora);lcd.print("         ");
          break;
        case 3:
          if (novel_num==1) {perc=perc+1;if (perc>59) {perc=0;}}
          if (csokkent_num==1) {perc=perc-1;if (perc==255) {perc=59;}}
          lcd.setCursor(5,1);lcd.print(perc);lcd.print("        ");
          break;
        case 4:
          lcd.setCursor(6,1);
          if (novel_num==1 or csokkent_num==1) {if (hetfo==0) {hetfo=1;lcd.print("IGEN     ");} 
          else {hetfo=0;lcd.print("NEM      ");}}
          break;
        case 5:
          lcd.setCursor(5,1);
          if (novel_num==1 or csokkent_num==1) {if (kedd==0) {kedd=1;lcd.print("IGEN      ");}
          else {kedd=0;lcd.print("NEM       ");}}
          break;
        case 6:
          lcd.setCursor(7,1);
          if (novel_num==1 or csokkent_num==1) {if (szerda==0) {szerda=1;lcd.print("IGEN    ");} 
          else {szerda=0;lcd.print("NEM     ");}}
          break;
        case 7:
          lcd.setCursor(10,1);
          if (novel_num==1 or csokkent_num==1) {if (csutortok==0) {csutortok=1;lcd.print("IGEN  ");} 
          else {csutortok=0;lcd.print("NEM   ");}}
          break;
        case 8:
          lcd.setCursor(7,1);
          if (novel_num==1 or csokkent_num==1) {if (pentek==0) {pentek=1;lcd.print("IGEN    ");} 
          else {pentek=0;lcd.print("NEM      ");}}
          break;
        case 9:
          lcd.setCursor(8,1);
          if (novel_num==1 or csokkent_num==1) {if (szombat==0) {szombat=1;lcd.print("IGEN    ");} 
          else {szombat=0;lcd.print("NEM     ");}}
          break;
        case 10:
          lcd.setCursor(9,1);
          if (novel_num==1 or csokkent_num==1) {if (vasarnap==0) {vasarnap=1;lcd.print("IGEN   ");} 
          else {vasarnap=0;lcd.print("NEM    ");}}
          break;
      }
      ism_ido_tmp=millis(); //azért, hogy 300msec múlva számoljunk egyet, ha nyomjuk a gombot
    }
    elozo_allapot_novel_num=novel_num;
    elozo_allapot_csokkent_num=csokkent_num;
    if (millis()>pulzal_ido_tmp+10) {   //10msec-enként növeljük vagy csökkentjük a szerkesztés led fényerejét, ezzel jelezzük, hogy szerkesztés van folyamatban 5-ről indul a fényerő
      pulzal_ido_tmp=millis();  
      if (pulzal_irany==1) {pulzal_fenyero=pulzal_fenyero+10;}
      else {pulzal_fenyero=pulzal_fenyero-10;}
      analogWrite(LED_IDOZITES,pulzal_fenyero);
      if (pulzal_fenyero==5) {pulzal_irany=1;}    //elértük a minimumot, növelni fogunk
      if (pulzal_fenyero==255) {pulzal_irany=0;}   //elértük a maximum fényerőt, csökkenteni fogunk
    }
  } while (kilep==0);

  //EEPROM írás beállítása
  EEPROM.put(idozito_num*10+0,aktiv);
  if (aktiv==0) {
    EEPROM.put(idozito_num*10+1,7);
    EEPROM.put(idozito_num*10+2,0);
    EEPROM.put(idozito_num*10+3,0);
    EEPROM.put(idozito_num*10+4,0);
    EEPROM.put(idozito_num*10+5,0);
    EEPROM.put(idozito_num*10+6,0);
    EEPROM.put(idozito_num*10+7,0);
    EEPROM.put(idozito_num*10+8,0);
    EEPROM.put(idozito_num*10+9,0);
    EEPROM.put(idozito_num+50,1);
  }
  else {
    EEPROM.put(idozito_num*10+1,ora);
    EEPROM.put(idozito_num*10+2,perc);
    EEPROM.put(idozito_num*10+3,hetfo);
    EEPROM.put(idozito_num*10+4,kedd);
    EEPROM.put(idozito_num*10+5,szerda);
    EEPROM.put(idozito_num*10+6,csutortok);
    EEPROM.put(idozito_num*10+7,pentek);
    EEPROM.put(idozito_num*10+8,szombat);
    EEPROM.put(idozito_num*10+9,vasarnap);
    EEPROM.put(idozito_num+50,lp_program);
  }
  lcd.clear();
  str_tmp="IP"+String(idozito_num+1);
  lcd.setCursor(2,0);lcd.print(str_tmp);lcd_print_hu(" beállitás ");
  lcd.setCursor(0,1);lcd_print_hu("     vége!      ");
  delay(2000);
  lcd.clear();
}

void ora_beallitas() {
 /*************************************************************************************************
  * Óra beállítása! A start gombbal lehet léptetni a dátum és perc egyes adatait, és a perc után
  * befejeződik a beállás és kilép a beállításból, újra a LP1 program beállításra kerülünk
  * A növel és csökkent gombokkal lehet változtatni az egyes adatok értékét
  *************************************************************************************************/
  bool kilep=0;
  long kilep_ido_tmp=millis(); //egy perc tétlenség után kiléptetjük a beálltásból
  long ido_tmp=millis()-1000;
  long ism_ido_tmp=millis();
  long pulzal_ido_tmp=millis(); //fél másodperces cilusidőbel pulzal az idozítés led a szerkesztes alatt, ehhez segédváltozó, 
                                //10millisec-eneként fogunk fényerőt változtatni 25 lépésben (10 fel, 10 le)
  byte pulzal_fenyero=255;      //a led pulzáláshoz tárolja az aktuális fényerőt (5-255 közötti), alapértelmezetten maximum
  bool pulzal_irany=0;          //a pulzálás iránya (növekszik=1, vagy csökken=0), maximum az alapértelmezett, így első lépésben csökkenteni fogunk
  kimenet_allapot[2]=-1; //a függvény meghívásakor már megnyomtuk, ezért az év beállítást kihagyná,mivel amikor a függvény meghívódik, még nyomva a gomb
  elozo_allapot_start_num=99;  //mert rögtön megnyomás nélkül az év beállításba kell bemenni, és egy megnyomás már volt a függvény meghívása előtt
  ev=Clock.getYear();ho=Clock.getMonth(Century);nap=Clock.getDate();ora=Clock.getHour(h12,PM);perc=Clock.getMinute();hetnapja=Clock.getDoW(); 
  do  {
    if (millis()>ido_tmp+1000) {
      str_tmp=String(ev)+"/";     //kiíráskor már nem olvasunk az órából, hogy a megváltoztatott érték jelenjen meg (ez lesz beállítva az órába a perc megadása után)
      if (ho<10) {str_tmp=str_tmp+"0"+String(ho)+"/";} else {str_tmp=str_tmp+String(ho)+"/";}
      if (nap<10) {str_tmp=str_tmp+"0"+String(nap)+" ";} else {str_tmp=str_tmp+String(nap)+" ";}
      if (ora<10) {str_tmp=str_tmp+"0"+String(ora)+":";} else {str_tmp=str_tmp+String(ora)+":";}
      if (perc<10) {str_tmp=str_tmp+"0"+String(perc);} else {str_tmp=str_tmp+String(perc);}
      lcd.clear();
      lcd.setCursor(0,0);lcd.print(str_tmp);
      ido_tmp=millis();
    }
    
    start_num=multi_button(2,2,SW_START,1,1,6);     //az SW_START nyomógombot figyeljuk, megnyomásra növeljük start_num változó értékét, 5 felett ujra 0
                                                         //start_num=0 év állítás, 1 hó állítás, 2 nap állítás, 3 hét napja állítás, 4 óra állítás, 5 perc állítás
                                                         //másodpercet nem állítunk, az a perc beállításával együtt nullázódik, 
         //2 csatorna, számláló mód, bemenet száma, lefutóél, nem használt, növekedés 1, max érték 5
    novel_num=multi_button(3,0,SW_NOVEL,1,0,0);
        //3. csatorna, megnyomás érzékelő mód, bemenet száma, lefutóél, nem használt, nem használt, nem használt
    csokkent_num=multi_button(4,0,SW_CSOKKENT,1,0,0);
        //4. csatorna, megnyomás érzékelő mód, bemenet száma, lefutóél, nem használt, nem használt, nem használt

    if (millis()>kilep_ido_tmp+60000) {kijelzo_kikapcs_ido_tmp=millis();return;} //ha félbehagyja a beállítást, akkor egy perc után kilépünk a beállításból

    if (elozo_allapot_start_num!=start_num) {            //csak akkor csinálunk valamit, ha változik a start_num értéke
      lcd.backlight();kijelzo_kikapcs_ido_tmp=millis();  //bekapcsoljuk a háttérvilágítást, és megjegyezzük az időt, hogy 60sec múlva kikapcsolhassuk a loop()-ban
      lcd.setCursor(0,1);lcd.print("                ");
      kilep_ido_tmp=millis(); //megnyomta a start gombot, folyik a beállítás, tehát ujraindítjuk az egy perces kilépési időzítést
      switch (start_num) {
        case 0:
          perc=Clock.getMinute();  //előfordulhat, hogy a beállítás közben változik az aktuális perc, és mivel eddig nema percet állítottuk, érdemes szinkronizálni
          ora=Clock.getHour(h12,PM);
          lcd.setCursor(0,1);lcd_print_hu("év: ");lcd.print(ev);
          break;
        case 1:
          perc=Clock.getMinute();  //előfordulhat, hogy a beállítás közben változik az aktuális perc, és mivel eddig nema percet állítottuk, érdemes szinkronizálni
          ora=Clock.getHour(h12,PM);
          lcd.setCursor(0,1);lcd_print_hu("Hó: ");lcd.print(ho);
          break;
        case 2:
          perc=Clock.getMinute();  //előfordulhat, hogy a beállítás közben változik az aktuális perc, és mivel eddig nema percet állítottuk, érdemes szinkronizálni
          ora=Clock.getHour(h12,PM);
          lcd.setCursor(0,1);lcd.print("Nap: ");lcd.print(nap);
          break;
        case 3:
          perc=Clock.getMinute();  //előfordulhat, hogy a beállítás közben változik az aktuális perc, és mivel eddig nema percet állítottuk, érdemes szinkronizálni
          ora=Clock.getHour(h12,PM);
          lcd.setCursor(0,1);lcd.print("Napja: ");
          switch (hetnapja) {
            case 1:
              lcd_print_hu("hétfő    ");
              break;
            case 2:
              lcd.print("kedd     ");
              break;
            case 3:
              lcd.print("szerda   ");
              break;
            case 4:
              lcd_print_hu("csütörtök");
              break;
            case 5:
              lcd_print_hu("péntek   ");
              break;
            case 6:
              lcd.print("szombat  ");
              break;
            case 7:
              lcd_print_hu("vasárnap ");
              break;
          }
          break;
        case 4:
          perc=Clock.getMinute();  //előfordulhat, hogy a beállítás közben változik az aktuális perc, és mivel eddig nema percet állítottuk, érdemes szinkronizálni
          ora=Clock.getHour(h12,PM);
          lcd.setCursor(0,1);lcd_print_hu("óra: ");lcd.print(ora);
          break;
        case 5:
          perc=Clock.getMinute();  //előfordulhat, hogy a beállítás közben változik az aktuális perc, és mivel eddig nema percet állítottuk, érdemes szinkronizálni
          lcd.setCursor(0,1);lcd.print("Perc: ");lcd.print(perc);
          break;
        case 6:
          //Serial.println(cikus_vege);   //itt nem értem mi történik! Ha ezen sorok bármelyikét kiveszem a kommentből, akkor ezen a ponton
          //kilep=1;                      //a program újraindítja az chip-et, mitha reszetelné magát. Próbáltam a változó nevét megváltoztatni
                                          //globális változót is csináltam belőle, típusát is változtttam, semmi nem segített.
                                          //Kezdetben működött ez a függvény, akkor romlott el, amikor elkészültem az idozites_beallitas() fügvénnyel!
          break;
      }
      if (start_num==6) {kilep=1;}        //Azért kell külön, mert a switch-ben a case 6: sor után bármit berakok, reseteli magát a chip.
    }
    
    elozo_allapot_start_num=start_num;
    if (millis()>ism_ido_tmp+300 and novel_num==1) {elozo_allapot_novel_num=0;}  //ha nyomjuk a novel gombot akkor 500msec mulva mindenképpen számol egyet
    if (millis()>ism_ido_tmp+300 and csokkent_num==1) {elozo_allapot_csokkent_num=0;}  //ha nyomjuk a novel gombot akkor 500msec mulva mindenképpen számol egyet
    if (elozo_allapot_novel_num==0 and novel_num==1 or elozo_allapot_csokkent_num==0 and csokkent_num==1) {            //csak akkor csinálunk valamit, ha változik a novel_num vagy csokkent_num értéke és éppen megnyomtuk a gombot
       kilep_ido_tmp=millis(); //megnyomta a növel vagy csökkenet gombot, folyik a beállítás, tehát ujraindítjuk az egy perces kilépési időzítést
       lcd.backlight();kijelzo_kikapcs_ido_tmp=millis();  //bekapcsoljuk a háttérvilágítást, és megjegyezzük az időt, hogy 60sec múlva kikapcsolhassuk a loop()-ban
       switch (start_num) {
        case 0:
          if (novel_num==1) {ev=ev+1;if (ev>50) {ev=21;}}
          if (csokkent_num==1) {ev=ev-1;if (ev<21) {ev=50;}}
          lcd.setCursor(4,1);lcd.print(ev);lcd.print("   ");
          break;
        case 1:
          if (novel_num==1) {ho=ho+1;if (ho>12) {ho=1;}}
          if (csokkent_num==1) {ho=ho-1;if (ho<1) {ho=12;}}
          lcd.setCursor(4,1);lcd.print(ho);lcd.print("   ");
          break;
        case 2:
          if (novel_num==1) {nap=nap+1;if (nap>31) {nap=1;}}
          if (csokkent_num==1) {nap=nap-1;if (nap<1) {nap=31;}}
          lcd.setCursor(5,1);lcd.print(nap);lcd.print("   ");
          break;
        case 3:
          if (novel_num==1) {hetnapja=hetnapja+1;if (hetnapja>7) {hetnapja=1;}}
          if (csokkent_num==1) {hetnapja=hetnapja-1;if (hetnapja<1) {hetnapja=7;}}
          lcd.setCursor(7,1);
          switch (hetnapja) {
            case 1:
            lcd_print_hu("hétfő    ");break;
            case 2:
            lcd.print("kedd     ");break;
            case 3:
            lcd.print("szerda   ");break;
            case 4:
            lcd_print_hu("csütörtök");break;
            case 5:
            lcd_print_hu("péntek   ");break;
            case 6:
            lcd.print("szombat  ");break;
            case 7:
            lcd_print_hu("vasárnap ");break;
          }
          break;
        case 4:
          if (novel_num==1) {ora=ora+1;if (ora>23) {ora=1;}}
          if (csokkent_num==1) {ora=ora-1;if (ora==255) {ora=23;}}
          lcd.setCursor(5,1);lcd.print(ora);lcd.print("           ");
          break;
        case 5:
          if (novel_num==1) {perc=perc+1;if (perc>59) {perc=0;}}
          if (csokkent_num==1) {perc=perc-1;if (perc==255) {perc=59;}}
          lcd.setCursor(6,1);lcd.print(perc);lcd.print("   ");
          break;
      }
      ism_ido_tmp=millis(); //azért, hogy 300msec múlva számoljunk egyet, ha nyomjuk a gombot
    }
    elozo_allapot_novel_num=novel_num;
    elozo_allapot_csokkent_num=csokkent_num;
    if (millis()>pulzal_ido_tmp+10) {   //10msec-enként növeljük vagy csökkentjük a szerkesztés led fényerejét, ezzel jelezzük, hogy szerkesztés van folyamatban 5-ről indul a fényerő
      pulzal_ido_tmp=millis();  
      if (pulzal_irany==1) {pulzal_fenyero=pulzal_fenyero+10;}
      else {pulzal_fenyero=pulzal_fenyero-10;}
      analogWrite(LED_IDOZITES,pulzal_fenyero);
      if (pulzal_fenyero==5) {pulzal_irany=1;}    //elértük a minimumot, növelni fogunk
      if (pulzal_fenyero==255) {pulzal_irany=0;}   //elértük a maximum fényerőt, csökkenteni fogunk
    }
  } while (kilep==0);
  
  //óra beállítása
  Clock.setYear(ev);
  Clock.setMonth(ho);
  Clock.setDate(nap);
  Clock.setDoW(hetnapja);
  Clock.setHour(ora);
  Clock.setMinute(perc);
  Clock.setSecond(0);
  lcd.clear();
  lcd.setCursor(0,0);lcd_print_hu("  óra beállitás ");
  lcd.setCursor(0,1);lcd_print_hu("     vége!      ");
  delay(2000);
  lcd.clear();
}

byte multi_button(byte csatorna,byte valasz_mod,byte bemenet,byte felfutoel, byte novekedes, byte max_ertek) 
/****************************************************************************************************************************
 * Bemenő paraméterek sorrendben:                                                                                           
 * csatorna: ez egy 0és 5 közötti szám, összesn 5 egymástól független nyomógombot figyel, és mindíg azzal foglalkozik,      *
 *           aminek a számát itt megadtuk.
 * valasz mod: ezzel állítjuk be, hogy milyen eseményt eredményez a nyomógomb lenyomása                                     *
 * bemenet: Az arduino bemenet azáma, amire a nyomógombot kötöttük                                                          *
 * felfutoel: A kimenet változása a nyomógomb megnomásakor (0-felfutó él), vagy elengedésekor következzen be (1-lefutó él)  *
 * novekedes: valasz_mod=2 esetén a gombnyomásonként ennyivel növeli a visszaadott értéket                                  *
 * max_ertek: valasz_mod=2 esetén ennél az értéknél nulázza a visszadott értéket                                            *
 *                                                                                                                          *
 * Visszaadott érték lehetséges állapotai:                                                                                  *
 * valasz_mod=0 esetén: 0-nincs lenyomva a nyomógomb, 1-le van nyomva a nyomógomb                                           *
 * valasz_mod=1 esetén: 0,1 minden lenyomáskor változik                                                                     *
 * valasz_mod=2 esetén: 0-255 gombnyomásonként felfelé számol, novekedes változóban beállított érték a növekmény, max_ertek *
 *                      változóban beállított érték elérésekor visszaesik a kimenet értéke 0-ra.                            *
 ****************************************************************************************************************************/
{ 
  //bemenet lekövetése a paraméterek alapján
   if (felfutoel==0)  //felfutó élre fognak bekövetkezni a visszaadott érték változásai
      {
      if (bemenet_allapot[csatorna]==0 and digitalRead(bemenet)==LOW and prell_tmp[csatorna]==0)                             //első lenyomás érzékelése
        {prell_tmp[csatorna]=1;prell_time[csatorna]=millis();} 
      if (bemenet_allapot[csatorna]==0 and digitalRead(bemenet)==LOW and prell_tmp[csatorna]==1 and millis()>prell_time[csatorna]+50)  // már 50msecv óta nyomva van, most már biztos, hogy lenyomták és nem prellezik
        {bemenet_allapot[csatorna]=1;prell_tmp[csatorna]=0;} 
      if (bemenet_allapot[csatorna]==1 and digitalRead(bemenet)==HIGH and prell_tmp[csatorna]==0) //első elengedés érzékelése
        {prell_tmp[csatorna]=1;prell_time[csatorna]=millis();} 
      if (bemenet_allapot[csatorna]==1 and digitalRead(bemenet)==HIGH and prell_tmp[csatorna]==1 and millis()>prell_time[csatorna]+50) // már 50msecv óta elengedve, most már biztos, hogy elengedték és nem prellezik
        {bemenet_allapot[csatorna]=0;prell_tmp[csatorna]=0;} 
      }
    else   //lefutó élre fognak bekövetkezni a visszaadott érték változásai
    {
      if (bemenet_allapot[csatorna]==0 and digitalRead(bemenet)==HIGH and prell_tmp[csatorna]==0)  //első elengedés érzékelése
        {prell_tmp[csatorna]=1;prell_time[csatorna]=millis();} 
      if (bemenet_allapot[csatorna]==0 and digitalRead(bemenet)==HIGH and prell_tmp[csatorna]==1 and millis()>prell_time[csatorna]+50) // már 50msecv óta elengedve, most már biztos, hogy elengedték és nem prellezik
        {bemenet_allapot[csatorna]=1;prell_tmp[csatorna]=0;} 
      if (bemenet_allapot[csatorna]==1 and digitalRead(bemenet)==LOW and prell_tmp[csatorna]==0)  //első lenyomás érzékelése
        {prell_tmp[csatorna]=1;prell_time[csatorna]=millis();} 
      if (bemenet_allapot[csatorna]==1 and digitalRead(bemenet)==LOW and prell_tmp[csatorna]==1 and millis()>prell_time[csatorna]+50) // már 50msecv óta lenyomták, most már biztos, hogy elengedték és nem prellezik
        {bemenet_allapot[csatorna]=0;prell_tmp[csatorna]=0;} 
    }
  switch (valasz_mod) {   //kimenet vezérlése a paraméterek alapján
    case 0: 
      if (bemenet_allapot[csatorna]==0) {kimenet_allapot[csatorna]=1;}
      else {kimenet_allapot[csatorna]=0;}
      break;
    case 1:
      if (bemenet_allapot[csatorna]==1 and bemenet_elozo_allapot[csatorna]==0) 
        {if (kimenet_allapot[csatorna]==0) {kimenet_allapot[csatorna]=1;} else {kimenet_allapot[csatorna]=0;}}
      bemenet_elozo_allapot[csatorna]=bemenet_allapot[csatorna];
      break;
    case 2:
      if (novekedes==0) {novekedes=1;}
      if (bemenet_allapot[csatorna]==1 and bemenet_elozo_allapot[csatorna]==0){
        kimenet_allapot[csatorna]=kimenet_allapot[csatorna]+novekedes;
         if (kimenet_allapot[csatorna]>max_ertek) {kimenet_allapot[csatorna]=0;}
      }
      bemenet_elozo_allapot[csatorna]=bemenet_allapot[csatorna];
      break;
    } 
  return kimenet_allapot[csatorna];
}


void lcd_print_hu(String szoveg) {
String kiir="";
byte karakter;
byte j=0;
byte hossz=szoveg.length();   //az átvett string hossza
if (hossz==0) {  //üres karakterrel hívtuk meg a függvényt, ez azt jelenti, hogy feltöltjük a kijelzőt a magyar kerekterek képével
  byte tt[8] = {B10,B100,B1110,B1,B1111,B10001,B1111};             //á betű karakterképe
  lcd.createChar(0,tt);
  tt[0]=B10;tt[1]=B100;tt[2]=B1110;tt[3]=B10001;tt[4]=B11111;tt[5]=B10000;tt[6]=B1110;        //é betű karakterképe
  lcd.createChar(1,tt);
  tt[0]=B10;tt[1]=B100;tt[2]=B0;tt[3]=B1110;tt[4]=B100;tt[5]=B100;tt[6]=B1110;                //í betű karekterképe
  lcd.createChar(2,tt);
  tt[0]=B10;tt[1]=B100;tt[2]=B0;tt[3]=B1110;tt[4]=B10001;tt[5]=B10001;tt[6]=B1110;            //ó betű karakterképe
  lcd.createChar(3,tt);
  tt[0]=B10;tt[1]=B100;tt[2]=B10001;tt[3]=B10001;tt[4]=B10001;tt[5]=B10011;tt[6]=B1101;       //ú betű karakterképe
  lcd.createChar(4,tt);
  tt[0]=B00101;tt[1]=B01010;tt[2]=B0;tt[3]=B1110;tt[4]=B10001;tt[5]=B10001;tt[6]=B1110;      //ő betű karakterképe
  lcd.createChar(5,tt);
  tt[0]=B00101;tt[1]=B01010;tt[2]=B0;tt[3]=B10001;tt[4]=B10001;tt[5]=B10011;tt[6]=B1101;     //ű betű karakterképe
  lcd.createChar(6,tt);
  return;
}
for (byte i=0;i<hossz;i++) {                             //minden karakteren sorban végig megyünk
  if ((byte) szoveg[i]==195 or (byte) szoveg[i]==197)    //ha a kerekter 195 vagy 197, akkor azt kihagyjuk az eredmény stringből és vesszük a következő karaktert
  {
    i++;
    karakter=(byte) szoveg[i];
    kiir.concat(" ");   //ez a hiányos C++ tudásom miatt van, mivel nem tudtam hozzáfűzni a 0-7 ASCII kódot, ezért hozzáfüzük egy szóközt, 
                        //amit a switch-ben lecserélek a megfelelő feltöltött karakter kódjára, illetve a karakterkészletben meglévő 
                        //ö és ü betű kódjára
    switch (karakter) {
      case 129: kiir.setCharAt(j,0);break;    //Á  //a j. pozicióban (utolsó hozzáfűzött karaktert cserélem a feltöltött karakter kódjára
      case 161: kiir.setCharAt(j,0);break;    //á
      case 137: kiir.setCharAt(j,1);break;    //É
      case 169: kiir.setCharAt(j,1);break;    //é
      case 141: kiir.setCharAt(j,2);break;    //Í
      case 173: kiir.setCharAt(j,2);break;    //í
      case 147: kiir.setCharAt(j,3);break;    //Ó
      case 179: kiir.setCharAt(j,3);break;    //ó
      case 150: kiir.setCharAt(j,239);break;  //Ö
      case 182: kiir.setCharAt(j,239);break;  //ö
      case 144: kiir.setCharAt(j,4);break;    //Ő
      case 145: kiir.setCharAt(j,4);break;    //ő
      case 154: kiir.setCharAt(j,5);break;    //Ú
      case 186: kiir.setCharAt(j,5);break;    //ú
      case 156: kiir.setCharAt(j,245);break;  //Ü
      case 188: kiir.setCharAt(j,245);break;  //ü
      case 176: kiir.setCharAt(j,6);break;    //Ű
      case 177: kiir.setCharAt(j,6);break;    //ű
    }
  }
  else {kiir.concat(szoveg[i]);}              //ez egy kijelzőn is megtalálható karakter, simán csak másoljuk
  j++;                                        //egy karakterrel több van a kijelzőre irantó stringben
}
  lcd.print(kiir);                            //..és akkor kiírjuk a kijelzőre az ékezetes kódokra cserélt szöveget
}

A forrás már olyan nagy, hogy a WordPress másodpercekig gondolkodik, ha valamit változtatok. Sebaj! Megnyugtat, hogy felkerült a felhőbe, mert mindig félek, hogy megtalálnak a kódolós vírusok, jobb, ha sok mentés van különböző eszközökön. Ezzel a forrással már legalább 40 órát dolgoztam!

Most megint forrasztgatni kell, mert be kell kötni a csatlakozók másik végét a kertben futó vezetékekhez, meg kell csinálni a motor és fő szolenonid vezérlő reléket, és ott még némi vezeték építés is vár. Be kell üzemelni a rédiós távvezérlőt a slag ki be kapcsolásához. Viszont megjött a tavasz, lassan a terepen is lehet dolgozni!

————————————————-

Lassan itt az ősz, és elfelejtettem megírni, hogy összeraktam, és sikeresen végig locsolta a nyarat a berendezés. Az idei évben csak 9 locsolókört használtunk. Vegyesen használtuk a manuális üzemmódot, hajnali 5-kor az időzített locsolást, és este a virágágyások locsolását, amikor kézzel indítottunk el egy locsolóprogramot. Szóval teljesen kihasználtuk a képességeit. Még a tanuló módot is használtuk kb. 4-5 alkalommal, nem szerkesztettem a locsoló programot, hanem újra betanítottam. Erre azért volt szükség, mert közben sorban értek be a termények, és egyes ágyásokat már nem kellett locsolni, vagy jóval kevesebbet kellett locsolni. Sajnos a víz kifogyás érzékelése még nem oldódott meg, mert a készen vett áramfigyelő nem akar működni. A télen ki fogom találni, hogy mi a baja, vagy építek egyet. A szivattyú monitorozó programhoz már csináltam egyet, azt fogom után építeni. Egész nyáron figyelnünk kellett az esőre, mivel azt még nem veszi figyelembe a locsolások indításakor (illetve el nem indításakor). Az idei évben a COVID miatt nem utaztunk, így nem volt szükség a teljesen automata, esőfigyelős üzemmódra, így ez nem okozott nagy problémát. A csapadékmérő már készen van, csak várja, hogy beépítsem a dobozba.

Összefoglalva: ez egy nagyon jól sikerült darab lett! Örülök, hogy megcsináltam. Rengeteget tanultam belőle, és jól szórakoztam.

Mennyire volt hasznos amit olvastál? Értékelés után szövegesen is leírhatod megjegyzéseidet és véleményedet!

Kattints egy csillagra az értékeléshez!

Szövegesen is leírhatod véleményedet! Ha kérdésed van, ne felejtsd el megadni az email címedet!