Rakennamme kesävesitornin ja Pumpauttimen

Eikös Säkylä/Köyliö suunnalla tehty se pohjavesi koeporaus, mitä ei tahdottu mitenkään saada rauhoittumaan.

Jokohan se on tukittu?
 
En tiedä, ovatko saaneet tulpattua sitä, tuolla Köyliössä. Ainakin pitkään, ja paljon sieltä vettä tuli, aika lujaakin, kun veden virtaus ihan ojia kaivoi.
 
Nyt Pumpautin on ollut oikeassa käytössä ja seuraavanlaisia havaintoja toiminnasta on:

* Laitteen layout on ihan perseestä - sitähän ei varsinaisesti ole. Kapine on kasa johtospagettia sullottuna kuoriinsa. Tästä seuraa tietysti se, että vahvasähkön piuhat ja releet saattavat indusoida häiriöitä hituvirtapuolelle, jolloin tulee jonkinsorttinen glitch in the matrix. :atom: Käytännössä tämä ilmenee useimmiten niin, että laite ilmoittaa viimeiseksi tilanvaihdon syyksi boottauksen. Samalla taukoaika-asetus on palannut oletusarvoonsa, joka on 240 minuuttia.

* Kapine on osin kasattu nurkista löytyneistä osista, eivätkä ne ehkä ole oikein fiksuja valintoja. Arduinon selässä ratsastaa Relay Shield, jossa on neljä viiden voltin relettä. En käyttäisi tällaista, jos muuta olisi tarjolla. Tuo nappaa itselleen neljä digilähtöä, joita ei voi valita, piikit kun menevät tiettyihin Arduinon vastakkeisiin. Ihan erillinen ei-viisivolttinen rele olisi paras.

* Käyttöjännite tulee 5V DIN-kiskoon käyvästä hakkurista. Se toimii kyllä, mutta kenties parempi ratkaisu olisi laittaa vaikkapa 12V teholähde ja syöttää sillä optoerotettua 12V relekorttia. Arduinolle tiputtaisi sitten jännitteen johonkin 7V nurkille ja pari konkkaa vielä väliin. Kaikki hituvirtavehkeet kotelon yhteen päähän ja vahvasähköt toiseen, niin että väliin jää vähän hajurakoa.

* Vesitiiviillä korkilla varustettu ohjelmointiliitin kuoressa olisi kätevä.

* Taukoajan pituuden voisi tallentaa Arduinon eeprommiin, niin se säilyisi myös boottauksen yli.

* Pumppauksen katkaisu ylärajapaineesta toimii kyllä luotettavasti, mutta paine saisi olla pienempi, jokin 2,4 baaria olisi kuitenkin niin korkea, ettei se tule vastaan normaalikäytössä, vaan ainoastaan kun uimuriventtiili alkaa nostaa painetta.

* Kuivakäynnin tunnistus toimii oikein hyvin ja nopeasti

IMG_2276.webp


Kaiken kaikkiaan Pumpauttimesta on todella paljon hyötyä ja se soveltuu omaan tarpeeseen mainiosti. Viime yönä se pumppaili säiliöt piripintaan ihan itsekseen, niin kuin kuuluukin. Nyt helteiden aikaan vettä on mennyt yli tuhat litraa kutakuinkin joka päivä. Pumpauttimen ansiosta voi keskittyä vain syytämään vettä kasvustoon, eikä tarvitse manuaalisesti hankkia uutta tilalle.

graph.webp


Tänä kesänä Pumpautin v.1 mahdollistaa takapihan nurmikon perustamisen ja viime syksynä kylvetyn etupihan hengissä pitämisen. Suunnitelmissa olisi hyvinkin todennäköisesti jossakin vaiheessa rakentaa Pumpautin v.2. Se sisältäisi nykyisen tekniikan lisäksi pinnankorkeuden ultraäänimittauksen ja myös kasteluun lähtevän veden määränmittauksen.

Pumpautin v.3 voisi sisältää vielä www-palvelimen, jolloin borgholmin lähiverkossa olisi aina saatavissa ajantasainen tilannekuva :pccoffee: kesävesitornin tilanteesta, ilman että tarvitsisi raahautua katsomaan Pumpauttimen näyttöä.

Tässä Pumpautin v.1:n kytkentä. Tietoa antureista on aiemmin tässä viestiketjussa.

Pumpautin_v1.webp


Tämänhetkinen koodi:

Koodi:
/*
  PumpController.ino – V1.4  (raw‑pressure logic + shield‑pin remap)
  -----------------------------------------------------------------
  •  Relay‑shield kanavat 4‑7 → käytämme kanavaa 2 (IN=6) pumpulle.
  •  Painikkeet siirretty vapaille navoille:  Start=D8, Pause=D9.
  •  Priming‑aika 5 s.

  *** UUTTA V1.4 ***
  ‑ Logiikka käyttää **raakapainetta (pressureBarRaw)**; filtteröity
    arvo (filtPressureBar) on vain näytölle → nopeat muutokset huomioidaan
    heti eikä NaN‑häiriö voi viivästyttää pysäytystä.
*/

#include <LiquidCrystal_I2C.h>
#include <Bounce2.h>

/* ---------------- Hardware ---------------- */
const byte FLOW_PIN       = 2;   // INT0 – flow sensor pulses
const byte PRESSURE_PIN   = A0;  // 0‑100 psi pressure
const byte RELAY_PIN      = 6;   // Relay‑shield channel 2 (pump)
const byte BTN_START_PIN  = 8;   // Start / Stop
const byte BTN_SET_PIN    = 9;   // Pause length select

LiquidCrystal_I2C lcd(0x27, 20, 4);
Bounce debStart, debSet;

/* ------------ Constants ------------- */
const float PULSES_PER_LITER = 595.0;
const float PSI_TO_BAR       = 0.0689476f;
const float FULL_SCALE_PSI   = 100.0;
const float VOLT_MIN         = 0.5;
const float VOLT_MAX         = 4.5;
const float ADC_TO_VOLT      = 5.0 / 1023.0;

const float DRY_PRESS_BAR    = 1.0;
const float DRY_FLOW_LPM     = 10.0;
const uint32_t DRY_TIMEOUT_MS  = 3000;
const float FULL_PRESS_BAR   = 2.8;
const uint32_t FULL_TIMEOUT_MS = 2000;
const uint32_t PRIMING_MS    = 5000;   // 5 s priming

const uint16_t pauseTable[] PROGMEM = {15,30,60,120,240,480,960};
const byte PAUSE_COUNT = sizeof(pauseTable)/sizeof(pauseTable[0]);
byte  pauseIdx = 4; // 240 min
uint32_t pauseRemainingMs;

/* ---------- Runtime vars ----------- */
volatile uint32_t pulseCount = 0;
uint32_t lastBucketMs, lastDisplayMs, lastBlinkMs;
uint32_t pulses1s = 0;

float filtPressureBar = 0.0f;           // only for display
const float ALPHA = 0.20f;

float lastVolumeLitres  = 0.0f;
float thisVolumeLitres  = 0.0f;

uint32_t pumpStartMs;
uint32_t dryDetectMs  = 0, fullDetectMs = 0;

bool blinkFlag = false;

enum State { WAITING, PUMPING } state = WAITING;
enum StopReason { NONE, BOOT, SHORTAGE, FILLED, MANUAL } stopReason = BOOT;
enum StartCause { PAUSEOVER, MANUALSTART } startCause = PAUSEOVER;

/* ---------- Helper: clear one LCD row ---------- */
void clearLine(byte row){ lcd.setCursor(0,row); lcd.print(F("                    ")); lcd.setCursor(0,row);}  // 20 spaces

/* ---------- Prototypes ---------- */
void enterWaiting();
void enterPumping(StartCause);
void flowISR(){ pulseCount++; }

/* ---------- Setup ---------- */
void setup(){
  pinMode(FLOW_PIN,INPUT_PULLUP);
  pinMode(PRESSURE_PIN,INPUT);
  pinMode(BTN_START_PIN,INPUT_PULLUP);
  pinMode(BTN_SET_PIN,INPUT_PULLUP);
  pinMode(RELAY_PIN,OUTPUT); digitalWrite(RELAY_PIN,LOW);

  attachInterrupt(digitalPinToInterrupt(FLOW_PIN),flowISR,RISING);
  debStart.attach(BTN_START_PIN); debStart.interval(20);
  debSet.attach(BTN_SET_PIN);     debSet.interval(20);

  lcd.init(); lcd.backlight(); lcd.print(F("Pump Controller")); delay(1500); lcd.clear();

  pauseRemainingMs = (uint32_t)pgm_read_word(&pauseTable[pauseIdx])*60000UL;
  lastBucketMs = lastDisplayMs = lastBlinkMs = millis();
}

/* ---------- Loop ---------- */
void loop(){
  uint32_t now = millis();

  /* --- Buttons --- */
  debStart.update(); debSet.update();
  if(debStart.fell()) {
    if(state==WAITING) enterPumping(MANUALSTART); else { stopReason = MANUAL; enterWaiting(); }
  }
  if(debSet.fell() && state==WAITING) {
    pauseIdx = (pauseIdx + 1) % PAUSE_COUNT;
    pauseRemainingMs = (uint32_t)pgm_read_word(&pauseTable[pauseIdx])*60000UL;
  }

  /* --- 1‑s flow bucket --- */
  if(now - lastBucketMs >= 1000) {
    lastBucketMs += 1000;
    pulses1s = pulseCount; pulseCount = 0;
    if(state == PUMPING) thisVolumeLitres += pulses1s / PULSES_PER_LITER;
  }
  float flowLPM = (pulses1s * 60.0f) / PULSES_PER_LITER;

  /* --- Pressure reading --- */
  int   adc = analogRead(PRESSURE_PIN);
  float voltage = adc * ADC_TO_VOLT;
  float pressureBarRaw;
  if (voltage < VOLT_MIN - 0.05 || voltage > VOLT_MAX + 0.05) pressureBarRaw = 0.0f; // invalid → 0
  else {
    pressureBarRaw = (voltage - VOLT_MIN) * (FULL_SCALE_PSI * PSI_TO_BAR) / (VOLT_MAX - VOLT_MIN);
    if (pressureBarRaw < 0) pressureBarRaw = 0;
  }
  // simple display filter
  filtPressureBar = filtPressureBar * (1.0f - ALPHA) + ALPHA * pressureBarRaw;

  /* --- State machine --- */
  if(state == PUMPING) {
    // dry‑run detection after priming
    if(now - pumpStartMs > PRIMING_MS) {
      if(pressureBarRaw < DRY_PRESS_BAR && flowLPM < DRY_FLOW_LPM) {
        if(!dryDetectMs) dryDetectMs = now;
        if(now - dryDetectMs >= DRY_TIMEOUT_MS) { stopReason = SHORTAGE; enterWaiting(); }
      } else dryDetectMs = 0;
    }
    // tank‑full detection using raw pressure
    if(pressureBarRaw >= FULL_PRESS_BAR) {
      if(!fullDetectMs) fullDetectMs = now;
      if(now - fullDetectMs >= FULL_TIMEOUT_MS) { stopReason = FILLED; enterWaiting(); }
    } else fullDetectMs = 0;
  } else {
    if(now - pumpStartMs >= pauseRemainingMs) enterPumping(PAUSEOVER);
  }

  /* --- Display (1 Hz) --- */
  if(now - lastDisplayMs >= 1000) {
    lastDisplayMs += 1000;
    if(state == WAITING) {
      uint16_t pauseSet = pgm_read_word(&pauseTable[pauseIdx]);
      uint32_t remMin = (pauseRemainingMs - (now - pumpStartMs)) / 60000UL;
      clearLine(0); lcd.print(F("WAITING: ")); lcd.print(pauseSet); lcd.print(F(" min   "));
      clearLine(1); lcd.print(F("To start: ")); lcd.print(remMin); lcd.print(F(" min   "));
      clearLine(2); lcd.print(F("REASON: "));
      switch(stopReason) {
        case NONE:     lcd.print(F("-          ")); break;
        case BOOT:     lcd.print(F("Boot       ")); break;
        case SHORTAGE: lcd.print(F("Shortage   ")); break;
        case FILLED:   lcd.print(F("Tank filled")); break;
        case MANUAL:   lcd.print(F("Manual pause")); break;
      }
      clearLine(3); lcd.print(F("Last: ")); lcd.print(lastVolumeLitres,0); lcd.print(F(" l"));
    } else {
      if(now - lastBlinkMs >= 500) { lastBlinkMs += 500; blinkFlag = !blinkFlag; }
      clearLine(0); lcd.print(blinkFlag ? F(">>  PUMP RUNNING >>") : F(" >> PUMP RUNNING  >>"));
      clearLine(1); uint16_t runMin = (now - pumpStartMs) / 60000UL; lcd.print(runMin); lcd.print(F(" min / ")); lcd.print(thisVolumeLitres,0); lcd.print(F(" l"));
      clearLine(2); lcd.print(startCause == PAUSEOVER ? F("REASON: Pause over") : F("STARTED MANUALLY"));
      clearLine(3);
      lcd.print(flowLPM,1); lcd.print(F(" l/min ")); lcd.print(filtPressureBar,1); lcd.print(F(" bar"));
    }
  }
}

/* ---------- State helpers ---------- */
void enterWaiting(){
  state = WAITING;
  digitalWrite(RELAY_PIN, LOW);
  lastVolumeLitres = thisVolumeLitres;
  thisVolumeLitres = 0.0f;
  pumpStartMs = millis();
  pauseRemainingMs = (uint32_t)pgm_read_word(&pauseTable[pauseIdx]) * 60000UL;
  dryDetectMs = fullDetectMs = 0;
}

void enterPumping(StartCause c){
  state = PUMPING;
  startCause = c;
  stopReason = NONE;
  digitalWrite(RELAY_PIN, HIGH);
  thisVolumeLitres = 0.0f;
  blinkFlag = false;
  dryDetectMs = fullDetectMs = 0;
  pumpStartMs = millis();
}

// END OF FILE
 
Viimeksi muokattu:
Ja tämähän oli siis koodattu ihan tyystin ChatGPT o3:n kanssa seurustelemalla. Simuloitu Wokwissa ja Wokwin virheilmoitukset kiikutettu takaisin ChatGPT:lle ja kysytty mitäs nyt.
 
Hieno projekti :peukku:

Lisää tehoa, flashia, rammia, verkkoyhteyttä, etäohjelmointia yms. on tarjolla edullisesti esim. ESP32:sta. Löytyy vaikka minkälaista valmista lautaa ja vaikka DIN-kiskoon istuvaa mallia ihan tehdastekoisesti.
 
on tarjolla edullisesti esim. ESP32:sta
Nykyään on kyllä vaikka mitä höpönhalpaa raketti-insinöörinörttitason teknologiaa saatavilla. Arduino sattui löytymään varmuusvarastoista ja anturit kun olivat lähinnä viisivolttisia, niin kyhäsin sillä. Mutta onhan tuosta menty jo viuhuen tekniikassa ohi oikealta ja vasemmalta.
 
jolloin tulee jonkinsorttinen glitch in the matrix
Mylläsin varmuusvarastoja ja taisin löytää 12V osia, joilla kenties saisi tuota häiriönsietoa parannettua. Pitää nyt funtsia, räjäyttäisikö tuon vielä osasiksi. Eihän siinä kovin mahdoton työ olisi. Yhdet pienet hakkurikortit pitäisi vielä löytää.
 
200l taas kannutettu 20,neen lavakaulus kehikkoon a" 20l/kehikko lämmentynyttä vettä, täytyy kyllä suunnitella joku automatic järjestelä niilekkin.
 
200l taas kannutettu 20,neen lavakaulus kehikkoon a" 20l/kehikko lämmentynyttä vettä, täytyy kyllä suunnitella joku automatic järjestelä niilekkin.
Eräs tuttava joka asuu kaupungissa, on jo varmaan 30 vuotta kastellu kesämökin kasvihuoneen kasvit jollain pikkupumpulla ja sadettimella joka pyörii tietyn määrän vuorokaudessa kellokytkimen ohjaamana, järvestä ottaa veden. Joku sille näitä täsmäkastelu-altakastelujuttuja yritti tuputtaa, totes että kasvit tykkää sateesta...
Toisella tutulla muuten suht samanlainen systeemi mutta sillä on kasvihuoneen kasvatuskouruissa reikäletkut pohjalla joihin pumppu työntää lammikosta vettä kellokytkimen ohjaamana.
 
Varsinki hiekkatien varsilla pitkän poudan jälkeen kasvustoissa on saakelisti pölyä joka tiestä ja muualtaki sinne laskeutunu, vesisade pesee ne pois. Varmaan lehmilläki hampaat ratisee märehtiessä heinää joka ei oo nähny sadetta kolmeen viikkoon ja eikä muutenkaan niin maistuvaa sitte kenties ole?
 
20 kymmenessä kasvillavassa "joissa 2 kaulusta päälekkäin" on tihkukastelu letkut, mutta 2m,ä ylempänä olevan vesitornin aikaansaama paine ei riitä tihkuttamaan. Kastelu veden täytyy olla hapetettua - lämmintä ei helvetinkylmää syvästä kaivosya suoraan pumpattua.
 
20 kymmenessä kasvillavassa "joissa 2 kaulusta päälekkäin" on tihkukastelu letkut, mutta 2m,ä ylempänä olevan vesitornin aikaansaama paine ei riitä tihkuttamaan. Kastelu veden täytyy olla hapetettua - lämmintä ei helvetinkylmää syvästä kaivosya suoraan pumpattua.
Pistä pumppu tuuppaamaan tihkuletkuihin, katot viiniä nautiskellen kauanko kestää vesitornin tyhjentyminen tai tarvittavan vesimäärän pumppautuminen niihin tihkuletkuihin ja laitat ajan kellokytkimeen, ei se sen vaikeempata ole ainakaan mun mielestä.
 
itellä on kasvihuoneen kyljessä 50cm korkeudessa 200l tynnyri. Tynnyrin perässä on 3 sarjaa blumat kastelu härvilöitä (ei tarvii pumppua, tai sähköä, kun maa kuivuu niin noi avaavat kastelu venttiileitä ja kostuessaan sulkevat venat). Linkki: https://www.hankkija.fi/Piha_ja_puutarha/kastelu/ia-kastelusarja-automaattinen-7-m-blumat-2011926 juuri nyt hankkija näyttää olevan nurin, niin ihan sata varma ole onko toi toimiva vai ei, hetken päästä lienee on kuha ryssä lopettaa kiusaamisen.
 
Kasvarissa on 12 kpl blumatteja 1/kasvuallas tiputtaassa, ei niiden teho riitä 1m2 asvulavoihin. Täytyy olla vuotava tihkuletku.
 
Pitää nyt funtsia, räjäyttäisikö tuon vielä osasiksi. Eihän siinä kovin mahdoton työ olisi. Yhdet pienet hakkurikortit pitäisi vielä löytää.

Hakkurikortit löytyi ja löytyi myös vedenpitävä 12V/20W hakkuri, josta tein varsinaisen teholähteen. Se ruokkii 12V relekorttia ja se vuorostaan potkii DIN-kiskossa olevaa 12V relettä, jossa on kolmet kärjet. Kahdet niistä on pätkimässä porakaivopumpun sähköjä.

12V hakkurin perässä on tuo pieni step-down-kortti, joka tiputtaa jännitteen kahdeksaan volttiin. Se menee Arduinon virtaliittimeen ja Arduinon oma lineaariregulaattori tekee siitä viittä volttia. Näin Arduinon oma sisäinen regulaattori ei kehitä liikaa häviötehoa. Relekuormat eivät kyykytä logiikan syöttöä, koska välissä on peräti kaksi regulointia.

Muutin ohjelmassa ylärajapaineen 2,4 baariin ja nyt laukaisu säiliön täyteen tulemisesta toimii aika mainiosti. Taukoajan oletusarvon laitoin 30 minuuttiin, koska lyhyt taukoaika on hyvä, kun kuivakäyntisuoja toimii hyvin. Vettä kertyy vähemmän, mutta vastaavasti ohjain pumppaa useammin ja pumpun käyntijaksot jäävät lyhyiksi.

Tuli tehtyä ihan rookie-errori, vaikka olevinaan vielä tarkistin asian. :facepalm: Helle rassaa ajattelua. Katsoin, että relekortissa varmasti on transienttidiodi kelan rinnalla, mutta autuaasti unohdin sen toisen, din-releen. Ja heti demonstroitui, mitä varten piikintappodiodi on olemassa. Kun rele päästi, niin siitä seurasi heti boottaus.

Laitoin 1N4007:n kelan rinnalle ja oireet katosivat kokonaan, niin kuin tietysti pitääkin tapahtua. Muutenhan maailmassa olisi virhe.
 
tämän tornihaahuilun innoittamana sain viimein tätä omaa tornia edistettyä, ibc kontti tattitalon sisällä.... ehkä tämä vaatii vielä tuotekehitystä
ja 2v pöydällä säilyttämäni hanan korkki vihdoin ja viimein hukassa kun sitä tarviis.. :baghead:

1753730921206.webp


tollanen blumat vois olla varteenotettava vaihtoehto kasveja kastelemaan
 
Pumpautin täytti taas kesävesitornin yöllä. On niin kuivaa, että vaahterakin on tiputellut lehtiään. Laitoin vettä menemään, kun sen torniin saanti on nyt niin helppoa.

IMG_2278.webp


Aamulla herätessä oli mielessä uusi oivallus. Kesävesitornista lähtevän veden virtausanturi olisi tietysti hyvä ihan kastelu-uteliaisuuden kannalta, mutta olisi siitä myös automaatiohyötyä. Tällä hetkellä kaivosta säiliöön pumppaus ei ole järin viisas, koska se yrittää aina lisätä vettä torniin kun pumppausten välinen taukoaika päättyy. Jos logiikalla olisi käytössä myös tieto, ettei vettä ole lainkaan käytetty viime varastoonpumppauksen jälkeen, voisi se jäädä odottamaan, eikä yrittäisi ajastettua täydennyspumppausta ollenkaan.

Jännitelähteen muutos 5V —> 12V näyttäisi näin äkkiseltään vakauttaneen toimintaa, eikä kummia räpsyjä ole eilisen jälkeen ollut havaittavissa.
 
Melkoista papatusta pitää tuo muovinen sektorisadetin. Naapuri varmaan ihmettelee, :epäilevä: että mahtaa tulla hintoihinsa pihan kastelu näillä veden hinnoilla. :haisemaan:
 
eikö se riitä että se katsoo onko säiliössä paljon vettä, jos on niin ei täytetä :raaps:
Se ei näe säiliöveden määrää kuin uimuriventtiilin vastapaineesta. Kapine saa tietoa vain virtauksesta ja paineesta ja sen perusteella tekee päätökset. Eli on pakko kokeilla, onko painetta vastassa vai ei.
 

Luo tili tai kirjaudu sisään kommentoidaksesi

Sinun täytyy olla jäsen voidaksesi jättää kommentin.

Luo käyttäjätili

Liity Konekansalaiseksi. Se on helppoa ja ilmaista! Rekisteröityneenä et näe mainoksia, voit käyttää hakua, näet alueita, joita nyt ovat piilossa...jne.

Kirjaudu sisään

Oletko jo Konekansan jäsen? Kirjaudu sisään tästä.

Takaisin
Ylös