REST’i bana verin – Bölüm 2: Müşteri

semaver

New member


  1. REST’i bana verin – Bölüm 2: Müşteri

Arduino kartları veya diğer mikrodenetleyici kartları veya gömülü sistemler veya tek kartlı bilgisayarlar, bir WiFi veya Ethernet bağlantısını entegre etmeleri halinde bir REST uygulamasıyla iletişim kurabilir. Burada sunulan gibi tipik bir uygulama esasen sensör ölçümleri yaptığından, gerçek zamanlı bir saatin (RTC) bir avantaj olduğu kanıtlanmıştır. Bu, ölçüm verilerine zaman damgalarının (tarih ve saat) eklenmesine izin verir ve bu, daha sonra belirli bir süre boyunca sıcaklık profili gibi tarihsel analize izin verir.

Duyuru








prof. Dr. Michael Stal, 1991’den beri Siemens Technology’de çalışıyor. Araştırmaları, büyük karmaşık sistemler (dağıtılmış sistemler, bulut bilgi işlem, IIoT), gömülü sistemler ve yapay zeka için yazılım mimarilerine odaklanıyor. Yazılım mimarisi konularında iş birimlerine tavsiyelerde bulunur ve Siemens’teki kıdemli yazılım mimarlarının mimari eğitiminden sorumludur.







Burada Arduino Giga’dan bahsediyor olsak da, uygulama hiçbir şekilde bu kartla sınırlı değildir ve Arduino’daki WiFi, WiFiUdp ve HTTPClient gibi işlevsel olarak benzer kütüphanelerin bulunduğu diğer Arduino, STM veya ESP kartlarına nispeten kolayca uyarlanabilir. IDE veya PlatformIO eklentisi ile Visual Studio Code’da.

Maker’ın I2C veya SPI aracılığıyla bağlandığı BME ailesinden (BME68x, BME58x, BME38x, BME28x) bir Bosch Sensortec sensörüne ihtiyacınız var. Örnek olarak, Pomoroni veya Adafruit gibi çeşitli üreticilerden ara kartı olarak temin edilebilen bir BME688 kullanıldı. Dilerseniz bir Bosch geliştirme kiti de satın alabilirsiniz. Bu kart, Adafruit Huzzah32 Feather Board’a (ESP32) bindirilmiş bir BME688 adaptöründen oluşur. Yaklaşık 100 avroya mal oluyor, ancak ücretsiz BME AI Studio yazılımı kullanılarak eğitilebilmenin cazibesine sahip. Sensör, bir sinir ağı aracılığıyla havadaki kahve, CO₂ veya klor gibi çeşitli gaz moleküllerini tanımayı öğrenir. Havadaki moleküller için ohm cinsinden dirençleri belirler ve gazları elektriksel özelliklerine göre sınıflandırabilir. Elbette, bu özel makine öğrenimi eğitimi, ara panolarla mümkün değildir – kullanıcı, belirli bir moleküle atama olmaksızın yalnızca gaz direncini deneyimler. Basit panoların maliyeti yalnızca 20 ila 30 Euro arasındadır.

Daha önce ilk bölümde bahsedildiği gibi, örneklerin kaynak kodları GitHub deposunda bulunabilir.

Önceden bir not: Burada bir RESTful mimarisi aracılığıyla sunulan entegrasyon için olası bir alternatif, istemci ile sunucu arasında olaya veya mesaja dayalı iletişime izin veren MQTT’yi kullanmak olabilir. Çoğu durumda, belki de şu anki durumda bile, MQTT harika bir seçenektir. Bununla birlikte, makalenin iki bölümü özellikle arka uç iletişimi ve REST API’leri aracılığıyla entegrasyonu açıklamaya odaklanmaktadır. Son olarak, arka uç tarafından yönetilen bir mikro hizmet genellikle bir REST API sağlar.

donanım yapılandırması


Duyuru

Belirli devrede aşağıdaki bağlantılar gereklidir:

Arduino ........ BME688

3.3V ............ Vin

GND ............. GND

SCL ............. SCK

SDA ............. SDI

Aşağıdaki Fritzing diyagramı bunu göstermektedir:








BME688 sensörünün ve Arduino’nun bağlantısı I2C veya SPI üzerinden çalışır. Mevcut durumda, I2C tercih edilen yöntemdir



Arduino uygulaması


Arduino yazılımı geliştirirken aşağıdaki sorumluluklar vardır:

Başlangıç konfigürasyonu:

  • Wi-Fi ağına bağlantı kurun
  • Geçerli saati NTP sunucusu aracılığıyla okuyun ve gerçek zamanlı saati (RTC) ayarlayın.
  • BME688 I2C sensörüne bağlantı kurun
Döngü:

  • BME688’den ölçüm sonuçlarını okuyun
  • Yerel saati RTC ile belirleyin
  • JSON mesajını birleştirin
  • WiFi/HTTP aracılığıyla REST sunucusuna bağlanın
  • POST mesajı gönder
  • Paketin başarıyla gönderilip gönderilmediğini kontrol edin
Taslak ayrıca test ve gözlem amaçları için seri monitör bilgisi sağlamalıdır.

Wi-Fi bağlantısı


Arduino taslağı aynı dizinde bir dosya bekliyor arduino_secrets.h, özellikle SSID ve WLAN anahtarı olmak üzere, istenen WLAN için tanımları içeren. Arduino WiFi’yi kullanmak için, başlığını eklediğimiz ilgili bir WiFi kitaplığına ihtiyacınız var, örneğin: #include <WiFi.h>. Ayrıca kütüphaneye ihtiyacımız var. ArduinoHttpClientArduino IDE’nin Kütüphane Yöneticisi veya VS Code & PlatformIO aracılığıyla kurduğumuz.

Aşağıdaki kod, WLAN bağlantısını kurar:



void setup() {
// Seriellen Stream starten
Serial.begin(9600);

// Verbindungsaufbau WiFi
while (status != WL_CONNECTED) {
Serial.print("Versuche Verbindungsaufbau zum WLAN-Netz: ");
Serial.println(ssid); // print the network name (SSID);

// Verbinden mit WPA/WPA2 Netzwerk:
status = WiFi.begin(ssid, pass);
}

// Name des WLANs nach erfolgtem Verbindungsaufbau:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());


NTP protokolü


Bu nedenle bir NTP sunucusunda oturum açmak, gerçek zamanlı saatin ayarlanmasına yardımcı olmalıdır.

Giga R1 kartı için aşağıdaki başlık dosyaları gereklidir:

#include <WiFiUdp.h> // zum Versenden von NTP-Paketen notwendig

#include <mbed_mktime.h>

Tabii ki, bu diğer panolarda farklı görünüyor ve bu konuda değiştirilmelidir.

Gerçek zamanlı saati ayarlamak için gerçek kod, yöntemdedir. setNtpTime()bu da yerel bir bağlantı noktasına bir UDP bağlantısı açar, istenen zaman sunucusuna bir istek paketi gönderir (sendNTPacket()) önceki cevaba parseNtpPacket() gerçek zamanlı saati geçerli zamanla almak, işlemek ve ayarlamak için. Bu doğru şekilde çalıştıysa, şimdi yöntemi kullanabilirsiniz. getLocalTime() her zaman şimdiki zamanı gerçek zamanlı saatten okuyun. Biri her durumda iade edilir Datetime– Tarih ve saatten oluşan dize: „2023-06-05 12:31:45“.


// NTP-Anfrage senden, Antwort erhalten und parsen
void setNtpTime()
{
status = WL_IDLE_STATUS;
Udp.begin(localPort);
sendNTPpacket(timeServer);
delay(1000);
parseNtpPacket();
}

// Rufe einen Zeitserver auf
unsigned long sendNTPpacket(const char * address)
{
memset(packetBuffer, 0, NTP_PACKET_SIZE);
packetBuffer[0] = 0b11100011; // LI, Version, Modus
packetBuffer[1] = 0; // Stratum, Art der Uhr
packetBuffer[2] = 6; // Abfrageintervall
packetBuffer[3] = 0xEC; // Präzision der Uhr
// 8 Bytes von Nullen für Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;

Udp.beginPacket(address, 123); // NTP Aufrufe erfolgen über Port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}

// Hier wird das NTP-Antwortobjekt empfangen und geparst:
unsigned long parseNtpPacket()
{
if (!Udp.parsePacket())
return 0;

Udp.read(packetBuffer, NTP_PACKET_SIZE); // Paket vom NTP-Server empfangen
const unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
const unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
const unsigned long secsSince1900 = highWord << 16 | lowWord;
constexpr unsigned long seventyYears = 2208988800UL;
const unsigned long epoch = secsSince1900 - seventyYears;
set_time(epoch);

// Folgende ausführliche Beschreibung lässt sich ausgeben,
// sobald man DETAILS definiert
#if defined(DETAILS)
Serial.print("Sekunden seit Jan 1 1900 = ");
Serial.println(secsSince1900);

// NTP time in "echte" Zeit umwandeln:
Serial.print("Unix Zeit = ");
// Ausgabe der Unix time:
Serial.println(epoch);

// Stunde, Minute, Sekunde ausgeben:
Serial.print("Die UTC Zeit ist "); // UTC entspricht Greenwich Meridian (GMT)
Serial.print((epoch % 86400L) / 3600); // Stunde ausgeben (86400 sind die Sekunden pro Tag)
Serial.print(':');
if (((epoch % 3600) / 60) < 10) {
// In den ersten 10 Minuten einer Stunde brauchen wir eine führende Null
Serial.print('0');
}
Serial.print((epoch % 3600) / 60); // Minute ausgeben (3600 = Sekunden pro Stunde)
Serial.print(':');
if ((epoch % 60) < 10) {
// In den ersten 10 Minuten einer Stunde brauchen wir eine führende Null
Serial.print('0');
}
Serial.println(epoch % 60); // Sekunde ausgeben
#endif

return epoch;
}

// Lokale Zeit mittels RTC (Real Time Clock) ermitteln:
String getLocaltime()
{
char buffer[32];
tm t;
_rtc_localtime(time(NULL), &t, RTC_FULL_LEAP_YEAR_SUPPORT);
strftime(buffer, 32, "%Y-%m-%d %k:%M:%S", &t);
return String(buffer);
}




NTP (Ağ Zaman Protokolü) hakkında daha fazla bilgi edinmek isteyenler için, bir şekil ve ardından bir NTP paketinin yapısını gösteren açıklamalar:







Gömülü sistemler, gerçek zamanlı saatlerini ayarlamak için NTP protokolünü kullanabilir.



Bir NTP paketinin başlık girişleri aşağıdaki gibi yapılandırılmıştır:

ORADA

Atlama göstergesi (2 bit)

Bu öznitelik, geçerli günün son dakikasının fazladan bir saniyeye ihtiyaç duyup duymadığını gösterir.

0: Saniye ayarı gerekmez

1: Son dakika 61 saniye olmalıdır

2: Son dakika 59 saniye olmalıdır

3: Saat senkronize değil

VN

NTP (3 bit) sürüm numarası (yaklaşık olarak sürüm 4).

Moda

NTP Paket Modu (3-bit)

0: Ayrıldı

1: Simetrik olarak aktif

2: Dengeli Pasif

3: müşteriler

4: minyonlar

5: iletim

6: NTP kontrol mesajı

7: Özel kullanım için ayrılmıştır

katman

Zaman kaynağının katman seviyesi (8 bit)

0: belirtilmemiş veya geçersiz

1: birincil sunucu

2-15: ikincil sunucu

16: senkronize değil

17-255: ayrılmış

Anket

Ardışık NTP mesajları arasındaki maksimum zaman aralığının ne olması gerektiğini saniye cinsinden tanımlayan Yoklama Aralığı (8 bitlik işaretli tamsayı).

Kesinlik

Saat hassasiyeti (8 bit işaretli tamsayı)

kök gecikmesi

Sunucudan ana zaman kaynağına gidiş-dönüş gecikmesi. Saniyeleri belirten 32 bitlik bir kayan noktalı sayıdır. Ondalık nokta 15 ve 16 bitleri arasındadır. Yalnızca sunucu mesajları için geçerlidir.

radikal dağılım

Saat frekansı toleransından kaynaklanan maksimum hata. Saniyeleri belirten 32 bitlik bir kayan noktalı sayıdır. Ondalık nokta 15 ve 16 bitleri arasındadır. Yalnızca sunucu mesajları ile ilgilidir.

referans tanımlayıcı

Stratum 1 sunucuları için bu değer (4 baytlık bir ASCII değeri), harici referans kaynaklarını tanımlar. İkincil sunucular için değer (4 bayt), senkronizasyon kaynağının IPv4 adresini veya senkronizasyon sunucusunun IPv6 adresinin MDA (MDA = Mesaj Özet Algoritması 5) karmasının ilk 32 bitini tanımlar.

sensör


BME688 sensörünü I2C’de çalıştırmak için, kitaplıkları Adafruit’ten kitaplık yöneticisi aracılığıyla yüklememiz gerekir – kod, SPI kullanmak için kolayca değiştirilebilir. Adafruit BME680 ve Adafruit Unified Sensor kitaplıklarını içe aktarmanız gerekir. Elbette BME280 gibi Bosch BME ailesinden başka bir sensörün kitaplığı da olabilir.

Sensör başlatma işlemi devam ediyor setup() Birleşik. İşte BME delegesinin anlaşması:

Adafruit_BME680 bme; // Vereinbarung der Variablen bme

Ve işte gerçek başlatma:


// Verbindung mit Sensor BME680 etablieren
if (!bme.begin()) {
Serial.println(F("Konnte keinen Sensor finden. Bitte Schaltung überprüfen!"));
while (1);
}

// Oversampling-Werte setzen und IIR-Filter initialisieren
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C für 150 ms
}


GÖNDERİ devre dışı

yöntem createJSONString() ölçüm verilerinden ve zaman damgasından bir JSON nesnesi oluşturur. Bunun yerine kasıtlı olarak manuel olarak oluşturmayı seçtim. ArduinoJson çaba çok açık olduğu için kullanılacak:


// Hier wird ein String generiert, der ein JSON-Objekt enthält
String createJSONString(double temp, double humi, double pres, double resi, String date, String time) {
String result = "{";
const String up = """;
const String delim = ",";
const String colon = ":";

result += up + "temperature" + up + colon + String(temp,2) + delim;
result += up + "humidity" + up + colon + String(humi,2) + delim;
result += up + "pressure" + up + colon + String(pres,2) + delim;
result += up + "resistance" + up + colon + String(resi,2) + delim;
result += up + "date" + up + colon + up + date + up + delim;
result += up + "time" + up + colon + up + time + up;
result += "}";
return result;
}


Bu ölçüm verilerinin bir kısmını içermeyen bir sensörünüz varsa, JSON nesnesi buna göre kırpılır. Sunucu veritabanında, aktarılmayan herhangi bir öznitelik yalnızca bir null kayıtlı.

Ölçüm verilerini HTTP POST aracılığıyla göndermek için callAPIPost() başarılı olursa durum kodu 200 ile yanıt veren sunucudan yanıtı da çıkaran yönetici:


// Hier erfolgt die Vorbereitung und die eigentliche Durchführung des POST-Aufrufes / REST-PUSH
void callAPIPost(double temperature, double humidity, double pressure, double resistance, const String& date, const String& time){
Serial.println("Durchführung eines neuen REST API POST Aufrufs:");
String contentType = "application/json"; // Wir übergeben ein JSON-Objekt

// JSON Nutzlast (Body) kreieren
String postData = createJSONString(temperature, humidity, pressure, resistance, date, time);
Serial.println(postData); // ... und ausgeben

// Per WiFi-Verbindung POST aufrufen und dabei "application/json" und das JSON-Objekt übergeben
client.post("/measurements/api", contentType, postData);

// Status und Body aus Antwort extrahieren
int statusCode = client.responseStatusCode();
String response = client.responseBody();

// Ausgabe der Ergebnisse:
Serial.print("Status code: ");
Serial.println(statusCode);
Serial.print("Antwort: ");
Serial.println(response);
}


Yukarıdaki yöntem çağrıları dosyada bulunabilir. loop()-yöntem, elbette program başlangıcındaki başlatmalar dışında.







Çizim çalışıyorsa WiFi aracılığıyla WLAN’a bağlanır, BME688’den gelen verileri sürekli olarak ölçer ve bunu bir JSON nesnesi olarak bir zaman damgasıyla birlikte POST aracılığıyla sunucuya iletir.



Çözüm


Bu, Bölüm 1’deki REST sunucusuna yeni ölçümler sağlayan Arduino taslağını tamamlar. Tabii ki, her zaman olduğu gibi, genişletme seçenekleri var:

  • Böylece, ilgili ölçülen değerleri veren bir SSD1306 OLED ekran eklemek mümkündür. Veya bir SD kart tabanlı veri kaydedici. Bir OLED ekranın IIC bağlantısıyla daha fazla entegrasyonu için bir örnek, yukarıda belirtilen GitHub deposunda da bulunabilir. Sensör ve I2C ekranı birbirine zincirleme bağlıdır. Gerekirse, yapılandırmanız için IIC adresini (varsayılan: 0x3C) ve çözünürlüğü (varsayılan: 128×64) değiştirmeniz gerekir.






IIC veriyoluna seri bağlı SSD1306 (128 x 64) ekran akım ölçüm verilerini verir



Burada 3.3V, GND, SDA, SCL bağlantısı, Arduino’dan IIC ekranına ve IIC sensörüne erişilebilen bir devre tahtasına yönlendirilir.

  • BME280, BME580 gibi başka iklimsel sensörlerin ve hatta diğer tip sensörlerin kullanılması düşünülebilir. Bu, istemci ve sunucu kodu değişikliklerini gerektirir.
  • Sensörlü farklı kartlarınız varsa, Kart Kimliği ve GPS verileri gibi veri şeması öznitelikleri sağlayabilirsiniz.
  • Raspberry Pi Picos, ESP32 kartları gibi alternatif kartlar kullanılabilir. Bir BME688’i doğrudan Mac OS/Windows/Linux bilgisayarınıza bağlamak da bir GPIO genişletme kartı aracılığıyla mümkündür.
  • Cep telefonu veya tablet için bir uygulama, mevcut ölçüm sürecini grafiksel olarak gösterebilir.
Ve henüz yolun sonu değil. Olasılıklar neredeyse sonsuzdur. Örnek istemci ve sunucu uygulamaları, prosedürü açıkça göstermeli ve sizi denemeye teşvik etmelidir. İstemci ve sunucu uygulamaları buna göre uyarlanabilir.

Her halükarda, burada sunulan vitrinin çok faydalı ve eğlenceli olmasını umuyorum.


(rm)



Haberin Sonu
 
Üst