Covenant

[본 프로젝트 목적]

 

  본 프로젝트에서는 MQTT프로토콜을 사용하여 nodeMCU에 있는 1개의 LED, 1개의 USB LED를 웹 페이지에서 조작할수 있으며 CDS를 통해서 조도 값을 DHT22를 통해서 온습도 값을 읽어들여서 웹  페이지에 표시할 것입니다. 이런 통신은 MQTT기반으로 제작합니다. 본 웹페이지를 서버는 Flask를 라즈베리파이에 올려서 작동시킬 것입니다..

 



[최종 작동영상]




[동작 구조] 



[설치]


[Raspberry pi] :: raspberry pi의 터미널에 접속

sudo apt-get install python-pip :: install python package manager
sudo pip install falsk  :: flask 설치



[Raspberry pi] :: raspberry pi에 MQTT Broker 설치

cd ~

wget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key

sudo apt-key add mosquitto-repo.gpg.key

cd /etc/apt/sources.list.d/ 

sudo wget http://repo.mosquitto.org/debian/mosquitto-stretch.list

sudo apt-get update


cd ~

wget http://security.debian.org/debian-security/pool/updates/main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u6_armhf.deb

sudo dpkg -i libssl1.0.0_1.0.1t-1+deb8u6_armhf.deb

wget http://ftp.nz.debian.org/debian/pool/main/libw/libwebsockets/libwebsockets3_1.2.2-1_armhf.deb

sudo dpkg -i libwebsockets3_1.2.2-1_armhf.deb

sudo apt-get install mosquitto mosquitto-clients



[Raspberry pi] :: raspberry pi에 mosquitto 설치 되었는지 확인

sudo /etc/init.d/mosquitto status

service mosquito status

service mosquito start

 


[nodeMCU Code]

#include <ESP8266WiFi.h>

#include <PubSubClient.h>

#include <ESP8266HTTPClient.h>

#include "DHT.h"

#define D0 16

#define D1 5

#define D2 4

#define D3 0

#define D4 2

#define D5 14

#define D6 12

#define D7 13

#define D8 15

#define RELAY1_PIN D1

#define RELAY_OFF HIGH // HIGH 신호이면 릴레이 동작하지 않음

#define RELAY_ON LOW  // LOW 신호이면 릴레이 동작함

int cdsPin = A0;

DHT dht(D2, DHT22);

const char* ssid = "여러분의 값을 입력하세요";

const char* password = "여러분의 값을 입력하세요"; 

char* topic = "nodemcu.iot.csee/1"; // # 하면 모든 토픽으로부터 수신을 한다.

char* server = "192.168.137.250"; //MQTT broker address

char message_buff[100]; //initialise storage buffer

char data[100] = {0};

WiFiClient wifiClient; //클라이언트로 작동

int ledPin = D0; //GPIO 13

int usbledPin = D1; // USB LED 위해서

float humidity, temperature;

int light_val;

void callback(char* topic, byte* payload, unsigned int length){

  int i = 0;

  Serial.println("Message arrived: topic: " + String(topic));

  Serial.println("Length: "+ String(length,DEC));

  for(i=0; i<length; i++){

  message_buff[i] = payload[i];  

  }

message_buff[i]= '\0';

 

String msgString = String(message_buff);

  Serial.println("Payload: "+ msgString);

  int state = digitalRead(ledPin);

  int usb_state = digitalRead(usbledPin);

    if (msgString == "led"){

    digitalWrite(ledPin, !state);

    Serial.println("Toggle LED");

   }

   else if ( msgString == "ledon"){

    digitalWrite(ledPin, HIGH);

    Serial.println("LED ON");

   }

   else if ( msgString == "ledoff"){

    digitalWrite(ledPin, LOW);

    Serial.println("LED OFF");

   }

  else if ( msgString == "usbledon"){ // usb 동작 부분

    digitalWrite(RELAY1_PIN, RELAY_ON);

    Serial.println("USB LED ON!");

  }

  else if ( msgString == "usbledoff"){

    digitalWrite(RELAY1_PIN, RELAY_OFF);

    Serial.println("USB LED OFF!");

  }

  else if ( msgString == "usbled"){ 

    digitalWrite(RELAY1_PIN, !usb_state);

    Serial.println("USB LED Toggle");

  }

}

PubSubClient client(server, 1883, callback, wifiClient);

void setup() {

  Serial.begin(115200);

  delay(10);

  pinMode(ledPin, OUTPUT);     // Initialize the LED_BUILTIN pin as an output

  digitalWrite(ledPin, LOW); //LED off

  pinMode(RELAY1_PIN, OUTPUT);

  digitalWrite(RELAY1_PIN, RELAY_OFF);

  //Connect to wifi my network;

  Serial.println();

  Serial.println();

  Serial.println("Connecting to ");

  Serial.println(ssid);

  //wifi 연결을 시도한다.

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);

    Serial.println(".");

  }

  //연결되면 접속한 IP 뭔지 출력한다.

  Serial.println("");

  Serial.println("WiFi Connected");

  Serial.println(WiFi.localIP());

  //Connection to broker

  if (client.connect("arduinoClient4")){

    client.publish("nodemcu/3", "Hello World");

    client.subscribe(topic); // nodemcu.iot.csee/1

    client.subscribe("nodemcu.iot.csee/1/light");

    Serial.println("브로커 연결에 성공했습니다.");

  }else{

    Serial.println("브로커 연결에 실패했습니다.....");

  }

}

void loop() {

  humidity = dht.readHumidity();

  temperature = dht.readTemperature();

  light_val = analogRead(cdsPin);

  if(isnan(humidity) || isnan(temperature))

    Serial.println("Failed to read from DHT sensor!");

  String payload = "";

  payload += humidity;

  payload += ",";

  payload += temperature;

  payload += ",";

  payload += light_val;

  payload.toCharArray(data, (payload.length()+1));

  client.publish("iot/1/sensors", data);

  client.loop();

}


 

 

함수 설명 


callback 함수 

    - 함수 원형 :: callback(char* topic, byte* payload, unsigned int length)
    - subscribe한 topic에 대해서 publish를 통해 메시지가 전달된다면 실행되는 함수이다.  
    - PubSubClient.h에 속한 파일이다. 
    - topic : subscribe 한 topic    
    - length : payload의 길이

 

    - callback함수 작동 : msgString에 publish한 message가 저장되어 있다. if 조건문을 지나면서 publish한 message가 led인지, ledon인지, ledoff인지, 등등 어떤 message가 전달되어 왔는가를 확인하는 것이다. 해당되는 조건문에 들어가면 digitalWrite를 이용여 전송된 message에 맞게 led가 동작시키는 것이다. 


 

loop 함수

    - DHT22와 CDS를 통한 온 습도 조도 값


[읽은 값 변수에 저장하기]

humidity = dht.readHumidity();

   temperature = dht.readTemperature();

   light_val = analogRead(cdsPin);

        dht객체에서의 readHumidity와 readTemperature함수를 호출해서 리턴되는 습도와 온도 값을 humidity와 temperature값에 저장한다. 

        analogRead함수에서 리턴되는 조도 값을 light_val 변수에 저장한다.


        [오류 체크하기]

        if(isnan(humidity) || isnan(temperature))

           isnan()은 괄호 안에 있는 변수가 숫자가 아닌 경우에 오류가 True가 되며 if문 안의 값이 실행된다. 즉 온 습도값을 정상적으로 읽지 못하면 if문이 실행된다.

       

        [String으로 전환하여 publish하기]




[html - sample]

<html>
    <head>
        <meta charset="utf-8">
        <!-- 합쳐지고 최소화된 최신 CSS -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">

        <!-- 부가적인 테마 -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css">

        <!-- 합쳐지고 최소화된 최신 자바스크립트 -->
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
        <script>
            function onLED(){
            //    location.href = "light/ledon";
                location.href = "/nodemcu.iot.csee/1/light/ledon";
            }
            function offLED(){
            //    location.href = "light/ledoff";
                location.href = "/nodemcu.iot.csee/1/light/ledoff";
            }
            function toggleLED(){
                location.href = "/nodemcu.iot.csee/1/light/led";
            } 
            function onUSBLED(){
                location.href= "/nodemcu.iot.csee/1/light/usbledon";
            }
            function offUSBLED(){
                location.href= "/nodemcu.iot.csee/1/light/usbledoff";
            }
            function toggleUSBLED(){
                location.href= "/nodemcu.iot.csee/1/light/usbled";
            }

        </script>
           
        <link href="https://gitcdn.github.io/bootstrap-toggle/2.2.2/css/bootstrap-toggle.min.css" rel="stylesheet">
     /head>
    <body>
        <h3>실전 프로젝트 IoT</h3>
   
    <p>
        MQTT를 이용한 nodemcu 컨트롤
    </p>
 
    <a href="/nodemcu.iot.csee/1" class="btn btn-primary" role="button">Home으로 이동</a>
    <br>

    <ul class="sensorList">
        <li>
            LED 켜고 끄기 ver2 <br><br>
            <button type="button" class="btn btn-primary" onclick="onLED()"> LED On </button>
            <button type="button" class="btn btn-primary" onclick="offLED()" > LED Off </button>
            <button type="button" class="btn btn-primary" onclick="toggleLED()"> LED Toggle </button>
           
            {% if flag == 1  %}
                <strong style="color:red" > led on </strong>
            {% else %}
                <strong style="color:green"> led off </strong>
            {% endif %}
        </li>
    </ul>

    <ul>
        <li>
            USB LED 켜고 끄기 - 1217 오후ver <br><br>
            <button type="button" class="btn btn-primary" onclick="onUSBLED()"> USB LED On </button>
            <button type="button" class="btn btn-primary" onclick="offUSBLED()"> USB LED Off </button>
            <button type="button" class="btn btn-primary" onclick="toggleUSBLED()"> USB LED Toggle </button>
           
            {% if flag2 == 1 %}
                <strong style="color:red"> usb led on </strong>
            {% else %}
                <strong style="color:green"> usb led off </strong>
            {% endif %}
        </li>
    </ul>


    <!-- jQuery (부트스트랩의 자바스크립트 플러그인을 위해 필요합니다) -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    <script src="https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js"></script>
    <script type="text/javascript">
    $(
        function(){
                $("#toggle_led").change(function(){
                    window.location.href="/led";
                }
            )
        }
    )
    </script>
    </body>
</html>



[참고 사이트]

  저 또한 공부하면서 글을 작성하였습니다. 다음 사이트를 참고하였습니다.

 

https://randomnerdtutorials.com/raspberry-pi-publishing-mqtt-messages-to-esp8266/     ::: Raspberry Pi Publishing MQTT Messages to ESP8266

 

https://blog.naver.com/cosmosjs/221041652734   :::  파이썬과 Flask를 이용한 나만의 웹앱 만들기(23): MQTT를 이용하여 NodeMCU(ESP8266) LED 제어하기


http://alnova2.tistory.com/710  ::: [Arduino] WiFly Shield에서 MQTT 사용하기


https://nodemcu.readthedocs.io/en/master/en/modules/mqtt/ ::: Nodemcu 공식 documentation