Chciałbym przedstawić łopatologiczny sposób przesyłania danych do Supli za pomocą nadajnika i odbiornika RF. Zaznaczam, że nie jestem programistą – kody powstały na bazie różnych przykładów oraz z pomocą wujka GPT. Projekt to efekt składania nazbieranych w szufladzie komponentów elektronicznych, znajduje się we wczesnej fazie i został zrealizowany w możliwie najdłuższy i najmniej optymalny sposób.
Do projektu wykorzystałem Arduino Uno, które zbiera sygnały z trzech sensorów wilgotności gleby oraz DHT11. Następnie dane są przetwarzane i przesyłane do drugiego Arduino Uno za pomocą nadajnika RF FS1000A. Odbiornik XY-MK, podłączony do drugiego Arduino, odbiera dane, przetwarza je i przesyła dalej przez I2C do Arduino Mega z Ethernet Shieldem W5100. To ostatnie urządzenie podmienia wartości wirtualnych sensorów i wyświetla je w Supli. Zamysł był taki aby obsługiwać szklarnie która znajduje się poza zasięgiem wi-fi i nie ma możliwości(chęci) ciągnięcia skrętki.
Projekt jest eksperymentalny, ale działa!
Kod do Arduino z nadajnikiem oraz sensorami:
Code: Select all
#include <RH_ASK.h>
#include <SPI.h> // Biblioteka SPI wymagana do poprawnej kompilacji
#include <DHT.h>
#define DHTPIN 7
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
RH_ASK driver;
// Piny czujników analogowych
int sensor_A0 = A0;
int sensor_A1 = A1;
int sensor_A2 = A2;
void setup() {
Serial.begin(9600);
dht.begin();
if (!driver.init()) { // Sprawdzenie poprawnej inicjalizacji modułu nadawczego
Serial.println("Błąd inicjalizacji nadajnika!");
}
}
void loop() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
int wartosc_A0 = analogRead(sensor_A0);
int wartosc_A1 = analogRead(sensor_A1);
int wartosc_A2 = analogRead(sensor_A2);
// Bufory do przechowywania wartości jako stringi
char tekst[10], tekst2[10], tekst3[10], tekst4[10], tekst5[10];
// Konwersja wartości liczbowych do postaci tekstowej
dtostrf(temperature, 6, 2, tekst);
dtostrf(humidity, 6, 2, tekst2);
dtostrf((float)wartosc_A0, 6, 2, tekst3);
dtostrf((float)wartosc_A1, 6, 2, tekst4);
dtostrf((float)wartosc_A2, 6, 2, tekst5);
// Wypisanie wartości do monitorowania w konsoli
Serial.print("Temperature: ");
Serial.println(temperature);
Serial.print("Humidity: ");
Serial.println(humidity);
Serial.print("S1: ");
Serial.println(wartosc_A0);
Serial.print("S2: ");
Serial.println(wartosc_A1);
Serial.print("S3: ");
Serial.println(wartosc_A2);
// Sprawdzenie, czy odczyt z czujnika DHT11 był poprawny
if (isnan(temperature) || isnan(humidity)) {
Serial.println("Błąd odczytu z DHT11");
return;
}
// Formowanie wiadomości do wysłania
char msg[50];
snprintf(msg, sizeof(msg), "T:%s H:%s S1:%s S2:%s S3:%s", tekst, tekst2, tekst3, tekst4, tekst5);
// Wysłanie danych przez moduł RF
driver.send((uint8_t *)msg, strlen(msg));
driver.waitPacketSent();
Serial.print("Wysłano: ");
Serial.println(msg);
delay(2000); // Przerwa przed kolejnym odczytem
}
Code: Select all
#include <Wire.h> // Biblioteka do obsługi komunikacji I2C
#include <RH_ASK.h> // Biblioteka do obsługi komunikacji RF ASK
#include <SPI.h> // Wymagana przez RH_ASK
// Tworzenie obiektu do obsługi odbiornika RF
RH_ASK driver;
void setup() {
Serial.begin(9600); // Inicjalizacja komunikacji szeregowej
Wire.begin(); // Inicjalizacja magistrali I2C
// Inicjalizacja odbiornika RF
if (!driver.init()) {
Serial.println("RF init failed");
while (1); // Zatrzymanie programu w przypadku błędu
}
}
void loop() {
uint8_t buf[50]; // Bufor na odebrane dane RF
uint8_t buflen = sizeof(buf);
// Sprawdzenie, czy odebrano dane RF
if (driver.recv(buf, &buflen)) {
buf[buflen] = '\0'; // Dodanie znaku końca ciągu
Serial.print("Odebrano: ");
Serial.println((char *)buf); // Wyświetlenie odebranej wiadomości
// Wyszukiwanie poszczególnych wartości w odebranych danych
char *t_ptr = strchr((char *)buf, 'T');
char *h_ptr = strchr((char *)buf, 'H');
char *s1_ptr = strchr((char *)buf, 'S');
char *s2_ptr = strstr((char *)buf, "S2");
char *s3_ptr = strstr((char *)buf, "S3");
// Inicjalizacja zmiennych do przechowywania wartości sensorycznych
float temperatura = 0.0, wilgotnosc = 0.0;
float sensor1 = 0.0, sensor2 = 0.0, sensor3 = 0.0;
// Konwersja odebranych wartości na liczby zmiennoprzecinkowe
if (t_ptr != NULL) temperatura = atof(t_ptr + 3);
if (h_ptr != NULL) wilgotnosc = atof(h_ptr + 3);
if (s1_ptr != NULL) sensor1 = atof(s1_ptr + 3);
if (s2_ptr != NULL) sensor2 = atof(s2_ptr + 3);
if (s3_ptr != NULL) sensor3 = atof(s3_ptr + 3);
// Wyświetlenie odczytanych wartości na porcie szeregowym
Serial.print("Temperatura: "); Serial.println(temperatura);
Serial.print("Wilgotność: "); Serial.println(wilgotnosc);
Serial.print("Sensor1: "); Serial.println(sensor1);
Serial.print("Sensor2: "); Serial.println(sensor2);
Serial.print("Sensor3: "); Serial.println(sensor3);
// Wysłanie danych do innego urządzenia poprzez I2C
sendDataToI2C(temperatura, wilgotnosc, sensor1, sensor2, sensor3);
delay(1000); // Opóźnienie przed kolejnym odbiorem danych
}
}
void sendDataToI2C(float temperatura, float wilgotnosc, float sensor1, float sensor2, float sensor3) {
byte data[5 * sizeof(float)]; // Bufor na dane do wysłania
// Konwersja wartości float na tablicę bajtów
memcpy(data, &temperatura, sizeof(temperatura));
memcpy(data + sizeof(temperatura), &wilgotnosc, sizeof(wilgotnosc));
memcpy(data + 2 * sizeof(temperatura), &sensor1, sizeof(sensor1));
memcpy(data + 3 * sizeof(temperatura), &sensor2, sizeof(sensor2));
memcpy(data + 4 * sizeof(temperatura), &sensor3, sizeof(sensor3));
// Wysłanie danych do urządzenia o adresie I2C 8
Wire.beginTransmission(8);
Wire.write(data, sizeof(data));
Wire.endTransmission();
Serial.println("Dane zostały wysłane przez I2C");
}
Code: Select all
#include <SuplaDevice.h>
#include <supla/sensor/thermometer.h>
#include <Wire.h>
// Wybór interfejsu sieciowego w zależności od architektury mikrokontrolera
#ifdef ARDUINO_ARCH_AVR
#include <supla/network/ethernet_shield.h> // Użycie EthernetShield dla Arduino Mega
uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; // Definicja adresu MAC
Supla::EthernetShield ethernet(mac); // Inicjalizacja obiektu EthernetShield z zadanym adresem MAC
#endif
// Klasa VirtualThermometer dziedziczy po Supla::Sensor::Thermometer i umożliwia ustawianie oraz pobieranie wartości
class VirtualThermometer : public Supla::Sensor::Thermometer {
public:
double getValue() override { // Metoda zwracająca aktualną wartość temperatury
return myValue;
}
void setValue(double val) { // Metoda ustawiająca nową wartość temperatury
myValue = val;
}
protected:
double myValue = TEMPERATURE_NOT_AVAILABLE; // Początkowa wartość informująca o niedostępności temperatury
};
// Wskaźniki na obiekty reprezentujące 5 termometrów
VirtualThermometer* t1;
VirtualThermometer* t2;
VirtualThermometer* t3;
VirtualThermometer* t4;
VirtualThermometer* t5;
// Zmienne globalne przechowujące dane odebrane przez I2C
float temperatura = 0.0;
float wilgotnosc = 0.0;
float sensor1 = 0.0;
float sensor2 = 0.0;
float sensor3 = 0.0;
void setup() {
Serial.begin(9600); // Inicjalizacja portu szeregowego dla komunikacji debugującej
Wire.begin(8); // Konfiguracja modułu I2C jako slave z adresem 8
Wire.onReceive(receiveData); // Ustawienie funkcji, która zostanie wywołana przy odbiorze danych przez I2C
Serial.println("Odbiornik I2C uruchomiony!");
// Konfiguracja identyfikatora GUID oraz klucza autoryzacyjnego AUTHKEY wymaganych przez SUPLA
char GUID[SUPLA_GUID_SIZE] = {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx};
char AUTHKEY[SUPLA_AUTHKEY_SIZE] = {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx};
// Przykładowe wartości początkowe dla każdego z 5 termometrów
double wartosc_t1 = 22.5;
double wartosc_t2 = 23.0;
double wartosc_t3 = 24.5;
double wartosc_t4 = 26.0;
double wartosc_t5 = 27.5;
// Dynamiczna alokacja obiektów VirtualThermometer
t1 = new VirtualThermometer;
t2 = new VirtualThermometer;
t3 = new VirtualThermometer;
t4 = new VirtualThermometer;
t5 = new VirtualThermometer;
// Ustawienie początkowych wartości temperatur dla poszczególnych termometrów
t1->setValue(wartosc_t1);
t2->setValue(wartosc_t2);
t3->setValue(wartosc_t3);
t4->setValue(wartosc_t4);
t5->setValue(wartosc_t5);
// Inicjalizacja urządzenia SUPLA z danymi logowania i autoryzacji
SuplaDevice.begin(GUID, "svr", "mail", AUTHKEY);
}
void loop() {
SuplaDevice.iterate(); // Aktualizacja stanu połączenia SUPLA
// Uaktualnienie wartości termometrów na podstawie danych odebranych przez I2C
t1->setValue(temperatura);
t2->setValue(wilgotnosc);
t3->setValue(sensor1);
t4->setValue(sensor2);
t5->setValue(sensor3);
}
// Funkcja wywoływana przy odbiorze danych przez I2C
void receiveData(int byteCount) {
byte data[5 * sizeof(float)]; // Bufor na odebrane bajty, gdzie spodziewamy się 5 wartości typu float
Wire.readBytes(data, sizeof(data)); // Odczytanie całego bloku danych z I2C
// Konwersja odebranych bajtów na zmienne typu float
memcpy(&temperatura, data, sizeof(temperatura));
memcpy(&wilgotnosc, data + sizeof(temperatura), sizeof(wilgotnosc));
memcpy(&sensor1, data + 2 * sizeof(temperatura), sizeof(sensor1));
memcpy(&sensor2, data + 3 * sizeof(temperatura), sizeof(sensor2));
memcpy(&sensor3, data + 4 * sizeof(temperatura), sizeof(sensor3));
// Wypisanie odebranych wartości na port szeregowy dla celów debugowania
Serial.print("Temperatura: ");
Serial.println(temperatura);
Serial.print("Wilgotność: ");
Serial.println(wilgotnosc);
Serial.print("Sensor1: ");
Serial.println(sensor1);
Serial.print("Sensor2: ");
Serial.println(sensor2);
Serial.print("Sensor3: ");
Serial.println(sensor3);
}