W tym poście chciałbym opisać sposób wprowadzania danych z czujników do dokumentu xls umieszczonego na dysku Google.
IFTTT
Na samym początku należy wykonać połączenie z usługą internetową IFTTT.
Po zalogowaniu na stronę IFTTT należy wybrać New Applet. Następnie WebHooks
Dla zakładki wybieramy opcję Receive a web request. Będzie on uruchamiany za każdym razem jak zostaną przesłane dane do serwisu:
Następnie wybieramy opcję dodawania nowych wierszy do dokumentu:
W darmowej wersji można umieścić maksymalnie 5 kolumn z danymi, z czego do dyspozycji użytkownika są trzy z nich (Value1, Value2, Value3). Dodatkowo należy wybrać lokalizację plików (domyślnie IFTT/MakerWebooks/<Event>). Nowy dokument zostanie utworzony po przekroczeniu 2000 wierszy.
Teraz wystarczy kliknąć Finish i pierwsza część jest już gotowa.
Test połączenia z dyskiem możemy wykonać przez wejście na stronę webhook service page, gdzie w zakładce Documentation można zobaczyć w jaki sposób wykonać wysłanie danych, oraz jak przetestować połączenie:
Wobec tego w celu aktualizowania danych z poziomu arduino należy przygotować następujące dane do przesłania (po nawiązaniu połaczenia z serwerem IFTTT):
Można go wykonać ręcznie, lub posłużyć się dostępną biblioteką na Githubie.
Funkcja przesyłająca dane wygląda w takim przypadku następująco:
- //https://github.com/Siytek/AnotherIFTTTWebhook/blob/master/AnotherIFTTTWebhook.h
- void send_webhook(char *MakerIFTTT_Event, char *MakerIFTTT_Key, char *value1, char *value2, char *value3) {
- // connect to the Maker event server
- client.connect("maker.ifttt.com", 80);
- // construct the POST request
- char post_rqst[256]; // hand-calculated to be big enough
- char *p = post_rqst;
- p = append_str(p, "POST /trigger/");
- p = append_str(p, MakerIFTTT_Event);
- p = append_str(p, "/with/key/");
- p = append_str(p, MakerIFTTT_Key);
- p = append_str(p, " HTTP/1.1\r\n");
- p = append_str(p, "Host: maker.ifttt.com\r\n");
- p = append_str(p, "Content-Type: application/json\r\n");
- p = append_str(p, "Content-Length: ");
- // we need to remember where the content length will go, which is:
- char *content_length_here = p;
- // it's always two digits, so reserve space for them (the NN)
- p = append_str(p, "NN\r\n");
- // end of headers
- p = append_str(p, "\r\n");
- // construct the JSON; remember where we started so we will know len
- char *json_start = p;
- // As described - this example reports a pin, uptime, and "hello world"
- p = append_str(p, "{\"value1\":\"");
- p = append_str(p, value1);
- p = append_str(p, "\",\"value2\":\"");
- p = append_str(p, value2);
- p = append_str(p, "\",\"value3\":\"");
- p = append_str(p, value3);
- p = append_str(p, "\"}");
- // go back and fill in the JSON length
- // we just know this is at most 2 digits (and need to fill in both)
- int i = strlen(json_start);
- content_length_here[0] = '0' + (i/10);
- content_length_here[1] = '0' + (i%10);
- // finally we are ready to send the POST to the server!
- client.print(post_rqst);
- client.stop();
- }
W przypadku ręcznego wykonywania, należy przesłać następujące dane:
- POST https://maker.ifttt.com/trigger/press_temp_read/with/key/<KLUCZ> HTTP/1.1
- Host: maker.ifttt.com
- Connection: close
- Content-Type: application/json
- Content-Length:
- 52
- {"value1":"22.00","value2":"21.50","value3":"51.80"}
ESP32 Program:
Program ma za zadanie wykonać połączenie z WIFI, odczytać dane z czujników DS18B20 oraz DHT22. Kolejnym krokiem jest przesłanie danych do serwera IFTT, po czym układ przechodzi w stan uśpienia na jedną godzinę.
Na samym początku należy dołożyć potrzebne biblioteki, zdefiniować dane do połączenia z Wifi, stałe do wysłania żądania do serwera, numery pinów do komunikacji z czujnikami.
- #include <WiFi.h>
- #include <Wire.h>
- #include <OneWire.h>
- #include <DallasTemperature.h>
- #include "DHT.h"
- #define DHTTYPE DHT22
- const char* ssid = "SSID";
- const char* password = "PASS";
- const char* request = "https://maker.ifttt.com/trigger/<EVENT>/with/key/<KEY>";
- const char* server = "maker.ifttt.com";
- const uint64_t TIME_TO_SLEEP = 3600;
- const uint8_t DHTPin = 22;
- const uint8_t DS18b20Pin = 4;
- OneWire oneWire(DS18b20Pin);
- DallasTemperature sensors(&oneWire);
- DHT dht(DHTPin, DHTTYPE);
Funkcja setup:
- void setup() {
- Serial.begin(115200);
- delay(3000);
- Serial.println("Program start");
- pinMode(DHTPin, INPUT);
- dht.begin();
- Serial.println("Init WIFI:");
- if(initWifi() == true){
- Serial.println("SendRequest:");
- SendIFTTTRequest();
- }
- esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * 1000000);
- esp_deep_sleep_start();
- }
Powyżej uruchamiał interfejs UART do przesyłania danych na konsolę, następnie uruchamiam komunikację z czujnikiem DHT22. Kolejnym krokiem jest połączenie z wifi. Jeśli połączenie zostało nawiązane to następuje próba połączenia z serwerem IFTTT i przesłanie do niego danych. Po zakończeniu operacji układ wchodzi w tryb uśpienia Deep Sleep na 60 minut.
- bool initWifi() {
- Serial.print("Try to connect: ");
- Serial.print(ssid);
- WiFi.begin(ssid, password);
- int timeout = 100; // 10 seconds
- while(WiFi.status() != WL_CONNECTED && (timeout > 0)) {
- delay(100);
- Serial.print(".");
- timeout--;
- }
- if(WiFi.status() != WL_CONNECTED) {
- Serial.println("/nWifi connection Error");
- return false;
- }
- Serial.print("/nWiFi connected, IP address: ");
- Serial.println(WiFi.localIP());
- return true;
- }
Funkcja initWifi nawiązuje połączenie z Wifi. W przypadku powodzenia zwraca true, jeśli nie uda się nawiązać połączenia zwracana jest wartość false.
Poniżej funkcja nawiązująca połączenie z serwerem i przesyłające dane:
- float GetDHTTemperature(void)
- {
- return dht.readTemperature();
- }
- float GetDHTHumid(void)
- {
- return dht.readHumidity();
- }
- float GetDS18B20Temperature(void)
- {
- sensors.requestTemperatures();
- return sensors.getTempCByIndex(0);
- }
- void SendIFTTTRequest() {
- WiFiClient client;
- float Humid_DHT22 = 0;
- float Temperature_DHT22 = 0;
- float Temperature_DS18B20 = 0;
- int retransmission = 5;
- while(!client.connect(server, 80) && (retransmission > 0)) {
- Serial.print(".");
- retransmission--;
- }
- Serial.println();
- if(!client.connected()) {
- Serial.println("Failed to connect...");
- }
- Temperature_DHT22 = GetDHTTemperature();
- Humid_DHT22 = GetDHTHumid();
- Temperature_DS18B20 = GetDS18B20Temperature();
- String jsonSensorData = String("{\"value1\":\"") +
- (Temperature_DHT22) +
- "\",\"value2\":\"" +
- (Temperature_DS18B20) +
- "\",\"value3\":\"" +
- (Humid_DHT22) + "\"}";
- client.println(String("POST ") + request + " HTTP/1.1");
- client.println(String("Host: ") + server);
- client.println("Connection: close\r\nContent-Type: application/json");
- client.print("Content-Length: ");
- client.println(jsonSensorData.length());
- client.println();
- client.println(jsonSensorData);
- int timeout = 50; // 5 seconds
- while(!client.available() && (timeout > 0)){
- delay(100);
- timeout--;
- if(timeout == 0){
- Serial.println("No response from server..");
- }
- }
- while(client.available()){
- //Print server response
- Serial.write(client.read());
- }
- Serial.println("\nClient close\n");
- client.stop();
- }
Po poprawnym przesłaniu danych od serwera otrzymujemy następującą odpowiedź:
- HTTP/1.1 200 OK
- Content-Type: text/html; charset=utf-8
- Content-Length: 55
- Connection: close
- Date: Mon, 19 Dec 2022 00:43:26 GMT
- X-Powered-By: Sad Unicorns
- X-Robots-Tag: none
- X-Top-SecreTTT: ...
- ETag: W/"..."
- X-Cache: Miss from cloudfront
- Via: ... (CloudFront)
- X-Amz-Cf-Pop: WAW51-P1
- X-Amz-Cf-Id: ...
- Congratulations! You've fired the press_temp_read event
- Client close
Dane zapisane w pliku na dysku Google można oczywiście dowolnie modyfikować. Nowe przesłane dane zostaną zapisane w następnym wolnym wierszu.