Inteligentne oświetlenie w łazience (Podsumowanie)

Tak używam MQTT. Właśnie to ogarniam.

Edit: w zasadzie mam ogarnięte. Zrobiłem z tego binary_sensor (jeśli odległość mniejsza od X to ON jeśli większa to OFF). Stworzyłem grupę z dwoma czujnikami ruchu plus czujnik odległości (ON/OFF) żeby sterować światłem w łazience.

Edit2: @RobinI30 w sumie to przyda się pomoc. Obecnie mój kod wygląda tak:
Czujnik.json (4,3 KB) (zmieniłem rozszerzenie na JSON bo TXT nie przechodzi)
Mam dwa problemy:

  1. Warunek w pętli loop “if (newstate != laststate)” nie wiem dlaczego warunek zawsze jest spełniony. Trochę programuję i powinno według mnie działać to poprawnie, a tak nie jest. ZMiana stanu wysyłana jest za każdym przebiegiem pętli.
  2. Utworzenie poprawnego JSON. ( MQTT Binary Sensor - Home Assistant (home-assistant.io)). Chciałbym aby zachowanie było tak jak w przypadku czujników ruchu
    czujnik

… a propos czujek ruchu
Kupiłem ostatnio takie coś, zamierzam sprawdzić jak to działa

Kod obejrzę jutro - w pracy mam więcej czasu :slight_smile:

Spoko nie ma presji. Co do czujek mikrofalowych gdzieś mi przemknęło że, może wyłapywać też przez ściany. Ja zastanawiam się nad tym czujnikiem Przedstawiono Aqara Lumi Human Sensor: Wysoce precyzyjny czujnik ruchu z 6-letnią autonomią (xiaomitoday.it)
No i wypuścili jeszcze nowy: Aqara ma w ofercie nowy czujnik obecności (oiot.pl)

Ten fragment:

   }
   
  }
  laststate = newstate;
  delay(5000);
}

powinien wyglądać tak:

   }
  laststate = newstate;   
  }

  delay(5000);
}

…inaczej w każdym obiegu pętli będziesz miał laststate = newstate - a musisz zapamiętać tylko raz w momencie zmiany stanu
…ale na ten delay dostałem wysypki.

Czasami wysypka nie szkodzi narazie jest w wersji testowej. Każda sugestia wskazana :slight_smile:

Ja stosuje harmonogram zadań, nic się nie blokuje loop się kręci z pełną prędkością.
Wywołuje tylko taski co określony czas. Oczywiście zadbać trzeba aby taski były też nieblokujące.

//*****scheduler*************************************
unsigned long previousMillis = 0;
const long sec = 1000;
const uint8_t timeout1 = 1;   //time proces1 [sec]
const uint8_t timeout2 = 250;  //time proces2 [sec]
boolean proces1 = false;
boolean proces2 = false;
uint8_t time1 = 0;
uint8_t time2 = 0;



void Scheduler() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis < sec) {
    return;
  }
  previousMillis = currentMillis;
  if (time1 < timeout1) {
    time1 += 1;
  }
  else {
    proces1 = true;
  }

  if (time2 < timeout2) {
    time2 += 1;
  }
  else {
    proces2 = true;
  }

}

//************************************************

void loop()
{
    Scheduler();
      if (proces2 == true) {
//   tu dopisujesz to co ma się wykonać co okres timeout2 



        time2 = 0;
        proces2 = false;
      }

      if (proces1 == true) {
//   tu dopisujesz to coma wykonać co okres timeout1 	  
	  
        time1 = 0;
        proces1 = false;
      }
 
}
1 Like

Fajne rozwiązanie zastosuję u siebie.

Rozglądałem się trochę pod kątem tego zastosowania.
Problem jest taki, że z drugim serialem w przypadku odczytu nie jest tak różowo.
Ponieważ we wszystkich płytkach w USB jest on trwale zajęty przez konwerter USB<>UART, a “golas”
wymaga dodatkowego “programatora”.
Znalazłem jeden zestaw co by mógł to pogodzić

Małe wymiary, konwerter jest na osobnej płytce i po zaprogramowaniu kanapkę można rozpiąć i podłączyć ME007YS.
Na czas uruchamiania ( gdy potrzebujesz debug) można te dwie płytki połączyć kabelkami w taki sposób aby mieć debug i odczyt czujnika na jednym sprzętowym UART.
Tx jako debug, a Rx odczyt z czujnika.
Konwerter pozostanie jako gratis dla innych zastosowań, jeśli się tym bawisz to wiesz jak się nieraz przydaje.

Na spokojnie przejrzałem również program i powiem … nie widzę tam błędu :shushing_face:
Może powodem takiego zachowania jest “pływanie” pomiarów? … nie jestem w stanie w głowie przeprowadzić symulacji.
Jednak na pomiary wprowadzi bym histerezę

  //  !!!!!!!!!!!!!!!!!!!!!!!newstate = 0;

  if (distanceCm > 100)
  {
    newstate = 0;
  }
  if (distanceCm < 80)
  {
    newstate = 1;
  }

Masz rację nie ma błędu. Wczoraj to było już chyba zmęczenie materiału. Serial.print mam przed IFem i to mnie zmyliło

Serial.println(newstate);
Serial.println(laststate);

  if (newstate != laststate)
  {
  //kod 
  }

Co do histerezy może zastosuję ale nie z takim dużym przedziałem. “Płwanie” jest mniej więcej w zakresie +/- 1cm

Edit:

Fajna ta płytka ale w Polsce problem z dostępnością. Znalazłem na Ali ESP8266 ESP 12F ESP12F CH340 WIFI i chyba sobie zamówię klik.

Analizowałem schemat Twojej płytki NodeMCU V3 i to powinno kurczę działać nawet dokładnie z tym projektem.
Napisałem wcześniej, że to niewłaściwe podłączenie z powodu tego, że D3(GPIO0) jest już zajęte przez konwerter USB na płytce… ale tego nie podłączamy?
Popytam trochę:

  1. Czujnik na pewno z wyjściem UART (są dwie wersje)?
    Czy udało Ci się czymkolwiek odczytać coś z tego czujnika?
  2. Czujnik zasilony z 5V?
  3. Skrzyżowane Tx<>Rx… tzn ESP Rx(D4) > dzielnik > Tx Czujnika?

Można spróbować ten softwarowy serial uruchomić na innych pinach. Ze schematu wynika, że D1 D2 są czyste.

Uruchomiłem ten czujnik na Arduino UNO i działa bez problemu. Mam dokładnie ten czujnik i kupiony z tego sklepu Ultradźwiękowy czujnik odległości ME007YS Botland - Sklep dla robotyków

Edit:
Dodałem wszystkie twoje sugestie kod wygląda obecnie tak:

#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// WIFI
const char* ssid = "ssid";
const char* password = "pass";
WiFiClient espClient;

// MQTT
const char* mqtt_server = "192.168.99.11";
const char* mqtt_username = "uid";
const char* mqtt_password = "pass";
PubSubClient client(espClient);

//*****scheduler*************************************
unsigned long previousMillis = 0;
const long sec = 1000;
const uint8_t timeout1 = 1;   //time proces1 [sec]
//const uint8_t timeout2 = 250;  //time proces2 [sec]
boolean proces1 = false;
//boolean proces2 = false;
uint8_t time1 = 0;
//uint8_t time2 = 0;

// CZUJNIK
const int trigPin = 12;
const int echoPin = 14;

//define sound velocity in cm/uS
#define SOUND_VELOCITY 0.034
#define CM_TO_INCH 0.393701

long duration;
float distanceCm;
int laststate;
int newstate;


void setup_wifi() 
{

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }

  //randomSeed(micros());

  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
//  Serial.print("Message arrived [");
//  Serial.print(topic);
//  Serial.print("] ");
//  for (int i = 0; i < length; i++) {
//    Serial.print((char)payload[i]);
//  }
//  Serial.println();
//
//  // Switch on the LED if an 1 was received as first character
//  if ((char)payload[0] == '1') {
//    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
//    // but actually the LED is on; this is because
//    // it is active low on the ESP-01)
//  } else {
//    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
//  }

}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    //clientId += String(random(0xffff), HEX);
    // Attempt to connect
    //if (client.connect(clientId.c_str())) {
    if (client.connect(clientId.c_str(),mqtt_username,mqtt_password)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "hello world");
      // ... and resubscribe
      client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}


void Scheduler() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis < sec) {
    return;
  }
  previousMillis = currentMillis;
  if (time1 < timeout1) {
    time1 += 1;
  }
  else {
    proces1 = true;
  }

//  if (time2 < timeout2) {
//    time2 += 1;
//  }
//  else {
//    proces2 = true;
//  }

}

void setup() 
{
  //pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  Serial.begin(115200);
 
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

  laststate = 0;
  newstate = 0;
  
  pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
  pinMode(echoPin, INPUT); // Sets the echoPin as an Input

}

void loop()
{
  if (!client.connected()) 
  { reconnect(); }
  
  client.loop();

    Scheduler();

      if (proces1 == true) {
        odczyt();
        time1 = 0;
        proces1 = false;
      }
 
}

void odczyt() 
{


  // Clears the trigPin
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  // Sets the trigPin on HIGH state for 10 micro seconds
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  // Reads the echoPin, returns the sound wave travel time in microseconds
  duration = pulseIn(echoPin, HIGH);
  
  // Calculate the distance
  distanceCm = duration * SOUND_VELOCITY/2;
 
  // Prints the distance on the Serial Monitor
  Serial.print("Distance (cm): ");
  Serial.println(distanceCm);
   

  if (distanceCm > 80)
  {
    newstate = 0;
  }
  if (distanceCm < 75)
  {
    newstate = 1;
  }

  if (newstate != laststate)
  {

    //Serial.println(newstate);
    //Serial.println(laststate);

    DynamicJsonDocument doc(1024);
    
    if (newstate == 0)
    {
      doc["occupancy"] = "off";  
    }
    else
    {
      doc["occupancy"] = "on";  
    }
    // Sending the request

    doc["dystans"] = distanceCm;

    char buffer[256];
    serializeJson(doc, buffer);
    Serial.println(buffer);
    if (client.publish("DIY/CzujnikKibelek", buffer) == true) 
    {
      Serial.println("Success sending message");
    } 
    else 
    {
      Serial.println("Error sending message");
    }

    laststate = newstate;
  }
  
  //delay(1000);
}

Jak dla mnie działa bardzo dobrze (fragment logu)

...........WiFi connected
IP address: 
192.168.99.253
Attempting MQTT connection...connected
Distance (cm): 145.50
Distance (cm): 143.79
Distance (cm): 143.80
Distance (cm): 143.80
Distance (cm): 143.80
Distance (cm): 143.80
Distance (cm): 143.80
Distance (cm): 11.80
{"occupancy":"on","dystans":11.79800034}
Success sending message
Distance (cm): 145.03
{"occupancy":"off","dystans":145.0269928}
Success sending message
Distance (cm): 11.20
{"occupancy":"on","dystans":11.20300007}
Success sending message
Distance (cm): 143.36
{"occupancy":"off","dystans":143.3609924}
Success sending message
Distance (cm): 144.60
Distance (cm): 143.36
Distance (cm): 143.79
Distance (cm): 145.49
Distance (cm): 143.36
Distance (cm): 14.47
{"occupancy":"on","dystans":14.46700001}
Success sending message
Distance (cm): 145.04
{"occupancy":"off","dystans":145.0440063}
Success sending message
Distance (cm): 143.79
Distance (cm): 144.21
Distance (cm): 13.16
{"occupancy":"on","dystans":13.15799999}
Success sending message
Distance (cm): 14.94
Distance (cm): 14.88
Distance (cm): 15.28
Distance (cm): 15.54
Distance (cm): 17.49
Distance (cm): 145.04
{"occupancy":"off","dystans":145.0440063}
Success sending message
Distance (cm): 145.04
Distance (cm): 143.36
Distance (cm): 143.79
Distance (cm): 143.77

1 Like

Ok… to już tylko możemy przyczepić się własnej niekompetencji.
Całkiem nieźle Sobie radzisz, wbrew temu co pisałeś wcześniej. :+1:

1 Like

Edit:
Przyszedł czas na odświeżenie wątku. Remont łazienki przeszedł z status planowany do statusu projektowania. Obecne rozwiązanie sprawuje się dobrze, więc będę szedł dalej tą ścieżką, ale jak wiadomo apetyt rośnie w miarę jedzenia. Do obecnego rozwiązania planuję dołożyć paski ledowe oraz jeszcze jeden czujnik odległości przy umywalce. Mam, więc do was pytanie, jakie ledy i sterownik zastosować oraz jaki profil z możliwością montażu pod prysznicem. Rozważam paski WS2812B patrzyłem na sterownik wLightBox - sterownik oświetlenia LED RGBW - BleBox ale niestety integracja HA nie obsługuje tego sterownika (BleBox devices - Home Assistant (home-assistant.io) może pójść w własny projekt oparty o jakieś ESP lub Arduino. Druga sprawa czy zmienić czujki ruchu bezprzewodowe na przewodowe i zastosować jeden moduł ESP32 do obsługi czujników ruchu i odległości (może nawet jeden kontroler do wszystkiego czujniki + ledy). Może ktoś ma już podobne rozwiązanie i coś podpowie.

Podsumowanie wersji Beta.

Przyszedł czas na podsumowanie projektu “Inteligentne oświetlenie w łazience”. Po kilku dniach działania wprowadziłem niewielki korekty i modyfikacje. W obecnej chwili rozwiązanie sprawdza się bardzo dobrze. Wszyscy zadowoleni a muzyczka uprzyjemnia pobyt w łazience. A teraz czas na podsumowanie sprzętu i automatyzacji:

Sprzęt

  • 2 x Aqara Motion Sensor
  • 1 x Aqara door and window sensor
  • 1 x Ultradzwiękowy czujnik odległości HC-SR04 (docelowo ME007YS jak ogarnę odczyt na esp8266)
  • 1 x ESP8266
  • 1 x Google Home Mini
  • 1 x Włącznik Światła 1 Klik. ZigBee TUYA

Konfiguracja i oprogramowanie

Zapalanie światła odbywa się na podstawie wykrycia otwarcia drzwi lub (jeśli nie zamknięte) na podstawie wykrytego ruchu z stworzonej grupy czujników ( 2x czujnik ruchu + czujnik odległości)

LazienkaRuch:
  name: Łazienka ruch
  entities:
    - binary_sensor.lazienkaczujnikruchulustro_occupancy
    - binary_sensor.lazienkaczujnikruchuprysznic_occupancy
    - binary_sensor.kibelek

Wyłączanie światła na podstawie tylko grupy czujników (zakładam że może ktoś nie zamknąć drzwi, a zdarza się często)

Kod dla ESP8266 (prawidłowe rozszerzenie to “ino” dla Arduino IDE)
ESP8266_HC04.json (5,3 KB)

Dodatkowo muzyczka jeśli siedzi ktoś na kibelku lub bierze prysznic.

Cała automatyzacja stworzona w NodeRed
lazienka.json (12,6 KB)

Poszukaj pod WLED https://kno.wled.ge/
LUB QuinLED https://quinled.info/

Cześć,
Przymierzam się do swojej pierwszej automatyzacji - padło na światło w łazience :slight_smile:
Chce aby światło zapalało się po wejściu do łazienki - pewnie na podstawie czujki ruchu. W nocy natężenie światła ma być zmniejszone, żeby nie oślepnąć.
Zastanawia mnie tylko kwestia posiedzenia na kibelku lub korzystanie z prysznica - czy wtedy czujka też wyłapie obecność w łazience?
Druga kwestia, to jeżeli chce coś takiego zrealizować, to powinienem umieścić jeszcze jakąś kostkę/przekaźnik przed samą żarówką?

hmmm @Marcin_K pięknie opisane czujniki i zadania… ;-DDDD przeczytałem opis żonie i mówi w zasadzie wystarczyłby jeden czujnik reagujący na ciepło ludzkiego ciała

Chętnie skorzystam z rady jaki czujnik proponujesz :slight_smile:

PIR (czujnik ruchu)

Typowy czujnik ruchu

PIR (ang. Passive Infra Red - pasywny czujnik podczerwieni) - czujnik elektroniczny służący do wykrywania ruchu. Powszechnie stosowany w systemach alarmowych, systemach automatycznego załączania oświetlenia i wentylacji itp.

Wykrywanie ruchu opiera się na bardzo precyzyjnym pomiarze temperatury. Każda zmiana temperatury na wyższą lub niższą (np. podmuch zimnego powietrza do nagrzanego pomieszczenia) jest traktowana jako alarm. Głównymi elementami czujnika PIR jest pyroelement (detektor podczerwieni) i soczewka Fresnela lub lustro.

W celu eliminacji tzw. fałszywych alarmów stosuje się bardzo skomplikowane algorytmy i montuje 2 lub 4 pyroelementy na bazie azotku galu (GaN) lub azotanu cezu (CsNO3).


@Mariusz_Kuciński
Wygląda i funkcjonalność dość ciekawa, oby był wart swojej ceny.
Widzę że ma też Wykrywanie upadku (Fall detection) w końcu żona będzie wiedziała jak upadniesz wracając po imprezie :joy:
Czekam na recenzje jak już go kupisz.

Wyjaśnienie było do czujnik reagujący na ciepło ludzkiego ciała

Dzięki @artpc za wyjaśnienie. Niestety trzeba pamiętać że jak siedzisz na tronie to jest brak ruchu :slight_smile: dlatego stosuję czujniki odległości.

Rozważam zakup tego czujnika Tuya WiFi/Zigbee Radar ludzka obecność czujnik świetlny czujnik jasności 2 w 1 funkcja ludzka detekcja ruchu wykrywanie ruchu PIR|Smart Human Body Sensors| - AliExpress