Meretas Sensor Gerak PIR dengan ESP8266

April 05, 2020 0
Meretas Sensor Gerak PIR dengan ESP8266 - Dalam proyek ini kami akan memodifikasi sensor gerak komersial dengan ESP8266 untuk mencatat data kapan pun gerakan terdeteksi. Data akan dikirim ke Node-RED menggunakan protokol komunikasi MQTT. ESP8266 akan ditenagai melalui kabel phase out sensor gerak menggunakan HLK-PM03 AC / DC converter.
Bagian yang diperlukan:
Berikut daftar bagian yang diperlukan untuk proyek ini:

  • Sensor Gerak PIR 220V (atau Sensor Gerak 110V PIR)
  • ESP8266-01 - baca Papan Pengembangan Wi-Fi ESP8266 Terbaik
  • ESP8266-01 Serial Adapter (untuk mengunggah kode ke ESP8266)
  • Hi-Link HLK-PM03 (untuk mengubah tegangan listrik ke DC 3.3V)
  • Protoboard kecil
  • Fuse Slow Blow (200mA)
  • 47 uF kapasitor elektrolit
  • Raspberry Pi (untuk menjadi tuan rumah Node-RED dan broker MQTT) - baca Best Raspberry Pi Kits

Ulasan Proyek
Proyek ini dibagi menjadi tiga bagian:

  1. Membangun sirkuit
  2. Menulis dan mengunggah kode ESP8266
  3. Menciptakan aliran Node-RED

Gambar berikut menunjukkan ikhtisar tingkat tinggi dari proyek yang akan kami bangun.
Sensor gerak
Kami akan meretas sensor gerak komersial yang memiliki ruang yang cukup untuk meletakkan modul konverter ESP-01 dan HLK-PM03 AC / DC di dalamnya. Kami membeli sensor gerak kami seharga $ 5 di toko lokal.
Ketika sensor PIR mendeteksi gerakan, ada daya yang keluar dari kabel panas merah yang dapat menyalakan lampu atau perangkat. Sensor gerak Anda harus memiliki diagram kabel yang serupa pada tutupnya atau dicetak dalam buku petunjuk.
Dalam proyek kami, beban output sensor gerak adalah modul konverter HLK-PM03 AC / DC yang akan memberi daya pada ESP8266.
Hi-Link HLK-PM03
Modul HLK-PM03 AC / DC converter memasok 3.3V dari 110VAC atau 220VAC. Ini membuatnya sempurna untuk menyalakan ESP8266 dari tegangan listrik.

Singkatnya, ketika gerakan terdeteksi ada kekuatan yang mencapai ESP8266. ESP8266 dapat menjalankan tugas selama sensor gerak dipicu.

Anda mungkin perlu menyesuaikan durasi waktu sensor tetap, sehingga ESP8266 Anda memiliki cukup waktu untuk menjalankan tugasnya. Sensor harus memiliki kenop untuk mengatur waktu (dan lainnya untuk menyesuaikan luminositas).
Dalam contoh kami, setiap kali ESP8266 menyala, ia menjalankan sketsa yang mengirimkan informasi ke Node-RED melalui MQTT untuk mencatat tanggal dan waktu gerakan terdeteksi.
Alih-alih mengirim informasi ke Node-RED, Anda dapat menjalankan tugas lain, seperti:

  • Log data ke Google Spreadsheet;
  • Kirim email peringatan bahwa gerakan terdeteksi;
  • Kirim pemberitahuan ke ponsel cerdas Anda.
Tugas-tugas ini dapat dengan mudah dilakukan menggunakan IFTTT.
1. Membangun Sirkuit
Diagram skematik berikut menunjukkan sirkuit untuk proyek ini.
Lepaskan tutup sensor gerak PIR Anda. Di dalam, itu harus memiliki tiga kabel: fase dalam, netral, dan fase keluar. Ikuti langkah ini:

Fase kawat dalam (coklat) dan netral (biru) ke sensor gerak
Kawat netral (biru) dan fase keluar (merah) ke input HLK-PM03
Dianjurkan untuk menambahkan sekering blow lambat tepat sebelum konverter HKL-PM03 dan kapasitor ke output.

Catatan: jika Anda menggunakan ESP8266 yang selalu dinyalakan dengan HLK-PM03, kami sarankan menggunakan sirkuit perlindungan ini.

HLK-PM03 menghasilkan 3.3V dan GND. Ini terhubung ke ESP8266 VCC dan pin GND untuk menyalakannya.
Kami telah membangun sirkuit HLK-PM03 dan ESP8266 pada papan kecil untuk menghemat ruang. Kami juga menambahkan beberapa pin tajuk untuk menempatkan ESP8266-01. Dengan cara ini Anda dapat mencolokkan dan mencabut papan setiap kali Anda perlu mengunggah kode baru.

2. Menulis dan Mengunggah Kode ESP8266
Kami akan memprogram ESP8266 menggunakan Arduino IDE. Untuk mengunggah kode ke ESP8266 Anda, Anda harus menginstal add-on ESP8266 terlebih dahulu, jika Anda belum melakukannya (Instal Papan ESP8266 di Arduino IDE).
Anda juga harus menginstal pustaka PubSubClient untuk membuat klien MQTT dengan ESP8266. Perpustakaan PubSubClient menyediakan klien untuk melakukan mempublikasikan / berlangganan pesan sederhana dengan server yang mendukung MQTT (pada dasarnya memungkinkan ESP8266 Anda untuk berbicara dengan Node-RED).

  • Klik di sini untuk mengunduh perpustakaan PubSubClient. Anda harus memiliki folder .zip di folder Unduhan Anda
  • Buka zip folder .zip dan Anda akan mendapatkan folder pubsubclient-master
  • Ganti nama folder Anda dari pubsubclient-master ke pubsubclient
  • Pindahkan folder pubsubclient ke folder pustaka instalasi Arduino IDE Anda
Kemudian, salin kode berikut ke Arduino IDE Anda, tetapi belum mengunggahnya. Anda perlu membuat beberapa modifikasi untuk membuatnya bekerja untuk Anda.
Anda perlu mengedit kode dengan SSID, kata sandi, dan Alamat IP Broker MQTT Anda sendiri (Alamat IP Raspberry Pi).
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// Replace with your SSID, password and MQTT broker IP address
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
const char* mqtt_server = "REPLACE_WITH_YOUR_MQTT_BROKER_IP";
//For example
//const char* mqtt_server = "192.168.1.144";

WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  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());
}

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 (client.connect(clientId.c_str())) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  digitalWrite(BUILTIN_LED, HIGH);
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  while (!client.connected()) {
    reconnect();
  }
  Serial.print("Motion Detected");
  // Publish MQTT message
  String mqttMessage = "Motion Detected";  
  client.publish("esp/pir", mqttMessage.c_str());
}

void loop() {
  client.loop();
}
Sertakan kredensial jaringan Anda
Anda harus memasukkan kredensial jaringan Anda di baris berikut.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Sertakan alamat IP broker MQTT Anda
Anda juga perlu memasukkan alamat IP broker MQTT Anda.
const char* mqtt_server = "REPLACE_WITH_YOUR_MQTT_BROKER_IP"; 
Untuk menemukan alamat IP broker MQTT Anda, harus dikonfigurasi terlebih dahulu. Kami menggunakan broker Mosquitto yang dihosting di Raspberry Pi.

Bagaimana kodenya bekerja
Kode ini sangat sederhana. Itu hanya menerbitkan pesan tentang suatu topik. Untuk tujuan pengujian, kami juga menyalakan LED on-board setiap kali ESP8266 diaktifkan. Ini dilakukan pada setup () karena hanya akan dieksekusi satu kali (ketika gerakan terdeteksi dan ketika ESP8266 diaktifkan).
void setup() {
   pinMode(BUILTIN_LED, OUTPUT); // BUILTIN_LED pin as an output
   digitalWrite(BUILTIN_LED, HIGH);
   Serial.begin(115200);
   setup_wifi();
   client.setServer(mqtt_server, 1883);
   while (!client.connected()) {
     reconnect();
   }
   Serial.print("Motion Detected");
   // Publish MQTT message
   String mqttMessage = "Motion Detected";  
   client.publish("esp/pir", mqttMessage.c_str());
}
Mengunggah kodenya
Setelah memodifikasi kode dengan kredensial jaringan Anda, Anda dapat mengunggahnya ke papan Anda. Untuk mengunggah kode ke ESP8266-01 Anda memerlukan adaptor serial atau programmer FTDI.

3. Membuat Aliran Node-RED
Sebelum membuat alur, Anda harus menginstal Raspberry Pi Anda:

  • Node-RED
  • Dashboard Node-RED
  • Mosquitto Broker

Mengimpor aliran Node-RED
Untuk mengimpor aliran Node-RED yang disediakan, buka repositori GitHub atau klik gambar di bawah untuk melihat file mentah, dan salin kode yang disediakan.

Selanjutnya, di jendela Node-RED, di sudut kanan atas, pilih menu, dan pergi ke Import  > Clipboard.

Kemudian, rekatkan kode yang disediakan dan klik Impor.

Inilah aliran yang diimpor. Ia menerima pesan ESP8266 MQTT dan mencatat waktu kapan gerakan terdeteksi.

Kami juga menambahkan dua tombol untuk menghapus dan menyegarkan log.

Dashboard Node-RED
Setelah melakukan semua perubahan yang diperlukan, klik tombol Deploy untuk menyimpan semua perubahan.
Sekarang, aplikasi Node-RED Anda sudah siap. Untuk mengakses Dashboard Node-RED dan melihat bagaimana aplikasi Anda, akses browser apa pun di jaringan lokal Anda dan ketik:
http://Your_RPi_IP_address:1880/ui
Demonstrasi
Sekarang, Anda dapat menguji proyek Anda. Setiap kali gerakan terdeteksi, ESP8266 menyala dan mengirim pesan melalui MQTT ke Node-RED.

Jika Anda pergi ke Dashboard Node-RED Anda, Anda dapat melihat semua log ketika gerakan terdeteksi. Aplikasi Anda akan terlihat seperti pada gambar berikut.

Dasbor menunjukkan gerakan terakhir kali terdeteksi dan semua log sebelumnya. Anda juga memiliki opsi untuk menyegarkan log, dan menghapus log. Harap dicatat bahwa menghapus log tidak dapat dipulihkan.

Decoding dan Encoding JSON dengan Arduino atau ESP8266

April 05, 2020 0
Dalam posting blog ini, Anda akan belajar cara mendekode (parse string JSON) dan menyandikan (menghasilkan string JSON) dengan pustaka ArduinoJson menggunakan Arduino menggunakan Arduino dengan perisai Ethernet. Panduan ini juga berfungsi dengan modul Wi-Fi ESP8266 dan ESP32 dengan perubahan kecil.
Penting: tutorial ini hanya kompatibel dengan perpustakaan ArduinoJSON 5.13.5.
Apa itu JSON?
JSON adalah singkatan dari JavaScript Object Notation. JSON adalah desain standar terbuka berbasis teks yang ringan untuk bertukar data. JSON terutama digunakan untuk membuat cerita bersambung dan mentransmisikan data terstruktur melalui koneksi jaringan - mengirimkan data antara server dan klien. Ini sering digunakan dalam layanan seperti API (Application Programming Interfaces) dan layanan web yang menyediakan data publik.

Dasar-dasar sintaksis JSON
Di JSON, data disusun dengan cara tertentu. JSON menggunakan simbol seperti {},: "" [] dan memiliki sintaks berikut:

  • Data direpresentasikan dalam pasangan kunci / nilai
  • Tanda titik dua (:) memberikan nilai pada kunci
  • pasangan kunci / nilai dipisahkan dengan koma (,)
  • Kurung keriting menahan objek ({})
  • Kurung persegi menahan array ([])

Misalnya, untuk merepresentasikan data dalam JSON, pasangan kunci / nilai datang sebagai berikut:
{"key1":"value1", "key2":"value2", "key3":"value3"}
Contoh JSON
Dalam contoh dunia nyata, Anda mungkin ingin menyusun data tentang pengguna:
{"name":"Rui", "country": "Portugal", "age":24}
Atau dalam proyek IoT, Anda mungkin ingin menyusun data dari sensor Anda:
{"temperature":27.23, "humidity":62.05, "pressure":1013.25}

Di JSON, nilainya bisa berupa objek JSON lain (olahraga) atau array (hewan peliharaan). Sebagai contoh:
{
  "name": "Rui",
  "sports": {
    "outdoor": "hiking",
    "indoor": "swimming"
  },
  "pets": [
    "Max",
    "Dique"
  ]
}
Di sini kami menyusun data tentang pengguna dan kami memiliki beberapa kunci: "nama", "olahraga", dan "hewan peliharaan".
Nama memiliki nilai yang ditetapkan Rui. Rui dapat berlatih berbagai olahraga yang berkaitan dengan tempat mereka berlatih. Jadi, kami membuat objek JSON lain untuk menyimpan olahraga favorit Rui. Objek JSON ini adalah nilai kunci "olahraga".
Kunci "hewan peliharaan" memiliki larik yang berisi nama hewan peliharaan Rui dan memiliki nilai "Max" dan "Dique" di dalamnya.
Sebagian besar API mengembalikan data dalam JSON dan sebagian besar nilai adalah objek JSON sendiri. Contoh berikut menunjukkan data yang disediakan oleh API cuaca.
 
  "coord": 
     "lon":-8.61,
     "lat":41.15
  },
  "weather": 
     
      "id":803,
      "main":"Clouds",
      "description":"broken clouds",
      "icon":"04d"
    }
  ],
  "base":"stations",
  "main": 
    "temp":288.15,
    "pressure":1020,
    "humidity":93,
    "temp_min":288.15,
    "temp_max":288.15
  },
  (...)
}
API ini menyediakan banyak informasi. Misalnya, baris pertama menyimpan koordinat dengan garis bujur dan garis lintang.

Arduino dengan perisai Ethernet
Contoh-contoh dalam posting ini menggunakan Arduino dengan perisai Ethernet. Cukup pasang pelindung ke papan Arduino Anda dan hubungkan ke jaringan Anda dengan kabel RJ45 untuk membuat koneksi Internet (seperti yang ditunjukkan pada gambar di bawah).

Catatan: contoh yang diberikan dalam tutorial ini juga berfungsi dengan ESP8266 dan ESP32 dengan perubahan kecil.

Mempersiapkan IDE Arduino
Cara termudah untuk mendekode dan menyandikan string JSON dengan Arduino IDE menggunakan ArduinoJson library 5.13.5 yang dirancang untuk menjadi perpustakaan JSON paling intuitif, dengan jejak terkecil dan manajemen memori paling efisien untuk Arduino.

Ini telah ditulis dengan mempertimbangkan Arduino, tetapi tidak tertaut ke perpustakaan Arduino sehingga Anda dapat menggunakan perpustakaan ini dalam proyek C ++ lainnya. Ada juga situs web dokumentasi untuk perpustakaan dengan contoh-contoh dan dengan referensi API.

fitur

  • Penguraian JSON (komentar didukung)
  • Pengkodean JSON (dengan indentasi opsional)
  • API elegan, sangat mudah digunakan
  • Memperbaiki alokasi memori (nol malloc)
  • Tidak ada duplikasi data (salinan nol)
  • Portable (ditulis dalam C ++ 98)
  • Mandiri (tidak ada ketergantungan eksternal)
  • Jejak kaki kecil
  • Perpustakaan hanya header
  • Lisensi MIT

Cocok dengan

  • Papan Arduino: Uno, Due, Mini, Micro, Yun…
  • ESP8266, ESP32, dan papan WeMos
  • Teensy, papan RedBearLab, Intel Edison, dan Galileo
  • PlatformIO, Partikel dan Energia

Menginstal perpustakaan ArduinoJson
Untuk proyek ini, Anda perlu menginstal perpustakaan ArduinoJson di IDE Arduino Anda:

Decoding JSON - Parse string JSON
Mari kita mulai dengan mendekode / parsing string JSON berikutnya:
{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
Impor perpustakaan ArduinoJson:
#include <ArduinoJson.h>
Arduino JSON menggunakan kumpulan memori yang telah dialokasikan sebelumnya untuk menyimpan pohon JsonObject, ini dilakukan oleh StaticJsonBuffer. Anda dapat menggunakan ArduinoJson Assistant untuk menghitung ukuran buffer yang tepat, tetapi untuk contoh ini 200 sudah cukup.
StaticJsonBuffer<200> jsonBuffer;
Buat array char yang disebut json [] untuk menyimpan contoh string JSON:
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}"; 
Gunakan fungsi parseObject () untuk memecahkan kode / parsing string JSON ke JsonObject yang disebut root.
JsonObject& root = jsonBuffer.parseObject(json);
Untuk memeriksa apakah decoding / parsing berhasil, Anda dapat memanggil root.success ():
if(!root.success()) {
  Serial.println("parseObject() failed");
  return false;
}
Hasilnya bisa salah karena tiga alasan:

  • string JSON memiliki sintaks yang tidak valid;
  • string JSON tidak mewakili objek;
  • StaticJsonBuffer terlalu kecil - gunakan ArduinoJson Assistant untuk menghitung ukuran buffer.

Sekarang objek atau array ada di memori, Anda dapat mengekstrak data dengan mudah. Cara paling sederhana adalah dengan menggunakan root JsonObject:
const char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
Anda dapat menggunakan sensor variabel yang didekodekan, waktu, lintang atau bujur dalam logika kode Anda.

OpenWeatherMap API
Untuk contoh nyata menggunakan Arduino dengan perisai Ethernet, kami akan menggunakan API gratis dari OpenWeatherMap untuk meminta ramalan cuaca hari itu untuk lokasi yang Anda pilih.
Belajar menggunakan API adalah keterampilan yang hebat karena memungkinkan Anda mengakses berbagai informasi yang terus berubah, seperti harga saham saat ini, nilai tukar mata uang, berita terbaru, pembaruan lalu lintas, dan banyak lagi.

Menggunakan API
Paket gratis OpenWeatherMap menyediakan semua yang Anda butuhkan sebagai contoh. Untuk menggunakan API, Anda memerlukan kunci API, yang dikenal sebagai APIID. Untuk mendapatkan APIID:

  1. Buka browser dan pergi ke OpenWeatherMap
  2. Tekan tombol Daftar dan buat akun gratis
  3. Setelah akun Anda dibuat, Anda akan disajikan dengan dasbor yang berisi beberapa tab (lihat gambar di bawah)
  4. Pilih tab Kunci API dan salin Kunci unik Anda


Ini adalah kunci unik yang Anda perlukan untuk menarik informasi dari situs. Salin dan tempel kunci ini di suatu tempat, Anda akan membutuhkannya sebentar lagi.

Untuk menarik informasi tentang cuaca di lokasi yang Anda pilih, masukkan URL berikut dengan bagian dalam kurung keriting diganti dengan informasi lokasi yang Anda pilih dan kunci API unik Anda:
http://api.openweathermap.org/data/2.5/weather?q={your city},{your country code}&APPID={your API Key}
Ganti {kota Anda} dengan kota yang Anda inginkan datanya, {kode negara Anda} dengan kode negara untuk kota itu, dan {kunci API Anda} dengan kunci API unik yang kami temukan sebelumnya. Misalnya, URL API kami untuk kota Porto di Portugal, setelah diganti dengan detailnya, adalah:
http://api.openweathermap.org/data/2.5/weather?q=Porto,PT&APPID=801d2603e9f2e1c70e042e4------
Catatan: informasi lebih lanjut tentang penggunaan API untuk mendapatkan informasi cuaca tersedia di sini.

Salin URL Anda ke browser Anda dan itu akan memberi Anda banyak informasi yang sesuai dengan informasi cuaca lokal Anda.

Dalam kasus kami, ini mengembalikan cuaca di Porto, Portugal pada hari penulisan:
{
  "coord": {
    "lon": -8.61,
    "lat": 41.15
  },
  "weather": [
    {
      "id": 701,
      "main": "Mist",
      "description": "mist",
      "icon": "50d"
    }
  ],
  "base": "stations",
  "main": {
    "temp": 290.86,
    "pressure": 1014,
    "humidity": 88,
    "temp_min": 290.15,
    "temp_max": 292.15
  },
  (...)
}
Membuat Permintaan API dengan Arduino
Sekarang Anda memiliki URL yang mengembalikan data cuaca lokal Anda. Anda dapat mengotomatiskan tugas ini dan mengakses data itu dalam proyek Arduino atau ESP8266 Anda. Inilah skrip lengkap yang harus Anda unggah ke Arduino Anda dengan perisai Ethernet untuk mengembalikan suhu dalam Kelvin dan kelembaban:
/*
 * Rui Santos 
 * Complete Project Details https://randomnerdtutorials.com
 * Based on the Arduino Ethernet Web Client Example
 * and on the sketch "Sample Arduino Json Web Client" of the Arduino JSON library by Benoit Blanchon (bblanchon.github.io/ArduinoJson)
 */

#include <ArduinoJson.h>
#include <Ethernet.h>
#include <SPI.h>

EthernetClient client;

// Name address for Open Weather Map API
const char* server = "api.openweathermap.org";

// Replace with your unique URL resource
const char* resource = "REPLACE_WITH_YOUR_URL_RESOURCE";

// How your resource variable should look like, but with your own COUNTRY CODE, CITY and API KEY (that API KEY below is just an example):
//const char* resource = "/data/2.5/weather?q=Porto,pt&appid=bd939aa3d23ff33d3c8f5dd1";

const unsigned long HTTP_TIMEOUT = 10000;  // max respone time from server
const size_t MAX_CONTENT_SIZE = 512;       // max size of the HTTP response

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};

// The type of data that we want to extract from the page
struct clientData {
  char temp[8];
  char humidity[8];
};

// ARDUINO entry point #1: runs once when you press reset or power the board
void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ;  // wait for serial port to initialize
  }
  Serial.println("Serial ready");
  if(!Ethernet.begin(mac)) {
    Serial.println("Failed to configure Ethernet");
    return;
  }
  Serial.println("Ethernet ready");
  delay(1000);
}

// ARDUINO entry point #2: runs over and over again forever
void loop() {
  if(connect(server)) {
    if(sendRequest(server, resource) && skipResponseHeaders()) {
      clientData clientData;
      if(readReponseContent(&clientData)) {
        printclientData(&clientData);
      }
    }
  }
  disconnect();
  wait();
}

// Open connection to the HTTP server
bool connect(const char* hostName) {
  Serial.print("Connect to ");
  Serial.println(hostName);

  bool ok = client.connect(hostName, 80);

  Serial.println(ok ? "Connected" : "Connection Failed!");
  return ok;
}

// Send the HTTP GET request to the server
bool sendRequest(const char* host, const char* resource) {
  Serial.print("GET ");
  Serial.println(resource);

  client.print("GET ");
  client.print(resource);
  client.println(" HTTP/1.1");
  client.print("Host: ");
  client.println(host);
  client.println("Connection: close");
  client.println();

  return true;
}

// Skip HTTP headers so that we are at the beginning of the response's body
bool skipResponseHeaders() {
  // HTTP headers end with an empty line
  char endOfHeaders[] = "\r\n\r\n";

  client.setTimeout(HTTP_TIMEOUT);
  bool ok = client.find(endOfHeaders);

  if (!ok) {
    Serial.println("No response or invalid response!");
  }
  return ok;
}

// Parse the JSON from the input string and extract the interesting values
// Here is the JSON we need to parse
/*{
    "coord": {
        "lon": -8.61,
        "lat": 41.15
    },
    "weather": [
        {
            "id": 800,
            "main": "Clear",
            "description": "clear sky",
            "icon": "01d"
        }
    ],
    "base": "stations",
    "main": {
        "temp": 296.15,
        "pressure": 1020,
        "humidity": 69,
        "temp_min": 296.15,
        "temp_max": 296.15
    },
    "visibility": 10000,
    "wind": {
        "speed": 4.6,
        "deg": 320
    },
    "clouds": {
        "all": 0
    },
    "dt": 1499869800,
    "sys": {
        "type": 1,
        "id": 5959,
        "message": 0.0022,
        "country": "PT",
        "sunrise": 1499836380,
        "sunset": 1499890019
    },
    "id": 2735943,
    "name": "Porto",
    "cod": 200
}*/

bool readReponseContent(struct clientData* clientData) {
  // Compute optimal size of the JSON buffer according to what we need to parse.
  // See https://bblanchon.github.io/ArduinoJson/assistant/
  const size_t bufferSize = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 
      2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + 
      JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12) + 390;
  DynamicJsonBuffer jsonBuffer(bufferSize);

  JsonObject& root = jsonBuffer.parseObject(client);

  if (!root.success()) {
    Serial.println("JSON parsing failed!");
    return false;
  }

  // Here were copy the strings we're interested in using to your struct data
  strcpy(clientData->temp, root["main"]["temp"]);
  strcpy(clientData->humidity, root["main"]["humidity"]);
  // It's not mandatory to make a copy, you could just use the pointers
  // Since, they are pointing inside the "content" buffer, so you need to make
  // sure it's still in memory when you read the string

  return true;
}

// Print the data extracted from the JSON
void printclientData(const struct clientData* clientData) {
  Serial.print("Temp = ");
  Serial.println(clientData->temp);
  Serial.print("Humidity = ");
  Serial.println(clientData->humidity);
}

// Close the connection with the HTTP server
void disconnect() {
  Serial.println("Disconnect");
  client.stop();
}

// Pause for a 1 minute
void wait() {
  Serial.println("Wait 60 seconds");
  delay(60000);
}
Catatan: pastikan Anda mengganti variabel sumber daya dengan sumber daya URL OpenWeatherMap unik Anda:
const char* resource = "REPLACE_WITH_YOUR_URL_RESOURCE";
Memodifikasi kode untuk proyek Anda
Dalam contoh ini, Arduino melakukan permintaan HTTP GET ke layanan yang diinginkan (dalam hal ini OpenWeatherMap API), tetapi Anda bisa mengubahnya untuk meminta layanan web lainnya. Kami tidak akan menjelaskan kode Arduino baris demi baris.

Untuk proyek ini, penting bagi Anda untuk memahami apa yang perlu Anda ubah dalam kode Arduino untuk memecahkan kode / parsing setiap respons JSON. Ikuti tiga langkah selanjutnya.

LANGKAH # 1 - struct
Buat struktur data yang dapat menyimpan informasi yang ingin Anda ekstrak dari API. Dalam hal ini, kami ingin menyimpan suhu dan kelembaban di array char:
struct clientData {
  char temp[8];
  char humidity[8];
};
LANGKAH # 2 - ukuran JsonBuffer
Pergi ke Asisten ArduinoJson dan salin respons OpenWeatherMap API lengkap ke bidang Input.




Salin Ekspresi yang dihasilkan (lihat gambar sebelumnya), dalam kasus saya:
JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12)
Anda harus mengedit fungsi readReponseContent () dengan ukuran JsonBuffer yang dihasilkan dari ArduinoJson Assistant untuk mengalokasikan memori yang sesuai untuk mendekode respons JSON dari API:
bool readReponseContent(struct clientData* clientData) {
  const size_t bufferSize = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 
    2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + 
    JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12) + 390; 

  DynamicJsonBuffer jsonBuffer(bufferSize);
  JsonObject& root = jsonBuffer.parseObject(client);
Masih di dalam fungsi readReponseContent () Anda perlu menyalin variabel yang Anda butuhkan untuk proyek Anda ke data struct Anda:
strcpy(clientData->temp, root["main"]["temp"]);
strcpy(clientData->humidity, root["main"]["humidity"]);
LANGKAH # 3 - mengakses data yang diterjemahkan
Kemudian, Anda dapat dengan mudah mengakses data JSON yang didekode dalam kode Arduino Anda dan melakukan sesuatu dengannya. Dalam contoh ini kami hanya mencetak suhu di Kelvin dan kelembaban di monitor serial Arduino IDE:
void printclientData(const struct clientData* clientData) {
  Serial.print("Temp = ");
  Serial.println(clientData->temp);
  Serial.print("Humidity = ");
  Serial.println(clientData->humidity);
}
Demonstrasi
Buka monitor serial Arduino IDE pada kecepatan baud 9600 dan Anda akan melihat suhu di Kelvin dan persentase kelembaban yang dicetak di monitor Serial setiap 60 detik.

Anda dapat mengakses informasi lainnya dalam respons OpenWeatherMap API, tetapi untuk tujuan demonstrasi, kami hanya mendekodekan suhu dan kelembaban.

Encoding JSON - Menghasilkan string JSON
Mari kita pelajari cara menyandikan / membuat string JSON berikutnya:
{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
Anda dapat membaca dokumen tentang enconding di sini.
Impor perpustakaan ArduinoJson:
#include <ArduinoJson.h>
Arduino JSON menggunakan kumpulan memori yang telah dialokasikan untuk menyimpan pohon objek, ini dilakukan oleh StaticJsonBuffer. Anda dapat menggunakan ArduinoJson Assistant untuk menghitung ukuran buffer yang tepat, tetapi untuk contoh ini 200 sudah cukup.
StaticJsonBuffer<200> jsonBuffer;
Buat JsonObject yang disebut root yang akan menampung data Anda. Kemudian, tetapkan nilai gps dan 1351824120 masing-masing ke sensor dan kunci waktu:

JsonObject& root = jsonBuffer.createObject();
root["sensor"] = "gps";
root["time"] = 1351824120;
Sangat mungkin bahwa Anda perlu mencetak JSON yang dihasilkan di monitor Seri Anda untuk keperluan debugging, untuk melakukan itu:
root.printTo(Serial);
Setelah informasi Anda dikodekan dalam string JSON, Anda dapat mempostingnya ke perangkat lain atau layanan web seperti yang ditunjukkan pada contoh berikut.

Contoh pengkodean dengan Arduino dan Node-RED
Untuk contoh ini Anda perlu Node-RED atau perangkat lunak serupa yang dapat menerima permintaan HTTP POST. Anda dapat menginstal Node-RED di komputer Anda, tetapi saya sarankan menjalankan Node-RED di Raspberry Pi.

Membuat Flow
Dalam flow ini, Anda akan menerima permintaan HTTP POST dan mencetak data terima di jendela Debug. Ikuti 6 langkah berikutnya untuk membuat aliran Anda:
1) Buka perangkat lunak Node-RED di browser Anda

2. Seret node input HTTP dan node debug
3. 3) Edit the HTTP input by adding the POST method and the /json-post-example URL

4) Anda dapat meninggalkan pengaturan default untuk node debug

5) Hubungkan node Anda

6) Untuk menyimpan aplikasi Anda, Anda perlu mengklik tombol deploy di sudut kanan atas

Aplikasi Anda disimpan dan siap.
Kirim data JSON dengan Arduino
Setelah Node-RED disiapkan untuk menerima permintaan POST di URL / json-post-example, Anda dapat menggunakan contoh kode berikut pada Arduino dengan perisai Ethernet untuk mengirim data ke sana.
/*
 * Rui Santos 
 * Complete Project Details https://randomnerdtutorials.com
 * Based on the Arduino Ethernet Web Client Example
 * and on the sketch "Sample Arduino Json Web Client" of the Arduino JSON library by Benoit Blanchon (bblanchon.github.io/ArduinoJson)
 */

#include <ArduinoJson.h>
#include <Ethernet.h>
#include <SPI.h>

EthernetClient client;

// Replace with your Raspberry Pi IP address
const char* server = "REPLACE_WITH_YOUR_RASPBERRY_PI_IP_ADDRESS";

// Replace with your server port number frequently port 80 - with Node-RED you need to use port 1880
int portNumber = 1880;

// Replace with your unique URL resource
const char* resource = "/json-post-example";

const unsigned long HTTP_TIMEOUT = 10000;  // max respone time from server
const size_t MAX_CONTENT_SIZE = 512;       // max size of the HTTP response

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};

// ARDUINO entry point #1: runs once when you press reset or power the board
void setup() {
  Serial.begin(9600);
  while(!Serial) {
    ;  // wait for serial port to initialize
  }
  Serial.println("Serial ready");
  if(!Ethernet.begin(mac)) {
    Serial.println("Failed to configure Ethernet");
    return;
  }
  Serial.println("Ethernet ready");
  delay(1000);
}

// ARDUINO entry point #2: runs over and over again forever
void loop() {
  if(connect(server, portNumber)) {
    if(sendRequest(server, resource) && skipResponseHeaders()) {
      Serial.print("HTTP POST request finished.");
    }
  }
  disconnect();
  wait();
}

// Open connection to the HTTP server (Node-RED running on Raspberry Pi)
bool connect(const char* hostName, int portNumber) {
  Serial.print("Connect to ");
  Serial.println(hostName);

  bool ok = client.connect(hostName, portNumber);

  Serial.println(ok ? "Connected" : "Connection Failed!");
  return ok;
}

// Send the HTTP POST request to the server
bool sendRequest(const char* host, const char* resource) {
  // Reserve memory space for your JSON data
  StaticJsonBuffer<200> jsonBuffer;
  
  // Build your own object tree in memory to store the data you want to send in the request
  JsonObject& root = jsonBuffer.createObject();
  root["sensor"] = "dht11";
  
  JsonObject& data = root.createNestedObject("data");
  data.set("temperature", "30.1");
  data.set("humidity", "70.1");
  
  // Generate the JSON string
  root.printTo(Serial);
  
  Serial.print("POST ");
  Serial.println(resource);

  client.print("POST ");
  client.print(resource);
  client.println(" HTTP/1.1");
  client.print("Host: ");
  client.println(host);
  client.println("Connection: close\r\nContent-Type: application/json");
  client.print("Content-Length: ");
  client.print(root.measureLength());
  client.print("\r\n");
  client.println();
  root.printTo(client);

  return true;
}

// Skip HTTP headers so that we are at the beginning of the response's body
bool skipResponseHeaders() {
  // HTTP headers end with an empty line
  char endOfHeaders[] = "\r\n\r\n";

  client.setTimeout(HTTP_TIMEOUT);
  bool ok = client.find(endOfHeaders);

  if(!ok) {
    Serial.println("No response or invalid response!");
  }
  return ok;
}

// Close the connection with the HTTP server
void disconnect() {
  Serial.println("Disconnect");
  client.stop();
}

// Pause for a 1 minute
void wait() {
  Serial.println("Wait 60 seconds");
  delay(60000);
}
Catatan: pastikan Anda mengganti variabel server dengan alamat IP Raspberry Pi Anda:
const char* server = "REPLACE_WITH_YOUR_RASPBERRY_PI_IP_ADDRESS";
Memodifikasi kode untuk proyek Anda
Dalam contoh ini, Arduino melakukan permintaan HTTP POST ke Node-RED, tetapi Anda bisa mengubahnya untuk membuat permintaan layanan web atau server lain. Kami tidak akan menjelaskan kode Arduino baris demi baris. Untuk proyek ini, penting bagi Anda untuk memahami apa yang perlu Anda ubah dalam kode Arduino untuk menyandikan / membuat permintaan JSON.

fungsi sendRequest ()
Untuk proyek ini, Anda dapat memodifikasi fungsi sendRequest () dengan struktur data JSON Anda sendiri:
bool sendRequest(const char* host, const char* resource) {
Mulailah dengan memesan ruang memori untuk data JSON Anda. Anda dapat menggunakan ArduinoJson Assistant untuk menghitung ukuran buffer yang tepat, tetapi untuk contoh ini 200 sudah cukup.
StaticJsonBuffer<200> jsonBuffer;
Buat JsonObject yang disebut root yang akan menampung data Anda dan menetapkan nilai ke kunci Anda (dalam contoh ini kita memiliki kunci sensor):
JsonObject& root = jsonBuffer.createObject();
root["sensor"] = "dht11";
Untuk menyimpan data di dalam array, Anda melakukan hal berikut:
JsonObject& data = root.createNestedObject("data");
data.set("temperature", "30.1");
data.set("humidity", "70.1");
Cetak string JSON yang dihasilkan di monitor serial Arduino IDE untuk keperluan debugging:
root.printTo(Serial);
Fungsi sendRequest () lainnya adalah permintaan POST.
client.print("POST ");
client.print(resource);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(host);
client.println("Connection: close\r\nContent-Type: application/json");
client.print("Content-Length: ");
client.print(root.measureLength());
client.print("\r\n");
client.println();
root.printTo(client);
Perhatikan bahwa Anda bisa menggunakan root.measureLength () untuk menentukan panjang JSON yang Anda hasilkan. Root.printTo (klien) mengirim data JSON ke klien Ethernet.

Demonstrasi
Buka monitor serial Arduino IDE dengan kecepatan baud 9600 dan Anda akan melihat objek JSON yang dicetak dalam monitor serial setiap 60 detik.

Di tab debug Node-RED Anda akan melihat objek JSON yang sama diterima setiap 60 detik:

Terakhir, Anda membuat fungsi di Node-RED yang melakukan sesuatu yang berguna dengan data yang diterima, tetapi untuk tujuan demonstrasi, kami hanya mencetak data sampel.