Parametry z sensorów przekazywane po RF

kuba98743
Posts: 9
Joined: Tue Apr 05, 2022 4:35 pm

Post

Witam,

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! 😊 Może w ramach ciekawostki lub inspiracji komuś się przyda :D

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
}
Schemat połącznia arduino nadajnik:
2.png
Kod do Arduino z odbiornikiem:

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");
}
Schemat arduino odbiornik + arduino mega:
1.png
Kod do Arduino Mega:

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);
}
Zdjęcie poglądowe z aplikacji:
Screenshot_20250210-161832.SUPLA.png
Ps: Komentarze wykonywał wuja :D
You do not have the required permissions to view the files attached to this post.
Last edited by kuba98743 on Tue Feb 11, 2025 9:56 am, edited 1 time in total.
[email protected]
Posts: 1585
Joined: Mon Feb 06, 2023 8:56 am
Has thanked: 18 times
Been thanked: 26 times

Post

kuba98743 wrote: Mon Feb 10, 2025 11:18 pm
Gratuluje projektu ;)
Wrzuć proszę zdjęcia jako załączniki i podepnij w tekście - po czasie znikną z imgur i nie będzie można ich zobaczyć
matrix0606
Posts: 496
Joined: Tue Nov 08, 2022 9:05 pm

Post

Pozwolę sobie dopisać nic nie znaczący komentarz, bo interesuje mnie ten temat.
W każdym razie projekt spoko.
Vivo V21 5G 8G RAM + 4G SWAP - Funtouch OS 12 Global
MOBO - MSI B350 Tomahawk || GPU - XFX Radeon RX 6600 Speedster
CPU - Ryzen5 1400 3,2G || PSU - SPC Vero | L2 500W 80 Plus Bronze
RAM - HyperX 2x8GB 3200MHz CL16 Predator RGB
Adamo28
Posts: 223
Joined: Sun Nov 08, 2020 2:54 pm

Post

Hej, sprawdzałeś jaki masz maksymalnie zasięg na tych modułach RF ?
mmiikk
Posts: 670
Joined: Mon Aug 06, 2018 1:27 pm
Has thanked: 1 time
Been thanked: 2 times

Post

Hej, to świetne, od lat koncepckja mi siedziała w głowie ale brak umiejętności do wykonania,
czy mógłbyś dołożyć sterowanie przekaźnikiem via RF i odczytywanie jego aktualnego stanu?, chyba nie było by to trudne, a od lat czekam na taką możliwość via RF. Chodzi i element wykonawczy który będzie załączał i wylączał przekaźnik a w supki będzie jego aktualny stan, przekaźnik powinno tez muc dać sie załączyć wyłaczyć lokalnie przez przycisk. Dzieki temu dało by se zorbić tam gdzie wifi nei siega i bez ciągnięcia kabli sterowanie np CO.
Nie ukrywam że najchętniej ożeniłbym to z termostatem z gui generic, choc nei wiem jak jeszcze żeby termostat myślał ze steruje przekaźnikiem do niego podłączonym.

Return to “Projekty użytkowników”