IoT-Elektronika in panel za zalivanje trave

Vsi se po malo ukvarjamo tudi z drugimi hobiji, eden takih je nedvomno vzgoja rastlin.
"Čudež življenja" je vsekakor ena od stvari, ki nikogar ne pusti ravnodušnega. Ni torej razloga, da bi tudi pri nas ne imeli takega kotička.

Moderator: Proteus

IoT-Elektronika in panel za zalivanje trave

OdgovorNapisal/-a Aleks » 29 Jan 2020, 18:33

Lansko leto sem se odločil, da elektronsko uro Gardena za zalivanje okrasnega vrta nadomestim z IoT zadevo. Thingspeak platforma je bolj procesno naravnana, Cayenne pa bolj uporabniško (hvala Clownfishu za info).
Sedaj po nekaj mesecih uporabe sem zelo zadovoljen. Zadeva deluje stabilno 24/7. Nobenih vmesnih MQTT-jev na kakšnih malinah, ki so pogosto faktor nestabilnosti. Samo en ESP8266 in dvojni rele. Edino ne uporabljam uradne android aplikacije Cayenne, ker sem stalno nehote prestavljal ikone. V brskalniku imam dve bližnici. Javno za pregled in uporabniško za manipulacije.

Poleg samega delovanja mi je sistem precej spremenil pogled na naravo, predvsem dinamiko temperature zemlje, do kdaj rastejo korenine, medtem ko nadzemni del že počiva, na frekvenco gnojenja itd, razliko med napovedmi padavin in realnostjo itd.

Javni pregled sistema se lahko vidi tu: https://cayenne.mydevices.com/shared/5d ... 3062ddfde1

Cayenne.JPG


Vrstica 1:
- ikona 1; prikaz stanja vlažnosti iz merilca Gardena. Prag on/off stanje se nastavi na Gardena merilcu. Trenutno ne kaže, ker je merilnik na prezimovanju.
- ikona 2 in 4; ročni vklop zalivanja, ročni ali časovni vklop enega izklopi drugega ker drugače za obe veji ne bi bilo dovolj pritiska; nastavitev koledarja zalivanja
- ikona 3 in 5; dejanski status releja, možen pregled zgodovine vklopov
- ikona 6; kumulativna napoved padavin v naslednjih 24 urah iz openweather apija
- ikona 7; nastavitev praga padavin; če je napoved 24h padavin večja od praga ne zaliva, vrednost shranjena v 8266 EEPROM

Vrstica 2:
- ikona 1; temperatura zemlje na 10 cm globine
- ikona 2: temperatura zemlje na 5 cm globine
- ikona 3; zračna temperatura za kraj iz openweather apija
- ikona 4; RSSI signal, zanimivi grafi ob megli
- ikona 5; reset obeh kumulativnih časov iz ikon 6,7
- ikona 6,7; kumulativni čas odprtja ventila za cono 1 in 2; po pretoku vode na uro zadostna infrmacija po porabi vode, zapis v EEPROM


Slika

Koda: Izberi vse
#define CAYENNE_DEBUG
#define CAYENNE_PRINT Serial

#include "CayenneMQTTESP8266.h" // ver. 1.3.0
#include "ESP8266WiFi.h"        // senses wifi ver. 0.2.2.
#include <OneWire.h>
#include <DallasTemperature.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>        // ver.
#include <EEPROM.h>
#include <math.h>

float vsotarain;
float temperatura;
int currentTime;
int lastTime1 = millis();
int lastTime2 = millis();
int razmereTime = 600000;        // timer za osvezevanje temp zraka?
int napovedTime = 600000;
int timeNowTemp1 = millis();
int timeNowTemp2 = millis();
int timeoutrele1 = 3600000;      // timeout za cona1rele
int timeoutrele2 = 3600000;      // timeout za cona2rele
int time1;
int time2;
bool time1bool = false;
bool time2bool = false;
bool cona1releState = false;
bool cona2releState = false;

char ssid[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
char wifiPassword[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

#define VIRTUAL_PIN V1
#define VIRTUAL_PIN V2
#define VIRTUAL_PIN V6
#define VIRTUAL_PIN V7
#define VIRTUAL_PIN V8
#define VIRTUAL_PIN V9
#define VIRTUAL_PIN V10
#define VIRTUAL_PIN V11
#define VIRTUAL_PIN V12
#define VIRTUAL_PIN V13
#define VIRTUAL_PIN V14
#define VIRTUAL_PIN V15

const int tmpPin = 13;    //temp 1
const int tmpPinB = 14;     // temp 2

OneWire oneWire(tmpPin);   //temp 1
DallasTemperature sensors(&oneWire);  //temp 1

OneWire oneWireB(tmpPinB);   //temp 2
DallasTemperature sensorsB(&oneWireB);  //temp 2

char username[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
char password[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
char clientID[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

int cona1rele = 0;
int cona2rele = 2;
int gardenasenz = 16;  // vhod Gardena senzorja bil 13
int cona1web = 5;
int cona2web = 4;

int casCona1 = 0;
int casCona1temp = 0;
int casCona2 = 0;
int casCona2temp = 0;
int prag;

unsigned long lastMillis = 0;                                          //

// ******************************************************************

void setup() {
  Serial.begin(115200);
  EEPROM.begin(512);
 
  struct {
    uint casC1;
    uint casC2;
    uint pragE;
  } data;


  uint addr = 0;
  EEPROM.get(addr,data);
  Serial.println();
  Serial.println("Zadnji shranjeni cas: Rele1: "+String(data.casC1)+", Rele2: "+String(data.casC2) + ", Prag: " + String(data.pragE));
  casCona1 = data.casC1;
  casCona2 = data.casC2;
  prag = data.pragE;
  Serial.print("casCona1min: ");
  Serial.println(round(casCona1/60));
  Serial.print("casCona2min: ");
  Serial.println(round(casCona2/60));
 
  delay(2000);  //added to give the onewire stuff time to initialize.
  Cayenne.begin(username, password, clientID, ssid, wifiPassword);
 
  sensors.begin();
  sensorsB.begin();
   
  pinMode(gardenasenz, INPUT);          //
  pinMode(cona1rele, OUTPUT);         //rele 1 D1
  pinMode(cona2rele, OUTPUT);       //rele 2  D2
  pinMode(cona1web, OUTPUT);  //LED 1
  pinMode(cona2web, OUTPUT);  //LED 2
 
  digitalWrite(cona1rele, HIGH);
  digitalWrite(cona2rele, HIGH);
  digitalWrite(cona1web, LOW);
  digitalWrite(cona2web, LOW);

  long rssi = WiFi.RSSI();
 
  napoved();
  razmere();

  cona1releState = digitalRead(cona1rele);
  cona2releState = digitalRead(cona2rele);
  Serial.println(cona1releState);
  Serial.println(cona2releState);
}


// ******************************************************************
void loop() {
  Cayenne.loop();
  sensors.requestTemperatures();
  sensorsB.requestTemperatures(); // ?????
  delay(100);

  casCona1funkcija();
  casCona2funkcija();

  preveriTimeout();
 
  if(digitalRead(cona1web) == HIGH && digitalRead(gardenasenz) == LOW && (vsotarain < prag)){                  //   timeoutrele1
    digitalWrite(cona1rele, LOW);
   
  }else{
    digitalWrite(cona1rele, HIGH);
  }
 
  if(digitalRead(cona2web) == HIGH && digitalRead(gardenasenz) == LOW && (vsotarain < prag)){                  //   timeoutrele2
    digitalWrite(cona2rele, LOW);
  }else{
    digitalWrite(cona2rele, HIGH);
  }

  //Serial.print("cona1web: ");
  //Serial.println(digitalRead(cona1web));
  //Serial.println("cona2web: " + digitalRead(cona2web));
  Serial.print("cona1rele: ");
  Serial.println(digitalRead(cona1rele));
  Serial.print("cona2rele: ");
  Serial.println(digitalRead(cona2rele));
  //Serial.print("T1: ");
  //Serial.println(digitalRead(tmpPin));
  //Serial.print("T2: ");
  //Serial.println(digitalRead(tmpPinB));

  currentTime = millis();

 if((currentTime - lastTime1) > napovedTime){
    napoved();
    lastTime1 = millis();
 }
 if((currentTime - lastTime2) > razmereTime){
    razmere();
    lastTime2 = millis();
 }
 
}



void preveriTimeout(){
  if(digitalRead(cona1rele) == LOW && time1bool == false){
      time1 = millis();
      time1bool = true;
      Serial.println("Zacenjam stopat cajt za cona1rele!");
  }else if(time1bool == true && (millis()-time1 >= timeoutrele1)){
    digitalWrite(cona1web, LOW);
    Serial.println("Cas za cona1rele je potekel, ugasujem!");
    time1bool = false;
  }
  if(digitalRead(cona1rele) == LOW){
    Serial.println("Razlika v casu: ");
    Serial.println(millis()-time1);
  }
 


if(digitalRead(cona2rele) == LOW && time2bool == false){
      time2 = millis();
      time2bool = true;
      Serial.println("Zacenjam stopat cajt za cona2rele!");
  }else if(time2bool == true && (millis()-time2 >= timeoutrele2)){
    digitalWrite(cona2web, LOW);
    Serial.println("Cas za cona2rele je potekel, ugasujem!");
    time2bool = false;
  }
  if(digitalRead(cona2rele) == LOW){
    Serial.println("Razlika v casu: ");
    Serial.println(millis()-time2);
  }
 


}

void casCona1funkcija(){
    if(!digitalRead(cona1rele)==HIGH && cona1releState == true){
        cona1releState = false;
        casCona1temp = millis();
        Serial.println("Pricenjam stopati cas!");
    }else if(!digitalRead(cona1rele)==LOW && cona1releState == false){
        cona1releState = true;
        casCona1 += (millis()-casCona1temp)/1000;
        Serial.println("Cona 1 je bila do sedaj vzgana: " + (String)(casCona1) + " sekund.");

        struct {
          uint casC1 = casCona1;
          uint casC2 = casCona2;
          uint pragE = prag;
        } data;
       
        uint addr = 0;

        EEPROM.put(addr,data);
        EEPROM.commit();
    }
}
void casCona2funkcija(){
    if(!digitalRead(cona2rele)==HIGH && cona2releState == true){
        cona2releState = false;
        casCona2temp = millis();
        Serial.println("Pricenjam stopati cas!");
    }else if(!digitalRead(cona2rele)==LOW && cona2releState == false){
        cona2releState = true;
        casCona2 += (millis()-casCona2temp)/1000;
        Serial.println("Cona 2 je bila do sedaj vzgana: " + (String)(casCona2) + " sekund.");
    }


    struct {
      uint casC1 = casCona1;
      uint casC2 = casCona2;
      uint pragE = prag;
    } data;
   
    uint addr = 0;

    EEPROM.put(addr,data);
    EEPROM.commit();
}


// ******************** gardenasenz ch 1, temperatura -5 cm **************************************************

CAYENNE_OUT_DEFAULT()         // TEMPERATURA 1 NA CAYENNE
{
  if(millis()-timeNowTemp1 > 600000){
  Cayenne.celsiusWrite(1, sensors.getTempCByIndex(0));
  timeNowTemp1 = millis();
  }

}

// ********************************** ******************************************************************
CAYENNE_OUT(V2)

{
  int val = digitalRead(gardenasenz);
   if (digitalRead(gardenasenz) == HIGH) // prenos stanja Gardena vlagomera 1/0
  {
    Cayenne.virtualWrite(2 , 1, "digital_sensor", "d");
  }

  else if (digitalRead(gardenasenz) == LOW)
  {
    Cayenne.virtualWrite(2 , 0, "digital_sensor", "d");

  }

 
}

// ************************** temperatua 2 (ch6) -10 cm ***************************************************

 CAYENNE_OUT(V6)       // TEMPERATURA 2 NA CAYENNE
{
  if(millis()-timeNowTemp2 > 600000){
  Cayenne.celsiusWrite(6, sensorsB.getTempCByIndex(0));
  timeNowTemp2 = millis();
 
  }
}
// ****************************************************************************

CAYENNE_IN_DEFAULT()
{
  CAYENNE_LOG("Channel %u, value %s", request.channel, getValue.asString());
}


// *********************** cayenne ukaz na  rele 1 *****************************************************
CAYENNE_IN(5)
{
  CAYENNE_LOG("Got a value: %s", getValue.asStr());
  int i = getValue.asInt();
 
  if (i == 0)
  {
    digitalWrite(cona1web, LOW);
  }
  else
  {
    digitalWrite(cona1web, HIGH);
    digitalWrite(cona2web, LOW);
   
  }
}



// *********************** cayenne ukaz na  rele 2 ****************************************************
CAYENNE_IN(4)
{
  CAYENNE_LOG("Got a value: %s", getValue.asStr());
  int i = getValue.asInt();
 
  if (i == 0)
  {
    digitalWrite(cona2web, LOW);
   
  }
  else
  {
    digitalWrite(cona2web, HIGH);
    digitalWrite(cona1web, LOW);
  }
}
// *******************status releja 1  na cayenne ***********************************

CAYENNE_OUT(V7)
{
  int val = digitalRead(cona1rele);                      // read the input pin
  Cayenne.virtualWrite(7 , !val, "digital_sensor", "d");
}

// *******************status releja 2  na cayenne ***********************************

CAYENNE_OUT(V8)
{
  int val = digitalRead(cona2rele);                      // read the input pin
  Cayenne.virtualWrite(8 , !val, "digital_sensor", "d");
}

// ************************ RSSI na cayenne *****************************************
CAYENNE_OUT(V9)
{
  long rssi = WiFi.RSSI();
  Cayenne.virtualWrite(9 , rssi, "RSSI", "dbm");
  Serial.println(digitalRead(rssi));
}

void napoved(){
Serial.println("IZVAJAM FUNKCIJO napoved()");
if (WiFi.status() == WL_CONNECTED) { //Check WiFi connection status
 
HTTPClient http;  //Declare an object of class HTTPClient
 
http.begin("http://api.openweathermap.org/data/2.5/forecast?q=grosuplje,SI&lang=sl&cnt=8&appid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");  //Specify request destination
int httpCode = http.GET();                                                                  //Send the request
 
if (httpCode > 0) { //Check the returning code
 
String payload = http.getString();   //Get the request response payload


//**********************************************************

const size_t capacity = 8*JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(8) + 24*JSON_OBJECT_SIZE(1) + 9*JSON_OBJECT_SIZE(2) + 8*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + 17*JSON_OBJECT_SIZE(8) + 2730;
DynamicJsonBuffer jsonBuffer(capacity);

const char* json = payload.c_str(); // usmeri sem ******************************** !!!!!!!!!!!!!!!!! ********************************

JsonObject& root = jsonBuffer.parseObject(json);
const char* cod = root["cod"];
float message = root["message"];
int cnt = root["cnt"];
JsonArray& list = root["list"];
JsonObject& list_0 = list[0];
JsonObject& list_0_main = list_0["main"];
JsonObject& list_0_weather_0 = list_0["weather"][0];
float list_0_rain_3h = list_0["rain"]["3h"];
// *******************************************************
JsonObject& list_1 = list[1];
JsonObject& list_1_main = list_1["main"];
JsonObject& list_1_weather_0 = list_1["weather"][0];
float list_1_rain_3h = list_1["rain"]["3h"];
// *******************************************************
JsonObject& list_2 = list[2];
JsonObject& list_2_main = list_2["main"];
JsonObject& list_2_weather_0 = list_2["weather"][0];
float list_2_rain_3h = list_2["rain"]["3h"];
// *******************************************************
JsonObject& list_3 = list[3];
JsonObject& list_3_main = list_3["main"];
JsonObject& list_3_weather_0 = list_3["weather"][0];
float list_3_rain_3h = list_3["rain"]["3h"];
JsonObject& city = root["city"];
//***********************4********************************
JsonObject& list_4 = list[4];
JsonObject& list_4_main = list_4["main"];
JsonObject& list_4_weather_0 = list_4["weather"][0];
float list_4_rain_3h = list_4["rain"]["3h"];
// *********************5*********************************
JsonObject& list_5 = list[5];
JsonObject& list_5_main = list_5["main"];
JsonObject& list_5_weather_0 = list_5["weather"][0];
float list_5_rain_3h = list_5["rain"]["3h"];
// *******************************************************
JsonObject& list_6 = list[6];
JsonObject& list_6_main = list_6["main"];
JsonObject& list_6_weather_0 = list_6["weather"][0];
float list_6_rain_3h = list_6["rain"]["3h"];
// *******************************************************
JsonObject& list_7 = list[7];
JsonObject& list_7_main = list_7["main"];
JsonObject& list_7_weather_0 = list_7["weather"][0];
float list_7_rain_3h = list_7["rain"]["3h"];

vsotarain = list_0_rain_3h + list_1_rain_3h +list_2_rain_3h + list_3_rain_3h + list_4_rain_3h + list_5_rain_3h + list_6_rain_3h + list_7_rain_3h;
// *******************************************************

Serial.println(payload);     //Print the response payload

Serial.print("0rain ");
Serial.println(list_0_rain_3h);

Serial.print("1rain ");
Serial.println(list_1_rain_3h);

Serial.print("2rain ");
Serial.println(list_2_rain_3h);

Serial.print("3rain ");
Serial.println(list_3_rain_3h);

Serial.print("4rain ");
Serial.println(list_4_rain_3h);

Serial.print("5rain ");
Serial.println(list_5_rain_3h);

Serial.print("6rain ");
Serial.println(list_6_rain_3h);

Serial.print("7rain ");
Serial.println(list_7_rain_3h);


Serial.print("rain 24h:    ");
Serial.println(vsotarain);



}
 
http.end();   //Close connection
}
}
// *********************** temperatura zraka na cayenne *****************************************

void razmere() {
Serial.println("IZVAJAM FUNKCIJO razmere()");
if (WiFi.status() == WL_CONNECTED) { //Check WiFi connection status
HTTPClient http;  //Declare an object of class HTTPClient

http.begin("http://api.openweathermap.org/data/2.5/weather?q=grosuplje,SI&lang=sl&cnt=8&appid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");  //Specify request destination
int httpCode = http.GET(); 
if (httpCode > 0) { //Check the returning code
String payload = http.getString();   //Get the request response payload

const size_t capacity = JSON_ARRAY_SIZE(1) + 2*JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(13) + 420;
DynamicJsonBuffer jsonBuffer(capacity);
const char* json = payload.c_str();
JsonObject& root = jsonBuffer.parseObject(json);
JsonObject& weather_0 = root["weather"][0];
JsonObject& main = root["main"];
float main_temp = main["temp"];
JsonObject& sys = root["sys"];

Serial.print("temperatura:  ");
Serial.println(main_temp - 273.15);
temperatura = main_temp - 273.15;
http.end();
}
}
}
// *************************************  trenutna temp iz openweather map na cayenne ***************************
CAYENNE_OUT(V10)
{
  Cayenne.celsiusWrite(10, temperatura);
 
}

// ********************************* napoved padavin na cayenne ******************************

CAYENNE_OUT(V11)
{
 Cayenne.virtualWrite(11, vsotarain);
}

// ******************************  minute rele 1 na cayenne ********************************

CAYENNE_OUT(V15)
{
 Cayenne.virtualWrite(15, round(casCona1/60));
}

// ******************************  minute rele 2 na cayenne ********************************

CAYENNE_OUT(V13)
{
 Cayenne.virtualWrite(13, round(casCona2/60));
}

// ***************************** reset obeh števcev minut za releja *****************************


CAYENNE_IN(V14)

{
  CAYENNE_LOG("Got a value: %s", getValue.asStr());
  int i = getValue.asInt();
  if(i == 1){
    Serial.println("BRISEM CAS!");
    casCona1 = 0;
    casCona2 = 0;
    struct {
      uint casC1 = 0;
      uint casC2 = 0;
      uint pragE = prag;
    } data;
   
    uint addr = 0;

    EEPROM.put(addr,data);
    EEPROM.commit();
  }
}

// ****************** slider iz cayenna *****************************************************

CAYENNE_IN(V12){
  CAYENNE_LOG("Got a value: %s", getValue.asStr());
  int i = getValue.asInt();
  Serial.print("Prag: ");
  Serial.println(i);
  prag = i;

  struct {
      uint casC1 = 0;
      uint casC2 = 0;
      uint pragE = prag;
    } data;
   
    uint addr = 0;

    EEPROM.put(addr,data);
    EEPROM.commit();
 
}
Zadnjič spremenil Aleks, dne 29 Jan 2020, 18:46, skupaj popravljeno 1 krat.
Aleks
 
Prispevkov: 191
Pridružen: 20 Jan 2015, 01:10
Zahvalil se je: 37 krat
Prejel zahvalo: 62 krat
Uporabnika povabil: forest70
Število neizkoriščenih povabil: 9

Re: IoT-Elektronika in panel za zalivanje trave

OdgovorNapisal/-a VolkD » 29 Jan 2020, 18:39

Lahko daš še kakšno sliko kako je to v naravi videti ?
Dokler bodo ljudje mislili, da živali ne čutijo bolečine, bodo živali čutile, da ljudje ne mislijowww.S5tech.net
Uporabniški avatar
VolkD
Administratorji strani
 
Prispevkov: 40497
Pridružen: 29 Dec 2014, 20:49
Kraj: Kačiče (Divača)
Zahvalil se je: 8498 krat
Prejel zahvalo: 4930 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 253

Re: IoT-Elektronika in panel za zalivanje trave

OdgovorNapisal/-a Aleks » 29 Jan 2020, 19:02

Veliko ne morem pokazati. V škatli, kot je na sliki sta dva 24V ventila, po trati sedem T200 in T380 pršilnikov. ESP8266 je na vrtu v tej škatli, sem ga dal še v vodotesno škatlico. Jo ne bi šel odpirati, ker je na spojih silikon.


Slika
Aleks
 
Prispevkov: 191
Pridružen: 20 Jan 2015, 01:10
Zahvalil se je: 37 krat
Prejel zahvalo: 62 krat
Uporabnika povabil: forest70
Število neizkoriščenih povabil: 9


Vrni se na Zelena elektronika - pametno vrtičkarstvo

Kdo je na strani

Po forumu brska: 0 registriranih uporabnikov in 1 gost