CCCPaste

f9c10f3a4e154

#################### ESP8266 - CZUJNIK PARKOWANIA ######################

#################### KONFIGURACJA ######################
esphome:
  name: ws2811_garage_led
  friendly_name: Czujnik parkowania
  comment: ESP8266

esp8266:
  board: d1_mini

time:
  - platform: homeassistant
    id: homeassistant_time 

#################### standardowe wifi

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  reboot_timeout: 5min

#################### Serwer WWW

web_server:
  port: 80

#################### Logi  

debug:
logger:

#################### OTA/API

ota:
  - platform: esphome
    password: !secret ota

api:
  encryption:
    key: !secret api
  services:
    - service: update_leds
      variables:
        distance: float
        garage_status: string
      then:
        - lambda: |-
            ESP_LOGD("led_effect", "Aktualna odległość: %f", id(distance_sensor_value));
            id(garage_status_value) = garage_status;

#################### ELEMENTY ZEWNETRZNE ######################

#################### Sterowanie LED

light:
  - platform: neopixelbus
    id: ws2811_strip
    pin: GPIO3
    num_leds: 50
    type: GRB
    variant: ws2811
    default_transition_length: 0.5s
    name: "WS2811 LED Strip"
    effects:
      - addressable_lambda:
                name: "Reakcja na bramę (otwieranie i zamykanie)"
                update_interval: 500ms
                lambda: |-
                  std::string garage_status = id(garage_status_value);

                  // Sprawdzenie statusu bramy (otwieranie/zamykanie)
                  if (garage_status == "otwieranie" || garage_status == "zamykanie") {
                    // Skrajne LED-y na niebiesko
                    it[0] = Color(0, 0, 255);
                    it[1] = Color(0, 0, 255);
                    it[it.size() - 2] = Color(0, 0, 255);
                    it[it.size() - 1] = Color(0, 0, 255);

                    // Mruganie skrajnych LED-ów
                    for (int i = 0; i < it.size(); i++) {
                      if (i == 0 || i == 1 || i == it.size() - 2 || i == it.size() - 1) {
                        if (millis() % 1000 < 500) {
                          it[i] = Color(0, 0, 255);  // Niebieskie
                        } else {
                          it[i] = Color::BLACK;
                        }
                      } else {
                        // Normalny efekt oparty na odległości
                        float distance = id(distance_sensor_value);
                        float distance_threshold = id(distance_threshold_value);

                        // Jeśli odległość jest nieznana, ustaw LED-y na zielono
                        if (std::isnan(distance)) {
                          it[i] = Color(0, 255, 0);  // Zielony pasek LED
                        } else {
                          // Nowy wzór na liczbę czerwonych LED-ów, który wyklucza skrajne LED-y
                          int leds_to_red = (int)((id(zero_point) + id(distance_threshold_value) - distance) / (id(distance_threshold_value)) * (it.size() - 4));  
                          leds_to_red = leds_to_red > (it.size() - 4) ? (it.size() - 4) : leds_to_red;


                          // Dostosowanie zakresu czerwonych diod, aby skrajne LED-y nadal działały jak wcześniej
                          if (i < leds_to_red / 2 + 2 || i >= it.size() - leds_to_red / 2 - 2) {
                            it[i] = Color(255, 0, 0);  // Czerwone diody przy krawędziach
                          } else {
                            it[i] = Color(0, 255, 0);  // Zielone diody w środku
                          }
                        }
                      }
                    }
                    return;
                  }
#                  // Jeśli brama nie jest w stanie otwierania, zamykania lub otwarta, wyłącz LED-y
#                  for (int i = 0; i < it.size(); i++) {
#                    it[i] = Color::BLACK;  // Wyłącz LED-y
#                  }
      - addressable_lambda:
                name: "Reakcja na bramę i odległość"
                update_interval: 200ms
                lambda: |-
                  static bool blink_state = false;
                  static unsigned long last_blink_time = 0; 
                  const unsigned long blink_interval = 100;  // Czas migania (w ms)

                  float distance = id(distance_sensor_value);
                  std::string garage_status = id(garage_status_value);

                  // Zmienna określająca próg odległości, od której zaczynają się zmiany
                  float distance_threshold = id(distance_threshold_value);

                  // Aktualizacja stanu migania
                  unsigned long current_time = millis();
                  if (current_time - last_blink_time >= blink_interval) {
                    blink_state = !blink_state;
                    last_blink_time = current_time;
                  }

                  // Normalny efekt oparty na odległości
                  if (std::isnan(distance)) {
                    // Jeśli wartość odległości jest nieznana, ustaw LED-y na zielono
                    for (int i = 0; i < it.size(); i++) {
                      it[i] = Color(0, 255, 0);  // Zielony pasek LED
                    }
                  } else if (distance <= (id(zero_point) - 0.05)) {
                    // Jeśli odległość jest mniejsza lub równa punktowi zero minus 5 cm, zapalić czerwony pasek
                    for (int i = 0; i < it.size(); i++) {
                      it[i] = blink_state ? Color(255, 0, 0) : Color(0, 0, 0);  // Mruganie na czerwono
                    }
                  } else if (distance <= id(zero_point) + id(distance_threshold_value)) {
                    // Jeśli odległość jest mniejsza niż threshold (odległość od zero_point + distance_threshold_value)
                    int leds_to_red = (int)((id(zero_point) + id(distance_threshold_value) - distance) / (id(distance_threshold_value)) * 50); 
                    leds_to_red = leds_to_red > 50 ? 50 : leds_to_red;
                    for (int i = 0; i < it.size(); i++) {
                      if (i < leds_to_red / 2 || i >= it.size() - leds_to_red / 2) {
                        it[i] = Color(255, 0, 0);  // Czerwone diody przy krawędziach
                      } else {
                        it[i] = Color(0, 255, 0);  // Zielone diody w środku
                      }
                    }
                  } else {
                    // Jeśli odległość jest większa niż threshold, wszystkie diody na zielono
                    for (int i = 0; i < it.size(); i++) {
                      it[i] = Color(0, 255, 0);  // Wszystkie diody zielone
                    }
                  }


#################### Funkcje globalne 


globals:
  - id: distance_sensor_value
    type: float
    initial_value: "1.25"  # Początkowa odległość w metrach
  - id: garage_status_value
    type: std::string
    initial_value: '"zamknięta"'
  - id: led_active
    type: bool
    initial_value: "false"
  - id: garage_status_open_time
    type: long
    initial_value: "0"  
  - id: garage_status_change_time
    type: long
    initial_value: "0" 
  - id: zero_point
    type: float
    initial_value: "0.40"  # Punkt 0 w metrach, np. 2m
  - id: distance_threshold_value
    type: float
    initial_value: "1.6"  # Próg, przy którym LED-y zaczynają zmieniać kolor
  - id: elapsed_time_open
    type: float
#    initial_value: "1.6"  # Próg, przy którym LED-y zaczynają zmieniać kolor
  - id: garage_status_is_open
    type: bool
    initial_value: "false"  # Początkowy stan: brama nieotwarta
  - id: transistor_active
    type: bool
    restore_value: no
    initial_value: "false"

#################### Obsługa zdrazeń z HA
  
text_sensor:
  - platform: homeassistant
    id: garage_status_sensor
    entity_id: sensor.3_gar_stan_bramy
    on_value: 
      then: 
        - lambda: |-
            std::string new_status = x.c_str();
            id(garage_status_value) = new_status;
            ESP_LOGD("garage_status", "Nowy status bramy: %s", new_status.c_str());

            if (new_status == "otwieranie") {
              id(led_active) = true;
              id(garage_status_change_time) = millis();

              if (!id(transistor_active)) {
                id(transistor_pin).turn_on();
                id(transistor_active) = true;
                delay(150);
              }

              auto call = id(ws2811_strip).make_call();
              call.set_state(true);
              call.set_brightness(1.0);
              call.set_effect("Reakcja na bramę (otwieranie i zamykanie)");
              call.perform();
            }

            if (new_status == "otwarta") {
              id(garage_status_open_time) = millis();
              ESP_LOGD("garage_status", "Brama otwarta, czas: %lu", id(garage_status_open_time));

              if (!id(transistor_active)) {
                id(transistor_pin).turn_on();
                id(transistor_active) = true;
                delay(150);
              }

              auto call = id(ws2811_strip).make_call();
              call.set_state(true);
              call.set_brightness(1.0);
              call.set_effect("Reakcja na bramę i odległość");
              call.perform();
              id(garage_status_is_open) = true;
            }

            if (new_status == "zamykanie") {
              id(led_active) = true;
              id(garage_status_change_time) = millis();

              if (!id(transistor_active)) {
                id(transistor_pin).turn_on();
                id(transistor_active) = true;
                delay(150);
              }

              auto call = id(ws2811_strip).make_call();
              call.set_state(true);
              call.set_brightness(1.0);
              call.set_effect("Reakcja na bramę (otwieranie i zamykanie)");
              call.perform();
            }

        - if:
            condition:
              lambda: 'return id(garage_status_value) == "zamknięta";'
            then:
              - script.execute: handle_gate_closed
     
#################### Obsługa wyłączeń timerów

interval: 
  - interval: 1s
    then:
      - lambda: |-
          if (id(garage_status_is_open)) {
            unsigned long elapsed_time_open = millis() - id(garage_status_open_time);
            ESP_LOGD("garage_status", "Czas otwarcia bramy: %lu ms", elapsed_time_open);

            if (elapsed_time_open >= 300000) {  // Po 5 minutach
              ESP_LOGD("garage_status", "Brama otwarta za długo, wyłączam LED-y.");
              auto call = id(ws2811_strip).make_call();
              call.set_state(false);  // Wyłącz LED-y
              call.perform();
              id(garage_status_is_open) = false;  // Zresetuj flagę otwarcia

              // Wyłączenie czujnika odległości, gdy brama jest otwarta za długo
              if (id(transistor_active)) {  // Sprawdzamy, czy czujnik był aktywowany
                ESP_LOGD("garage_status", "Czujnik odległości wyłączony.");
                id(transistor_pin).turn_off();
                id(transistor_active) = false;  // Użycie id() zamiast przypisania bezpośredniego
              }
            }
          }

          // Monitorowanie stanu otwierania/zamykania bramy
          if ((id(garage_status_value) == "otwieranie" || id(garage_status_value) == "zamykanie") && id(led_active)) {
            unsigned long elapsed_time_changing = millis() - id(garage_status_change_time);
            ESP_LOGD("garage_status", "Czas otwierania/zamykania: %lu ms", elapsed_time_changing);

            if (elapsed_time_changing >= 180000) {  // Po 3 minutach (lub innym ustawionym czasie)
              ESP_LOGD("garage_status", "Brama otwiera się/zamyka za długo, wyłączam LED-y.");
              auto call = id(ws2811_strip).make_call();
              call.set_state(false);  // Wyłącz LED-y
              call.perform();
              id(garage_status_is_open) = false;  // Zresetuj flagę otwarcia
              id(led_active) = false;  // Wyłącz aktywność LED-ów


              // Wyłączenie czujnika odległości, gdy brama jest otwarta za długo
              if (id(transistor_active)) {  // Sprawdzamy, czy czujnik był aktywowany
                ESP_LOGD("garage_status", "Czujnik odległości wyłączony.");
                id(transistor_pin).turn_off();
                id(transistor_active) = false;  // Użycie id() zamiast przypisania bezpośredniego
              }
            }
          }

#################### Czujnik ultradzwiękowy 

sensor:
  - platform: ultrasonic
    id: distance_sensor
    trigger_pin: D2
    echo_pin: D3
    timeout: 4m
    update_interval: 250ms
    name: "Czujnik odległości"
    filters:
      # Lambda filtrująca błędne odczyty (NaN i skrajne różnice)
      - lambda: |-
          static float last_valid_value = 0.0;  // Przechowuje ostatnią poprawną wartość
          static float buffer[5] = {0};  // Bufor do przechowywania ostatnich odczytów
          static int index = 0;  // Indeks bufora

          if (isnan(x)) {  // Sprawdzanie NaN
              return last_valid_value;  // Zwraca ostatnią poprawną wartość
          }

          // Aktualizacja bufora
          buffer[index] = x;
          index = (index + 1) % 5;  // Cykl bufora

          // Obliczanie średniej z bufora
          float sum = 0.0;
          for (int i = 0; i < 5; i++) {
              sum += buffer[i];
          }
          float average = sum / 5;

          // Odrzucanie wartości mocno odbiegających od średniej
          if (abs(x - average) > 0.3) {  // Próg różnicy 0.3 m (30 cm)
              return last_valid_value;
          }

          last_valid_value = x;  // Aktualizacja poprawnej wartości
          return x;

      # Wygładzanie odczytów za pomocą filtru wykładniczego
      - exponential_moving_average:
          alpha: 0.3
          send_every: 1

    # Działania do wykonania przy zmianie wartości
    on_value:
      then:
        - lambda: |-
            id(distance_sensor_value) = x;  // Aktualizacja wartości odległości

script:
  - id: handle_gate_closed
    mode: restart
    then:
      - logger.log: "Brama zamknięta, czekam 10 sekund..."
      - delay: 10s

      - logger.log: "Wyłączam LED-y"
      - light.turn_off:
          id: ws2811_strip
          transition_length: 0.5s

      - delay: 1s

      - if:
          condition:
            lambda: 'return id(transistor_active);'
          then:
            - logger.log: "Wyłączam czujnik odległości"
            - switch.turn_off: transistor_pin
            - lambda: 'id(transistor_active) = false;'

switch:
  - platform: gpio
    pin: D1
    name: "Przekaźnik"
    id: transistor_pin