2018年5月10日 星期四

Nodemcu + PIR + NTP + MQTT

//NodeMcu + PIR紅外線移動偵測 +NTP server網址是
 tock.stdtime.gov.tw
 watch.stdtime.gov.tw
 time.stdtime.gov.tw
 clock.stdtime.gov.tw 
 tick.stdtime.gov.tw


 +MQTT  Message Queuing Telemetry Transport

    MQTT訊息傳遞原理

MQTT通訊為一對多的M2M傳輸,使用發佈(Publish)/訂閱(Subscribe)的訊息傳送機制,此機制中包含4個主要的元素,發佈者(Publisher)、訂閱者(Subscriber)、主題(Topic)、訊息中轉站(Broker)Publisher為訊息的來源,傳送夾帶有Topic資訊的訊息至Broker,訂閱者向Broker註冊想要接受到之訊息的Topic,例如有一Publisher發佈一則Topic”Test”的訊息,只要是有對Broker註冊Topic”Test”Subscriber都能接收到此訊息。









/*
    ESP8266 NodeMCU NTP (Network Time Protocol) Example
    Hardware: NodeMCU   Date: 2018
*/

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <PubSubClient.h>

char ssid[] = "PTS-2F";  //  your network SSID (name)
char pass[] = "";       // your network password

//Your UTC Time Zone Differance  Taiwan +8:00
char HH = 8;
char MM = 0;
char hours, minutes, seconds;

unsigned int localPort = 2390;      // local port to listen for UDP packets

/* Don't hardwire the IP address or we won't get the benefits of the pool.
 *  Lookup the IP address for the host name instead */
//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server

IPAddress timeServerIP; // time.nist.gov NTP server address

const char* ntpServerName = "time.stdtime.gov.tw";  //time.nist.gov";

const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

// A UDP instance to let us send and receive packets over UDP
WiFiUDP udp;

//=======================================================================
int ledPin = D0;                // choose the pin for the LED
int relayInput = D1;             // choose the pin for the relay
int inputPin = D2;               // choose the input pin (for PIR sensor)
int pirState = LOW;             // we start, assuming no motion detected
int val = 0;                    // variable for reading the pin status
int cnt=0;
//=======================================================================
const char* mqtt_server = "broker.mqttdashboard.com";
//const char* mqtt_server = "iot.eclipse.org";

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

//=======================================================================
void callback(char* topic, byte* payload, unsigned int length)
{
} //end callback
//=======================================================================
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected())
  {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    //if you MQTT broker has clientID,username and password
    //please change following line to    if (client.connect(clientId,userName,passWord))
    if (client.connect(clientId.c_str()))
    {
      Serial.println("connected");
     //once connected to MQTT broker, subscribe command if any
      client.subscribe("alex9ufo_PIR_Command");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 6 seconds before retrying
      delay(6000);
    }
  }
} //end reconnect()

//=======================================================================
//                     SETUP
//=======================================================================
void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.println();
 
  pinMode(ledPin, OUTPUT);      // declare LED as output
  pinMode(inputPin, INPUT);     // declare sensor as input
  pinMode(relayInput, OUTPUT);  // declare relay as output
  digitalWrite(relayInput, HIGH);//assuming relay is off
 
  // We start by connecting to a WiFi network
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  randomSeed(micros());
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  client.setServer(mqtt_server, 1883);//the default mqqt port is 1883.
  client.setCallback(callback);

  Serial.println("Starting UDP");
  udp.begin(localPort);
  Serial.print("Local port: ");
  Serial.println(udp.localPort());
}

//=======================================================================
//  send an NTP request to the time server at the given address
//=======================================================================
unsigned long sendNTPpacket(IPAddress& address)
{
  Serial.println("sending NTP packet...");
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
 
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
 
  udp.beginPacket(address, 123); //NTP requests are to port 123
  udp.write(packetBuffer, NTP_PACKET_SIZE);
  udp.endPacket();
}

//=======================================================================
//                        LOOP
//=======================================================================
void NTP_loop()
{
  //char hours, minutes, seconds;
  //get a random server from the pool
  WiFi.hostByName(ntpServerName, timeServerIP);

  sendNTPpacket(timeServerIP); // send an NTP packet to a time server
  // wait to see if a reply is available
  delay(1000);
 
  int cb = udp.parsePacket();
  if (!cb) {
    Serial.println("no packet yet");
  }
  else {
    Serial.print("packet received, length=");
    Serial.println(cb);
    // We've received a packet, read the data from it
    udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer

    //the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    Serial.print("Seconds since Jan 1 1900 = " );
    Serial.println(secsSince1900);

    // now convert NTP time into everyday time:
    Serial.print("Unix time = ");
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;
    // print Unix time:
    Serial.println(epoch);

    // print the hour, minute and second:
    minutes = ((epoch % 3600) / 60);
    minutes = minutes + MM; //Add UTC Time Zone
    hours = (epoch  % 86400L) / 3600;   
    if(minutes > 59)
    {     
      hours = hours + HH + 1; //Add UTC Time Zone 
      minutes = minutes - 60;
    }
    else
    {
      hours = hours + HH;
    }
   
    Serial.print("The UTC time is ");       // UTC is the time at Greenwich Meridian (GMT)
   
    Serial.print(hours,DEC); // print the hour (86400 equals secs per day)
    Serial.print(':');
    if ( minutes < 10 ) {
      // In the first 10 minutes of each hour, we'll want a leading '0'
      Serial.print('0');
    }   
    Serial.print(minutes,DEC); // print the minute (3600 equals secs per minute)
    Serial.print(':');
   
    seconds = (epoch % 60);
    if ( seconds < 10 ) {
      // In the first 10 seconds of each minute, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.println(seconds,DEC); // print the second
   
  }
  // wait ten seconds before asking for the time again
}
//=======================================================================
void loop(){
  val = digitalRead(inputPin);  // read input value
  if (val == HIGH) {            // check if the input is HIGH
    digitalWrite(ledPin, HIGH);  // turn LED ON
    if (pirState == LOW) {
      // we have just turned on
      Serial.print("<");
      Serial.print(String(cnt,DEC));
      Serial.println(">. Motion detected!");
      NTP_loop();
      // We only want to print on the output change, not state
      pirState = HIGH;
      digitalWrite(relayInput, LOW); // The Relay Input works Inversly
      Serial.print("Turn on the Lamp!");
      Serial.println(".....Wait for 10 seconds");
      delay(10000);              // delay for 30 seconds
      digitalWrite(relayInput, HIGH);// Relay input operation is positive
      Serial.println("Turn off the Lamp!");
      cnt++;
      if (cnt >=9999)
         cnt=0;
      //=========================================================
      if (!client.connected()) {
        reconnect();
      }
      client.loop();
      long now = millis();
      //send data every 6 second
      if (now - lastMsg > 500) {
        lastMsg = now;
        String msg="";
        msg= msg+ String(hours,DEC) ;
        msg= msg+ ":";
        msg= msg+ String(minutes,DEC) ;
        msg= msg+ ":";
        msg= msg+ String(seconds,DEC);
        msg= msg+ " <";
        msg= msg + (String(cnt,DEC));
        msg= msg +">. Motion detected!";   
       char message[58];
        msg.toCharArray(message,58);
        Serial.println(message);
 
        //publish sensor data to MQTT broker

          client.publish("alex9ufo_PIR_Data", message);
      } //end   (now - lastMsg > 500)
      //=========================================================
   
    }
  }
  else
  {
    digitalWrite(ledPin, LOW); // turn LED OFF
    if (pirState == HIGH)
    {
      // we have just turned of
      Serial.println("Motion ended!");
      // We only want to print on the output change, not state
      pirState = LOW;
    }
  }
}


//=======================================================================

沒有留言:

張貼留言

Messaging API作為替代方案

  LINE超好用功能要沒了!LINE Notify明年3月底終止服務,有什麼替代方案? LINE Notify將於2025年3月31日結束服務,官方建議改用Messaging API作為替代方案。 //CHANNEL_ACCESS_TOKEN = 'Messaging ...