본문 바로가기
카테고리 없음

쌩 초짜의 WEMOS D1 mini width Telegram을 이용한 iOT 완성? (온습도 /등스위치 on off/에어컨 리모컨 on off

by 뚜父 2019. 11. 20.

2021-02-14 : post없이도 로그인 효과를 볼수 있도록 하는 방법을 찾았습니다. ^^;

오케이구글도 연동해보려고 합니다 ^^;

릴레이는 5v짜리여서 좀 에러가 있는것 같아 3v짜리로 변경해보려구 구입중입니다. ^^;


사용 자재 입니다. ^^; 

wemos mini 4,550원 + dht온도센서 15,000원?(알리에서 2.78불에 구매) + 릴레이 650원? (알리에서 0.54불) + 적외선 송신센서 3,150 (다음엔 2,300원짜리 쓸듯) + 수신센서 1,700원(이건 만들때 마다 재활용 ㅋ)  대충 2만원 내외로 만든것 같네요 ^^; 사무실건 사무실사람 다 채널에 들어오고... 집에건 온가족 다 모이면... 제입장엔 뿌듯할듯... 

 

가끔 릴레이가 정상작동 안함... ㅠㅠ;

릴레이를 3v용으로 (3,800원? ㅠㅠ) 재구매 해서 해야 할듯... ㅠㅠ; // 원래는 5v전원공급하고 3.3볼트 gpio신호로 정상 작동 되는게 맞다고 하는데... 안됨... ㅠㅠ; (2019.11.27 업데이트)

gpio 5번을 사용하기 위해 핀을 자로고 땜했습니다.
아래 그림 보다는 좀 낳죠?

 

밑부분은 등이 켜졌는지 꺼졌는지 표시할 겁니다. %때문에 시간만 보낸.... ㅋ

 

정해진 단어가 아니면 채널아이디나 챗 아이디를 날려주니 코드 수정할때 활용하세요...

 

/********* Base Code THX
  Rui Santos
  Complete project details at https://randomnerdtutorials.com/esp8266-dht11dht22-temperature-and-humidity-web-server-with-arduino-ide/ (Thank You!)
*********/
/* THX
 *  UniversalTelegramBot libray. (Thank You!)
 */
/*********
  TDUBU's iOT HOME
  WEMOS D1 mini + DHT22 + BUTTON width Telegram
  
  다 있는거 가져다가 조합해서 사용하고... 거기다 모르는거 다 물어봐서 만들어 놓고는... 공개하기는... 아깝... 다른사람도 나처럼 고생해서 얻어야지.... ㅋㅋㅋ
  같은 말도 안되는 생각이 없었던것은 아니지만.... 그럼 라이브러리나 예제파일들을 공개한 사람은 정말 신... 그중에 정말 착한 신 인것 같다.

  내가 필요한건 몇개 안되는데 머 이렇게 많이 섞어놨어... 하는 분도 있겠지만.... 추가하는 것 보다 삭재하는 것이 더 쉽다는 점.... ㅋ
  주석도 지저분하지만 나름대로 최대한 정리해서 주저리 주저리 함... 
  주저리 주저리가 많은 이유는 에러도 발생나 보고 대처법도 찾아봐야 하지만.... 에러를 겪지 않고 지나감으로서 얻지 못하는 게 너무 많을까바 최대한 주저리 주저리 함...
  나처럼 고생하지 않았으면 좋겠고.... 그래도 알고 넘어갔으면 좋겠고.... 모르겠음...
  소스 내게 아니니 라이센스 그런것 모르겠고... 
  이걸 이용해 좀더 좋게 만든사람은 살짝 나한테 공개해 주면 안될까용? ㅋ
  tdubu@naver.com... 주 메일이 아니라서 자주 확인은 안함 ㅋ
  https://tdubu.tistory.com/40
*********/

// Import required libraries
//#include <Arduino.h>             // 혹시몰라 남겨둠
//#include <Hash.h>                // 혹시몰라 남겨둠
//#include <Adafruit_Sensor.h>     // 혹시몰라 남겨둠

#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>           // 이 어여쁜 웹서버
#include <ESPAsyncWebServer.h>     // 이 어여쁜 웹서버
#include <DHT.h>                   // DHT 온도센서

#include <WiFiClientSecure.h>      // 텔레그램에 필요
#include <UniversalTelegramBot.h>  // 유니버셜~ 텔레그램 최고!!!

#include <IRremoteESP8266.h>       // ESP 8266에서 사용하기 편한 IRremote!!!
#include <IRsend.h>                // IR 발신용

// Replace with your network credentials
const char* ssid = "SSID";
const char* password = "1234567890";
//------------------------------------------ 고정아이피(DHCP사용시 제거)
IPAddress ip(192, 168, 0, 100);//쩜(.)이 아니라 콤마(,)라는 부분을 잘 보자.... 전 노안이라 한동안 왜 에러가 나는 지 알지 못함 ㅠㅠ;
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(168, 126, 63, 1);//skt_219.250.36.130//kt_168.126.63.1//lg_164.124.101.2//google_8.8.8.8(제가 알아본거니 틀릴수도 있다는 점)
//dns1,dns2넣는 코드도 있었으나 전 이거로 만족
//------------------------------------------ 고정아이피 끝

//------------------------------------------ USE PIN SETTING ------------------------------------------//
//자유로이 사용해도 되는 핀은... GPIO4, GPIO5, GPIO12 ,GPIO13, GPIO14 이렇게 5개라고 한다.
//그걸 몰라서 여러모로 힘들었음...

//------------------------------------------ DHT
#define DHTPIN 5                   // Digital pin connected to the DHT sensor 5

//------------------------------------------ BUTTON
#define SW1 12                  // onoff Digital input pin...
#define SW2 13                  // onoff Digital input pin...
#define RELAY 16                // onoff Digital output pin...

//------------------------------------------ IR send
const uint16_t kIrLed = 4;        // ESP8266 GPIO pin to use. Recommended: 4 (D2).//

//------------------------------------------ Telegram setting
#define BOTtoken "0000000000:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" //봇의 토큰값에 맞게 수정
#define BOTchannel "채널에게 물어보면 알려줌?"//채널에 맞게 수정

//------------------------------------------ Uncomment the type of sensor in use:
//#define DHTTYPE    DHT11         // DHT 11
//#define DHTTYPE    DHT21         // DHT 21 (AM2301)
#define DHTTYPE    DHT22           // DHT 22 (AM2302)

//------------------------------------------ current temperature & humidity, updated in loop()
float t = 0.0;
float h = 0.0;
int o = 0;                         // 접점 확인

boolean CUR = 1;
String mychatID ="자신의 쳇 아이디번호";  
String line;                       // 외부IP값 입력
String linePORT = ":5555";         // 외부 접속 포트... 없다면 ""...

int Bot_mtbs = 500;                //봇 딜레이 값?으로 생각됨... 원래 1000
long Bot_lasttime;

const long interval = 10000;       // 온도 딜레이... 원래 10000(10초) // Updates DHT readings every 10 seconds
unsigned long previousMillis = 0;  // will store last time DHT was updated

DHT dht(DHTPIN, DHTTYPE);
IRsend irsend(kIrLed);             // Set the GPIO to be used to sending the message.
WiFiClientSecure BOTclient;
UniversalTelegramBot bot(BOTtoken, BOTclient);
AsyncWebServer server(80);         // Create AsyncWebServer object on port 80

// 하기 HTML부분에서 %는 원본소스로 운영시 문제되지 않으나... 그 이후에 소스 추가시 에러 발생.... ㅠㅠ;
// 왜? 에러가 나는 지 한참 고민하다... 특수문자 문제일것 같아서 %대신 &#37;를 사용 ^^; 잘됨....

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
  <style>
    html {
     font-family: Arial;
     display: inline-block;
     margin: 0px auto;
     text-align: center;
    }
    h2 { font-size: 3.0rem; }
    p { font-size: 3.0rem; }
    .units { font-size: 1.2rem; }
    .dht-labels{
      font-size: 1.5rem;
      vertical-align:middle;
      padding-bottom: 15px;
    }
  </style>
</head>
<body>
  <center>
  <h2>TDUBU's iOT Server</h2>
  <p>
    <i class="fas fa-thermometer-half" style="color:#059e8a;"></i> 
    <span class="dht-labels">Temperature</span> 
    <span id="temperature">%TEMPERATURE%</span>
    <sup class="units">&deg;C</sup>
  </p>
  <p>
    <i class="fas fa-tint" style="color:#00add6;"></i> 
    <span class="dht-labels">Humidity</span>
    <span id="humidity">%HUMIDITY%</span>
    <sup class="units">&#37;</sup>
  </p>
  <p>
    <i class="fas fa-check-circle" style="color:#059e8a;"></i> 
    <span class="dht-labels">Light</span> 
    <span id="onoff">%ONOFF%</span>
    <sup class="units">______</sup>
  </p>
</body>
<script>
setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("temperature").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/temperature", true);
  xhttp.send();
}, 10000 ) ;

setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("humidity").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/humidity", true);
  xhttp.send();
}, 10000 ) ;

setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("onoff").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/onoff", true);
  xhttp.send();
}, 10000 ) ;
</script>
</html>)rawliteral";

// Replaces placeholder with DHT values
String processor(const String& var){
  //Serial.println(var);
  if(var == "TEMPERATURE"){
    return String(t);
  }
  else if(var == "HUMIDITY"){
    return String(h);
  }
  else if(var == "ONOFF"){
    return String(o);
  }
  return String();
}

//------------------------------------------ GET IP
String getIp() //https://stackoverflow.com/questions/48413803/cant-get-public-ip-address-from-esp8266-using-ipify answered Pedro Lobito (Thank You!)
{
  WiFiClient client;
  if (client.connect("api.ipify.org", 80)) 
  {
      Serial.println("connected");
      client.println("GET / HTTP/1.0");
      client.println("Host: api.ipify.org");
      client.println();
  } else {
      Serial.println("Connection to ipify.org failed");
      return String();
  }
  delay(5000);

  while(client.available())
  {
    line = client.readStringUntil('\n');
    Serial.println(line);
  }
  return line;
}
//------------------------------------------ 

void setup(){
//Pin state
  pinMode(SW1, INPUT_PULLUP); //PIN을 입력모드로 설정 INPUT으로 설정하면 잘 안됨//핀 번호에 따라 PULLUP과 PULLDOWN으로 구분 사용해야 하는 것 같음(미확인)
  pinMode(SW2, INPUT_PULLUP); 
  pinMode(RELAY, OUTPUT);
  digitalWrite(RELAY, HIGH);
  CUR = digitalRead(SW1);
  o = 0;
// Serial port for debugging purposes
  Serial.begin(115200);
  dht.begin();

// Connect to Wi-Fi
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);
//---------------------------------------------------------------------
  WiFi.config(ip, gateway, subnet, dns);//-----고정아이피(DHCP사용시 제거)
//---------------------------------------------------------------------
  WiFi.begin(ssid, password);
  Serial.println(ssid);  
  Serial.println("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println(".");
  }

// Print ESP8266 Local IP Address
  Serial.println(WiFi.localIP());

// Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });
  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", String(t).c_str());
  });
  server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", String(h).c_str());
  });
  server.on("/onoff", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", String(o).c_str());
  });

  // Start server
  server.begin();

  getIp();//외부아이피가져오기 서버가 대답이 없으면 오류발생 가능//DDNS없이 외부에서 접속가능//포트포워딩은 알아서 환경에 맞게 잘... 텔레그램으로 물어보면 한번 다시 실행...
  bot.sendMessage(BOTchannel, "THIS WEB is http://"+line+linePORT, "");//채널에다가 자기 주소 말하기 ^^;
  
  irsend.begin();//ir리모컨 기능 시작
}

void loop(){
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    // save the last time you updated the DHT values
    previousMillis = currentMillis;
    // Read temperature as Celsius (the default)
    float newT = dht.readTemperature();
    // Read temperature as Fahrenheit (isFahrenheit = true)
    //float newT = dht.readTemperature(true);
    // if temperature read failed, don't change t value
    if (isnan(newT)) {
      Serial.println("Failed to read from DHT sensor!");
    }
    else {
      t = newT;+
      Serial.println(t);
    }
    // Read Humidity
    float newH = dht.readHumidity();
    
    // if humidity read failed, don't change h value 
    
    if (isnan(newH)) {
      Serial.println("Failed to read from DHT sensor!");
    }
    else {
      h = newH;
      Serial.println(h);
    }
  }

  //----------------------------------------
    if (millis() >= Bot_lasttime + Bot_mtbs)  {
      Serial.println("BOT");
      int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
      while(numNewMessages) {
        for (int i=0; i<numNewMessages; i++) {
          Serial.println("got response : "+bot.messages[i].text);
          if(bot.messages[i].type == "channel_post") {//----------------- CHANNEL
          if(bot.messages[i].text == "/server"){
            bot.sendMessage(BOTchannel, "잠시 기다려 주세요", "");
            getIp();
            bot.sendMessage(BOTchannel, "THIS WEB is http://"+line+linePORT, "");
          }else if(bot.messages[i].text == "air" || bot.messages[i].text == "AIR"){
            irsend.sendNEC(0x3B73C03F); //에어컨 전원 on off 버튼이 하나라서 키 하나밖에 못 가져 옴. ㅠㅠ 카메라를 하나 달아서 사진한장 날리라고 해야 할듯... ㅠㅠ;
            Serial.println("에어컨 전원을 눌렀습니다.");
            bot.sendMessage(BOTchannel, "에어컨 전원 버튼을 눌렀습니다.", "");
          }else if(bot.messages[i].text == "on" || bot.messages[i].text == "ON"){
            if(o == 1){
              bot.sendMessage(BOTchannel, "켜져있음", "");
            }else{
              digitalWrite(RELAY, LOW);
              Serial.println("사무실 전등 ON");
              bot.sendMessage(BOTchannel, "사무실 전등 ON", "");
              o=1;
            }            
          }else if(bot.messages[i].text == "off" || bot.messages[i].text == "OFF"){
            digitalWrite(RELAY, HIGH);
            Serial.println("사무실 전등 OFF");
            bot.sendMessage(BOTchannel, "사무실 전등 OFF", "");
            o=0;
          }else{
            bot.sendMessage(bot.messages[i].chat_id, bot.messages[i].chat_title + " " + bot.messages[i].text, "");
            Serial.println("이건 채널"+bot.messages[i].chat_id);
            bot.sendMessage(bot.messages[i].chat_id, bot.messages[i].chat_title + " " + "채널 ["+bot.messages[i].chat_id+"]", "");
          }
        } else {//------------------------- 개인
          Serial.println("이건 개인"+bot.messages[i].chat_id);
          if (bot.messages[i].chat_id == mychatID){
            bot.sendMessage(bot.messages[i].chat_id, bot.messages[i].text, "");
            bot.sendMessage(bot.messages[i].chat_id, "개인 ["+bot.messages[i].chat_id+"]", "");
          }else{//모르는 사람과 대화 금지 ㅋ//
            bot.sendMessage(bot.messages[i].chat_id, "You are not my BOS!!!", "");                    
          }
        }
      }

      numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    }
//------------------------------------------ 접점감지...
    if (CUR != digitalRead(SW1)){
      if (o == 0){
        Serial.println("불 키라1... ");
        digitalWrite(RELAY, LOW);
        Serial.println(CUR);
        o=1;
        CUR = digitalRead(SW1);
        bot.sendMessage(BOTchannel, "사무실 전등 ON", "");
      }else{
        Serial.println("불 끄라1... ");
        digitalWrite(RELAY, HIGH);
        Serial.println(CUR);
        o=0;
        CUR = digitalRead(SW1);
        bot.sendMessage(BOTchannel, "사무실 전등 OFF", "");
      }      
    }
//------------------------------------------ 접점감지... 는 텔레그램 봇과 함께하겠당 ㅋ

    Bot_lasttime = millis();
  }

/*
  irsend.sendNEC(0x3B73C03F); //전원
  irsend.sendNEC(0x3B73A05F); //운전
  이건 명령 처리 구문 만든 후 사용예정
*/

}

 

글쓸 공간...

 

 

급하신 분은 먼저 보시고 해보셔도 될듯 합니다. 저는 일단 생각한대로 잘 돌아 갑니다....

저는 능력이 안되어 소스내용 이해 못하며, 각종 예제 가져다 붙인겁니다.

그리고 여지껏 에러와 싸우고 여기저기 물어서 답변을 들을때 마다 옆에다 주석 달고 해서 만든것이니... 

완벽할리 없습니다. ^^;

변수 이름만 보셔도 규칙성이 없다는 걸 바로 알수 있겠죠?

 

아무튼 공개의 이유는 누가 잘 설명해주면 좋고, 좋게 고쳐주셔도 좋고, 틀린데 알려주셔도 좋으니 그냥 가져만 가지 마시고 조언도 한자씩 해주세요 ^^;

 

 

인제 여기다 하기의 텔레그램 메뉴... 를 추가해 보도록 해야겠다...

InlineKeyboard(테스트시 개인톡/채널 모두 실행됨)

ReplyKeyboard(개인톡에서만 실행됨)

 

* 참고사항 :

1. esp8266 보드메니저에서 2.4.2 이하로 설치를 권장합니다. 왜 안되는지 한참 헤멨습니다.

2. 라이브러리 중 ArduinoJson by Benoit Blanchon... 이것도 5.13.5를 사용하였습니다.
원래 6.몇설치되어 있었는데 컴파일시 5로 업그레이드해달란 메시지를 보여줍니다.

3. 이건 처음이라 바보같은 짓인지 몰라도 릴레이... 전원 5볼트로 주면 계속 켜져 있습니다.

전원을 3볼트로 줘야 한다는 것을 알게되는데 3일 걸렸습니다. ㅠㅠ;

4. wimos d1은 왜? high가 불끄고 low가 불킬까요? 희안하네.... ㅡ,.ㅡ;

 

웹에도 스위치 등 만들려다가 임시 보류입니다. 외부에서 접근가능하게 하면 누구라도 그냥 껏다켰다 할수 있어서...

일단은 로그인관련자료 찾고 있습니다.

댓글