Slack bot na ESP8266
W pracy często zamawiamy sobie kebaba na obiad. Kiedy w końcu na recepcję dostawca przywiezie upragnione jedzenie trzeba jakoś powiadomić wszystkich, że kebaby dojechały :P Jak to mówią potrzeba jest matką wynalazków – tak właśnie powstał kebabowy przycisk wysyłający powiadomienie na Slacku :)
Tworzymy aplikację
Aby utworzyć aplikację należy wejść na stronę https://api.slack.com/, a następnie wcisnąć przycisk „Start Building”, a następnie „Create New App”.
W okienku podajemy nazwę bota oraz workspace, do którego chcemy dodać aplikację.
Teraz dodajemy odpowiednie funckjonalności. My chcemy tylko wysyłać wiadomość na kanał, więc wystarczy nam feature o nazwie „Incoming webhooks”. W okienku tworzenia takiego webhooka musimy podać kanał na który będą postowane wiadomości:
Po utworzeniu webhooka dostaniemy jego adres URL, dzięki czemu możemy przetestować jego działanie za pomocą Postmana.
Do postmana importujemy następujący CURL:
curl -X POST -H 'Content-type: application/json' --data '{"text":"Hello, World!"}' URL_DO_WEBHOOKA
Implementacja w ESP8266
Podłączenie
Ja podłączyłem sobie przycisk łączący piny GND oraz D6 (akurat tak pasował :P) + rezystor podciągający 10K pomiędzy pinami D6, a 3V3.
Kod programu
Do implementacji bota wykorzystamy bibliotekę ESP8266HTTPClient (standardowo dołączoną do SDK NodeMCU dla Arduino).
#include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h>
ustalamy pin, do którego podłączony jest przycisk:
#define BUTTON_PIN D6
teraz dodajemy kilka przydatnych stałych:
const char* host = "hooks.slack.com"; const char* fingerprint = "C1 0D 53 49 D2 3E E5 2B A2 61 D5 9E 6F 99 0D 3D FD 8B B2 B3"; const char *ssid = "Nazwa sieci WiFi"; const char *password = "Hasło sieci WiFi"; const char* webhookUrl = "/services/TUTAJ/KLUCZE/API";
poza standardowymi ssid i password ważnymi polami są fingerprint oraz webhookUrl. W webhookUrl podajemy adres URL na jaki ma zostać wysłane zapytanie. Znajdziemy go w sekcji „Incoming webhooks” w ustawieniach aplikacji na samym dole. WAŻNE: Nie podajemy w nim części hosta, czyli https://hooks.slack.com.
Bardzo ważnym parametrem jest fingerprint. Niestery NodeMCU słabo radzi sobie z połączeniami SSL, dlatego też musimy mu podać ręcznie jaki jest fingerprint certyfikatu SSL używanego przez hosta z którym chcemy się połączyć. Taki fingerprint możemy odczytać np. na stronie https://www.grc.com/fingerprints.htm podając w okienku adres hooks.slack.com. Z wyniku musimy usunąć dwukropki i zastąpić je spacjami.
W funkcji setup() standardowo łączymy się z wifi i ustawiamy piny:
void setup() { Serial.begin(9600); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while(WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); Serial.println("Polaczono z WiFi"); pinMode(BUTTON_PIN, INPUT); }
W funkcji loop jedyną rzeczą, której potrzebujemy jest nasłuchiwanie wciśnięcia przycisku kebabowego:
void loop() { if(!digitalRead(BUTTON_PIN)) { sendMessageToAll("Kebaby :)"); } }
Teraz czas na funkcję sendMessageToAll, która wyśle wiadomość na kanał:
void sendMessageToAll(String message) { HTTPClient https; Serial.println("[HTTPS] Wysylanie wiadomosci..."); if(https.begin(host, 443, webhookUrl, true, fingerprint)) { https.addHeader("Content-Type", "application/json"); Serial.print("[HTTPS] POST...\n"); int httpCode = https.POST("{\"text\":\"<!channel> " + message + "\"}"); if (httpCode > 0) { Serial.printf("[HTTPS] POST... kod odp.: %d\n", httpCode); if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { String payload = https.getString(); Serial.println(payload); } } else { Serial.printf("[HTTPS] POST... blad: %s\n", https.errorToString(httpCode).c_str()); } https.end(); } else { Serial.printf("[HTTPS] Blad polaczenia\n"); } }
Są tu 3 ważne wysołania:
https.begin, https.addHeader oraz https.POST.
Pierwsza z nich inicjuje połączenie. Podajemy w niej hosta, port serwera, url, czy request będzie HTTPS? oraz fingerprint certyfikatu.
Kolejna dodaje nagłówek. W naszym przypadku jest to nagłówek „Content-type” z wartością „application/json”, który oznacza, że wysyłamy dane JSONem.
Ostatnia wykonuje zapytanie typu POST na danym połączeniu. Jako parametr przyjmuje zawartość zapytania. W tym momencie serwer zwraca nam odpowiedź, którą logujemy na port szeregowy. Jeżeli kod odpowiedzi HTTP to 200, a wiadomość ok, to na naszym kanale powinna pojawić się nowa wiadomość.
PS. W naszym przypadku mamy małego JSONa i możemy go wysłać jako zahardcodowany string, ale jeżeli potrzebujemy przesłać jakąś większą strukturę danych warto zapoznać się z biblioteką ArduinoJson.