ESP32 ile Veritabanına Veri Loglama
Esp32 kartında projenize göre tutmanız gereken bir sürü değişken olabilir ve bunları gözlemlemek istediğinizde aşağıdaki yolları kullanmanız gereklidir.
-
Yerel Depolama (Flash): Preferences kütüphanesi (NVS - Non-Volatile Storage).
ESP32 için özel olarak geliştirilmiş Preferences kütüphanesi kullanılmalıdır. Verileri adres hesabı yapmadan key-value olarak flash bellekte NVS bölümünde saklar.
nvs_handle_t my_handle; esp_err_t err; err = nvs_open(NVS_NAMESPACE,NVS_READWRITE,&my_handle); //nvs sistemini açma if ( err == ESP_OK) { // cache ve sonra flash ile güncelle nvs_set_str(my_handle, key, value); nvs_commit(my_handle); } nvs_close(my_handle);Bu kullanım tipi en son tutulan veri için kullanımı uygundur. Veritabanında sorun çıkarsa veya bağlantı koparsa, esp32 kartından bu verinin son halini alarak veri kaybını önleriz.
-
Uzaktan Loglama (Database): HTTP POST (REST API) ve MQTT protokolü.
ESP32 kartının log tutmak için direkt veritabanına bağlanması kartı çok yorar ve direkt güvenlik açığı ortaya çıkarabilir.
Bunun yerine bir Backend-as-a-Service modeli kullanacağız.
ESP32 kartı standalone (tek başına) internete çıkıp verileri bir yere bırakması gereklidir.
Supabase bu işi bizim için çözecektir. Tablo oluşturduktan sonra bize o tabloya veri yazmak için bir web linki (REST API) verir. Eğer böyle olmasaydı araya bir REST API yazmamız gerekli olacaktı, bu da sadece esp32 kartının kullanıldığı bir proje için çok mümkün bir senaryo değildir.
Supabase Kullanımı
Supabase’e github ile kayıt olduktan sonra free versiyon ile arayüze erişim yapalım.
- Yeni bir proje oluşturup gerekli bilgileri giriyoruz.
- Daha sonra soldaki panelden yeni bir tablo oluşturalım.
- Ben denemelik şu anda esp32 kartımın GPIO 2 pinine bağlı olan LED bilgisini veritabanına kaydedeceğim.
Tablonun bilgileri aşağıdaki gibidir:
| Name | led_test_log | veritabanı ismi |
| id | int8 | default id |
| created_at | timestamp | default tarih |
| esp_device | text | esp32 kartının ismi |
| value | bool | LED’in durumu |
Daha sonra settings içerisinde Data API seçeneğinden Project URL kopyalayalım. URL sonuna tablo ile ilgili kısımları eklememzi gerekli. Çünkü gönderilen verinin nereye tam olarak ulaşması gerektiğini söylemeliyiz.
Benim tabloma göre URL sonuna /rest/v1/led_test_log eklenmesi gereklidir.
API Keys kısmından da Legacy anoni service_role API keys kısmına girelim. anon_public verisini kopyalayıp kaydedelim. Bu anahtar ile REST API kullanabileceğiz.
Son olarak veritabanındaki tablonun RLS ayarının değiştirilmesi gereklidir. Bu RLS korumalı mod anlamına gelir. RLS kapatmak bir çözümdür.
Diğer bir çözüm ise Authentication -> Policies kısmından yeni bir politika ekleyip INSERT işlemine anon rolü için izin verilmelidir. Ben şu anlık RLS kapatıp devam ediyorum.
Veri kaydetme kütüphanesi oluşturma
İlk olarak aşağıdaki gibi bir proje oluşturarak yaptıklarımı siz de örnekleyebilirsiniz. Ya da yazının sonundaki github sayfamdan kodlara erişebiliriniz.
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = espidf
monitor_speed = 115200
build_flags =
-I include
Bunları yaptıktan sonra artık projemizde veritabanı işlemlerini kullanabiliriz.
Veritabanı işlemleri ve NVS Flash işlemlerini kullanmak için bir adet kütüphane oluşturmak istiyorum. Bütün fonksiyonlar orada bulunsun, main.c içerisinde kalabalık oluştursun istemiyorum.
Oluşturacağımız aslında bir kütüphane sayılmaz, kodu daha iyi kontrol etmek için ayrı bir yere fonksiyonlarımızı ve değişkenlerimizi yazıyoruz.
lib klasörü içerisine espDatabase adında bir klasör oluşturup içerisine de db_manager.h ve db_manager.c dosyalarını oluşturuyorum.
Ek olarak Database bilgilerini include içerisinde config.h içerisinde bulundurmayı tercih ettim. Bu .h dosyası diğer wifi gibi bilgilerimi içeren ayar dosyasıdır.
// --- DATABASE AYARLARI ---
#define NVS_NAMESPACE "esp32_led_test"
#define DATABASE_URL ""
#define DATABASE_KEY ""
JSON Veri Gönderme
Bu yazıda wifi bağlanma işlemleri yapılmış varsayılarak ilerliyorum. Daha sonra ESP32 Wifi bağlantısı için bir yazı oluşturacağım. (buraya linkini koyacağım.)
API le HTTP veri gönderimini JSON olarak yapıyorum.
static void _send_json_package(cJSON *json_root)
bu fonksiyon içerisinde:
cJSON.hkütüphanesi ile JSON formatını parameter olarak alır ve içeride gönderir.- http client config oluşturarak ayarlamalar yapılır
esp_http_client_initile client oluşturup config ayarları girilir- Authoriation bilgileri ve API bilgileri ile doğrulama işlemlerini yapılır
esp_http_client_set_post_fieldile veri gönderilir.- En son veri doğrulama için loglama yapılır.
static void _send_json_package(cJSON *json_root) {
// gönderilecek veri JSON objesini parametre olarak alır.
char *post_data = cJSON_PrintUnformatted(json_root);
//JSON oluşturulamadıysa işlemi iptal et (Crash önleyici)
if (post_data == NULL) {
ESP_LOGE(TAG, "JSON olusturma hatasi (Bellek yetersiz olabilir)");
return;
}
// config ayraları
esp_http_client_config_t config = {
.url = DATABASE_URL,
.transport_type = HTTP_TRANSPORT_OVER_SSL,
.crt_bundle_attach = esp_crt_bundle_attach,
.timeout_ms = 5000, // 5 saniye zaman aşımı koyalım ki sonsuza kadar
.buffer_size = 1024, // Gelen veri (Response) için 4KB yer aç (YETMİYORDU)
.buffer_size_tx = 2048, // Giden veri için 2KB yer aç
.disable_auto_redirect = true
};
//client (istemci) oluşturma
esp_http_client_handle_t client = esp_http_client_init(&config);
if (client == NULL) {
ESP_LOGE(TAG, "HTTP Client baslatilamadi");
free(post_data);
return;
}
esp_http_client_set_method(client, HTTP_METHOD_POST);
esp_http_client_set_header(client, "Content-Type", "application/json");
esp_http_client_set_header(client, "apikey", DATABASE_KEY);
char auth_header[300];
snprintf(auth_header, sizeof(auth_header), "Bearer %s", DATABASE_KEY);
esp_http_client_set_header(client, "Authorization", auth_header);
// verinin gönderilmesi
esp_http_client_set_post_field(client, post_data, strlen(post_data));
// verinin gittiğini öğrenmek için doğrulama
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "Log Gonderildi. Kod: %d", esp_http_client_get_status_code(client));
} else {
ESP_LOGE(TAG, "Log Hatasi: %s", esp_err_to_name(err));
}
// hafızayı boşaltma işlemleri
esp_http_client_cleanup(client);
free(post_data);
}
LED Değerini Gönderme
Bu uygulamada GPIO2’ye bağlı bir ledin son durumunu veritabanına kaydedeceğim.
Bu sistemi kolay yapabilmek için fonskiyon yazdım.
static void _send_http_bool(const char *key, bool value) {
cJSON *root = cJSON_CreateObject();
if (root == NULL) return;
cJSON_AddStringToObject(root,"esp_device",ESP_NAME);
cJSON_AddStringToObject(root, "variable_name", key);
cJSON_AddBoolToObject(root, "value", value);
_send_json_package(root);
cJSON_Delete(root);
}
Bu fonksiyon key value olarak bool değerin NVS sistemine kaydedilmesin sağlar. İlk olarak JSON verisi oluşturarak veri tabanına gönderilecek şekilde veriler yazılır.
Daha sonra _send_json_package ile bu veri gönderilir
LED Değerini Kaydetme
Veritabanına gönderilecek olan veriyi paralelinde NVS olarak da ESP32 içerisinde kaydedeceğim. Eğer veritabanında bir sorun olursa, son halini ESP32 içerisinden alabilelim.
Bunun için yazılan fonskiyon:
void update_variable_bool(const char* key, bool value){
nvs_handle_t my_handle;
uint8_t saved_u8 = 2; // Başlangıç değeri (ilk kayıt için)
esp_err_t err;
// NVS sistemi açılır.
err = nvs_open (NVS_NAMESPACE, NVS_READWRITE, &my_handle);
if (err == ESP_OK) {
// NVS sistemi açılır.
err = nvs_get_u8(my_handle, key, &saved_u8);
bool current_bool_val = (saved_u8 == 1);
// değer farklıysa veya doğru bir şekilde bulunduysa
if (err == ESP_ERR_NVS_NOT_FOUND || current_bool_val != value) {
ESP_LOGI(TAG, "Bool degisti: %s -> %d", key, value);
// değer güncellenir
nvs_set_u8(my_handle, key, (value ? 1 : 0));
nvs_commit(my_handle);
// paralelinde HTTP olarak Db API ile gönderim yapılır
_send_http_bool(key, value);
}
// NVS sistemi kapanır.
nvs_close(my_handle);
}
}
Bu fonksiyon ile beraber güncellenen değerimiz veritbanına da gönderilir.
Kullanımını main.c içerisinde görelim.
Kullanım örneği
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "cJSON.h"
#include "esp_crt_bundle.h"
// ============================================================
// AYARLAR
// ============================================================
# include "config.h"
// Wifi işlemleri için gerekli ayarlar
//#include "wifi_manager.h"
// Veritabanı işlemleri için gerekli ayarlar
#include "db_manager.h"
void nvs_initialize(void);
static const char *TAG = "ESP_32_MAIN";
#include "driver/gpio.h"
#define BLINK_GPIO 2
void app_main(void) {
nvs_initialize(); //NVS başlatır.
wifi_init_sta(); // wifi işlemleri başlatılır. (wifi işlemleri için yazılan fonksiyon- sizin yaptığınız varsayılır.)
gpio_reset_pin(BLINK_GPIO);
gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
while(1) {
// LED YAK
ESP_LOGI(TAG, "LED 1");
gpio_set_level(BLINK_GPIO, 1);
// veritabanı gönderimi
update_variable_bool("LED",true);
vTaskDelay(10000 / portTICK_PERIOD_MS);
// LED SONDUR
ESP_LOGI(TAG, "LED 0");
gpio_set_level(BLINK_GPIO, 0);
// veritabanı gönderimi
update_variable_bool("LED",false);
vTaskDelay(10000 / portTICK_PERIOD_MS);
}
}
void nvs_initialize(void){
// 1. Sistem Başlatma (NVS ve Wifi)
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
}
NVS sistemini initialize etmeniz gerekir. Bu işlemi ben main fonskiyonu içerisinde yapmayı tercih ettim.
Bu yazımda bulunan tüm kodları Github repo’mda bulabilirsiniz.
WIFI kodları mevcut değildir. WIFI ile ilgili yazı yazdıktan sonra buraya da belirteceğim. Bundan dolayı kodların çalışması için wifi kodlarını yazmanız gerekmektedir.
SONUÇ
Evet bu yazımda supabase veritabanını kullanarak ESP32 ile LED durumunun loglanmasını yaptık. Umarım anlattıklarım size yardımcı olmuştur.
Sonraki yazılarımda görüşene dek iyi çalışmalar dilerim.