안녕하세요, 이상민입니다.
이번 프로젝트는 아두이노(esp8266 Node MCU보드)와 firebase의 Realtime Database(RTDB)를 연결하는 프로젝트입니다. 이를 통해 RTDB의 데이터를 아두이노에서 읽어 불을 켜고 끄는 등의 간단한 IOT 기기를 만들 수 있습니다.
※이 글은 23.08.29에 작성되었습니다. 시간이 많이 지난 경우 라이브러리 등이 호환되지 않을 수 있습니다.※
목차는 다음과 같습니다.
1. 아두이노 IDE에서 esp8266 보드 및 firebase 라이브러리 추가
2023.08.25 - [전자공학/아두이노 프로젝트] - [Firebase] 1. 아두이노 IDE에서 esp8266 보드 및 firebase 라이브러리 추가
2. firebase RTDB 설정
- 2023.08.25 - [전자공학/아두이노 프로젝트] - [Firebase] 2. Firebase RTDB 설정
3. 아두이노와 firebase RTDB 연결
- 2023.08.25 - [전자공학/아두이노 프로젝트] - [Firebase] 3. 아두이노와 firebase RTDB 연결
4. firebase RTDB 값을 통해 아두이노 불 켜고 끄기
- 현재 글
이번 포스팅에선 firebase의 Realtime Database를 아두이노에서 읽고 LED를 제어해 보도록 하겠습니다.
1) Firebase Realtime Database(RTDB) 구조 및 작동 설명
아두이노 코드 설명에 앞서 Firebase RTDB의 구조 및 작동에 대해 설명드리겠습니다.
Firebase RTDB는 Json이라는 "키" 와 "값" 으로 이루어진 자료구조로 데이터를 저장합니다. 그리고 이 값들은 데이터베이스 내에서 주소를 통해 접근할 수 있습니다. 따라서 아래 그림과 같이 표현할 수 있습니다.
(Json 자료구조 및 주소를 통해 접근할 수 있다는 사진)
Firebase 콘솔 화면(PC화면) 에서는 이들 값을 추가, 삭제, 수정할 수 있습니다.
(Firebase RTDB 화면 중 수정)
2) 아두이노에서 firebase RTDB 읽기
먼저 저번 포스팅의 예제로부터 시작됩니다. 예제코드의 위치는 다음과 같습니다.
"파일" 탭 -> 예제 -> "Firebase Arduino Client Library for ESP8266 and ESP32 -> Client -> Firebase" 클릭
후에 저번 포스팅을 참고하여 WIFI 이름, Password, API key, database URL, User Email, password를 입력한 상태에서 시작하겠습니다.
(대충 어디어디 해야하는지 체크)
3) 주요 변수 설명
전역변수
- fbdo : FirebaseData 자료형, firebase에서 받은 데이터. 이 값의 주소(&fbdo)를 함수로 이동시키며 값을 뽑아내는 역할
- sendDataPrevMillis : 이전에 데이터를 처리한 시각, 이를 기준으로 프로그램 작동 시간을 조절할 수 있음
Loop 내 지역변수
- json : FirebaseJson 자료형, 여기에 데이터를 먼저 저장한 후 setJSON 함수를 이용해 DB에 업로드 하는 변수
- temp : int형, DB 내 자료를 읽고 데이터를 잠시 저장할 변수
4) 아두이노 firebase함수 설명
데이터 읽기 관련
- Firebase.RTDB.getJSON(&fbdo, "찾고자 하는 주소") : &fbdo에 저장된 주소를 바꾸고, 새 주소에 접근 가능하면 True를 반환, 실패면 False를 리턴합니다. 이를 통해 오류를 걸러냅니다.
- fbdo.to<int>() : fbdo의 주소에 "value" 값을 읽어서 < >안에 있는 자료형으로 리턴합니다. 여기선 숫자를 리턴합니다.
데이터 쓰기 관련
- json.set("key", value) : json 데이터를 새로 작성합니다. key : value로 json형식으로 저장됩니다.
- Firebase.RTDB.setJSON(&fbdo, "찾고자 하는 주소", &json) : &fbdo에 저장된 주소를 바꾸고, 새 주소에 미리 저장해둔 json데이터를 입력합니다. 만약 업로드에 성공했다면 True를 반환, 실패는 False를 반환합니다. 이를 통해 데이터를 DB에 업로드 함과 동시에 성공 여부도 확인합니다.
오류 찾기 관련
- fbdo.errorReason().c_str() : fbdo에서 오류가 났을 때 오류코드를 리턴합니다.
5) 쓰기 예제 및 주요 구문 설명
아래 코드는 데이터베이스 "쓰기" 예제이고, 2)에서 연 예제문의 loop부분을 통채로 바꾸시면 됩니다.
void loop()
{
// Flash string (PROGMEM and (FPSTR), String C/C++ string, const char, char array, string literal are supported
// in all Firebase and FirebaseJson functions, unless F() macro is not supported.
// Firebase.ready() should be called repeatedly to handle authentication tasks.
if (Firebase.ready() && (millis() - sendDataPrevMillis > 15000 || sendDataPrevMillis == 0))
{
sendDataPrevMillis = millis();
FirebaseJson json;
json.setDoubleDigits(3);
json.set("value1", 0);
Serial.printf("Set json... %s\n", Firebase.RTDB.setJSON(&fbdo, "/test/json", &json) ? "ok" : fbdo.errorReason().c_str());
json.set("value2", 1);
Serial.printf("Set json... %s\n", Firebase.RTDB.setJSON(&fbdo, "/test/json", &json) ? "ok" : fbdo.errorReason().c_str());
} // end of if Firebase.ready()
} // end of loop()
if (Firebase.ready() && (millis() - sendDataPrevMillis > 15000 || sendDataPrevMillis == 0)
Firebase 작동이 준비되었고, 이전 data 쓰기에서 15초가 지났다면 아래 구문들을 실행합니다.
json.setDoubleDigits(3);
json.set("value1", 0);
json에 키가 "value1"이고 그 데이터를 "0"으로 저장합니다.
Firebase.RTDB.setJSON(&fbdo, "/test/json", &json)
DB의 /test/json 주소에 json을 입력합니다. 여기선 {value1 : 0} 이 DB에 저장됩니다.
json.set("value2", 0);
Firebase.RTDB.setJSON(&fbdo, "/test/json", &json)
마찬가지로 {value2 : 1}을 DB에 저장합니다.
그 후 결과는 다음과 같습니다.
시리얼창
Firebase RTDB
5) 읽기 예제 및 주요 구문 설명
아래 코드는 데이터베이스 "읽기" 예제이고, 2)에서 연 예제문의 loop부분을 통채로 바꾸시면 됩니다.
void loop()
{
// Flash string (PROGMEM and (FPSTR), String C/C++ string, const char, char array, string literal are supported
// in all Firebase and FirebaseJson functions, unless F() macro is not supported.
int temp = 0;
// Firebase.ready() should be called repeatedly to handle authentication tasks.
if (Firebase.ready() && (millis() - sendDataPrevMillis > 15000 || sendDataPrevMillis == 0))
{
sendDataPrevMillis = millis();
if(Firebase.RTDB.getJSON(&fbdo, "/test/json/value1"))
{
temp = fbdo.to<int>();
Serial.print("Get json Value1 : ");
Serial.println(temp);
}
else Serial.printf(fbdo.errorReason().c_str());
if(Firebase.RTDB.getJSON(&fbdo, "/test/json/value2"))
{
temp = fbdo.to<int>();
Serial.print("Get json Value2 : ");
Serial.println(temp);
}
else Serial.printf(fbdo.errorReason().c_str());
} // end of if Firebase.ready()
} // end of loop()
if (Firebase.ready() && (millis() - sendDataPrevMillis > 15000 || sendDataPrevMillis == 0)
Firebase 작동이 준비되었고, 이전 data 읽기에서 15초가 지났다면 아래 구문들을 실행합니다.
if(Firebase.RTDB.getJSON(&fbdo, "/test/json/value1"))
fbdo의 주소를 "test/json/value1"로 옮기고, 여기에 접근 가능하면 아래 구문을 실행합니다.
※쓰기와 주소가 다른데요, value1이라는 키값까지 주소에 포함시켜야 정상적으로 나옵니다※
temp = fbdo.to<int>();
Serial.print("Get json Value1 : ");
Serial.println(temp);
temp변수에 fbdo에 저장된 값을 넣습니다. 그 후 시리얼화면으로 출력합니다.
value2도 value1과 동일합니다.
그 후 결과는 다음과 같습니다.
FirebaseRTDB
시리얼창
중간에 RTDB값을 바꾸면 따라서 시리얼창에도 바뀐 값이 나옵니다.
6) Firebase RTDB를 이용한 LED 제어 코드
위 5) 예제에서 실험한 RTDB 읽기를 이용해 LED를 끄고켜는 간단한 코드를 작성해 봅시다.
value1과 value2는 각각 LED1과 LED2를 제어하고, 값이 0이면 끄고, 1이면 켜도록 했습니다.
LED1과 LED2는 각각 GPIO 4번핀, 5번핀에 연결했습니다.
코드는 setup문과 loop문만 확인하면 됩니다. 어려운 내용은 아니라서 코드설명은 생략하겠습니다.
// board : ESP8266Boards (3. 1. 2) -> Node MCU 1.0 (ESP-12E Module)
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <Firebase_ESP_Client.h>
// Provide the token generation process info.
#include <addons/TokenHelper.h>
// Provide the RTDB payload printing info and other helper functions.
#include <addons/RTDBHelper.h>
/* 1. Define the WiFi credentials */
#define WIFI_SSID ""
#define WIFI_PASSWORD ""
/* 2. Define the API Key */
#define API_KEY ""
/* 3. Define the RTDB URL */
#define DATABASE_URL "test-blog1-default-rtdb.firebaseio.com" //<databaseName>.firebaseio.com or <databaseName>.<region>.firebasedatabase.app
/* 4. Define the user Email and password that alreadey registerd or added in your project */
#define USER_EMAIL "testblog1@gmail.com"
#define USER_PASSWORD "123123"
/* 5. Define LED Pin number in GPIO num */
#define LED1 4
#define LED2 5
// Define Firebase Data object
FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;
unsigned long sendDataPrevMillis = 0;
int led_mem[2];
void setup()
{
Serial.begin(115200);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to Wi-Fi");
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
Serial.printf("Firebase Client v%s\n\n", FIREBASE_CLIENT_VERSION);
/* Assign the api key (required) */
config.api_key = API_KEY;
/* Assign the user sign in credentials */
auth.user.email = USER_EMAIL;
auth.user.password = USER_PASSWORD;
/* Assign the RTDB URL (required) */
config.database_url = DATABASE_URL;
/* Assign the callback function for the long running token generation task */
config.token_status_callback = tokenStatusCallback; // see addons/TokenHelper.h
// Or use legacy authenticate method
// config.database_url = DATABASE_URL;
// config.signer.tokens.legacy_token = "<database secret>";
Firebase.begin(&config, &auth);
// Comment or pass false value when WiFi reconnection will control by your code or third party library
Firebase.reconnectWiFi(true);
// LED Control
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
led_mem[0] = 0;
led_mem[1] = 0;
}
void loop()
{
// Flash string (PROGMEM and (FPSTR), String C/C++ string, const char, char array, string literal are supported
// in all Firebase and FirebaseJson functions, unless F() macro is not supported.
int temp = 0;
// Firebase.ready() should be called repeatedly to handle authentication tasks.
if (Firebase.ready() && (millis() - sendDataPrevMillis > 1000 || sendDataPrevMillis == 0))
{
sendDataPrevMillis = millis();
FirebaseJson json;
if(Firebase.RTDB.getJSON(&fbdo, "/test/json/value1"))
{
temp = fbdo.to<int>();
Serial.print("Get json Value1 : ");
Serial.println(temp);
}
else Serial.printf(fbdo.errorReason().c_str());
if(Firebase.RTDB.getJSON(&fbdo, "/test/json/value2"))
{
temp = fbdo.to<int>();
Serial.print("Get json Value2 : ");
Serial.println(temp);
}
else Serial.printf(fbdo.errorReason().c_str());
} // end of if Firebase.ready()
} // end of loop()
아래는 작동영상입니다.
좌상단에 RTDB를 수정하면 그에 따라 우상단 시리얼창에 어떤 작동인지 나오며 LED를 제어하는 모습을 볼 수 있습니다.
이것으로 Firebase Realtime Database를 이용해 LED를 제어하는것을 확인할 수 있습니다.
감사합니다.
'전자공학 > 아두이노 프로젝트' 카테고리의 다른 글
[아두이노 기초] 아두이노 프로그램 코드(스케치) 작성 방법 (0) | 2023.11.22 |
---|---|
[아두이노 기초] 아두이노 IDE 설치 방법 및 설명 (0) | 2023.11.21 |
[Firebase] 3. 아두이노와 firebase RTDB 연결 (0) | 2023.08.25 |
[Firebase] 2. Firebase Real Time Data Base(RTDB) 설정 (0) | 2023.08.25 |
[Firebase] 1. 아두이노 IDE에서 esp8266 보드 및 firebase 라이브러리 추가 (0) | 2023.08.25 |