아누이노와 여기에 연결된 부품간에는 신호용 전류 정도가 흐르기 때문에 일반적인 듀폰케이블이나 가는 연결 케이블을 사용해도 무방하다. 하지만 모터를 가동시킨다 든지 대형 전구를 가동시킨다 든지 할 때에는 큰 전류가 흐르기 때문에 케이블도 이 용량에 맞는 케이블을 사용해서 연결해 주어야 한다. 그렇지 않으면 기기가 작동을 하지 않거나 열이 발생해서 케이블이 불타 버리는 현상이 발생할 수 있다. 

 

 

케이블의 규격 및 허용 전류     

 

일반적으로 미국에서 사용하는 AWG(American Wire Guauge) 전선규격으로 케이블의 굵기 및 허용 전류치를 사용하는데 AWG값이 커질수록 전선의 굵기가 가늘어 지고 허용전류가 적어진다. 여기에서 허용전류치는 최대치이므로 실제 사용은 두배정도의 용량을 가진 케이블을 사용하는 것이 안전하다.

 

 

-위는 일반 PVC비닐 피복전선 기준이고 실리콘 전선일 경우 2~3배 용량이 더 크다.

 

 

점퍼선 : 아두이노 점퍼선으로 사용하는 듀폰 케이블은 보통 28AWG~24AWG로서 허용 전류는 250mA ~588mA이다.   

 

 

 

 

소형전원용 : 소형기기 전원 공급용 케이블은 다음과 같이 18AWG ~ 26AWG 규격이 많이 사용된다.  

 

 

 

 대용량 케이블 : 파워뱅크라든지 중대형기기 전원 공급용은 굵은 실리콘케이블을 사용하는 것이 좋다.  

 

 

 

 

 

모터연결용 케이블  : 서보모터를 연결하기 위해서는 3개의 선이 필요하고 스테핑모터를 연결하기 위해서는 4선이 필요하므로 모터 연결용으로 3~4선을 함께 구성하고 커넥터까지 연결해 놓은 모터연결용 케이블을 사용하면 편리하다. 

 

 

 

 

 

 

ESP8266은 중국 ESPressif Systems라는 회사에서 개발한 다음과 같은 저가형 WIFI 칩인데, 완전한 WIFI통신을 지원함과 동시에 32bit Micro Processor를 함께 내장하고 있어 저렴한 비용으로 WIFI통신 뿐만 아니라 프로세서의 기능을 함께 사용할 수 있어 많이 사용된다.     

 

 

 

ESP8266의 주요 사양

 

- 80Mhz대 빠른 속도의 32비트 Micro Precessors내장 ( 아두이노 우노는 16Mhz )

 

- 80KB의 사용자데이터 RAM

 

- 2.4GHz대의 802.11b/g/a WIFI 통신 지원

 

- 16개의 범용입출력 핀, 1개의 아날로그 입력

 

- SPI,I2C,I2S,UART 등 다양한 인터페이스 지원

 

- 자체 ESP8266 SDK 이외에도 다양한 개발 환경을 지원하는데 특히 아두이노IDE를 그대로 이용할 수 있도록 지원  

 

 

그런데 이 ESP8266에는 펌웨어 저장을 위한 플래시메모리가 포함되어 있지 않아 단독으로는 사용하기 곤란하기 때문에 메모리 등 기타 부품을 부착하여 여러가지 모듈형태로 제작되어 유통된다.  AI-Thinker라는 회사에서 이 ESP8266칩을 이용한 ESP-01이라는 통신 및 프로세서 기능을 결합한 모듈이 출시되었고  이후 시리즈로 계속해서 비슷한 모듈들이 출시되고 있어 사양에 따라 여러 용도로 활용되고 있다.  종류별 상세 사양은 다음 Wikipedia 링크에서 참조할 수 있다.

            https://en.wikipedia.org/wiki/ESP8266

 

 

NodeMCU

 

위 ESP01~ESP14 모듈들은 대부분 PCB 납땜용 또는 타 모듈에 연결장치로 부착하는 형태이어서 실습이나 개발용으로 활용하기에는 아두이노처럼 편리하지 못하다.  

 

ESP모듈시리즈 중 가장 많이 사용되는 ESP-12 모듈을 기본으로 하여 아두이노 개발환경에 통합할 수 있는 펌웨어와 USB연결장치 등을 부착하여 마치 아두이노의 한 종류인 것처럼 사용할 수 NodeMCU라는 모듈이 메이커 제작용 프로세서로 많이 사용된다.


즉, 인터넷 환경에서 하나의 노드 역할을 할 수 있도록 제작된 아두이노의 한 종류로 이해하고 사용할 수 있다.

 

 

 

WeMos D1, D1 Mini

 

NodeMCU 보드들 중 WeMos라는 모듈이 있는데 다음과 같이 아두이노 우노에 ESP-12를 합친 형태의 제품으로써, 아두이노 우노를 사용하듯이  듀폰케이블만으로 편리하게 임시회로를 구성하면서 실습할 수 있다.그리고  WeMos D1 Mini는 WeMos D1을  작게 소형화한 것으로서 일반적인 NodeMCU 모듈들 보다 크기가 작다.  

 

 

 

 

아두이노 피지컬컴퓨팅 교구로 활용할 수 있는 실 생할용품 메이킹 프로젝트(워터맨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