Pada percobaan ini dilakukan pengiriman data telemetri dari ESP32 ke Thingsboard. Sensor yang dipakai adalah sakelar on-off. Percobaan ini adalah bagian dari pembuatan sistem IoT (Internet of Things) yang terdiri dari beberapa ESP32 dan software ThingsBoard.
Pada percobaan ini , tidak semua komponen ThingsBoard dipakai. Yang dipakai adalah sebagai berikut
Devices: menggunakan ESP32 dan sakelar sebagas sensor
Protokol HTTP sebagai ThingsBoard Transports
ThingsBoard Core
SQL Database
External Systems
Aliran data pada sistem yang dibuat adalah sebagai berikut:
Sakelar bertindak sebagai sensor. Besaran yang dihasilkan oleh sakelar adalah 0 dan 1. ESP32 membaca status sensor setiap interval tertentu, dan kemudian mengirimkannya ke ThingsBoard menggunakan protokol HTTP. Data ini kemudian disimpan di Database.
Data dari database ini dapat ditampilkan menggunakan Dashboard pada Thingsboard, dan juga dapat diambil oleh aplikasi eksternal menggunakan REST API (REpresentational State Transfer Application Program Interface)
Hardware yang dipakai adalah sebagai berikut:
ESP32 Lolin Wemos
2 buah sakelar. Pada percobaan ini digunakan sakelar geser SPDT dan push button.
ESP32 Lolin Wemos
Daftar pin ESP32 yang dipakai adalah sebagai berikut
pin 13 sebagai input digital, diberi nama SW0. Input active low.
pin 15 sebagai input digital, diberi nama SW1. Input active low.
Berikut ini foto rangkaian setelah dirakit
Perangkat lunak yang dipakai
Arduino versi 1.8.19 (Windows)
ThingsBoard versi 3.3.4.1
Ubuntu Linux 20.04.04 LTS
Wireshark versi 3.02
Setting ThingsBoard
[under construction]
Perangkat Lunak ESP32
Perangkat lunak ESP32 dibuat dengan Arduino
Library yang dipakai di Arduino adalah sebagai berikut
// demo switch telemetry to Thingsboard
// adapted from https://thingsboard.io/docs/samples/esp32/gpio-control-pico-kit-dht22-sensor/
#include <WiFi.h> // WiFi control for ESP32
#include <ThingsBoard.h> // ThingsBoard SDK
// onboard LED
#define BUILTIN_LED 22
// switch pin definition
#define SW0 13
#define SW1 15
// Helper macro to calculate array size
// #define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
// WiFi access point
#define WIFI_AP_NAME "ACCESS_POINT_NAME"
// WiFi password
#define WIFI_PASSWORD "ACCESS_POINT_PASSWORD"
// See https://thingsboard.io/docs/getting-started-guides/helloworld/
// to understand how to obtain an access token
#define TOKEN "QdqSrxBAjBvxAoJyeoXN"
// ThingsBoard server instance.
#define THINGSBOARD_SERVER "192.168.0.90"
// Baud rate for debug serial
#define SERIAL_DEBUG_BAUD 115200
// Initialize ThingsBoard client
WiFiClient espClient;
// Initialize ThingsBoard instance
ThingsBoard tb(espClient);
// the Wifi radio's status
int status = WL_IDLE_STATUS;
// main application loop delay (ms)
int quant = 20;
// Period of sending a temperature/humidity data.
int send_delay = 2000;
// Time passed after telemetry data was sent, milliseconds.
int send_passed = 0;
char mac_str[20]; // storing MAC address string
byte mac_byte[6]; // storing MAC address bytes
int led_counter = 0; //blinking built int led
// Setup an application
void setup() {
pinMode(SW0, INPUT_PULLUP); // input switch
pinMode(SW1, INPUT_PULLUP);
pinMode(BUILTIN_LED , OUTPUT);
// Initialize serial for debugging
Serial.begin(SERIAL_DEBUG_BAUD);
WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
InitWiFi();
WiFi.macAddress(mac_byte);
sprintf(mac_str, "%02x%02x%02x%02x%02x%02x", mac_byte[0], mac_byte[1], mac_byte[2], mac_byte[3], mac_byte[4], mac_byte[5]);
Serial.print("ESP board MAC address: ");
Serial.println(WiFi.macAddress());
Serial.print("ESP board IP address: ");
Serial.println(WiFi.localIP());
}
// Main application loop
void loop() {
delay(quant);
send_passed += quant;
// Reconnect to WiFi, if needed
if (WiFi.status() != WL_CONNECTED) {
reconnect();
return;
}
// Reconnect to ThingsBoard, if needed
if (!tb.connected()) {
// Connect to the ThingsBoard
Serial.print("Connecting to: ");
Serial.print(THINGSBOARD_SERVER);
Serial.print(" with token ");
Serial.println(TOKEN);
if (!tb.connect(THINGSBOARD_SERVER, TOKEN)) {
Serial.println("Failed to connect");
return;
}
}
// Check if it is a time to send switch data
if (send_passed > send_delay) {
int switch0, switch1;
switch0 = digitalRead(SW0);
switch1 = digitalRead(SW1);
Serial.print("Sending telemetry data...");
Serial.print(" SW0:");
Serial.print(switch0);
Serial.print(" SW1:");
Serial.println(switch1);
tb.sendTelemetryInt("switch00", switch0);
tb.sendTelemetryInt("switch01", switch1);
send_passed = 0;
}
// Process messages
tb.loop();
led_counter++; // LED blink at 1 Hz
if (led_counter > 50) {
led_counter = 0;
}
if (led_counter > 25) {
digitalWrite(BUILTIN_LED , LOW);
} else {
digitalWrite(BUILTIN_LED , HIGH);
}
}
void InitWiFi()
{
Serial.println("Connecting to AP ...");
// attempt to connect to WiFi network
WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Connected to AP");
}
void reconnect() {
// Loop until we're reconnected
status = WiFi.status();
if ( status != WL_CONNECTED) {
WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Connected to AP");
}
}
Pengecekan Telemetri
Setelah sistem dirakit dan ESP32 diprogram, perlu dilakukan pengecekan apakah sistem berfungsi dengan baik. Pengecekan pengiriman data telemetri dilakukan dengan cara:
Memantau output dari port serial ESP32
Mengecek data telemetri di server Thingsboard
Berikut ini output dari serial monitor ESP32.
19:45:30.745 -> Connecting to AP ...
19:45:31.225 -> ......Connected to AP
19:45:33.738 -> ESP board MAC address: 3C:71:BF:03:41:4C
19:45:33.738 -> ESP board IP address: 192.168.0.124
19:45:33.773 -> Connecting to: 192.168.0.90 with token QdqSrxBAjBvxAoJyeoXN
19:45:35.798 -> Sending telemetry data... SW0:1 SW1:1
19:45:37.819 -> Sending telemetry data... SW0:1 SW1:1
19:45:39.850 -> Sending telemetry data... SW0:1 SW1:1
Dari output tersebut dapat disimpulkan:
ESP32 berhasil terhubung ke access point
ESP32 berhasil mendapatkan IP address
ESP32 berhasil mengirim data ke ThingsBoard
Untuk mengecek data yang masuk ke server, prosedurnya sebagai berikut:
Login ke ThingsBoard sebagai tenant. username: tenant@thingsboard.org, password: tenant (jika belum diganti)
Klik di “Devices”
Klik di “ESP32 Dual Switch”
Klik di “Latest telemetry”
Jika pengiriman data normal, maka status sakelar terakhir akan muncul di Device details, seperti gambar berikut ini.
Angka di kolom “Value” akan sesuai dengan status sakelar. Pada percobaan ini pengiriman data dilakukan dengan interval 2 detik, jadi selambatnya dalam 2 detik status sakelar terakhir akan masuk.
Dashboard di ThingsBoard
Setelah data dicek masuk, kita dapat membuat dashboard di Thingsboard untuk menampilkan data dari sensor. Berikut ini contoh tampilan dashboard.
Pengambilan Data Telemetri Dengan REST API
Data telemetri di server ThingsBoard dapat diambil menggunakan REST API dari aplikasi lain.
Pada percobaan ini data diambil dengan menggunakan software ‘curl’ di Ubuntu Linux.
Berikut ini contoh program sederhana untuk membuat LED onboard berkedip di pada ESP32 Lolin32 Lite. Sistem operasi yang digunakan adalah FreeRTOS. IDE menggunakan Arduino. Delay menggunakan delay dari FreeRTOS, dengan fungsi vTaskDelayUntil().
ESP32 Lolin32 Lite (atas) dan ESP32 DevkitC (bawah)
Lampu berkedip dengan frekuensi 1 Hz. Suatu angka (counter) dikirim melalui port serial setiap detik. Kecepatan port serial adalah 115200 bps
#define LED_BUILTIN 22 # Wemos Lolin32 onboard LED di pin 22
void setup() {
Serial.begin(115200);
Serial.println("Start");
pinMode(LED_BUILTIN, OUTPUT);
if (1)
xTaskCreate(
TaskBlinker, /* Task function. */
"TaskBlinker", /* String with name of task. */
1000, /* Stack size in bytes. */
NULL, /* Parameter passed as input of the task */
1, /* Priority of the task. */
NULL); /* Task handle. */
}
// the loop function runs over and over again forever
void loop() {
delay(10000);
}
void TaskBlinker(void *parameter) {
int counter = 0;
TickType_t xLastWakeTime;
const TickType_t xPeriod = 500 ;
xLastWakeTime = xTaskGetTickCount();
while (1) {
digitalWrite(LED_BUILTIN, HIGH);
vTaskDelayUntil(&xLastWakeTime, xPeriod);
digitalWrite(LED_BUILTIN, LOW);
vTaskDelayUntil(&xLastWakeTime, xPeriod);
Serial.print("Counter:");
Serial.println(counter);
counter++;
}
}
Pada percobaan ini dilakukan pengukuran kadar gas CO2 (karbon dioksida) di udara dengan sensor CCS811.
Mikrokontroler yang digunakan adalah modul ESP32 Lolin32 Lite
Modul CJMCU-811 tidak dilengkapi sensor temperatur & kelembaban, sehingga perlu tambahan sensor BME280.
Kompensasi temperatur dan kelembaban untuk sensor CCS811 menggunakan sensor BME280
Berikut ini foto perangkat keras yang digunakan
Berikut ini rangkaian sistem mikroprosesornya
Berikut ini source code program yang dipakai (dengan Arduino)
// https://bitbucket.org/christandlg/bmx280mi/src/master/examples/BMx280_I2C/BMx280_I2C.ino
// BMx280_I2C.ino
//
// shows how to use the BMP280 / BMx280 library with the sensor connected using I2C.
//
// Copyright (c) 2018 Gregor Christandl
//
// connect the AS3935 to the Arduino like this:
//
// Arduino - BMP280 / BME280
// 3.3V ---- VCC
// GND ----- GND
// SDA ----- SDA
// SCL ----- SCL
// some BMP280/BME280 modules break out the CSB and SDO pins as well:
// 5V ------ CSB (enables the I2C interface)
// GND ----- SDO (I2C Address 0x76)
// 5V ------ SDO (I2C Address 0x77)
// other pins can be left unconnected.
// https://github.com/adafruit/Adafruit_CCS811
// https://github.com/adafruit/Adafruit_CCS811/blob/master/examples/CCS811_test/CCS811_test.ino
#include "Adafruit_CCS811.h"
Adafruit_CCS811 ccs;
#include <Arduino.h>
#include <Wire.h>
#define I2C_SDA 15
#define I2C_SCL 13
#include <BMx280I2C.h>
#define I2C_ADDRESS 0x76
//create a BMx280I2C object using the I2C interface with I2C Address 0x76
BMx280I2C bmx280(I2C_ADDRESS);
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
delay(1000);
//wait for serial connection to open (only necessary on some boards)
while (!Serial);
// Wire.begin();
Wire.begin(I2C_SDA, I2C_SCL);
I2C_Scan() ; // just for verifying
// check CCS811
Serial.println("CCS811 test");
if (!ccs.begin()) {
Serial.println("Failed to start sensor! Please check your wiring.");
while (1);
} else {
Serial.println("CCS811 ready");
}
//begin() checks the Interface, reads the sensor ID (to differentiate between BMP280 and BME280)
//and reads compensation parameters.
if (!bmx280.begin())
{
Serial.println("begin() failed. check your BMx280 Interface and I2C Address.");
while (1);
}
if (bmx280.isBME280())
Serial.println("sensor is a BME280");
else
Serial.println("sensor is a BMP280");
//reset sensor to default parameters.
bmx280.resetToDefaults();
//by default sensing is disabled and must be enabled by setting a non-zero
//oversampling setting.
//set an oversampling setting for pressure and temperature measurements.
bmx280.writeOversamplingPressure(BMx280MI::OSRS_P_x16);
bmx280.writeOversamplingTemperature(BMx280MI::OSRS_T_x16);
//if sensor is a BME280, set an oversampling setting for humidity measurements.
if (bmx280.isBME280())
bmx280.writeOversamplingHumidity(BMx280MI::OSRS_H_x16);
}
void loop() {
float temperature = 0;
float pressure = 0;
float humidity = 60; // default humidity
float co2 = 0;
float tvoc = 0;
delay(1000);
//start a measurement
if (!bmx280.measure())
{
Serial.println("could not start measurement, is a measurement already running?");
return;
}
//wait for the measurement to finish
do
{
delay(100);
} while (!bmx280.hasValue());
// Serial.print("Pressure: "); Serial.println(bmx280.getPressure());
// Serial.print("Pressure (64 bit): "); Serial.println(bmx280.getPressure64());
// Serial.print("Temperature: "); Serial.println(bmx280.getTemperature());
pressure = bmx280.getPressure();
temperature = bmx280.getTemperature();
//important: measurement data is read from the sensor in function hasValue() only.
//make sure to call get*() functions only after hasValue() has returned true.
if (bmx280.isBME280())
{
// Serial.print("Humidity: ");
// Serial.println(bmx280.getHumidity());
humidity = bmx280.getHumidity();
}
ccs.setEnvironmentalData( humidity, temperature );
if (ccs.available()) {
if (!ccs.readData()) {
// Serial.print("CO2: ");
//Serial.print(ccs.geteCO2());
//Serial.print("ppm, TVOC: ");
//Serial.println(ccs.getTVOC());
co2 = ccs.geteCO2();
tvoc = ccs.getTVOC();
}
}
Serial.print("Temp\t");
Serial.print(temperature);
Serial.print("\t");
Serial.print("Humidity\t");
Serial.print(humidity);
Serial.print("\t");
Serial.print("Pressure\t");
Serial.print(pressure);
Serial.print("\t");
Serial.print("CO2\t");
Serial.print(co2);
Serial.print("\t");
Serial.print("TVOC\t");
Serial.print(tvoc);
Serial.println("");
}
void I2C_Scan() {
byte error, address;
int nDevices;
Serial.println("I2C Scanning...");
nDevices = 0;
for (address = 1; address < 127; address++ ) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address < 16) {
Serial.print("0");
}
Serial.println(address, HEX);
nDevices++;
}
else if (error == 4) {
Serial.print("Unknow error at address 0x");
if (address < 16) {
Serial.print("0");
}
Serial.println(address, HEX);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found\n");
}
else {
Serial.println("done\n");
}
}
Berikut ini software versi lain
// pengukuran CO2, tanpa wifi
// https://bitbucket.org/christandlg/bmx280mi/src/master/examples/BMx280_I2C/BMx280_I2C.ino
// BMx280_I2C.ino
//
// shows how to use the BMP280 / BMx280 library with the sensor connected using I2C.
//
// Copyright (c) 2018 Gregor Christandl
//
// connect the AS3935 to the Arduino like this:
//
// Arduino - BMP280 / BME280
// 3.3V ---- VCC
// GND ----- GND
// SDA ----- SDA
// SCL ----- SCL
// some BMP280/BME280 modules break out the CSB and SDO pins as well:
// 5V ------ CSB (enables the I2C interface)
// GND ----- SDO (I2C Address 0x76)
// 5V ------ SDO (I2C Address 0x77)
// other pins can be left unconnected.
// https://github.com/adafruit/Adafruit_CCS811
// https://github.com/adafruit/Adafruit_CCS811/blob/master/examples/CCS811_test/CCS811_test.ino
#include "Adafruit_CCS811.h"
Adafruit_CCS811 ccs;
#include <Arduino.h>
#include <Wire.h>
#include <BMx280I2C.h>
#include "ClosedCube_HDC1080.h"
#define I2C_SDA 15
#define I2C_SCL 13
#define I2C_ADDRESS 0x76
#define LED_ONBOARD 22
const char *ssid = "First";
const char *password = "satu2345";
//create a BMx280I2C object using the I2C interface with I2C Address 0x76
BMx280I2C bmx280(I2C_ADDRESS);
ClosedCube_HDC1080 hdc1080;
char mac_str[20];
byte mac_byte[6];
void setup() {
pinMode(LED_ONBOARD, OUTPUT);
// put your setup code here, to run once:
Serial.begin(9600);
delay(1000);
//wait for serial connection to open (only necessary on some boards)
while (!Serial);
// Wire.begin();
Wire.begin(I2C_SDA, I2C_SCL);
I2C_Scan() ; // just for verifying
// check CCS811
Serial.println("CCS811 test");
if (!ccs.begin()) {
Serial.println("Failed to start sensor! Please check your wiring.");
while (1);
} else {
Serial.println("CCS811 ready");
}
SetupBME280();
SetupHDC1080();
}
void SetupBME280() {
//begin() checks the Interface, reads the sensor ID (to differentiate between BMP280 and BME280)
//and reads compensation parameters.
if (!bmx280.begin())
{
Serial.println("begin() failed. check your BMx280 Interface and I2C Address.");
while (1);
}
if (bmx280.isBME280())
Serial.println("sensor is a BME280");
else
Serial.println("sensor is a BMP280");
//reset sensor to default parameters.
bmx280.resetToDefaults();
//by default sensing is disabled and must be enabled by setting a non-zero
//oversampling setting.
//set an oversampling setting for pressure and temperature measurements.
bmx280.writeOversamplingPressure(BMx280MI::OSRS_P_x16);
bmx280.writeOversamplingTemperature(BMx280MI::OSRS_T_x16);
//if sensor is a BME280, set an oversampling setting for humidity measurements.
if (bmx280.isBME280())
bmx280.writeOversamplingHumidity(BMx280MI::OSRS_H_x16);
}
void SetupHDC1080() {
hdc1080.begin(0x40);
Serial.println("HDC1080");
Serial.print("Manufacturer ID=0x");
Serial.println(hdc1080.readManufacturerId(), HEX); // 0x5449 ID of Texas Instruments
Serial.print("Device ID=0x");
Serial.println(hdc1080.readDeviceId(), HEX); // 0x1050 ID of the device
hdc1080.setResolution(HDC1080_RESOLUTION_11BIT, HDC1080_RESOLUTION_11BIT);
}
void loop() {
float temperature = 0;
float pressure = 0;
float humidity = 60; // default humidity
float co2 = 0;
float tvoc = 0;
if (1) {
//start a measurement
if (!bmx280.measure())
{
Serial.println("could not start measurement, is a measurement already running?");
}
do
{
delay(100);
} while (!bmx280.hasValue());
pressure = bmx280.getPressure();
temperature = bmx280.getTemperature();
//important: measurement data is read from the sensor in function hasValue() only.
//make sure to call get*() functions only after hasValue() has returned true.
if (bmx280.isBME280())
{
humidity = bmx280.getHumidity();
}
}
ccs.setEnvironmentalData( humidity, temperature ); // kompensasi humidity & temperature
if (ccs.available()) {
if (!ccs.readData()) {
// Serial.print("CO2: ");
//Serial.print(ccs.geteCO2());
//Serial.print("ppm, TVOC: ");
//Serial.println(ccs.getTVOC());
co2 = ccs.geteCO2();
tvoc = ccs.getTVOC();
}
}
Serial.print("Temp\t");
Serial.print(temperature);
Serial.print("\t");
Serial.print("Humidity\t");
Serial.print(humidity);
Serial.print("\t");
Serial.print("Pressure\t");
Serial.print(pressure);
Serial.print("\t");
Serial.print("CO2\t");
Serial.print(co2);
Serial.print("\t");
Serial.print("TVOC\t");
Serial.print(tvoc);
Serial.println("");
delay(500);
digitalWrite(LED_ONBOARD, HIGH);
delay(500);
digitalWrite(LED_ONBOARD, LOW);
}
void I2C_Scan() {
byte error, address;
int nDevices;
Serial.println("I2C Scanning...");
nDevices = 0;
for (address = 1; address < 127; address++ ) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address < 16) {
Serial.print("0");
}
Serial.println(address, HEX);
nDevices++;
}
else if (error == 4) {
Serial.print("Unknow error at address 0x");
if (address < 16) {
Serial.print("0");
}
Serial.println(address, HEX);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found\n");
}
else {
Serial.println("done\n");
}
}
Berikut ini contoh tampilan outputnya
13:08:18.861 -> I2C Scanning...
13:08:18.861 -> I2C device found at address 0x5A
13:08:18.896 -> I2C device found at address 0x76
13:08:18.931 -> done
13:08:18.931 ->
13:08:18.931 -> CCS811 test
13:08:19.101 -> CCS811 ready
13:08:19.101 -> sensor is a BME280
13:08:19.135 -> HDC1080
13:08:19.135 -> Manufacturer ID=0xFFFF
13:08:19.135 -> Device ID=0xFFFF
13:08:19.239 -> Temp 30.83 Humidity 50.10 Pressure 87156.00 CO2 0.00 TVOC 0.00
13:08:20.368 -> Temp 30.83 Humidity 50.29 Pressure 91715.00 CO2 0.00 TVOC 0.00
13:08:21.464 -> Temp 30.84 Humidity 50.37 Pressure 91714.00 CO2 0.00 TVOC 0.00
Berikut ini percobaan menghubungkan ESP32 Lolin32 Lite dengan display LCD 20×4. Antar muka menggunakan komunikasi serial I2C. LCD 20×4 menggunakan protokol serial, sehingga perlu modul I2C. ESP32 menggunakan tegangan 3,3 volt, sedangkan LCD 20×4 menggunakan tegangan 5 volt, sehingga perlu level converter antara I2C di ESP32 dan I2C di modul PCF8752. Pada LCD 20×4 dipasang modul serial to paralel PCF8574 untuk menghubungkan protokol I2C ke paralel input/output pada LCD.
ESP32 Lolin-32 dari WEMOS
Berikut ini blok diagram sistem
Skema Rangkaian
Berikut ini skema rangkaian lengkap.
Skema rangkaian ESP32 Lolin32 Lite dengan LCD I2C
Arduino Nano pada rangkaian tersebut hanya berfungsi untuk memberikan tegangan 5 volt, karena pada ESP32 Lolin32 Lite tidak ada pin 5V. Jika menggunakan ESP32 Devkit mestinya lebih enak, karena di ESP32 Devkit ada pin 5V. Tegangan 5V ini dapat diganti dengan regulator / adaptor 5V lain.
Komunikasi I2C
ESP32 tidak memiliki pin I2C yang spesifik, jadi kita dapat memilih pin mana yang dipakai sebagai pin untuk I2C (SDA dan SCL). Pada percobaan ini dipilih pin 15 untuk SDA dan pin 13 untuk SCL. Konfigurasi ini dimasukkan di software dalam bentuk parameter I2C_SDA dan I2C SCL yang didefinisikan di awal software.
Semua pin pada ESP32 termasuk pin I2C menggunakan tegangan kerja 3 volt, sedangkan display menggunakan tegangan 5 volt. Untuk itu tegangan kerja PCF8574 disamakan dengan display LCD (5 volt), sedangkan tegangan I2C diubah dari 3 volt (di ESP32) menjadi 5 volt (di PCF8574). Komunikasi harus 2 arah, karena protokol I2C mensyaratkan slave menjawab setiap kali ada pengiriman data. Untuk itu pada jalur I2C digunakan komponen ‘bi directional level converter‘.
Power Supply
Sumber daya ESP32 menggunakan USB charger 5 volt. Pada board ESP32 sudah ada regulator 3,3 volt yang mengubah tegangan supply USB 5 volt menjadi 3,3 volt.
Sumber daya 5 volt untuk LCD dan PCF8574 diberikan melalui sebuah modul Arduino Nano yang dipakai. Seharusnya dapat menggunakan power supply 5 volt apa saja. Kebetulan saja yang tersedia saat ini adalah board Arduino Nano.
Software
Berikut ini software yang dipakai untuk menghasilkan tampilan.
// Demo LCD dengan ESP32 I2C
#include <LiquidCrystal_I2C.h>
// https://www.makerguides.com/character-i2c-lcd-arduino-tutorial/
// Include the libraries:
// LiquidCrystal_I2C.h: https://github.com/johnrickman/LiquidCrystal_I2C
#include <Wire.h> // Library for I2C communication
#include <LiquidCrystal_I2C.h> // Library for LCD
//LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2); // Change to (0x27,16,2) for 16x2 LCD.
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4);
#define I2C_SDA 15
#define I2C_SCL 13
#define LED_BUILTIN 22 // LED built in pada ESP32 Lolin32 Lite
void setup() {
Wire.begin(I2C_SDA, I2C_SCL);
// Initiate the LCD:
lcd.init();
lcd.backlight();
Serial.begin(115200);
Serial.println("\nLCD Test");
pinMode(LED_BUILTIN, OUTPUT);
}
int counter = 0;
void loop() {
// Print 'Hello World!' on the first line of the LCD:
lcd.setCursor(0, 0);
lcd.print("Elektrologi");
lcd.setCursor(0, 1);
lcd.print("iptek.web.id");
lcd.setCursor(0, 2);
lcd.print("ESP32 Lolin32 Lite");
lcd.setCursor(0, 3);
lcd.print("31 Januari 2021");
lcd.setCursor(12, 0);
lcd.print(counter);
Serial.print("Send data: ");
Serial.println(counter);
delay(500);
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500); // wait for a second
digitalWrite(LED_BUILTIN, LOW);
counter++;
}
Selama ini saya menggunakan ESP32 dari model Lolin32. Sebagai alternatif, saya mencari board ESP32 dengan ukuran mirip dengan Lolin32, supaya dapat dipasang juga di breadboard. Hal ini penting karena saya sering melakukan percobaan di atas breadboard, dan mesti siap-siap juga kalau-kalau Lolin32 tidak ada lagi. Lolin32 mini sudah tidak diproduksi lagi oleh Wemos, sehingga bisa saja suatu hari tidak ada lagi.
Setelah cari sana-sini, kandidat board yang cocok adalah ESP32 DevkitC clone, atau disebut juga di pasaran sebagai NodeMCU ESP32.
Penampakan
Berikut ini tampak atas dari ESP32 DevkitC.
ESP32 DevkitC Clone tampak atas
Berikut ini tampak bawah dari ESP32 DevkitC
ESP32 DevkitC Clone tampak bawah
Berikut ini ESP32 DevkitC di atas breadboard. ESP32 ini tidak terlalu lebar, sehingga cocok untuk percobaan dengan breadboard.
ESP32 DevkitC Clone di breadboard
Ukuran board ESP32 ini mirip sekali dengan Lolin32 (Wemos). Berikut ini perbandingan lebar antara DevkitC (kiri) dan Lolin32 Lite (kanan).
ESP32 DevkitC Clone dan Lolin32
Berikut ini perbandingan panjang antara DevkitC (bawah) dan Lolin32 Lite (atas).
ESP32 Lolin32 Lite (atas) dan ESP32 DevkitC (bawah)
Pinout
Berikut ini daftar pin pada ESP32 DevkitC. Total ada 38 pin yang dikeluarkan dari ESP32, namun ada 8 pin yang sifatnya internal, jadi praktis tidak dapat dipakai untuk aplikasi normal.
Pada board ESP32 tersebut terdapat sebuah LED yang dapat dikendalikan melalui GPIO2. Berikut ini contoh membuat LED kedip dengan modifikasi software Blink.ino bawaan Arduino. Mesti ditambahkan baris ‘#define LED_BUILTIN 2’ supaya dapat mengakses pin GPIO yang benar.
#define LED_BUILTIN 2
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
Pada board DevkitC yang asli tidak ada LED on board, sedangkan pada board clone ini ada LEDnya. Keberadaan LED ini cukup membantu untuk melakukan percobaan sederhana dan debugging sederhana.
Keuntungan DevkitC ini dibandingkan Lolin32 adalah tersedia tegangan 5 volt, tidak hanya 3 volt. Tegangan 5 volt ini perlu untuk beberapa sensor yang hanya dapat bekerja di tegangan 5 volt.
Mikrokontroler ESP32 dapat berkirim data melalui jaringan dengan komputer lain. Untuk menjaga kerahasiaan data yang dikirim tersebut, maka perlu dilakukan enkripsi data yang dikirim. Pada tulisan ringkas ini akan ditinjau library enkripsi data yang kompatibel antara ESP32 dan Windows, sehingga memungkinkan pertukaran data dengan enkripsi antara keduanya.
menggunakan AES-128 dengan mode ECB (Electronic Codebook). Seperti diketahui, mode ECB ini punya banyak kelemahan, sehingga kalau mau lebih profesional kita mesti menggunakan mode lain seperti CBC (Cipher Block Chaining).
ukuran data harus kelipatan 16 byte. Jika ukuran data lebih dari 16 byte, maka fungsi mesti dipanggil berulangkali, dan kalau ukuran data bukan kelipatan 16, perlu dilakukan padding (pengisian) supaya menjadi kelipatan 16.
Selanjutnya bagaimana supaya data yang dienkripsi di ESP32 dapat dibaca di Windows? Untuk itu perlu diinstall library yang sama / kompatibel di Windows. Untuk mudahnya, pada contoh ini akan digunakan library yang sama supaya tidak perlu mengubah source code.
Library yang dipakai pada ESP32 tersebut adalah Mbed TLS(https://tls.mbed.org/) . Library Mbed TLS tersedia dalam bentuk source code, jadi dapat juga dicompile sendiri untuk platform lain. Untuk Windows, sudah ada library yang sudah dicompile, jadi tinggal diinstall saja. Versi yang tersedia untuk compiler GNU based (Cygwin, MinGW) dan Visual Studio.
Pada contoh berikut ini akan dipakai IDE Netbeans 8.2 dengan compiler Cygwin. Netbeans terbaru adalah versi 11, namun Netbeans yang sudah support C/C++ baru sampai versi 8.2, jadi versi 11 belum mendukung bahasa C / C++.
Library perlu diinstall dari program Setup dari Cygwin. Jalankan program instalasi Cygwin (setup-x86_64.exe), kemudian masuk ke menu pemilihan packages. Pilih View “Full”, dan Search di “mbedtls”. Pilih untuk install library mbedtls dan mbedtls-devel.
Cygwin Mbed TLS library
Nama library untuk Mbed TLS adalah libmbedcrypto. Selanjutnya tambahkan library tersebut di setting project dari Netbeans
Berikut ini tampilan library di Netbeans. Lokasi library tersebut adalah di C:/cygwin64/lib/libmbedcrypto.dll.a
/* * enkripsi data dengan AES-CBC * modifikasi dari https://everythingesp.com/esp32-arduino-tutorial-encryption-aes128-in-ecb-mode/ * menggunakan library mbedtls dari cygwin */ #include "mbedtls/aes.h" #include "string.h" #include "stdio.h"
printf("\n\nDeciphered text:\n"); for (int i = 0; i < 16; i++) { printf("%c", (char) decipheredTextOutput[i]); //printf("%c", (char) decipheredTextOutput[i]); } return 0; }
Perubahan yang dilakukan:
memindahkan isi setup() di Arduino ke main() di Netbeans
menambahkan header file stdio.h dan string.h
mengganti Serial.print() dengan printf()
Output di ESP32 Arduino
Output Windows 32
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:1 load:0x3fff0018,len:4 load:0x3fff001c,len:928 ho 0 tail 12 room 4 load:0x40078000,len:8740 load:0x40080400,len:5788 entry 0x4008069c Original plain text: Tech tutorials x Ciphered text: 567a3b23b683d8488d5d40d2a56e31d2 Deciphered text: Tech tutorials x
Original plain text: Tech tutorials x Ciphered text: 567a3b23b683d8488d5d40d2a56e31d2 Deciphered text: Tech tutorials x RUN SUCCESSFUL (total time: 70ms)
Dari hasil di atas, nampak bahwa ciphered text adalah identik, dan keduanya dapat melakukan proses dekripsi. Jadi dapat disimpulkan kedua program tersebut mempunyai fungsi yang sama, jadi data yang dienkripsi di ESP32 dapat dibaca di Windows dan sebaliknya.
Tahap selanjutnya adalah menambahkan proses komunikasi data dengan menggunakan UDP/TCP di ESP32 dan Windows, namun hal itu akan menjadi tulisan lain lagi.