Supla+AI, rozpoznawanie tablic rejestracyjnych i kur na podwórku

User avatar
SOYER
Posts: 1623
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry
Been thanked: 2 times

Post

Cześć, ostatnio zamówiłem esp32 cam z zamiarem rozpoznawania tablic rejestracyjnych.
Skończyło się na:
- integracji esp32 z rejestratorem dahua który wysyła powiadomienie o przekroczeniu linii na kamerze, czyli pojawieniu się nowego obiektu przed bramą,
- esp32 nasłuchuje tego komunikatu i kiedy coś pojawia się przed bramą:
- esp32 wtedy ustawia virtualRelay na ON przez 2s
- na ten ON virtualRelay-a reaguje esp32 cam i robi zdjęcie które następnie wysyła do gemini AI z odpowiednim promptem
- gemini odsyła odpowiedź do esp32cam i jeśli pasuje numer rejestracyjny, marka, model i kolor samochodu...
- esp32cam otwiera z pomocą Supli bramę wjazdową
- wszystko trwa 2-3 sekundy
- i działa...

Jutro dalszy ciąg z kodami i zdjęciami.
Last edited by SOYER on Sat Mar 14, 2026 3:16 pm, edited 1 time in total.
https://youtube.com/@tomaszhamer8134?si=_J1cT_QWsXxgt1Fm
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
https://github.com/Soyer79
User avatar
Zibi_007
Posts: 3985
Joined: Tue Oct 31, 2023 10:06 pm
Has thanked: 10 times
Been thanked: 31 times

Post

Fajnie! Czekam na ciąg dalszy.

Ale z tytułem to "pojechałeś" :lol:
Image Wiesz, że Supla obsługuje Zigbee? Wstąp do Klubu Promila: https://forum.supla.org/viewtopic.php?t=18018
Image Szukasz nowego GG? Jest tutaj: https://forum.supla.org/viewtopic.php?t=18036
zzrr
Posts: 1864
Joined: Wed Oct 26, 2022 7:35 pm
Has thanked: 76 times
Been thanked: 119 times

Post

Cały opis + wiadomość w tytule. Można? Można :lol:
SOYER wrote: Fri Mar 13, 2026 7:38 pm ....

Jutro dalszy ciąg z kodami i zdjęciami.
@SOYER ale napiszesz chociaż w tym samym czy będzie nowy temat? :) ;)
User avatar
malarz
Posts: 506
Joined: Wed Jan 27, 2021 4:04 pm
Been thanked: 2 times

Post

zzrr wrote: Fri Mar 13, 2026 8:51 pm Cały opis + wiadomość w tytule. Można? Można :lol:
SOYER wrote: Fri Mar 13, 2026 7:38 pm ....

Jutro dalszy ciąg z kodami i zdjęciami.
@SOYER ale napiszesz chociaż w tym samym czy będzie nowy temat? :) ;)
Oczywiście: Supla+rozpoznawanieSamochodu+inegracjaZrejestratoremDahua+reakcjaNaPrzekroczenieLini+otwarcieBramyPoPodjechaniuAuta+Kody+Zdjęcia

:-)
Próbuję przerobić pomysły na działające projekty w ArduinoIDE.
User avatar
Zibi_007
Posts: 3985
Joined: Tue Oct 31, 2023 10:06 pm
Has thanked: 10 times
Been thanked: 31 times

Post

malarz wrote: Sat Mar 14, 2026 10:35 am
zzrr wrote: Fri Mar 13, 2026 8:51 pm Cały opis + wiadomość w tytule. Można? Można :lol:
SOYER wrote: Fri Mar 13, 2026 7:38 pm ....

Jutro dalszy ciąg z kodami i zdjęciami.
@SOYER ale napiszesz chociaż w tym samym czy będzie nowy temat? :) ;)
Oczywiście: Supla+rozpoznawanieSamochodu+inegracjaZrejestratoremDahua+reakcjaNaPrzekroczenieLini+otwarcieBramyPoPodjechaniuAuta+Kody+Zdjęcia

:-)
I następny nowy temat:
Supla+rozpoznawanieSamochodu+inegracjaZrejestratoremDahua+reakcjaNaPrzekroczenieLini+otwarcieBramyPoPodjechaniuAuta+Kody+Zdjęcia+Opis :lol:
Image Wiesz, że Supla obsługuje Zigbee? Wstąp do Klubu Promila: https://forum.supla.org/viewtopic.php?t=18018
Image Szukasz nowego GG? Jest tutaj: https://forum.supla.org/viewtopic.php?t=18036
User avatar
Robert Błaszczak
Posts: 5222
Joined: Sat Dec 22, 2018 8:55 pm
Location: Zielona Góra
Has thanked: 37 times
Been thanked: 27 times

Post

Zibi_007 wrote: Sat Mar 14, 2026 1:03 pm I następny nowy temat:
Supla+rozpoznawanieSamochodu+inegracjaZrejestratoremDahua+reakcjaNaPrzekroczenieLini+otwarcieBramyPoPodjechaniuAuta+Kody+Zdjęcia+Opis :lol:
:lol:

A tak poważnie to prośba do @klew o skrócenie tego tematu. Taki temat nie jest czytelny, a rozwala Forum.
Propozycja: Otwarcie bramy na podstawie tablicy rejestracyjnej
Pozdrawiam
Robert Błaszczak


Moja prywatna strona: www.blaszczak.pl
User avatar
SOYER
Posts: 1623
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry
Been thanked: 2 times

Post

Hej, widzę, że temat budzi duże zainteresowanie :D

Aktualnie mam 2 urządzenia: esp32u(było c3 ale nie dawało rady) i esp32 cam.
Esp32u działa na dwóch wątkach, jeden obsługuje suplę i pojedynczy kanał wirtualnego przekaźnika, a na drugim wątku łaczy się poprzez API z rejestratorem Dahua i nasłuchuje informacji o przekroczeniu linii(wirtualnej) na kamerze która patrzy przed bramę. W momencie przekroczenia linii, esp włącza vr na 2 sekundy i tutaj kończy się jego praca,
a zaczyna robota esp32 cam, który przez MQTT nasłuchuje powyższy vr i kiedy ten jest włączony, esp wykonuje zdjęcie i wysyła je do AI gemini z prośbą o podanie numeru tablicy rejestracyjnej i marki samochodu. AI odpowiada, esp porównuje odpowiedź z bazą samochodów, jeśli pasuje marka i numer, przez MQTT otwiera bramę.
Skrótowo: jedno esp nasłuchuje rejestratora i kiedy ten mówi "coś wjechało przed bramę" esp włącza na moment virtualrelay. Na tą informację czeka już esp cam który robi zdjęcie i jeśli pasuje marka i numer otwiera bramę.

Kod dla esp32 cam:

Code: Select all

//płytka AI Thinker ESP32-CAM

#include "esp_camera.h"
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include "Base64.h"
#include <PubSubClient.h>
#include <WiFiClientSecure.h>

#include <WebServer.h>
WebServer server(80);
uint8_t* last_photo_buf = NULL;
size_t last_photo_len = 0;
void handleRoot() {
  if (last_photo_buf != NULL && last_photo_len > 0) {
    server.setContentLength(last_photo_len);
    server.send(200, "image/jpeg", ""); // Wysyła tylko nagłówek
    server.client().write(last_photo_buf, last_photo_len); // Wysyła czyste bajty
  } else {
    server.send(200, "text/plain; charset=UTF-8", "Brak zdjęcia. Wyzwol analize MQTT.");
  }
}

// --- WIFI CONFIGURATION ---
const char* ssid = "x";
const char* password = "x";

// --- GEMINI CONFIGURATION ---
const char* apiKey = "x";

// --- MQTT SUPLA CONFIGURATION ---
const char* mqtt_server = "mqttx.supla.org";
const int mqtt_port = 8883; 
const char* mqtt_user = "x";
const char* mqtt_pass = "x";

// LISTENING TOPIC (Trigger)
const char* topic_sub = "supla/x/devices/x/channels/x/state/on";
// SENDING TOPIC (Opening the gate )
const char* topic_pub = "supla/x/devices/x/channels/x/execute_action";

WiFiClientSecure espClient;
PubSubClient client(espClient);

bool triggerPhoto = false;

struct Samochod {
  String tablica;
  String marka;
};

// Twoja lista uprawnionych pojazdów
Samochod baza[] = {
  {"SPS xxx", "VOLVO"},
  {"SPS xxx", "OPEL"}
};
int ileWBazie = 2;

// --- PINS ESP32-CAM AI-THINKER ---
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22

void callback(char* topic, byte* payload, unsigned int length) {
  String message = "";
  for (int i = 0; i < length; i++) message += (char)payload[i];
  
  // In Supla, the ON state is usually "1"
  if (message == "true") {
    Serial.println(">>> ON signal received via MQTT! Starting analysis...");
    triggerPhoto = true;
  }
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Connecting to MQTT...");
    if (client.connect("ESP32_CAM_LPR_Node", mqtt_user, mqtt_pass)) {
      Serial.println("Connected!");
      client.subscribe(topic_sub);
    } else {
      Serial.print("Error: ");
      Serial.print(client.state());
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM; config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 10000000; config.pixel_format = PIXFORMAT_JPEG;
  config.frame_size = FRAMESIZE_VGA; // Optimal for RAM
  config.jpeg_quality = 12;
  config.fb_count = 1;

  esp_camera_init(&config);
  sensor_t * s = esp_camera_sensor_get();
  s->set_vflip(s, 1);
  s->set_hmirror(s, 0);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
  Serial.println("\nWiFi OK");
  Serial.println("MQTT config...");
  espClient.setInsecure();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
   server.on("/", handleRoot);
  server.begin();
  Serial.print("Podglad pod: http://");
  Serial.println(WiFi.localIP());
}

void loop() {
  if (!client.connected()) reconnect();
  client.loop();
  server.handleClient();
  if (triggerPhoto) {
    triggerPhoto = false;
    analyzeWithGemini();
  }
}

void analyzeWithGemini() {
   camera_fb_t * fb_warmup = esp_camera_fb_get();
  if (fb_warmup) esp_camera_fb_return(fb_warmup);
  delay(500); 
  
  camera_fb_t * fb = esp_camera_fb_get();
  if (!fb) { Serial.println("Camera error"); return; }
  // --- KOPIOWANIE DLA PODGLĄDU ---
  if (last_photo_buf) free(last_photo_buf); 
  last_photo_buf = (uint8_t*)malloc(fb->len);
  if (last_photo_buf) {
    memcpy(last_photo_buf, fb->buf, fb->len);
    last_photo_len = fb->len;
  }
  String base64Image = base64::encode(fb->buf, fb->len);
  esp_camera_fb_return(fb);

  HTTPClient http;
  http.setTimeout(30000); 
  String url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=" + String(apiKey);
  http.begin(url);
  http.addHeader("Content-Type", "application/json");

  String prompt = "Analyze this image. Return ONLY a JSON object with fields: plate, brand. Format: {\\\"plate\\\":\\\"...\\\", \\\"brand\\\":\\\"...\\\"}. Do not add any extra text or markdown.";
  String payload = "{\"contents\":[{\"parts\":[{\"text\":\"" + prompt + "\"},{\"inline_data\":{\"mime_type\":\"image/jpeg\",\"data\":\"" + base64Image + "\"}}]}]}";

  int httpResponseCode = http.POST(payload);
  
  if (httpResponseCode == 200) {
    String response = http.getString();
    DynamicJsonDocument doc(8192);
    deserializeJson(doc, response);   
    String rawJson = doc["candidates"][0]["content"]["parts"][0]["text"];
    Serial.print("ODPOWIEDŹ GEMINI: ");
    Serial.println(rawJson);
    rawJson.replace("```json", "");
    rawJson.replace("```", "");
    rawJson.trim();

    DynamicJsonDocument car(1024);
    deserializeJson(car, rawJson);
    
    String odczytanaTablica = car["plate"];
    String odczytanaMarka = car["brand"];

    Serial.println("\n--- WYNIK ANALIZY ---");
    Serial.printf("TABLICA: %s | %s %s (%s)\n", odczytanaTablica.c_str(), odczytanaMarka.c_str());

    bool znaleziono = false;
    for (int i = 0; i < ileWBazie; i++) { 
      // 1. Przygotowanie tablic (bez spacji, wielkie litery)
      String t1 = odczytanaTablica; t1.replace(" ", ""); t1.toUpperCase();
      String t2 = baza[i].tablica; t2.replace(" ", ""); t2.toUpperCase();

      // 2. Przygotowanie marek (wielkie litery, usunięcie zbędnych spacji)
      String m1 = odczytanaMarka; m1.trim(); m1.toUpperCase();
      String m2 = baza[i].marka; m2.trim(); m2.toUpperCase();

      // WARUNEK: Musi zgadzać się tablica ORAZ marka musi pasować do odczytu
      if (t1 == t2 && (m1.indexOf(m2) != -1 || m2.indexOf(m1) != -1)) {
        Serial.println(">>> DOSTĘP PRZYZNANY: " + baza[i].marka + " [" + baza[i].tablica + "]");
        client.publish(topic_pub, "OPEN");//_CLOSE
        Serial.println("Wysłano MQTT: Otwieram bramę");
        znaleziono = true;
        break;
      }
    }
    if (!znaleziono) {
      Serial.println("XXX POJAZD NIEZGODNY LUB NIEZNANY XXX");
    }
  } else {
    Serial.printf("HTTP error: %d\n", httpResponseCode);
  }
  http.end();    
}
Dodatkowo jest tam jeszcze lokalny podgląd w przeglądarce na zrobione zdjęcie, potrzebne do testów.

Kod dla obsługi zdarzeń rejestratora:

Code: Select all

//curl -g --digest -u xx:xxx "http://192.x.x.x/cgi-bin/eventManager.cgi?action=attach&codes=[CrossLineDetection]"
//płytka esp32 dev module
#include <WiFi.h>
#include <MD5Builder.h>
#define SUPLA_LOG_LEVEL 3 
#include <SuplaDevice.h>
#include <supla/network/esp_wifi.h>
#include <supla/control/virtual_relay.h>

// --- KONFIGURACJA ---
const char* ssid = "x";
const char* password = "x";
const char* host = "x";
const char* user = "x";
const char* pass = "x";
const char* url  = "/cgi-bin/eventManager.cgi?action=attach&codes=[CrossLineDetection]&channel=2&heartbeat=5";

char GUID[16] = {x};
char AUTHKEY[16] = {x};

WiFiClient d_client;
Supla::ESPWifi supla_wifi(ssid, password); 
auto vRelay = new Supla::Control::VirtualRelay();

unsigned long lastEventTime = 0;
unsigned long lastDataTime = 0;

// --- FUNKCJE POMOCNICZE ---
String md5(String payload) {
  MD5Builder _md5; _md5.begin(); _md5.add(payload); _md5.calculate();
  return _md5.toString();
}

String getDigestAuth(String header) {
  auto getParam = [&](String param) {
    int start = header.indexOf(param + "=\"");
    if (start == -1) return String("");
    start += param.length() + 2;
    return header.substring(start, header.indexOf("\"", start));
  };
  String realm = getParam("realm"), nonce = getParam("nonce"), qop = "auth", nc = "00000001", cnonce = "abcdefgh";
  String ha1 = md5(String(user) + ":" + realm + ":" + String(pass));
  String ha2 = md5("GET:" + String(url));
  String resp = md5(ha1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + ha2);
  return "Digest username=\"" + String(user) + "\", realm=\"" + realm + "\", nonce=\"" + nonce + 
         "\", uri=\"" + url + "\", qop=" + qop + ", nc=" + nc + ", cnonce=\"" + cnonce + 
         "\", response=\"" + resp + "\", algorithm=MD5";
}

// --- WĄTEK DAHUA (URUCHAMIANY NA RDZENIU 0) ---
void dahuaTask(void * pvParameters) {
  Serial.println("[Dahua] Wątek wystartował na Core 0.");
  
  while(1) {
    if (WiFi.status() == WL_CONNECTED) {
      if (!d_client.connected()) {
        Serial.println("[Dahua] Próba połączenia (Krok 1/2)...");
        
        if (d_client.connect(host, 80)) {
          // Wysłanie zapytania o Digest (udajemy curl dla stabilności)
          d_client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                         "Host: " + host + "\r\n" +
                         "User-Agent: curl/7.68.0\r\n" +
                         "Accept: */*\r\n" +
                         "Connection: close\r\n\r\n");

          String response = "";
          unsigned long t = millis();
          // Czekamy na wyzwanie Digest max 3s
          while ((d_client.connected() || d_client.available()) && (millis() - t < 3000)) {
            if (d_client.available()) {
              char c = d_client.read();
              response += c;
              if (response.indexOf("\r\n\r\n") != -1) break;
            }
            vTaskDelay(1 / portTICK_PERIOD_MS);
          }

          int authPos = response.indexOf("WWW-Authenticate: Digest");
          if (authPos != -1) {
            String authLine = response.substring(authPos, response.indexOf("\r", authPos));
            Serial.println("[Dahua] Logowanie (Krok 2/2)...");
            
            d_client.stop();
            vTaskDelay(150 / portTICK_PERIOD_MS);
            
            if (d_client.connect(host, 80)) {
              d_client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                             "Host: " + host + "\r\n" +
                             "Authorization: " + getDigestAuth(authLine) + "\r\n" +
                             "User-Agent: curl/7.68.0\r\n" +
                             "Accept: */*\r\n" +
                             "Connection: keep-alive\r\n\r\n");
              
              Serial.println("[Dahua] POŁĄCZONO I NASŁUCHUJĘ!");
              lastDataTime = millis();
            }
          } else {
            Serial.println("[Dahua] BŁĄD: Brak autoryzacji Digest w odpowiedzi.");
            d_client.stop();
          }
        }
        if (!d_client.connected()) vTaskDelay(5000 / portTICK_PERIOD_MS);
      }

      // --- STABILNY ODBIÓR STRUMIENIA ZNAK PO ZNAKU ---
      String currentLine = "";
      currentLine.reserve(256); // Optymalizacja pamięci

      while (d_client.connected()) {
        if (d_client.available()) {
          char c = d_client.read();
          lastDataTime = millis(); // Reset timeoutu - coś przyszło!
          
          // Opcjonalne: Serial.print(c); // Odkomentuj, by widzieć "surowy" zrzut danych
          
          if (c == '\n') {
            // Analiza kompletnej linii
            if (currentLine.indexOf("Code=CrossLineDetection") != -1) {
              if (currentLine.indexOf("action=Start") != -1) {
                Serial.println("\n>>> [DAHUA] !!! ALARM PRZEKROCZENIA LINII !!! <<<");
                vRelay->turnOn();
                lastEventTime = millis();
              } else if (currentLine.indexOf("action=Stop") != -1) {
                Serial.println("\n[Dahua] Koniec zdarzenia.");
              }
            }
            currentLine = ""; // Czyścimy bufor po znaku nowej linii
          } 
          else if (c != '\r') {
            currentLine += c;
          }

          // Zabezpieczenie przed zbyt długą linią (brak znaku \n)
          if (currentLine.length() > 512) currentLine = "";
        }

        // Timeout: Dahua milczy (brak ruchu). Restart po 2 minutach ciszy.
        if (millis() - lastDataTime > 120000) { 
          Serial.println("\n[Dahua] Timeout (2 min) - restart połączenia...");
          d_client.stop();
          break;
        }

        vTaskDelay(1 / portTICK_PERIOD_MS); // Kluczowe dla stabilności WiFi/Supla
      }
    } else {
      vTaskDelay(1000 / portTICK_PERIOD_MS); // Czekaj na WiFi
    }
    vTaskDelay(100 / portTICK_PERIOD_MS);
  }
}


void setup() {
  Serial.begin(115200);
  // Start Supli na domyślnym rdzeniu (1)
  SuplaDevice.begin(GUID, "svrx.supla.org", "[email protected]", AUTHKEY);

  // Uruchomienie wątku Dahua na rdzeniu 0
  xTaskCreatePinnedToCore(dahuaTask, "DahuaTask", 8192, NULL, 1, NULL, 0);
  
  Serial.println("System gotowy (Dual Core).");
}

void loop() {
  SuplaDevice.iterate();

  if (vRelay->isOn() && (millis() - lastEventTime > 2000)) {
    vRelay->turnOff();
    Serial.println("[Supla] OFF.");
  }
}
Potestuję jeszcze kilka dni, a potem muszę tą kamerkę jakoś zainstalować.
Trzeba oczywiście też zmienić prompt tak by gemini odrzucał wszelkie "zdjęcia ze zdjęciem". W aktualnym prompcie wystarczy pokazać zdjęcie naszego auta i już brama się otwiera:).
Bawiąc się z rejestratorem, coś naknociłem bo już nie dostaję na moim telefonie powiadomień push z apki Dahua, pewnie będę musiał ją przeinstalować :( .
Projekt powstał z chęci zrobienia czegoś ciekawego. Przy jego powstawaniu ogromnie korzystałem z pomocy AI(również gemini). Potwierdza się pogląd, że z AI krótko piszesz ale długo debugujesz:).

Jeszcze jedna informacja, od pojawienia się na podjeździe do momentu włączenia otwierania bramy mija maksymalnie 5 sekund. Także dość użyteczne. Będę tego używał chyba tylko dla zabawy bo wolę otwierać bramę wcześniej, a nie czekać aż się otworzy.
Jednak projekt dość rozwojowy bo przecież AI może rozpoznawać wszystko, czy pada deszcz(zamknij okna dachowe), jest ciemno(włącz światło), kury uciekły z kurnika i biegają po podwórku(wyślij powiadomienie push z Supli) i wiele innych....

P.S. już zmieniam temat:)
https://youtube.com/@tomaszhamer8134?si=_J1cT_QWsXxgt1Fm
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
https://github.com/Soyer79
zzrr
Posts: 1864
Joined: Wed Oct 26, 2022 7:35 pm
Has thanked: 76 times
Been thanked: 119 times

Post

Sam pomysł ciekawy, warty gratulacji. Jakieś wyzwanie, realizacja, efekty. Samo otwieranie bramy można oczywiście rozwiązać na wiele innych prostszych sposobów. Nawet dzisiaj rano na rolkach w FB pokazał mi się filmik jak gościu połączył mikrokontroler do świateł w aucie i sekwencja trzech mignięć uruchamiała mu bramę. Ale Twój pomysł z tą kamerką w połączeniu z AI to ciekawa sprawa. Np. może ostrzegać jak żona idzie. A jak np. koledzy to milczy albo uruchamia większe mrożenie w lodówce :) ;) A tak na poważnie to podobają mi się takie różne nietypowe pomysły 👍
User avatar
SOYER
Posts: 1623
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry
Been thanked: 2 times

Post

Mam jeszcze prośbę, jakby mi ktoś powiedział jak ograniczyć logi supli w czasie działania programu. Wiem(?), że jest kilka „poziomów” dla logów, ale z moim kolegą ejajem poległem na tym.
https://youtube.com/@tomaszhamer8134?si=_J1cT_QWsXxgt1Fm
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
https://github.com/Soyer79
zzrr
Posts: 1864
Joined: Wed Oct 26, 2022 7:35 pm
Has thanked: 76 times
Been thanked: 119 times

Post

SOYER wrote: Sat Mar 14, 2026 7:26 pm Mam jeszcze prośbę, jakby mi ktoś powiedział jak ograniczyć logi supli w czasie działania programu. Wiem(?), że jest kilka „poziomów” dla logów, ale z moim kolegą ejajem poległem na tym.
Używasz ArduinoIDE czy PlatformIO? To robi różnicę jeśli chodzi o Twoje pytanie.

Return to “Projekty użytkowników”