ESPhome warunki if, else

Witam.
Od niedawna zacząłem bawić się esphome, więc bardzo proszę o wyrozumiałość.
Do tej pory oprogramowanie na mikrokontrolery, czy też PC pisałem w C, C++, C# i w tych środowiskach sobie radzę, natomiast esphome, to dla mnie nowość, której nie do końca potrafię zrozumieć. Tu proszę was o pomoc. Do ESP12-F mam dołączone 3 czujniki: BMP280, DHT11 oraz SDS01. Skrypt jak poniżej

sensor:
  - platform: bmp280
    i2c_id: bus_a
    temperature:
      name: "Temperatura_BMP"
      oversampling: 16x
    pressure:
      name: "Ciśnienie"
    address: 0x76
    update_interval: 30sec

  - platform: dht
    pin: D0
    temperature: 
      name: "Temperatura_DHT"
    id: hum
    humidity: 
      name: "Wilgotność"
    update_interval: 30sec
  
  
  - platform: sds011
    pm_2_5:
      name: "PM <2.5µm"
    pm_10_0:
      name: "PM <10.0µm "
    update_interval: 30min

Wszystko działa pięknie, dane przesyłane są do HA ale czy istnieje możliwość wstawiania warunku, w którym załączanie SDS011 nastąpi tylko i wyłącznie wtedy jeśli wilgotność odczytana z DHT będzie poniżej zadanej wartości?
coś jak:

if(humidity<75){
  wykonajPomiar;
}
else{
  nieRobNic;
}

Dziękuję.

Musisz zmienić sposób myślenia, nie jesteś pierwszy, który ma z tym problem ale to nic trudnego :slight_smile:.

HA i ESPHome wykorzystują automatyzacje, które wykonują się jeżeli coś się zmieni, jeżeli encja zmieni swój stan i tak w przypadku sensor w ESPHome masz takie możliwości - sensor-automation. Proponuje dokładnie czytać dokumentację, jest tam sporo przykładów, nawet Twój przypadek:

sensor:
  - platform: dht
    # ...
    on_value_range:
      - below : 75.0
        then:
          - switch.turn_on: relay_1

Bardzo dziekuje za konkretną i wyczerpującą odpowiedź. O to mi chodziło.

Jednak nie jest tak łatwo jakby się wydawało. Korzystając z metody on_value_range edytor nie podpowiada/nie widzi id czujnika. Jeśli spróbuję wprowadzić go ręcznie, to zgłasza błędy. Też zauważyłem, że zamiana miejscami poszczególnych czujników (zamiana w kodzie) powoduje wywalanie się kompilatora lub zgłaszanie błędu w edytorze.
ESPhome jest fajnym narzędziem, ale jakoś nie potrafię zrozumieć jego logiki.

Chyba będę musiał oprogramować urządzenie w tradycyjny sposób. Czyli na piechotę w C++ z wykorzystaniem MQTT.

A jeszcze jedna rzecz mi się nasuwa na myśl. Czy spod HA można odnieść się do zmiany interwału odpytywania konkretnego urządzenia - czujnika?

Sorry ale nie wiem o czym piszesz więc nie jestem wstanie pomóc. Jezeli bedziesz potocznie coś opisywał bez przykładów to raczej marna szansa żeby rozwiązać problem techniczny.

Problem opisany na samym początku z przykładem. Trzy czujniki podłączone do esp8266. Chodzi o to aby zezwolenie na uruchomienie czujnika SDS011 nastąpiło tylko i wyłącznie jeśli wilgotność powietrza jest niższa niż 75%. Co masz na myśli mówiąc o potocznym przedstawianiu problemu?

Jeśli zaczynasz pisać, to edytor podpowiada składnię tak? Natomiast w przypadku czujnika sds011 nie robi tego. Jesli ręcznie wprowadzę dane takie jak id czujnika, to z automatu mam podkreślenie błędu.

Przegladajac dokumentacje, czy przykłady nie spotkałem aby ktoś uzależniał działanie jednego czujnika od drugiego. Są co prawda akcje związane z przyciskiem i przekaźnikiem ale to nie to samo.

Niestety nie jestem Yamlowy. Nie potrafię przestawić się na taki język. Na codzień pisze w pochodnych języka C wiec proszę nie dziwcie się, ze yaml jest dla mnie mało logiczny.

Jest mało logiczny, bo to nie jest język programowania, pod spodem tego YAMLa są kilometry c++, więc skoro to jest coś czym żyjesz, to świetnie, bo raczej będziesz musiał sobie stworzyć komponent niestandardowy na bazie sds011, zobacz jak jest zbudowany komponent standardowy (być może to co wymyślisz da się wdrożyć jako bardziej ogólne rozwiązanie w ESPHome lub wybranych komponentach, którym by się właśnie coś podobnego przydało)

1 polubienie

Dziekuje. To wiele wyjaśnia.

Co masz na myśli? Jak technicznie to się ma odbyć. Mam nadzieję, że próbujesz użyć switch.turn_on do encji typu sensor.

Zrób print screen tego błędu tak aby byla widoczna definicja encji czujnika.

Ja rozumiem ideę - ale switch tu nie pomoże.
Mało technicznie, ale zrozumiesz - SDS011 (jak i wiele innych czujników pyłu zawieszonego) ma własny MCU w który nie ingerujemy (ten się komunikuje UARTem).

Natomiast czujnik jako całość nie jest wieczny - tam pracuje mechaniczny wentylator oraz naświetlacz LED (z wykręconą mocą tak daleko, że wytrzymuje tylko parę tysięcy godzin pracy), można jego żywotność znacznie przedłużyć aktywując go tylko na czas jednego pomiaru oraz nie aktywując go wcale jeśli warunki w których nie jest w stanie dać wiarygodnych wartości (za wysoka wilgotność).

Komponent standardowy przewiduje tylko możliwość pracy ciągłej (interwał 0 minut) lub pracy cyklicznej (w zakresie 1-30 min), ale nie przewiduje możliwości wyłączenia.
Technicznie jest to możliwe, ale nie na bazie komponentu standardowego.

Tak wiem o tym i dlatego chce usypiać czujnik na dłużej i blokować go przy dużej wilgotności powietrza. Kilka lat temu zbudowałem sobie stacje monitorująca, która działa do dziś, dzięki temu, ze czujnik nie działa w trybie automatycznym, tylko w najlepszych dla niego warunkach (czyli przy niskiej wilgotności). Program do obsługi SDS011 pisalem w oparciu o kartę katalogowa czujnika, stad wiem jakie są jego słabe punkty. Wtedy jako protokół komunikacyjny z HA wykorzystałem MQTT. Dwa dni temu wpadło mi w oko właśnie esphome i spodobało mi się api. Stad tez pomysł aby przenieść mój projekt na platformę esphome. Spróbuje w takim razie połączyć swój kod z yaml. Jeśli będzie działać, to się podzielę.

Na twoim miejscu, to bym raczej zgłosił propozycję kluczowym deweloperom, bo to projekt, który się rozwija i chyba każde sensowne ulepszenia są mile widziane.
Tu taką ogólną ideą jest możliwość wstrzymania pracy tego czujnika (i wielu innych podobnych), bo to jest dobrze uzasadnione jako nowa funkcjonalność.

Oczywiście komponent niestandardowy jest jakimś posunięciem, ale widziałem że bywały takie sytuacje, gdy ktoś napisał coś lepszego niż to co było wcześniej i w całości wymieniono cały komponent na nowy innego autora.

Z braku czasu trochę to trwało ale w końcu rozwiązałem problem. Oprogramowałem “własny czujnik”. W pliku konfiguracyjnym podajemy interwał pomiaru w minutach (1-255 typ uint8_t) oraz graniczną wartość wilgotności, która jeśli nie zostanie osiągnięta, to czujnik SDS011 zostanie wybudzony i dokona pomiaru. Sterowanie SDS011 oraz DHT22 zawarte jest w pliku źródłowym, który należy zaimportować do projektu. Należy jeszcze zwrócić uwagę do jakiego kanału UART podłączymy czujnik. Jeśli mamy do dyspozycji tylko jeden sprzętowy UART, to należy bezwzględnie wyłączyć logi w pliku konfiguracyjnym YAML (inaczej będzie pluł logami do czujnika). Przed podłączeniem SDS011 do reszty elektroniki, należy też go odpowiednio ustawić - interwał pomiaru na 0 (praca ciągła) oraz ręczny tryb pracy. Wtedy mamy pewność, że czujnik nie będzie się sam niepotrzebnie wybudzał. Poniżej wrzucę kod oraz aplikację PC do SDS011 mojego autorstwa. Może komuś się przyda.

plik YAML i plik źródłowy h

esphome:
  name: monitorpowietrza
  friendly_name: MonitorPowietrza
  includes:  #dodajemy nasz plik z kodem do obsługi SDS011
    - /config/my_code/moj.h
  libraries: # i jeszcze biblioteki
    - Wire
    - "beegee-tokyo/DHT sensor library for ESPx @ ^1.19"
    - "plerup/EspSoftwareSerial @ ^8.2.0"
    - "lewapek/Nova Fitness Sds dust sensors library @ ^1.5.1"
  

esp8266:
  board: nodemcuv2

# Enable logging 
#logger: !UWAGA - należy zakomentować aby wyłączyć

# Enable Home Assistant API
api:
  encryption:
    key: "xxxxxxxxxxxxxxxx"

ota:
  - platform: esphome
    password: "xxxxxxxxxxxxxx"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Monitorpowietrza"
    password: "xxxxxxxxxx"

web_server:
  port: 80

i2c:
   id: bus_a
   scl: D1
   sda: D2
   scan: True

captive_portal:

sensor:
  - platform: bmp280
    i2c_id: bus_a
    temperature:
      name: "Temperatura_BMP"
      unit_of_measurement: °C
      accuracy_decimals: 1
      oversampling: 16x
    pressure:
      name: "Ciśnienie"
      unit_of_measurement: hPa
      accuracy_decimals: 1
    address: 0x76
    update_interval: 60sec

 - platform: wifi_signal
    name: "Sygnał WiFi"
    filters: 
      - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
    unit_of_measurement: "%"
    update_interval: 10s

# Poniżej wszystko co potrzebne do pełni szczęścia
  - platform: custom 
    lambda: |-
      auto my_sensor = new MyCustomSensor();
      App.register_component(my_sensor);
      my_sensor->setSdsParameter(60, 85); # interwał pomiaru i wartość RH, 60min, 85% wilgotności
      return {my_sensor->czujnikTemperatury, my_sensor->czujnikWilgotnosci, my_sensor->czujnikPm25, my_sensor->czujnikPm10, my_sensor->sds011Stan, my_sensor->sds011CzasDoPomiaru, my_sensor->napiecie};
    
    sensors:
      - name: "Temperatura"
        accuracy_decimals: 1
        unit_of_measurement: °C
      - name: "Wilgotność"
        accuracy_decimals: 1
        unit_of_measurement: "%"
      - name: "PM2.5"
        accuracy_decimals: 1
        unit_of_measurement: "µg/m³"
      - name: "PM10"
        accuracy_decimals: 1
        unit_of_measurement: "µg/m³"
      - name: "Stan czujnika"
      - name: "Czas do Pomiaru"
        accuracy_decimals: 0
        unit_of_measurement: "min"
      - name: "Napięcie"
        accuracy_decimals: 2
        unit_of_measurement: "V"

`
plik moj.h
`
#include "esphome.h"
#include "DHTesp.h"
//#include "SoftwareSerial.h" // jeśli używamy UART programowy
#include "SdsDustSensor.h"
#include <Arduino.h> 

//SoftwareSerial sds011Serial = SoftwareSerial(D5, D6,false); // ustawienie UART na programowy na liniach D5 i D6
//SdsDustSensor sds(sds011Serial); // 
SdsDustSensor sds(Serial);



class MyCustomSensor : public Component, public Sensor { 
    private:
      const unsigned long msInterval = 1000; // interwał czasomierza 1000ms
      unsigned long actMs = 0; // 
      unsigned long prevMs = 0;
	  
	  uint8_t sec = 0;
      uint8_t timeForVoltageRead = 10; // 10s - timer pomiaru napięcia
	  uint8_t timeForBufferClear = 40; // 40s - po odliczeniu będzie czyszczony bufor odbiorczy
	  uint8_t bufferClearFlag = 0; // flaga czyszczenia bufora odbiorczego - jednokrotne po odliczeniu czasu
	  
	  uint8_t dhtMeasureTimer = 0; // timer do odczytu z dht [sekundy]
	  uint8_t dhtMeasureTimerMaxTime = 60; // maksymalny czas do odczytu z dht [sekundy]
      uint8_t sds011WorkingTimerMaxTime = 30; //maksymalny czas pracy czujnika sds011 [sekundy]
	  uint8_t sds011SleepTimerMaxTime = 3; // maksymalny czas uśpienia czujnika sds011 [minuty]
	  uint8_t sds011WorkingTimer = 0; // timer pracy czujnika sds011 [sekundy]
	  uint8_t sds011SleepTimer = 1; // timer do wybudzenia czujnika sds011 [minuty] (pierwszy pomiar po 3minutach)
	  uint8_t sds011Step = 0;
	  uint8_t sds011AllowHumidityMaxValue = 99; // dopuszczalna wartość wilgotności dla pomiarów z czujnika sds w %
      
      uint8_t sds011SleepTimerPrev = 0;
	  float pm25 = 0;
      float pm10 = 0;
     
	  float humidity = 100.00;
	  float temperature = 0.00;
	  float voltage = 0.00;
      
    public:
      float get_setup_priority() const override { return esphome::setup_priority::LATE; }
	  
	  Sensor *czujnikTemperatury = new Sensor();
      Sensor *czujnikWilgotnosci = new Sensor();
      Sensor *czujnikPm25 = new Sensor();
      Sensor *czujnikPm10 = new Sensor();
	  Sensor *sds011Stan = new Sensor();
	  Sensor *sds011CzasDoPomiaru = new Sensor();
	  Sensor *napiecie = new Sensor();
      
	  DHTesp dht;
	  
	  
	  
	  void setup() override {
	    Serial.begin(9600);
        dht.setup(D0, DHTesp::DHT22);
        sds.begin();
        delay(1000);
        sds011Sleep();
   
        
		czujnikTemperatury->publish_state(temperature);
		czujnikWilgotnosci->publish_state(humidity);
		czujnikPm25->publish_state(pm25);
        czujnikPm10->publish_state(pm10);
        sds011Stan->publish_state(sds011Step);
        sds011CzasDoPomiaru->publish_state(sds011SleepTimer);
		
      }
      

      void loop() override {
		  
        actMs = millis();
		if(prevMs > actMs) prevMs = actMs; // zabezpieczenie przed przekręceniem licznika
		if(actMs - prevMs >= msInterval){ // jeśli odmierzy 1s
			if(sec < 59){ // jesli wartość < 59sec
				sec++; // inkrementacja licznika sekund
				
				if(timeForVoltageRead > 1){
				    timeForVoltageRead --;
				}
				else{
				    voltageRead();
				    timeForVoltageRead = 10;
				}
				
				if(dhtMeasureTimer > 0) dhtMeasureTimer --; // jesli timer ustawiony, to odliczaj czas do odczytu czujnika dht
				
				if(sds011Step == 1 && sds011WorkingTimer > 0) sds011WorkingTimer--; // jesli krok i timer ustawiony, to odliczaj czas do odczytu czujnika SDS011
				
			}
			else{ // odliczył minutę
				sec = 0;// zerowanie sekund
				if(sds011Step == 0 && sds011SleepTimer > 0) sds011SleepTimer--; // jesli krok i timer ustawiony, to odliczaj czas do wybudzenia czujnika SDS011
				if(sds011SleepTimer != sds011SleepTimerPrev){
				    sds011CzasDoPomiaru->publish_state(sds011SleepTimer);
				    sds011SleepTimerPrev = sds011SleepTimer;
				}
				
			}
			prevMs = actMs;
		}
		
		
		
		if(sds011SleepTimer == 0 && sds011Step == 0){ 
			if(humidity <= sds011AllowHumidityMaxValue){
				sds011WorkingTimer = sds011WorkingTimerMaxTime;
				sds011WakeUp();
				sds011Step = 1;
			}
		}
		
		if(sds011WorkingTimer == 0 && sds011Step == 1){
			sds011ReadVal();
			sds011Sleep();
			sds011Step = 0;
			sds011SleepTimer = sds011SleepTimerMaxTime;
			sds011CzasDoPomiaru->publish_state(sds011SleepTimer);
			czujnikPm25->publish_state(pm25);
			czujnikPm10->publish_state(pm10);
		}
		
		if(dhtMeasureTimer == 0){
			dhtReadVal();
			dhtMeasureTimer = dhtMeasureTimerMaxTime;
			czujnikTemperatury->publish_state(temperature);
			czujnikWilgotnosci->publish_state(humidity);
			
			if(humidity > sds011AllowHumidityMaxValue){
				sds011Stan->publish_state(4);
			}
		}
	 
        
		
      }
      
      void setSdsParameter(uint8_t sds011MeasureInterval, uint8_t allowHumidity){
		sds011SleepTimerMaxTime = sds011MeasureInterval;
		sds011AllowHumidityMaxValue = allowHumidity;
		
      }
      
      void sds011WakeUp(){
        sds.wakeup();
		sds011Stan->publish_state(1);
		
      }
      
      void sds011ReadVal(){
        PmResult pm = sds.queryPm();
        if(pm.isOk()){
			sds011Stan->publish_state(2);
            pm25 = pm.pm25;
            pm10 = pm.pm10;    
        }
        else{ // wartości -1 oznaczają problemy z odczytem
			sds011Stan->publish_state(3);
			pm25 = -1;
			pm10 = -1;
        }
      }
      
      void sds011Sleep(){
        WorkingStateResult state = sds.sleep();
		sds011Stan->publish_state(0);
      }
	  
	  void dhtReadVal(){
		delay(dht.getMinimumSamplingPeriod());	
		humidity = dht.getHumidity();
		temperature = dht.getTemperature();
	  }

	  void voltageRead(){ 
		voltage = analogRead(A0);
		voltage = voltage/1024; //rozdzielczość przetwornika 1024
		voltage = voltage*10680; // R1=10k R2=680R
		voltage = voltage/680;
		
		napiecie->publish_state(voltage);
	  }

	
	  
	
};
1 polubienie

Fajnie ale dlaczego użyłeś czego co nie jest rekomendowane przez ESPHome:

Warning
Custom components are deprecated, not recommended for new configurations and will be removed from ESPHome in a future release.
Custom Sensor Component — ESPHome

Na chwile obecna działa. Jeśli go usuną, na 100% pojawi się nowy komponent o podobnych właściwościach. Jeśli nie, to wrócę do podstawowej wersji jaką popełniłem dawno temu czyli wysyłanie danych po mqtt i obróbka w nodered. Chciałem sprawdzić funkcjonalności esphome. A z drugiej strony jak oni będą tak dodawać i usuwać komponenty, to ludziska zaczną sie wkurzać i przestaną używać esphome. Tak to działa niestety.

1 polubienie

Już jest opisane jak powinno się to robić.

“Nie myli się (tylko) ten, kto nic nie robi” więc wątpię, że ESPHome przestanie być popularne z powodu zmian :wink:, osobiście widzę zmiany na lepsze ale to mój punkt widzenia.