Licznik wody kto zrobi mi pewną funkcję? bardzo mi zależy

Masz pomysł na funkcjonalność lub koncepcję na rozwój projektu. Opisz wszystko tutaj.
User avatar
SOYER
Posts: 1623
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry
Been thanked: 2 times

Post

Pietras81 wrote: Tue Jan 06, 2026 8:36 am
SOYER wrote: Tue Jan 06, 2026 7:42 am „Fakt ten przeoczyłem ja”, powiedział mistrz Yoda w grze dzisiaj kiedy najmłodszy mój szkrab grał:))
Poprawiłem i chyba jeszcze taki problem że odczytuje 2 miejsca a nie trzy po przecinku.

Code: Select all

user.............:39a3ea88ec1dd225b1c9b8fd252af7fa
serwer.............:mqtt20.supla.org
password:.............e0i8cDXpQjyLGsNi66ni7fw@8UZqjIM=
dv.............1: 9540
channel.............1: 25561
message:.............1: Powódz
devName message:.............1: Woda
level alarm:.............1: 0.002
level alarm night:.............1: 10
time period.............1: 600000
time period night.............1: 1000
supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value
dv.............2: 1
channel.............2: 1
message:.............2: a
devName message:.............2: a
level alarm:.............2: 40
level alarm night:.............2: 10
time period.............2: 40
time period night.............2: 10
supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/1/channels/1/state/calculated_value
dv.............3: 1
channel.............3: 1
message:.............3: a
devName message:.............3: a
level alarm:.............3: 40
level alarm night:.............3: 10
time period.............3: 40
time period night.............3: 10
supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/1/channels/1/state/calculated_value
numofcounter.............: 1
MQTT config...
E (3623) wifi:Association refused too many times, max allowed 1
E (3628) wifi:sta is connecting, return error
E (5753) wifi:sta is connecting, return error
!!connected to MQTT!!
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.067
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.068
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.069
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.069
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.070
COUNTER1:......................209.07level alarm:.............3: 40
level alarm night:.............3: 10
time period.............3: 40
time period night.............3: 10
supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/1/channels/1/state/calculated_value
numofcounter.............: 1
MQTT config...
E (3623) wifi:Association refused too many times, max allowed 1
E (3628) wifi:sta is connecting, return error
E (5753) wifi:sta is connecting, return error
!!connected to MQTT!!
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.067
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.068
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.069
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.069
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.070
COUNTER1:......................209.07
valveClose:  1
valveClose:  0
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.071
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.071
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.072
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.072
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.073
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.073
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.074
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.074
COUNTER1:......................209.07
valveClose:  1
valveClose:  0
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 
COUNTER1:......................0.00
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.074
COUNTER1:......................209.07
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 
COUNTER1:......................0.00
Message arrived [supla/39a3ea88ec1dd225b1c9b8fd252af7fa/devices/9540/channels/25561/state/calculated_value] 209.074
COUNTER1:......................209.07
Zmienna do której zapisuje odczyt jest typu double, @klew jak poprawić by zapisywało wartość z pełną dkokładnością?
https://youtube.com/@tomaszhamer8134?si=_J1cT_QWsXxgt1Fm
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
https://github.com/Soyer79
User avatar
klew
Posts: 13905
Joined: Thu Jun 27, 2019 12:16 pm
Location: Wrocław
Has thanked: 134 times
Been thanked: 137 times

Post

SOYER wrote: Tue Jan 06, 2026 10:01 am Zmienna do której zapisuje odczyt jest typu double, @klew jak poprawić by zapisywało wartość z pełną dkokładnością?
Nie wczytywałem się we wszystko dokładnie.
Jaka wartość? Skąd brana? Pisałeś coś o polu tekstowym, więc jak konwertujesz do typu liczbowego?
Najlepsze suple dla Twojego domu :mrgreen:
User avatar
SOYER
Posts: 1623
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry
Been thanked: 2 times

Post

klew wrote: Tue Jan 06, 2026 10:05 am
SOYER wrote: Tue Jan 06, 2026 10:01 am Zmienna do której zapisuje odczyt jest typu double, @klew jak poprawić by zapisywało wartość z pełną dkokładnością?
Nie wczytywałem się we wszystko dokładnie.
Jaka wartość? Skąd brana? Pisałeś coś o polu tekstowym, więc jak konwertujesz do typu liczbowego?
Wydaje się, że problem wynika z domyślnej wartości wyświetlanej dla Serial.println, domyślnie są zdaje się dwie cyfry po przecinku, jednak sama wartość zapisana jest ok.
Zaraz to sprawdzę.
Chodzi o te linijki:

Code: Select all

if (strcmp(topic, top1.c_str()) == 0) {
    payload[length] = '\0';
    counter_1 = atof((char*)payload);
wartość zmiennej jest wypisywana tak:

Code: Select all

USBSerial.print("COUNTER1:......................");
    USBSerial.println(counter_1);
a zdaje się powinno być chociaż tak, jeśli chcemy większą precyzję pokazać:

Code: Select all

USBSerial.print("COUNTER1:......................");
    USBSerial.println(counter_1, 3);
https://youtube.com/@tomaszhamer8134?si=_J1cT_QWsXxgt1Fm
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
https://github.com/Soyer79
Pietras81
Posts: 2409
Joined: Sun Feb 17, 2019 6:56 am
Location: Osielsko
Been thanked: 1 time

Post

SOYER wrote: Tue Jan 06, 2026 10:20 am
klew wrote: Tue Jan 06, 2026 10:05 am
SOYER wrote: Tue Jan 06, 2026 10:01 am Zmienna do której zapisuje odczyt jest typu double, @klew jak poprawić by zapisywało wartość z pełną dkokładnością?
Nie wczytywałem się we wszystko dokładnie.
Jaka wartość? Skąd brana? Pisałeś coś o polu tekstowym, więc jak konwertujesz do typu liczbowego?
Wydaje się, że problem wynika z domyślnej wartości wyświetlanej dla Serial.println, domyślnie są zdaje się dwie cyfry po przecinku, jednak sama wartość zapisana jest ok.
Zaraz to sprawdzę.
Chodzi o te linijki:

Code: Select all

if (strcmp(topic, top1.c_str()) == 0) {
    payload[length] = '\0';
    counter_1 = atof((char*)payload);
wartość zmiennej jest wypisywana tak:

Code: Select all

USBSerial.print("COUNTER1:......................");
    USBSerial.println(counter_1);
a zdaje się powinno być chociaż tak, jeśli chcemy większą precyzję pokazać:

Code: Select all

USBSerial.print("COUNTER1:......................");
    USBSerial.println(counter_1, 3);
Poprawiłem i zaraz testuje :)
https://pietras-81.aqi.eco/
User avatar
SOYER
Posts: 1623
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry
Been thanked: 2 times

Post

Pietras81 wrote: Tue Jan 06, 2026 11:27 am
SOYER wrote: Tue Jan 06, 2026 10:20 am
klew wrote: Tue Jan 06, 2026 10:05 am

Nie wczytywałem się we wszystko dokładnie.
Jaka wartość? Skąd brana? Pisałeś coś o polu tekstowym, więc jak konwertujesz do typu liczbowego?
Wydaje się, że problem wynika z domyślnej wartości wyświetlanej dla Serial.println, domyślnie są zdaje się dwie cyfry po przecinku, jednak sama wartość zapisana jest ok.
Zaraz to sprawdzę.
Chodzi o te linijki:

Code: Select all

if (strcmp(topic, top1.c_str()) == 0) {
    payload[length] = '\0';
    counter_1 = atof((char*)payload);
wartość zmiennej jest wypisywana tak:

Code: Select all

USBSerial.print("COUNTER1:......................");
    USBSerial.println(counter_1);
a zdaje się powinno być chociaż tak, jeśli chcemy większą precyzję pokazać:

Code: Select all

USBSerial.print("COUNTER1:......................");
    USBSerial.println(counter_1, 3);
Poprawiłem i zaraz testuje :)
Nie zadziała Ci, musisz jeszcze wrzucić inne zmiany w kodzie. Daj mi 10 minut.
https://youtube.com/@tomaszhamer8134?si=_J1cT_QWsXxgt1Fm
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
https://github.com/Soyer79
User avatar
SOYER
Posts: 1623
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry
Been thanked: 2 times

Post

Ten kod, binarka i github:

https://github.com/Soyer79/LIWx3_MQTT_valve

Pamiętajcie, że w progu wpisujemy wartości tak by pasowały do tego co mamy ustawione w cloud dla wyświetlania w apce. Jeśli nam wyświetla w m3 np: 128.456m3, a chcemy zareagować na 40 litrów to w progu wpisujemy 0.040.

Code: Select all

#include <SuplaDevice.h>//////https://github.com/SUPLA
#include <WiFiClientSecure.h>
#include <supla/network/esp_wifi.h>
#include <supla/storage/littlefs_config.h>
#include <supla/network/esp_web_server.h>
#include <supla/network/html/device_info.h>
#include <supla/network/html/protocol_parameters.h>
#include <supla/network/html/wifi_parameters.h>
#include <supla/network/html/custom_parameter.h>
#include <supla/network/html/custom_text_parameter.h>
#include <supla/device/supla_ca_cert.h>
#include <supla/device/notifications.h>
#include <supla/control/relay.h>
#include <supla/clock/clock.h> //int clock1.getYear(); getMonth(); getDay(); getDayOfWeek();1 - Sunday, 2 - Monday getHour(); getMin(); getSec();
#include "HWCDC.h"
#include <supla/device/enter_cfg_mode_after_power_cycle.h>
#include <PubSubClient.h>

HWCDC USBSerial;
Supla::ESPWifi wifi;
Supla::Clock clock1;
Supla::LittleFsConfig configSupla(4000);
Supla::EspWebServer suplaServer;
Supla::Html::DeviceInfo htmlDeviceInfo(&SuplaDevice);
Supla::Html::WifiParameters htmlWifi;
Supla::Html::ProtocolParameters htmlProto;

WiFiClientSecure client1;
PubSubClient client(client1);

const char PARAM1[] = "MQTTserver";
const char PARAM2[] = "MQTTuser";
const char PARAM3[] = "MQTTpass";
const char PARAM4[] = "dvID:1";
const char PARAM5[] = "channID:1";
const char PARAM6[] = "night_h_st:1";
const char PARAM7[] = "night_h_end:1";
const char PARAM8[] = "dvNameMssg:1";
const char PARAM9[] = "message:1";
const char PARAM10[] = "lvlAlarm:1";
const char PARAM11[] = "lvlAlarmN:1";
const char PARAM12[] = "periodTtime:1";
const char PARAM13[] = "periodTimeN:1";

const char PARAM14[] = "dvID:2";
const char PARAM15[] = "channID:2";
const char PARAM16[] = "night_h_st:2";
const char PARAM17[] = "night_h_end:2";
const char PARAM18[] = "dvNameMssg:2";
const char PARAM19[] = "message:2";
const char PARAM20[] = "lvlAlarm:2";
const char PARAM21[] = "lvlAlarmN:2";
const char PARAM22[] = "periodTtime:2";
const char PARAM23[] = "periodTtimeN:2";

const char PARAM24[] = "dvID:3";
const char PARAM25[] = "channID:3";
const char PARAM26[] = "night_h_st:3";
const char PARAM27[] = "night_h_end:3";
const char PARAM28[] = "dvNameMssg:3";
const char PARAM29[] = "message:3";
const char PARAM30[] = "lvlAlarm:3";
const char PARAM31[] = "lvlAlarmN:3";
const char PARAM32[] = "periodTtime:3";
const char PARAM33[] = "periodTtimeN:3";
const char PARAM34[] = "numberOfCounters";

double counter_1 = 0;
double tempCounter_1;
double tempCounterNight_1;
boolean ResetTempCounterNight_1= 0;
double counter_2 = 0;
double tempCounter_2;
double tempCounterNight_2;
boolean ResetTempCounterNight_2= 0;
double counter_3 = 0;
double tempCounter_3;
double tempCounterNight_3;
boolean ResetTempCounterNight_3= 0;

char mqtt_server[200] ="a";
char mqtt_user[200] ="a";
char mqtt_pass[200] ="a";

int32_t dv_id_1 =1;
int32_t chann_id_1 =1;
int32_t night_h_start_1 =1;
int32_t night_h_stop_1 =1;
char dev_name_message_1[200] ="a";
char message_1[200] ="a";
char level_alarm_1[10] = "40";
char level_alarm_night_1[10] = "10";
double levelAlarm1 = 1;
double levelAlarmNight1 = 1;
int32_t time_period_1 = 40;
int32_t time_period_night_1 = 10;

int32_t dv_id_2 =1;
int32_t chann_id_2 =1;
int32_t night_h_start_2 =1;
int32_t night_h_stop_2 =1;
char dev_name_message_2[200] ="a";
char message_2[200]="a";
char level_alarm_2[10] = "40";
char level_alarm_night_2[10] = "10";
double levelAlarm2 = 1;
double levelAlarmNight2 = 1;
int32_t time_period_2 = 40;
int32_t time_period_night_2 = 10;

int32_t dv_id_3 =1;
int32_t chann_id_3 =1;
int32_t night_h_start_3 =1;
int32_t night_h_stop_3 =1;
char dev_name_message_3[200] ="a";
char message_3[200] ="a";
char level_alarm_3[10] = "40";
char level_alarm_night_3[10] = "10";
double levelAlarm3 = 1;
double levelAlarmNight3 = 1;
int32_t time_period_3 = 40;
int32_t time_period_night_3 = 10;

int32_t num_of_counter = 0;
String top1 = "xxx";
String top2 = "xxx";
String top3 = "xxx";
String tim;

boolean first_run1=true;
boolean first_run2=true;
boolean first_run3=true;
boolean night_1 = 0;
boolean night_2 = 0;
boolean night_3 = 0;
boolean on_milli_start = 0;
boolean off_milli_start = 0;
unsigned long valveOn_millis;
unsigned long valveOff_millis;
unsigned long sek_millis;
unsigned long prev_min_millis_1;
unsigned long prev_hour_millis_1;
unsigned long prev_min_millis_2;
unsigned long prev_hour_millis_2;
unsigned long prev_min_millis_3;
unsigned long prev_hour_millis_3;
unsigned long prev_minute_millis;
unsigned long lastReconnectAttempt = 0;
Supla::Control::Relay *valveOpen = nullptr;
Supla::Control::Relay *valveClose = nullptr;

void setup() {
  USBSerial.begin(9600);
  Supla::Storage::Init();
 
  SuplaDevice.addClock(new Supla::Clock);
  auto clock1 = SuplaDevice.getClock();
  if(num_of_counter==0){
    new Supla::Html::CustomParameter(PARAM34, "number of counters(1,2,3)");
  }

  if (Supla::Storage::ConfigInstance()->getInt32(PARAM34, &num_of_counter)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM34, num_of_counter);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM34);
  }

  if(num_of_counter==1){
    inputs1();
  }
  else if(num_of_counter==2){
    inputs1();
    inputs2();
   }
  else if(num_of_counter==3){
    inputs1();
    inputs2();
    inputs3();
  }
  new Supla::Device::EnterCfgModeAfterPowerCycle(15000, 3, true);
  Supla::Notification::RegisterNotification(-1);
  SuplaDevice.setSuplaCACert(suplaCACert);
  SuplaDevice.setSupla3rdPartyCACert(supla3rdCACert);
  SuplaDevice.begin();
  paramSave();
  
  top1 = "supla/"+String(mqtt_user)+"/devices/"+String(dv_id_1)+"/channels/"+String(chann_id_1)+"/state/calculated_value";
  top2 = "supla/"+String(mqtt_user)+"/devices/"+String(dv_id_2)+"/channels/"+String(chann_id_2)+"/state/calculated_value";
  top3 = "supla/"+String(mqtt_user)+"/devices/"+String(dv_id_3)+"/channels/"+String(chann_id_3)+"/state/calculated_value";
  
  valveOpen = new Supla::Control::Relay(8, false);
  valveClose = new Supla::Control::Relay(9, false);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  valveOpen->turnOff();
  valveClose->turnOff();
  prev_min_millis_1 = millis();
  prev_hour_millis_1 = millis();
  prev_min_millis_2 = millis();
  prev_hour_millis_2 = millis();
  prev_min_millis_3 = millis();
  prev_hour_millis_3 = millis();
  sek_millis = millis();
  lastReconnectAttempt = 0;

  delay(2000);
  charToDouble();
  USBSerial.print("user.............:");
  USBSerial.println(mqtt_user);
  USBSerial.print("serwer.............:");
  USBSerial.println(mqtt_server);
  USBSerial.print("password:.............");
  USBSerial.println(mqtt_pass);
  USBSerial.print("dv.............1: ");
  USBSerial.println(dv_id_1);
  USBSerial.print("channel.............1: ");
  USBSerial.println(chann_id_1);
  USBSerial.print("message:.............1: ");
  USBSerial.println(message_1);
  USBSerial.print("devName message:.............1: ");
  USBSerial.println(dev_name_message_1);
  USBSerial.print("level alarm:.............1: ");
  USBSerial.println(levelAlarm1, 4);
  USBSerial.print("level alarm night:.............1: ");
  USBSerial.println(levelAlarmNight1, 4);
  USBSerial.print("time period.............1: ");
  USBSerial.println(time_period_1);
  USBSerial.print("time period night.............1: ");
  USBSerial.println(time_period_night_1);
  USBSerial.println(top1);
  USBSerial.print("dv.............2: ");
  USBSerial.println(dv_id_2);
  USBSerial.print("channel.............2: ");
  USBSerial.println(chann_id_2);
  USBSerial.print("message:.............2: ");
  USBSerial.println(message_2);
  USBSerial.print("devName message:.............2: ");
  USBSerial.println(dev_name_message_2);
  USBSerial.print("level alarm:.............2: ");
  USBSerial.println(levelAlarm2, 4);
  USBSerial.print("level alarm night:.............2: ");
  USBSerial.println(levelAlarmNight2, 4);
  USBSerial.print("time period.............2: ");
  USBSerial.println(time_period_2);
  USBSerial.print("time period night.............2: ");
  USBSerial.println(time_period_night_2);
  USBSerial.println(top2);
  USBSerial.print("dv.............3: ");
  USBSerial.println(dv_id_3);
  USBSerial.print("channel.............3: ");
  USBSerial.println(chann_id_3);
  USBSerial.print("message:.............3: ");
  USBSerial.println(message_3);
  USBSerial.print("devName message:.............3: ");
  USBSerial.println(dev_name_message_3);
  USBSerial.print("level alarm:.............3: ");
  USBSerial.println(levelAlarm3, 4);
  USBSerial.print("level alarm night:.............3: ");
  USBSerial.println(levelAlarmNight3, 4);
  USBSerial.print("time period.............3: ");
  USBSerial.println(time_period_3);
  USBSerial.print("time period night.............3: ");
  USBSerial.println(time_period_night_3);
  USBSerial.println(top3);
  USBSerial.print("numofcounter.............: ");
  USBSerial.println(num_of_counter);
   if(dv_id_1 != 1){
    mqttConfig();
   }
   
}

void loop() {
 SuplaDevice.iterate();
  if(dv_id_1 != 1){
   valveControl();
    nightReady();
    if (!client.connected()) {
      long now = millis();
      if (now - lastReconnectAttempt > 5000) {
       lastReconnectAttempt = now;
        if (reconnect()) {
         lastReconnectAttempt = 0;
        }
      }
    } 
    else {
     client.loop();
    }

  if(num_of_counter==1){
    waterControl1();
  }
  else if(num_of_counter==2){
    waterControl1();
    waterControl2();
   }
  else if(num_of_counter==3){
    waterControl1();
    waterControl2();
    waterControl3();
  }
}
}

boolean reconnect() {
  if (WiFi.status() == WL_CONNECTED) {
    String clientId = "ESP32Client-";
    clientId += String(random(0xffff), HEX);
    if (client.connect(clientId.c_str(), mqtt_user, mqtt_pass)) {
      USBSerial.println("!!connected to MQTT!!");
      if(num_of_counter==1){
        client.subscribe(top1.c_str());
      }
      else if(num_of_counter==2){
        client.subscribe(top1.c_str());
        client.subscribe(top2.c_str());
      }
      else if(num_of_counter==3){
        client.subscribe(top1.c_str());
        client.subscribe(top2.c_str());
        client.subscribe(top3.c_str());
      }
    } else {
      USBSerial.print("failed, rc=");
      USBSerial.print(client.state());
    }
  }
  return client.connected();
}
void mqttConfig() {
  USBSerial.println("MQTT config...");
  client1.setInsecure();
  client.setServer(mqtt_server, 8883);
  client.setCallback(callback);
}

void callback(char* topic, byte* payload, unsigned int length) {
  USBSerial.print("Message arrived [");
  USBSerial.print(topic);
  USBSerial.print("] ");
  for (int i = 0; i < length; i++) {
    USBSerial.print((char)payload[i]);
  }
  USBSerial.println();
  if (strcmp(topic, top1.c_str()) == 0) {
    payload[length] = '\0';
    counter_1 = atof((char*)payload);
    if(first_run1){
      tempCounter_1 = counter_1;
      tempCounterNight_1 = counter_1;
      first_run1=false;
    }
    USBSerial.print("COUNTER1:......................");
    USBSerial.println(counter_1, 4);
  }
  if (strcmp(topic, top2.c_str()) == 0) {
    payload[length] = '\0';
    counter_2 = atof((char*)payload);
    if(first_run2){
      tempCounter_2 = counter_2;
      tempCounterNight_2 = counter_2;
      first_run2=false;
    }
    USBSerial.print("COUNTER2:......................");
    USBSerial.println(counter_2, 4);
  }
  if (strcmp(topic, top3.c_str()) == 0) {
    payload[length] = '\0';
    counter_3 = atof((char*)payload);
    if(first_run3){
      tempCounter_3 = counter_3;
      tempCounterNight_3 = counter_3;
      first_run3=false;
    }
    USBSerial.print("COUNTER3:......................");
    USBSerial.println(counter_3, 4);
  }
}

void paramSave(){
 if(num_of_counter==1){
  stor1();
 }
 else if(num_of_counter==2){
  stor1();
  stor2();
 }
 else if(num_of_counter==3){
  stor1();
  stor2();
  stor3();
 }
}
void valveControl(){
  if((millis() - sek_millis) >100){
    isOnValve();
    sek_millis = millis();
  }
}
void isOnValve(){
  if(valveClose->isOn()) { 
    valveOpen->turnOff();
    if(!off_milli_start){
     USBSerial.print("valveClose:  ");
     USBSerial.println(valveClose->isOn());
     valveOff_millis = millis();
     off_milli_start = true;
    }
    else if((off_milli_start) && ((millis() - valveOff_millis) > 60000)){
     valveClose->turnOff();
     USBSerial.print("valveClose:  ");
     USBSerial.println(valveClose->isOn());
     off_milli_start = false;
    }
  }
  if(valveOpen->isOn()) { 
    valveClose->turnOff();
    if(!on_milli_start){
     USBSerial.print("valveOpen:  ");
     USBSerial.println(valveOpen->isOn());
     valveOn_millis = millis();
     on_milli_start = true;
    }
    else if((on_milli_start) && ((millis() - valveOn_millis) > 60000)){
     valveOpen->turnOff();
     USBSerial.print("valveOpen:  ");
     USBSerial.println(valveOpen->isOn());
     on_milli_start = false;
    }
  }
}

void waterControl1() {
  if (millis() - prev_min_millis_1 > time_period_1) {
    if (counter_1 > (tempCounter_1 + levelAlarm1)) {
      valveOpen->turnOff();
      valveClose->turnOn();
      Supla::Notification::Send(-1, dev_name_message_1, message_1);
    }
    tempCounter_1 = counter_1;
    prev_min_millis_1=millis();
  }
  if ((prev_hour_millis_1 - millis() > time_period_night_1) && night_1) {
    if (counter_1 > (tempCounterNight_1 + levelAlarmNight1)) {
      valveOpen->turnOff();
      valveClose->turnOn();
      String n = "NIGHT1: ";
      String n_message = n + message_1;
      Supla::Notification::Send(-1, dev_name_message_1, n_message.c_str());
    }
    tempCounterNight_1 = counter_1;
    prev_hour_millis_1=millis();
  }
}
void waterControl2() {
  if (millis() - prev_min_millis_2 > time_period_2) {
    if (counter_2 > (tempCounter_2 + levelAlarm2)) {
      Supla::Notification::Send(-1, dev_name_message_2, message_2);
    }
    tempCounter_2 = counter_2;
    prev_min_millis_2=millis();
  }
  if ((prev_hour_millis_2 - millis() > time_period_night_2) && night_2) {
    if (counter_2 > (tempCounterNight_2 + levelAlarmNight2)) {
      String n = "NIGHT2: ";
      String n_message = n + message_2;
      Supla::Notification::Send(-1, dev_name_message_2, n_message.c_str());
    }
    tempCounterNight_2 = counter_2;
    prev_hour_millis_2=millis();
  }
}
void waterControl3() {
  if (millis() - prev_min_millis_3 > time_period_3) {
    if (counter_3 > (tempCounter_3 + levelAlarm3)) {
      Supla::Notification::Send(-1, dev_name_message_3, message_3);
    }
    tempCounter_3 = counter_3;
    prev_min_millis_3=millis();
  }
  if ((prev_hour_millis_3 - millis() > time_period_night_3) && night_3) {
    if (counter_3 > (tempCounterNight_3 + levelAlarmNight3)) {
      String n = "NIGHT3: ";
      String n_message = n + message_3;
      Supla::Notification::Send(-1, dev_name_message_3, n_message.c_str());
    }
    tempCounterNight_3 = counter_3;
    prev_hour_millis_3=millis();
  }
}
static bool isNight(int32_t tim, int32_t night_start, int32_t night_end){
    if(night_start < night_end){
      return tim >= night_start && tim < night_end;
    }
    else{
      return tim >= night_start || tim < night_end;
    }
}
void nightReady(){
  if((millis()-prev_minute_millis)> 30000){//sprawdzamy czas co 30s

     bool nn_1 = isNight(clock1.getHour(), night_h_start_1, night_h_stop_1);
     bool nn_2 = isNight(clock1.getHour(), night_h_start_2, night_h_stop_2);
     bool nn_3 = isNight(clock1.getHour(), night_h_start_3, night_h_stop_3);
  
  if (!night_1 && nn_1){
    tempCounterNight_1 = counter_1;  
  }   
  if (!night_2 && nn_2){
    tempCounterNight_2 = counter_2;  
   }  
  if (!night_3 && nn_3){
   tempCounterNight_3 = counter_3;  
  }  
     night_1 = nn_1;
     night_2 = nn_2;
     night_3 = nn_3;
     prev_minute_millis=millis(); 
  }
}
void inputs1(){
  new Supla::Html::CustomTextParameter(PARAM1, "MQTT server", 50);
   new Supla::Html::CustomTextParameter(PARAM2, "MQTT user", 50);
   new Supla::Html::CustomTextParameter(PARAM3, "MQTT password", 50);
   new Supla::Html::CustomParameter(PARAM4, "Device ID :1");
   new Supla::Html::CustomParameter(PARAM5, "Channel ID :1");
   new Supla::Html::CustomParameter(PARAM6, "Night_h_start :1");
   new Supla::Html::CustomParameter(PARAM7, "Night_h_end :1");
   new Supla::Html::CustomTextParameter(PARAM8, "DevName message :1", 25);
   new Supla::Html::CustomTextParameter(PARAM9, "Push message :1", 25);
   new Supla::Html::CustomTextParameter(PARAM10, "Level alarm :1", 10);
   new Supla::Html::CustomTextParameter(PARAM11, "Level alarm night :1", 10);
   new Supla::Html::CustomParameter(PARAM12, "Time period(s) :1");
   new Supla::Html::CustomParameter(PARAM13, "Time period(s) night :1");
}
void inputs2(){
  new Supla::Html::CustomParameter(PARAM14, "Device ID :2");
  new Supla::Html::CustomParameter(PARAM15, "Channel ID :2");
  new Supla::Html::CustomParameter(PARAM16, "Night_h_start :2");
  new Supla::Html::CustomParameter(PARAM17, "Night_h_end :2");
  new Supla::Html::CustomTextParameter(PARAM18, "DevName message :2", 25);
  new Supla::Html::CustomTextParameter(PARAM19, "Push message :2", 25);
  new Supla::Html::CustomTextParameter(PARAM20, "Level alarm :2", 10);
  new Supla::Html::CustomTextParameter(PARAM21, "Level alarm night :2", 10);
  new Supla::Html::CustomParameter(PARAM22, "Time period(s) :2");
  new Supla::Html::CustomParameter(PARAM23, "Time period night(s) :2");
}
void inputs3(){
  new Supla::Html::CustomParameter(PARAM24, "Device ID :3");
  new Supla::Html::CustomParameter(PARAM25, "Channel ID :3");
  new Supla::Html::CustomParameter(PARAM26, "Night_h_start :3");
  new Supla::Html::CustomParameter(PARAM27, "Night_h_end :3");
  new Supla::Html::CustomTextParameter(PARAM28, "DevName message :3", 25);
  new Supla::Html::CustomTextParameter(PARAM29, "Push message :3", 25);
  new Supla::Html::CustomTextParameter(PARAM30, "Level alarm :3", 10);
  new Supla::Html::CustomTextParameter(PARAM31, "Level alarm night :3", 10);
  new Supla::Html::CustomParameter(PARAM32, "Time period(s) :3");
  new Supla::Html::CustomParameter(PARAM33, "Time period night(s) :3");
}
void stor1(){
  if (Supla::Storage::ConfigInstance()->getString(PARAM1, mqtt_server, 200)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %s", PARAM1, mqtt_server);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM1);
  }
  
  if (Supla::Storage::ConfigInstance()->getString(PARAM2, mqtt_user, 200)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %s", PARAM2, mqtt_user);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM2);
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM3, mqtt_pass, 200)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %s", PARAM3, mqtt_pass);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM3);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM4, &dv_id_1)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM4, dv_id_1);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM4);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM5, &chann_id_1)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM5, chann_id_1);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM5);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM6, &night_h_start_1)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM6, night_h_start_1);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM6);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM7, &night_h_stop_1)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM7, night_h_stop_1);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM7);
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM8, dev_name_message_1, 200)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %s", PARAM8, dev_name_message_1);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM8);
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM9, message_1, 200)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %s", PARAM9, message_1);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM9);
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM10, level_alarm_1, 10)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM10, level_alarm_1);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM10);
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM11, level_alarm_night_1, 10)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM11, level_alarm_night_1);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM11);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM12, &time_period_1)) {
    time_period_1 = time_period_1*1000;
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM12, time_period_1);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM12);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM13, &time_period_night_1)) {
    time_period_night_1 = time_period_night_1*1000;
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM13, time_period_night_1);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM13);
  }
}
void stor2(){
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM14, &dv_id_2)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM14, dv_id_2);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM14);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM15, &chann_id_2)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM15, chann_id_2);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM15);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM16, &night_h_start_2)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM16, night_h_start_2);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM16);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM17, &night_h_stop_2)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM17, night_h_stop_2);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM17);
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM18, dev_name_message_2, 200)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %s", PARAM18, dev_name_message_2);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM18);
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM19, message_2, 200)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %s", PARAM19, message_2);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM19);
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM20, level_alarm_2, 10)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM20, level_alarm_2);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM20);
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM21, level_alarm_night_2, 10)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM21, level_alarm_night_2);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM21);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM22, &time_period_2)) {
    time_period_2 = time_period_2*1000;
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM22, time_period_2);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM22);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM23, &time_period_night_2)) {
    time_period_night_2 = time_period_night_2*1000;
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM23, time_period_night_2);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM23);
  }
}
void stor3(){
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM24, &dv_id_3)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM24, dv_id_3);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM24);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM25, &chann_id_3)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM25, chann_id_3);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM25);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM26, &night_h_start_3)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM26, night_h_start_3);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM26);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM27, &night_h_stop_3)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM27, night_h_stop_3);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM27);
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM28, dev_name_message_3, 200)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %s", PARAM28, dev_name_message_3);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM28);
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM29, message_3, 200)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %s", PARAM29, message_3);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM29);
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM30, level_alarm_3, 10)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM30, level_alarm_3);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM30);
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM31, level_alarm_night_3, 10)) {
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM31, level_alarm_night_3);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM31);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM32, &time_period_3)) {
    time_period_3 = time_period_3*1000;
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM32, time_period_3);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM32);
  }
  if (Supla::Storage::ConfigInstance()->getInt32(PARAM33, &time_period_night_3)) {
    time_period_night_3 = time_period_night_3*1000;
    SUPLA_LOG_DEBUG(" **** Param[%s]: %d", PARAM33, time_period_night_3);
  } else {
    SUPLA_LOG_DEBUG(" **** Param[%s] is not set", PARAM33);
  }
}
void charToDouble(){
 levelAlarm1 = atof(level_alarm_1);
 levelAlarmNight1 = atof(level_alarm_night_1);
 levelAlarm2 = atof(level_alarm_2);
 levelAlarmNight2 = atof(level_alarm_night_2);
 levelAlarm3 = atof(level_alarm_3);
 levelAlarmNight3 = atof(level_alarm_night_3);
}
You do not have the required permissions to view the files attached to this post.
https://youtube.com/@tomaszhamer8134?si=_J1cT_QWsXxgt1Fm
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
https://github.com/Soyer79
User avatar
SOYER
Posts: 1623
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry
Been thanked: 2 times

Post

@Pietras81 sprawdź to proszę:)
https://youtube.com/@tomaszhamer8134?si=_J1cT_QWsXxgt1Fm
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
https://github.com/Soyer79
Pietras81
Posts: 2409
Joined: Sun Feb 17, 2019 6:56 am
Location: Osielsko
Been thanked: 1 time

Post

SOYER wrote: Tue Jan 06, 2026 11:49 am @Pietras81 sprawdź to proszę:)
Testuje tak na szybko ale teraz działa czy poprawnie to jeszcze muszę trochę się pobawić. Oczywiście obie tylko testy ja 1 liczniku. Co do zmian jakie zrobiłeś to teraz wartości licznika wyświetlają się aż 4 miejsca po przecinku ale to chyba nie ma znaczenia.
Wgrałem gotowy plik bin bo nie chciało mi się czekać.

Z góry dziękuje za poświęcony czas. Będę się jeszcze bawił.
https://pietras-81.aqi.eco/
User avatar
SOYER
Posts: 1623
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry
Been thanked: 2 times

Post

Pietras81 wrote: Tue Jan 06, 2026 2:10 pm
SOYER wrote: Tue Jan 06, 2026 11:49 am @Pietras81 sprawdź to proszę:)
Testuje tak na szybko ale teraz działa czy poprawnie to jeszcze muszę trochę się pobawić. Oczywiście obie tylko testy ja 1 liczniku. Co do zmian jakie zrobiłeś to teraz wartości licznika wyświetlają się aż 4 miejsca po przecinku ale to chyba nie ma znaczenia.
Wgrałem gotowy plik bin bo nie chciało mi się czekać.

Z góry dziękuje za poświęcony czas. Będę się jeszcze bawił.
Tak, są wyświetlane cztery cyfry po przecinku bo tak jest wpisane w kodzie:
USBSerial.println(levelAlarm3, 4);
lub:
USBSerial.print("COUNTER1:......................");
USBSerial.println(counter_1, 4);
To powinno wystarczyć do większości przypadków;)
Zmienne counter_x przechowują wartość z taką dokładnością z jaką przesyła serwer.
https://youtube.com/@tomaszhamer8134?si=_J1cT_QWsXxgt1Fm
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
https://github.com/Soyer79
Pietras81
Posts: 2409
Joined: Sun Feb 17, 2019 6:56 am
Location: Osielsko
Been thanked: 1 time

Post

SOYER wrote: Tue Jan 06, 2026 2:19 pm
Pietras81 wrote: Tue Jan 06, 2026 2:10 pm
SOYER wrote: Tue Jan 06, 2026 11:49 am @Pietras81 sprawdź to proszę:)
Testuje tak na szybko ale teraz działa czy poprawnie to jeszcze muszę trochę się pobawić. Oczywiście obie tylko testy ja 1 liczniku. Co do zmian jakie zrobiłeś to teraz wartości licznika wyświetlają się aż 4 miejsca po przecinku ale to chyba nie ma znaczenia.
Wgrałem gotowy plik bin bo nie chciało mi się czekać.

Z góry dziękuje za poświęcony czas. Będę się jeszcze bawił.
Tak, są wyświetlane cztery cyfry po przecinku bo tak jest wpisane w kodzie:
USBSerial.println(levelAlarm3, 4);
lub:
USBSerial.print("COUNTER1:......................");
USBSerial.println(counter_1, 4);
To powinno wystarczyć do większości przypadków;)
Zmienne counter_x przechowują wartość z taką dokładnością z jaką przesyła serwer.
Też to zauważyłem w kodzie że jest 4 a nie 3 chodź w tą stronę to nie przeszkadza :)

A jak dobrze rozumiem zasadę działania ??

Ustawiam np 5 litrów w czasie 2 minut.
Program liczy impulsy w czasie i jak miną dwie minuty to wysyła powiadomienie i zamyka zawór ??

Czy liczy impulsy i w momencie jak będzie ich 6 ale czasowo nie miną dwie minuty to po 6 impulsie wysyła powiadomienie i zamyka zawór ??
Z tego co obserwuje to pierwsza opcja ale zapytam autora :)
https://pietras-81.aqi.eco/

Return to “Pomysły i koncepcje”