W trzeciej części opisuję bramkę odpowiedzialną za odbiór danych z transmiterów RB-10 i wysłanie tych danych do SUPLA Cloud. Pod względem elektroniki jak i oprogramowania jest to wersja na etapie wczesnego prototypu. Zdecydowałem się jednak upublicznić schemat elektroniki oraz kod licząc, że ktoś z czytelników lub członków Społeczności SUPLA wspomoże mnie w zakresie rozwoju oprogramowania bramki RB-10G. Ja sam jestem „bardzo początkujący” w pisaniu programów 😀 , a obowiązki zawodowe i rodzinne nie zawsze pozwalają na większe zaangażowanie w swój rozwój w tym zakresie.
ELEKTRONIKA
Bramka RB-10G oparta jest o mikrokontroler ESP8266 oraz moduł radiowy RFM69CW 868 MHz. Ja w swoich projektach wykorzystuję najchętniej płytki WEMOS (LOLIN) D1 mini. Oczywiście nic nie stoi na przeszkodzie, aby zbudować bramkę na innych płytkach (NodeMCU, SparkFun, Adafruit).
PROGRAM
Aby móc skompilować i wgrać program do mikrokontrolera ESP8266 musimy jeszcze uzupełnić konfigurację środowiska Arduino IDE. Udajemy się na stronę https://github.com/SUPLA/arduino i pobieramy biblioteki SuplaDevice (klikając w zielony przycisk Clone or download >> Download ZIP). Pobrany plik rozpakowujemy i kopiujemy z otwartego archiwum cały folder SuplaDevice do folderu \Dokumenty\Arduino\libraries.
Aby nasza bramka poprawnie wysyłała dane z więcej niż dwóch czujników musimy jeszcze dokonać małej zmiany w bibliotece SuplaDevice. Odnajdujemy w \Dokumenty\Arduino\libraries\SuplaDevice plik srpc.c, otwieramy plik do edycji (polecam używać do tego celu Notepad++) i modyfikujemy (linie 40 oraz 46):
#define SRPC_QUEUE_SIZE 10
Teraz pozostaje nam podłączyć nasz ESP8266 do komputera, uruchomić Arduino IDE, wybrać właściwą płytkę oraz właściwy port COM (dla WEMOS D1 mini jest to płytka: „LOLIN(WEMOS) D1 R2 & mini”). Przypominam o wersji bibliotek ESP8266 max. 2.5.0.
/* Bramka RB-10G Copyright (C) 2019 Robert Błaszczak Niniejszy program jest wolnym oprogramowaniem; możesz go rozprowadzać dalej i/lub modyfikować na warunkach Powszechnej Licencji Publicznej GNU, wydanej przez Fundację Wolnego Oprogramowania - według wersji 2-giej tej Licencji lub którejś z późniejszych wersji. Niniejszy program rozpowszechniany jest z nadzieją, iż będzie on użyteczny - jednak BEZ JAKIEJKOLWIEK GWARANCJI, nawet domyślnej gwarancji PRZYDATNOŚCI HANDLOWEJ albo PRZYDATNOŚCI DO OKREŚLONYCH ZASTOSOWAŃ. W celu uzyskania bliższych informacji - Powszechna Licencja Publiczna GNU. Z pewnością wraz z niniejszym programem otrzymałeś też egzemplarz Powszechnej Licencji Publicznej GNU (GNU General Public License); jeśli nie - napisz do Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <RFM69_ATC.h> //Pobierz z: https://github.com/lowpowerlab/rfm69 #define NODEID 1 //Unikalny numer bramki (1 - 254). #define NETWORKID 100 //Numer sieci (1 - 254) w której działą bramka SUPLA oraz inne transmitery. Bramka oraz max. 6 transmiterów musi działać w sieci o takim samym ID. #define FREQUENCY RF69_868MHZ //Jeśli posiadasz moduł radiowy pracujący z inną częstotliwością zamień parametr na RF69_433MHZ lub RF69_915MHZ. //#define IS_RFM69HW_HCW //Usuń zacznik komentarza, jeśli posiadasz moduł radiowy w wersji RFM69HW/HCW. #define ENCRYPTKEY "sampleEncryptKey" //Klucz kodowania - 16 znaków (ani mniej, ani więcej) - identyczny w bramce SUPLA i we wszystkich transmiterach. #define ENABLE_ATC //Wstaw znacznik komentarza jeśli chcesz wyłączyć automatyczną kontrolę transmisji (ATC). #define SERIAL_BAUD 115200 //Prędkość transmisji portu szeregowego. #define SUPLADEVICE_CPP #include <SuplaDevice.h> #define SUPLA_SERVER "svrxx.supla.org" #define LOCATION_ID xxxx #define LOCATION_PASSWORD "xxxx" // pobierz identyfikator urządzenia ze strony https://www.supla.org/arduino/get-guid i wprowadź go poniżej #define GUID {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x11,0x12,0x13,0x14,0x15} RFM69_ATC radio(D8, D2, false); bool promiscuousMode = false; const unsigned long period = 600000; //Czas (10 minut) po którym bramka uznaje brak odczytu z transmitera i ustawia wartości wysyłane do Supla Cloud na 0. double temperature = 0.0; double humidity = 0.0; unsigned long startMillis = 0; unsigned long currentMillis = 0; unsigned long RFNodesCount = 0; typedef struct { int nodeid; int channelNumber; double temperature; double humidity; double batteryLevel; unsigned long lastContact; } RF_TemperatureandHumidityNode; RF_TemperatureandHumidityNode RFNodes[6]; void get_temperature_and_humidity(int channelNumber, double *temp, double *humidity) { for (int i = 0; i < RFNodesCount; i++) if (RFNodes[i].channelNumber == channelNumber) { *temp = RFNodes[i].temperature; *humidity = RFNodes[i].humidity; } } void setup() { Serial.begin(SERIAL_BAUD); SuplaDevice.setTemperatureHumidityCallback(&get_temperature_and_humidity); SuplaDevice.addDHT22(); SuplaDevice.addDHT22(); SuplaDevice.addDHT22(); SuplaDevice.addDHT22(); SuplaDevice.addDHT22(); SuplaDevice.addDHT22(); char guid[SUPLA_GUID_SIZE] = GUID; uint8_t mac[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; SuplaDevice.setName("BRAMKA RB-10G"); SuplaDevice.begin(guid, mac, SUPLA_SERVER, LOCATION_ID, LOCATION_PASSWORD); radio.initialize(FREQUENCY,NODEID,NETWORKID); #ifdef IS_RFM69HW_HCW radio.setHighPower(); #endif radio.encrypt(ENCRYPTKEY); radio.promiscuous(promiscuousMode); char buff[65]; sprintf(buff, "BRAMKA RB-10G. Start komunikacji radiowej na częstotliwości %d MHz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); Serial.println(buff); } byte ackCount = 0; uint32_t packetCount = 0; String getValue(String data, char separator, int index) { int found = 0; int strIndex[] = {0, -1}; int maxIndex = data.length() - 1; for (int i = 0; i <= maxIndex && found <= index; i++) { if (data.charAt(i) == separator || i == maxIndex) { found++; strIndex[0] = strIndex[1] + 1; strIndex[1] = (i == maxIndex) ? i + 1 : i; } } return found > index ? data.substring(strIndex[0], strIndex[1]) : ""; } void readRadioData() { String value = ""; if (radio.receiveDone()) { int foundIdx = -1; for (int i = 0; i < RFNodesCount; i++) if (RFNodes[i].nodeid == radio.SENDERID) { foundIdx = i; break; } Serial.println("Odbieram dane..."); if (foundIdx == -1) { if (RFNodesCount < 6) { Serial.println("Znalazłem nowy transmiter. Dodaję go do SUPLA Cloud"); RFNodes[RFNodesCount].nodeid = radio.SENDERID; RFNodes[RFNodesCount].lastContact = millis(); RFNodes[RFNodesCount].channelNumber = radio.SENDERID - 1; RFNodes[RFNodesCount].temperature = 0.0; RFNodes[RFNodesCount].humidity = 0.0; RFNodes[RFNodesCount].batteryLevel = 0; foundIdx = RFNodesCount; RFNodesCount++; } else { Serial.println("Maksymalna ilość transmiterów przekroczona!"); foundIdx = 0; } } else { RFNodes[foundIdx].temperature = 0.0; } Serial.print("#["); Serial.print(++packetCount); Serial.print(']'); Serial.print('['); Serial.print(radio.SENDERID, DEC); Serial.print("] "); value = ""; for (byte i = 0; i < radio.DATALEN; i++) if (radio.DATA[i] != ' ') value += (char)radio.DATA[i]; Serial.println(value); String tempStr = getValue(value, '|', 0); String humStr = getValue(value, '|', 1); String battLevelStr = getValue(value, '|', 2); Serial.print("Temperatura: "); Serial.println(tempStr); Serial.print("Wilgotność: "); Serial.println(humStr); Serial.print("Poziom baterii: "); Serial.println(battLevelStr); RFNodes[foundIdx].temperature = tempStr.toFloat(); RFNodes[foundIdx].humidity = humStr.toFloat(); RFNodes[foundIdx].batteryLevel = battLevelStr.toFloat(); RFNodes[foundIdx].lastContact = millis(); Serial.print("Poziom sygnału transmitera [RX_RSSI]:"); Serial.print(radio.RSSI); Serial.print(" dBm"); if (radio.ACKRequested()) { byte theNodeID = radio.SENDERID; radio.sendACK(); if (ackCount++ % 3 == 0) { Serial.print(" ACK TEST - Transmiter "); Serial.print(theNodeID); delay(5); radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0); } } Blink(LED_BUILTIN, 100); Serial.println(); Serial.println(); } for (int i = 0; i < RFNodesCount; i++) { if (millis() - RFNodes[i].lastContact >= period) { RFNodes[i].temperature = -375; RFNodes[i].humidity = -1; RFNodes[i].batteryLevel = 0; Serial.print("Brak odczytu z czujnika "); Serial.println (RFNodes[i].nodeid); }; } } void Blink(byte PIN, int DELAY_MS) { pinMode(PIN, OUTPUT); digitalWrite(PIN,LOW); delay(DELAY_MS); digitalWrite(PIN,HIGH); } void loop() { readRadioData(); SuplaDevice.iterate(); }
W powyższym kodzie zmieniamy parametry w wierszach 24, 27, 35, 36, 37, i 39.
W tym samym folderze co plik RB-10G_LOLIN_D1.ino dodajemy też plik SuplaTCP.cpp, w którym modyfikujemy:
#define wifiname "SSID" #define wifipassword "password"
podając dane do sieci Wi-Fi, w której będzie działała bramka RB-10G.
SuplaTCP.cpp oraz pozostałe kody programów do pobrania: https://download.blaszczak.pl/?dir=SUPLA/RB-10.
W miarę rozwoju projektu będę starał się umieszczać kolejne wersje oprogramowania oraz przedstawiać modyfikacje części elektronicznej bramki.
<<< CZĘŚĆ 2 <<< |