Am achizitionat de pe Temu o fantana pentru animalele de companie, la un pret modic. Are o pompa, destul de silentioasa, cu debit reglabil. Am vrut sa o modernizez, astfel incat functionarea sa fie temporizata si numai la detectia pisicii.
Initial am incercat cu senzor PIR AM312, dar din cauza limitarilor senzorului (nu se poate regla timpul de detectie) am renuntat si am incercat cu senzor laser VL53L0XV2.
Partea dificila este setarea in program a distantei de detectie ; dar se poate scrie un program simplu care sa afiseze pe monitorul serial momentul cand senzorul detecteaza corpul in miscare. In functie de acest prag se modifica corespunzator programul. Deocamdata functioneaza destul de bine...
#include "Adafruit_VL53L0X.h"
// Configurare Pini
const int pinPompa = 3;
const int pinLedL = 13;
// Parametri Proiect Finali
const int distantaPragMax = 170; // 170 mm (17 cm) - Prag optim de siguranță
const int distantaPragMin = 15; // Min 1.5 cm - Ignoră reflexiile parazite
const int secundeDetectie = 3; // Trebuie să stea 3 secunde continuu
const int secundePompa = 180; // Pompa merge 3 minute
const int minutePauza = 3; // Pauză de siguranță de 3 minute după băut
Adafruit_VL53L0X lox = Adafruit_VL53L0X();
void setup() {
pinMode(pinPompa, OUTPUT);
pinMode(pinLedL, OUTPUT);
digitalWrite(pinPompa, LOW);
digitalWrite(pinLedL, LOW);
Serial.begin(9600);
while (!Serial) { delay(1); }
Serial.println("--- Fantana Pisa ---");
if (!lox.begin()) {
while (1) {
digitalWrite(pinLedL, HIGH); delay(100);
digitalWrite(pinLedL, LOW); delay(100);
}
}
Serial.println("Sistem pornit si calibrat. Pregatit pentru utilizare.");
}
void loop() {
VL53L0X_RangingMeasurementData_t measure;
lox.rangingTest(&measure, false);
// Verificăm dacă apare un obiect în zona de băut (între 1.5 cm și 17 cm)
if (measure.RangeStatus != 4 && measure.RangeMilliMeter >= distantaPragMin && measure.RangeMilliMeter < distantaPragMax) {
Serial.print("[Detecție] Obiect la ");
Serial.print(measure.RangeMilliMeter);
Serial.println(" mm. Începe monitorizarea de 3 secunde...");
unsigned long startDetectie = millis();
bool prezentaContinua = true;
int contorSecunde = 0;
// --- MONITORIZARE 3 SECUNDE ---
while (millis() - startDetectie < (secundeDetectie * 1000)) {
lox.rangingTest(&measure, false);
// Dacă pisica pleacă sau se îndepărtează peste 17 cm, anulăm totul
if (measure.RangeStatus == 4 || measure.RangeMilliMeter > distantaPragMax || measure.RangeMilliMeter < distantaPragMin) {
Serial.println("[Anulare] Pisica a plecat înainte de termen.");
prezentaContinua = false;
break;
}
delay(100);
contorSecunde++;
if (contorSecunde % 10 == 0) {
Serial.print("... confirmat ");
Serial.print(contorSecunde / 10);
Serial.println(" sec.");
}
}
// --- DETECȚIE VALIDATĂ ---
if (prezentaContinua) {
Serial.println(">>> PISICA CONFIRMATA! PORNESTE POMPA (3 MINUTE) <<<");
digitalWrite(pinLedL, HIGH);
digitalWrite(pinPompa, HIGH);
// Ciclul de funcționare 3 minute
for (int s = 1; s <= secundePompa; s++) {
delay(1000);
if (s % 30 == 0) {
Serial.print("Pompa rulează de ");
Serial.print(s);
Serial.println(" secunde.");
}
}
Serial.println("<<< Timp expirat. Oprire pompă. >>>");
digitalWrite(pinPompa, LOW);
digitalWrite(pinLedL, LOW);
// --- PERIOADĂ DE PAUZĂ (3 MINUTE) ---
Serial.println("Intrare în pauza de 3 minute...");
for (int i = 1; i <= (minutePauza * 2); i++) {
delay(29900);
digitalWrite(pinLedL, HIGH); delay(100); digitalWrite(pinLedL, LOW);
}
Serial.println("Pauză terminată. Sistemul revine în Stand-by.");
}
}
// Heartbeat Stand-by la fiecare 10 secunde
static unsigned long timpUltimaClipire = 0;
if (millis() - timpUltimaClipire > 10000) {
digitalWrite(pinLedL, HIGH); delay(50); digitalWrite(pinLedL, LOW);
timpUltimaClipire = millis();
Serial.println("Stand-by: Monitorizare activă...");
}
}
La cererea prietenului Dragos (care mi-a trimis un clip cu un vu-metru cu display color), bazandu-ma pe IA am conceput acest vu-metru, cu un Arduino Nano si un display LCD tip ST7735.
Are un encoder care permite selectia diferitelor tipuri de afisare ; rotirea encoderului permite navigarea printre moduri, apasarea permite selectarea/deselectarea modurilor (se pot selecta toate). Prin combinatiile intre moduri se poate ajunge la o functionare conforma preferintelor.
Semnalul audio se aplica pe pinii A0 si A1 ; audio stereo de la orice preamp (prin 1N4148, 10k, 1-10uF spre masa, A0/A1) sau de la iesirea unui preamplificator de microfon electret (caz in care se unesc A0si A1 iar semnalul afisat va fi mono).
// 4. ACE ORE & MINUTE // Parametri: Unghi, Lungime vârf, Lungime, Lățime, Culoare drawStickHand(hDeg, 58, 18, 10, 1); // Ore: Grosime 10px, coadă 18px drawStickHand(mDeg, 105, 18, 6, 1); // Minute: Lung (până la marcaje), subțire 6px, coadă 18px
// 5. SECUNDARUL drawStickHand(sDeg, 110, 25, 2, 5); // Secundar: Foarte subțire 2px, coadă lungă 25px
// 6. CENTRUL (Cerc alb cu contur negru) spr.fillCircle(120, 120, 4, 2); spr.drawCircle(120, 120, 4, 0);
spr.pushSprite(0, 0); delay(150); }
// --- FUNCȚIE PENTRU ACE DREPTUNGHIULARE --- void drawStickHand(float deg, int len, int tail, int width, int colIdx) { float rad = (deg - 90) * 0.0174532925; // Vector normal pentru lățime constantă float nx = -sin(rad) * (width / 2.0); float ny = cos(rad) * (width / 2.0);
// Calculăm cele 4 puncte: coada acului se extinde în direcția opusă vârfului int x1 = 120 - cos(rad) * tail + nx; int y1 = 120 - sin(rad) * tail + ny; int x2 = 120 - cos(rad) * tail - nx; int y2 = 120 - sin(rad) * tail - ny; int x3 = 120 + cos(rad) * len + nx; int y3 = 120 + sin(rad) * len + ny; int x4 = 120 + cos(rad) * len - nx; int y4 = 120 + sin(rad) * len - ny;
Va prezint statia mea de lipit cu Arduino. Realizata cu AI Gemini, updatata cu Vercel si Qwen ; eu
doar am formulat cerintele si am testat codul, deci nu am prea multe
merite. Inspiratia mea au fost nenumaratele exemple existente.
Pe scurt : ciocan Pensol SL-10 (cel pe care-l am de mai bine de 15 ani
si nu renunt la el, e prea bun !), Arduino Nano, display LED 7 segmente 3
digiti, encoder rotativ, 2 butoane pentru memorare 2 temperaturi de
lucru, stand-by dupa 30 minute.
Am testat-o cateva zile, pe parcursul carora am rezolvat diverse
buguri. In prezent functioneza destul de bine, zic eu. Am vrut initial
cu PID, dar inertia termica mare a ciocanului m-a facut sa renunt ; Qwen a sugerat un algoritm "predictiv" surprinzator de eficient .
Orice comentariu sau sugestie sunt binevenite. Statia este prezentata si pe Elforum (https://www.elforum.info/topic/165506-statie-de-lipit-cu-arduino/),
cine vrea o poate modifica dupa cum doreste (recomand
Vercel / Perplexity / Qwen / Gemini, nu neaparat in aceasta ordine). Numai
bine !
Update : versiunea imbunatatita/updatata pe Elforum.
/* // // STATIE DE LIPIT CU ARDUINO // DISPLAY LED CU 7 SEGMENTE // ENCODER SI 2 MEMORII // STAND-BY DUPA 30 MINUTE // pt PENSOL SL-10 // // // mai multe info aici : // // www.elforum.info/topic/165506-statie-de-lipit-cu-arduino */
void setup() { for (int i = 0; i < 7; i++) pinMode(segPins[i], OUTPUT); for (int i = 0; i < 3; i++) pinMode(digitPins[i], OUTPUT); pinMode(heaterPin, OUTPUT); analogWrite(heaterPin, 0);
Tot cu ajutorul AI am realizat un ceas, cu Wemos D1 mini, care afiseaza pe un dispay LCD si temperatura citita cu SHT40, transmisa din exteriorul locuintei, tot de un Wemos D1 mini . Dupa muuuulte teste si muuuuulte buguri rezolvate, pot spune ca functioneaza foarte bine, nu am mai gasit nicio problema.Trecerea la ora de vara/iarna se face automat.
Ceasul propriu-zis il alimentez dintr-un alimentator de telefon mobil, de 5 volti. Emitatorul este alimentat dintr-un acumulator Li-Ion, a carui tensiune este citita periodic ; daca scade sub pragul critic, apare mesajul "ACCU" pe displayul ceasului. Consumul emitatorului este foarte mic pentru ca transmisia temperaturii se face o data la 5 minute, dupa care montajul intra in deep sleep. Alimentarea se face cu un IC specializat, HT7333.
UPDATE 12/03/2026 (bug conectare corectat).
UPDATE 28/03/2026 - Modificand putin codul si folosind aplicatia BLYNK pot vedea temperatura pe telefonul mobil, de oriunde. Inclusiv graficul evolutiei zilnice, saptamanala, lunara
// Variabilă pentru tracking reconectare WiFi unsigned long lastWiFiAttempt = 0; const unsigned long WIFI_RECONNECT_INTERVAL = 10000; // 10 secunde între încercări
void handleUpdate() { if (server.hasArg("temp")) { float v = server.arg("temp").toFloat(); if (v >= -50 && v <= 100) receivedTemp = v; } lowBattery = (server.hasArg("bat") && server.arg("bat") == "LOW"); server.send(200, "text/plain", "OK"); }
unsigned long prevDisplay = 0;
void displayInfo() { time_t utc = timeClient.getEpochTime();
// Dacă nu am obținut NICIODATĂ ora corectă, afișăm "Sincronizare..." if (!timeInitialized) { display.fillScreen(TFT_BLACK); display.setTextColor(TFT_WHITE, TFT_BLACK); display.setFreeFont(&FreeSansBold12pt7b); display.setTextDatum(MC_DATUM); display.drawString("Sincronizare...", 120, 100); return; }
// AVEM ORA VALIDĂ - afișăm ceasul (chiar dacă WiFi pică între timp) time_t local = Bucharest.toLocal(utc); tmElements_t tm; breakTime(local, tm);
int dd=tm.Day, mm=tm.Month-1, wd=tm.Wday-1, h=tm.Hour, m=tm.Minute, s=tm.Second;
static int lh=-1, lm=-1; if (h!=lh || m!=lm) { display.fillRect(20,80,220,80,TFT_BLACK); display.setTextFont(7); display.setTextColor(TFT_CYAN,TFT_BLACK); display.setTextDatum(TR_DATUM); display.drawString(String(h)+":"+(m<10?"0":"")+String(m), 175, 95); lh=h; lm=m; }
static bool lb=false; if (lowBattery!=lb) { display.fillRect(95,17,50,20,TFT_BLACK); if (lowBattery) { display.setTextFont(2); display.setTextDatum(MC_DATUM); display.setTextColor(TFT_RED,TFT_BLACK); display.drawString("ACCU",120,25); } lb=lowBattery; }
static int lw=-1; int cw=(wd==0)?6:wd-1; if (cw!=lw) { display.fillRect(0,185,240,30,TFT_BLACK); display.setFreeFont(&FreeSansBold9pt7b); display.setTextDatum(MC_DATUM); int pz[]={10,50,90,125,155,185,220}; for (int i=0;i<7;i++) { int zi=(i+1)%7; uint16_t c=(i==cw)?(zi==0||zi==6?TFT_RED:TFT_GREEN):TFT_DARKGREY; display.setTextColor(c,TFT_BLACK); display.drawString(zileAbrev[zi],pz[i],200); } lw=cw; } }
Va salut !
Fiindca o lunga perioada de timp am fost in concediu medical, dupa o afectiune oncologica ce a necesitat operatie, in timpul liber disponibil am lucrat la o serie de proiecte, care sa-mi tina mintea distrasa de la alte ganduri ...
Cu ajutorul AI (Vercel, Perplexity, Gemini, Qwen, Le Chat) am conceput si finalizat, dupa multe, multe incercari si aceasta statie meteo color. Functioneaza foarte bine, prietenul meu, Dragos, o are "activa" si e multumit de ea.
Nota : am experimentat cu datele meteo de pe toate siteurile care pun la dispozitie apiKey. Nu sunt doua la fel !! Exista mari variatii, in special in privinta temperaturii, dar, la unele siteuri, si la starea vremii propriu-zisa (afara era soare, senin si prognoza era innorat, sanse de ploaie :( ). Acesta este si motivul pentru care eu nu folosesc aceasta statie, prefer ceasul cu termometru (ce poate fi vazut tot aici, pe blog).
Cine doreste poate face statia, ideea este sa va obtineti propriul apiKey (google_it) si sa va setati locatia. Succes !
Si inca un montaj cu excelentul Wemos D1 mini : ceas cu matrice de leduri, cu senzor de temperatura DS18B20. Are efect de scroll a afisarii. Testat, functioneaza perfect. L-am montat in bucatarie, iar senzorul de temperatura l-am scos in balcon. Succes !
// Ceas matrice LED cu ora automata vara/iarna + DS18B20
// Conexiuni : DS18B20 la D2 ; matrice DIN - D8 ; CS - D7 ; CLK - D6
#include <ESP8266WiFi.h> #include <time.h> #include <MD_MAX72xx.h> #include <SPI.h> #include <OneWire.h> #include <DallasTemperature.h>