아두이노 피지컬컴퓨팅 교구로 활용할 수 있는 실 생할용품 메이킹 프로젝트(워터맨IOT) 열네번째.

 

 

종합과제  :   현재까지 학습한 내용을 종합하여 다음과 같은 기능을 가진 WATERman IOT 시스템을 제작.

 관리대상 화분에 꽃아 두고 언제 어디에서는 스마트폰으로 화분을 관리.

 1)화분의 조도LUX, 온도및습도, 토양수분상태가 변화되는 내역을 그래프형태로 모니터링  
 2)수분이 부족하면 스마트폰으로 "목 말라요" 알람메세지 전송받기
 3)원격지에서 스마트폰 버튼 조작으로 펌프 가동시켜 화분에 물주기

 

 

 

구현할 기능 : 이를 위해 IOT Device 프로그램에서는 다음과 같은 기능을 수행

1) 1분에 한번씩 조도LUX, 온도및습도, 토양수분상태를 측정하여
    - ThingSpeak 서버에 Upload하기
    - 온도가 4도 이하로 떨어지면 스마트폰에 ‘추워요’메시지 보내기
    - 토양수분이 10이하로 떨어지면 스마트폰에 ‘목말라요’ 메시지 보내기
    - 필요시 스마트폰에서는 Blynk기능으로 원격에서 토양수분수치 확인하며 물주기  
    - 사용자가 원격물주기를 하지 않아 토양수분이 10이하인 상태가 4회이상 계속되면 워터펌프를 자동으로 가동시켜 10초간 물주기
    - 토양수분이 10이하인 상태가 5회이상 반복되면, 즉 펌프를 자동기동시켜도 토양수분이 올라가지 않는 것은 물통에 물이 떨어진 경우이므로 ‘물이 없어요’메시지 보내기
2) Device가 정상 가동중임을 알리기 위해 내부 LED 1초에 한번씩 깜박이기 
3) 접속할 공유기의 SSID,password와 ThingSpak,IFTT,Blynk키 등을 프로그램 변경없이 다른 값으로 교체할 수 있는 설정하기 기능    

 

샘플프로그램

 

#include <Wire.h>
#include <BH1750.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <BlynkSimpleEsp8266.h>
#include <EEPROM.h>
BH1750 lightMeter;
#include "DHT.h"
#define DHTTYPE DHT11  
int BtnSetting = D3;   
int pinPower = D5; 
int pinRelay = D7; 
#define DHTPIN D6
DHT dht(DHTPIN, DHTTYPE);
uint16_t lux;
int temp;
int humid;
int moist;
int moistr;
char  ssid[30] = "xxxx";
char  password [30] = "xxxxxxxxxxxxxx";
const char* ThingSpeak_server = "api.thingspeak.com"; 
const char* IFTTT_server = "maker.ifttt.com"; 
char ThingSpeak_key[50] = "COZ4HZEITR4F0X9R";
char IFTTT_key[50] = "xxxxxxxxxxxxxxxxxxxxxxx";
char Blynk_auth[50] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";   
const int recordPeriod = 600;                
ESP8266WebServer server(80); 
WiFiClient client; 
int   WifiMode = 0 ; // 0: AP mode,  1 : STA Mode
const char *ap_ssid = "WatermanS_setting";
const char *ap_pass = "";
String postStr;
long time_upload = 0;
long  time_start = 0;
long time_blink = 0;
int  flag_blink =  0;
int   time_on = 0;
int  go_stop = 0;
int i, ii,ss;
int cnt_low_temp = 0;
int cnt_low_moist = 0;
long tmDown;

void procReadSensors(){
    digitalWrite(pinPower, HIGH);
    delay(500);
    for ( int i= 0; i < 30; i++ ) {
      delay(200);
      temp  = dht.readTemperature();
      humid = dht.readHumidity();
      if ( humid >  0 &&  temp < 100 && humid < 101 ) break;
    }
    lux = lightMeter.readLightLevel();
    moistr = analogRead(A0);
    moist = map(moistr,1023,0,0,100) ; 
    digitalWrite(pinPower, LOW);
}

void procIFTTT(String trigger){
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(300);
    WiFi.begin(ssid, password); 
    for ( int i= 0; i < 10; i++ ) {
      if ( WiFi.status() == WL_CONNECTED ) {
        break;
      }
      delay(1000);
    } 
    if ( WiFi.status() != WL_CONNECTED ) {
       return;
    }
    if (client.connect(IFTTT_server, 80)) { 
        String getStr = "/trigger/";
        getStr += trigger;
        getStr += "/with/key/";
        getStr += IFTTT_key; 
        
        Serial.print("IFTTT="); 
        Serial.println(getStr);
        
        client.print("GET "); 
        client.print(getStr);
        client.print(" HTTP/1.1\r\n");
        client.print("Host: maker.ifttt.com\r\n"); 
        client.print("Connection: close\r\n"); 
        client.print("Content-Type: 'text/html;'"); 
        client.print("\r\n\r\n"); 
        delay(1000); 
        client.stop(); 
     }
    delay(100);
}
void procThingSpeak(){
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(100);
    WiFi.begin(ssid, password);  
    for ( int i= 0; i < 10; i++ ) {
      if ( WiFi.status() == WL_CONNECTED ) {
        break;
      }
      delay(1000);
    } 
    if ( WiFi.status() != WL_CONNECTED ) {
       return;
    }
    if (client.connect(ThingSpeak_server, 80)) { 
         String postStr = ThingSpeak_key; 
         postStr += "&field1="; 
         postStr += String(temp); 
         postStr += "&field2="; 
         postStr += String(humid); 
         postStr += "&field3="; 
         postStr += String(lux); 
         postStr += "&field4="; 
         postStr += String(moist); 
         postStr += "\r\n\r\n"; 
         
        Serial.print("ThingSpeak="); 
        Serial.println(postStr);
        
        client.print("POST /update HTTP/1.1\n"); 
        client.print("Host: api.thingspeak.com\n"); 
        client.print("Connection: close\n"); 
        client.print("X-THINGSPEAKAPIKEY: ");   
        client.print(ThingSpeak_key); 
        client.print("\n"); 
        client.print("Content-Type: application/x-www-form-urlencoded\n"); 
        client.print("Content-Length: "); 
        client.print(postStr.length()); 
        client.print("\n\n"); 
        client.print(postStr); 
        delay(1000); 
        client.stop(); 
     }
    delay(100);
}
void procBlynk() {
     if ( go_stop ==  1 ) {
          time_on = ( millis() - time_start ) / 1000; 
          Blynk.virtualWrite(V2, time_on);
          delay(200);
          moistr = analogRead(A0);
          moist = map(moistr,1023,0,0,100) ; 
          Blynk.virtualWrite(V3, moist);
          
    }
    if ( time_on > 20 ) {
        go_stop = 0; 
        digitalWrite(pinRelay, LOW);
        digitalWrite(LED_BUILTIN, LOW);
    }
}

BLYNK_WRITE(V1) {  
   go_stop = param.asInt();
   if ( go_stop ==  1 ) {
      digitalWrite(pinPower, HIGH);
      digitalWrite(pinRelay, HIGH);
      digitalWrite(LED_BUILTIN, HIGH);
      time_start =  millis();
   }
   else{
      digitalWrite(pinPower, LOW);
      digitalWrite(pinRelay, LOW);
      digitalWrite(LED_BUILTIN, LOW);
   }
}
void config_read() {
    EEPROM.begin(300);  
    WifiMode = EEPROM.read(0); 
    if ( WifiMode == 1)  {   
       if ( EEPROM.read(1) == 1  ) { // if config is written
         ss = 2;
         for (i = 0;  i < 30; i++ ) {
             ssid[i] = EEPROM.read(ss + i );
         }
         ss = 32;
         for (i = 0;  i < 30; i++ ) {
             password[i] = EEPROM.read(ss + i );
         }          
         ss = 62;
         for (i = 0;  i < 50; i++ ) {
             ThingSpeak_key[i] = EEPROM.read(ss + i );
         }          
         ss = 112;
         for (i = 0;  i < 50; i++ ) {
             IFTTT_key[i] = EEPROM.read(ss + i );
         }          
         ss = 162;
         for (i = 0;  i < 50; i++ ) {
             Blynk_auth[i] = EEPROM.read(ss + i );
         }  
       }  
    }
    else if ( WifiMode != 0 ){
       WifiMode = 0;
    }
}
void config_write() {
    EEPROM.begin(300);  
    EEPROM.write(0, 1);
    EEPROM.write(1, 1);
    ss = 2;
    for (i = 0;  i < 30; i++ ) {
       EEPROM.write(ss + i, ssid[i] );
    }
    ss = 32;
    for (i = 0;  i < 30; i++ ) {
       EEPROM.write(ss + i, password[i] );
    }          
    ss = 62;
    for (i = 0;  i < 50; i++ ) {
       EEPROM.write(ss + i, ThingSpeak_key[i] );
    }         
    ss = 112;
    for (i = 0;  i < 50; i++ ) {
       EEPROM.write(ss + i, IFTTT_key[i] );
    }         
    ss = 162;
    for (i = 0;  i < 50; i++ ) {
       EEPROM.write(ss + i, Blynk_auth[i] );
    }             
    EEPROM.commit();
    delay(500);
    WifiMode = EEPROM.read(0); 
    EEPROM.end(); 
 }
void procAProot() {
   Serial.println("procAProot start");
   String strHtml = "<!DOCTYPE html><html><head><meta name='viewport' content='width=device-width,initial-scale=1.0' /></head><body>";
   strHtml = strHtml +  "<form action='/setting' method='POST'><table width=100%><tr><td align=center><h3> Setting Waterman IOT</h3><br></td></tr>";
   strHtml = strHtml+ "<tr><td>WiFI ID: <input type=text name='ID' value='" + ssid + "'/><br></td></tr>"; 
   strHtml = strHtml+ "<tr><td>Password: <input type=text name='PW' value='" + password + "'/><br></td></tr>"; 
   strHtml = strHtml+ "<tr><td>ThingSpeak key: <input type=text name='TSK' value='" + ThingSpeak_key + "'/><br></td></tr>"; 
   strHtml = strHtml+ "<tr><td>IFTTT key: <input type=text name='IFK' value='" + IFTTT_key + "'/><br></td></tr>"; 
   strHtml = strHtml+ "<tr><td>Blynk key: <input type=text name='BLK' size=25 value='" + Blynk_auth + "'/><br></td></tr>"; 
   strHtml = strHtml+ "<tr><td></p></fieldset>";
   strHtml = strHtml+ "<tr><td align=center> <input type=submit value='confirm' /></td></tr></table></form></body>";
   server.send(200,"Text/html",strHtml);
}
void procAPsetting() {
    server.send(200,"Text/html","<body><br><h1>Registering...<h1></body>");
    String ID = server.arg("ID");
    String PW = server.arg("PW");
    String TSK = server.arg("TSK");
    String IFK = server.arg("IFK");
    String BLK = server.arg("BLK");
    strcpy(ssid, ID.c_str());
    strcpy(password, PW.c_str());
    strcpy(ThingSpeak_key, TSK.c_str());
    strcpy(IFTTT_key, IFK.c_str());
    strcpy(Blynk_auth, BLK.c_str());
    config_write();
    ESP.restart();
}
void ICACHE_RAM_ATTR procSetting();
void procSetting() {
    EEPROM.begin(300);  
    EEPROM.write(0, 0);
    EEPROM.commit();
    EEPROM.end();
    ESP.restart();
}
void setup() {
   Serial.begin(115200);
   Serial.println("==waterman IOT  START==");
   Wire.begin();
   pinMode(pinPower, OUTPUT);
   digitalWrite(pinPower, HIGH);
   pinMode(pinRelay, OUTPUT);
   digitalWrite(pinRelay, LOW);
   pinMode(LED_BUILTIN, OUTPUT);  
   lightMeter.begin();
   dht.begin();
   config_read();
   if ( WifiMode  == 1 )  {   
     Serial.println("READY mode Server start"); 
     WiFi.mode(WIFI_STA);
     WiFi.disconnect();
     pinMode(BtnSetting,INPUT_PULLUP);
     attachInterrupt(BtnSetting,  procSetting, FALLING); 
     Blynk.begin(Blynk_auth, ssid, password);
   }
   else{
       WiFi.mode(WIFI_AP);
      Serial.println("strart AP MODE ");
      WiFi.softAP(ap_ssid,ap_pass );
      IPAddress myIP = WiFi.softAPIP();
      Serial.print("AP mode ip=");
      Serial.println(myIP);
      server.on("/",procAProot);
      server.on("/setting",procAPsetting);
      server.begin();
      Serial.println("AP mode Server start"); 
   }
}
void loop() {
   if ( WifiMode  != 1 )  {
       server.handleClient();
       delay(500);
   }
   else {
      if ( millis() - time_blink  > 1000 ) {
          if ( flag_blink == 1 ) {
             digitalWrite(LED_BUILTIN, HIGH);
             flag_blink = 0;
          }
          else {
             digitalWrite(LED_BUILTIN, LOW);
             flag_blink = 1; 
          }
          time_blink = millis();
      }
      if ( millis() - time_upload  > 1000 * 60 * 1) {
         procReadSensors();
         if ( temp < 5) {
              if ( cnt_low_temp++ < 4 ) 
                 procIFTTT("low_temp");
         }
         else {
             cnt_low_temp = 0;
         }
        if ( moist < 10) {
            cnt_low_moist++;
            if ( cnt_low_moist < 4 ) {
                 procIFTTT("low_moist");
            }
            if ( cnt_low_moist == 4 ) {
               digitalWrite(LED_BUILTIN, HIGH);
               digitalWrite(pinRelay, HIGH);
               delay(10000);
               digitalWrite(LED_BUILTIN, LOW);
               digitalWrite(pinRelay, LOW);
            }
            if ( cnt_low_moist == 5 ) {
                procIFTTT("low_water");
            }
        }
        else {
           cnt_low_moist = 0;
        }
         procThingSpeak();
         time_upload  = millis();
      }
  Blynk.run();
  procBlynk();
  }
}

 

+ Recent posts