// ==================== MODUL 4 - SENZORJI VITRINE ====================
// ESP32-S3 - Koda za MCN32R16V s PRAVIMI senzorji
#include <esp_now.h>
#include <esp_wifi.h>
#include <esp_mac.h>
#include <WiFi.h>
#include <DHT.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Preferences.h>
#include <HardwareSerial.h>
// ==================== DEFINICIJE PINOV ZA MCN32R16V ====================
// DHT22 (temperatura in vlaga zraka)
#define DHTPIN 14
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
// DS18B20 (temperatura zemlje)
#define ONE_WIRE_BUS 10
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature soilTempSensor(&oneWire);
// LDR (svetloba) - z napetostnim delilnikom (LDR + 10kΩ upor)
#define LDR_PIN 4
// Senzor vlage tal (kapacitivni) - analogni vhod
#define SOIL_MOISTURE_PIN 5
// YS-Y01 V2 (TVOC/eCO2/eCH2O) - UART2
#define YS01_RX_PIN 17
#define YS01_TX_PIN 18
HardwareSerial YS01(2);
// ==================== GLOBALNE SPREMENLJIVKE ====================
// Senzorske spremenljivke
float airTemperature = 0;
float airHumidity = 0;
int lightPercent = 0;
float soilTemperature = 0;
int soilMoisturePercent = 0;
float tvoc_ppb = 0;
float eco2_ppm = 0;
float ech2o_ppb = 0;
// Status inicializacije
bool dhtInitialized = false;
bool ds18b20Initialized = false;
bool ys01Initialized = false;
// Kalibracijske vrednosti
int ldrMinADC = 500; // Svetlo (nizek ADC)
int ldrMaxADC = 3000; // Temno (visok ADC)
int SOIL_DRY_VALUE = 4095;
int SOIL_WET_VALUE = 1500;
// Časovniki za meritve
unsigned long lastSensorRead = 0;
#define SENSOR_READ_INTERVAL 2000 // Beri senzorje vsake 2 sekundi
// ESP-NOW
// ⚠️ **POMEMBNO: VSTAVITE PRAVILEN MAC NASLOV VAŠEGA GLAVNEGA SISTEMA!**
// MAC naslov glavnega sistema iz Serial Monitorja: B4:3A:45:F3:EB:F0
uint8_t masterMAC[] = {0xB4, 0x3A, 0x45, 0xF3, 0xEB, 0xF0};
unsigned long lastSendTime = 0;
#define SEND_INTERVAL 10000 // Pošlji vsakih 10 sekund
Preferences preferences;
// ==================== FUNKCIJE ZA BRANJE SENZORJEV ====================
void readDHT22() {
if (!dhtInitialized) return;
// Preberi večkrat za boljšo zanesljivost
float h = dht.readHumidity();
float t = dht.readTemperature();
// Če je napaka, poskusi ponovno
if (isnan(t) || isnan(h)) {
delay(100);
h = dht.readHumidity();
t = dht.readTemperature();
}
if (!isnan(t) && !isnan(h)) {
airTemperature = t;
airHumidity = h;
Serial.printf(" DHT22: T=%.1f°C, H=%.1f%%\n", airTemperature, airHumidity);
} else {
Serial.println(" DHT22: Napaka pri branju!");
}
}
void readDS18B20() {
if (!ds18b20Initialized) return;
soilTempSensor.requestTemperatures();
float temp = soilTempSensor.getTempCByIndex(0);
if (temp != -127.00 && !isnan(temp)) {
soilTemperature = temp;
Serial.printf(" DS18B20: SoilT=%.1f°C\n", soilTemperature);
} else {
Serial.println(" DS18B20: Napaka pri branju!");
}
}
void readLDR() {
int rawValue = analogRead(LDR_PIN);
rawValue = constrain(rawValue, 0, 4095);
// Izračun procenta (0% = tema, 100% = svetlo)
// Uporabi kalibrirane vrednosti ali privzete
if (ldrMaxADC > ldrMinADC) {
lightPercent = map(rawValue, ldrMinADC, ldrMaxADC, 100, 0);
} else {
// Privzeta kalibracija: svetlo = 500, temno = 3000
lightPercent = map(rawValue, 500, 3000, 100, 0);
}
lightPercent = constrain(lightPercent, 0, 100);
Serial.printf(" LDR: ADC=%d, Light=%d%%\n", rawValue, lightPercent);
}
void readSoilMoisture() {
int rawValue = analogRead(SOIL_MOISTURE_PIN);
rawValue = constrain(rawValue, 0, 4095);
// Izračun procenta vlage (0% = suho, 100% = mokro)
if (SOIL_DRY_VALUE > SOIL_WET_VALUE) {
soilMoisturePercent = map(rawValue, SOIL_DRY_VALUE, SOIL_WET_VALUE, 0, 100);
} else {
// Privzeta kalibracija
soilMoisturePercent = map(rawValue, 4095, 1500, 0, 100);
}
soilMoisturePercent = constrain(soilMoisturePercent, 0, 100);
Serial.printf(" Soil Moisture: ADC=%d, Percent=%d%%\n", rawValue, soilMoisturePercent);
}
void readYS01() {
// Pošlji ukaz za podatke (odvisno od senzorja)
YS01.print("AT+DATA\r\n");
unsigned long startTime = millis();
while (millis() - startTime < 500) {
while (YS01.available()) {
String data = YS01.readStringUntil('\n');
data.trim();
if (data.length() > 0) {
Serial.printf(" YS01: %s\n", data.c_str());
// Poskusi parsirati TVOC, CO2, CH2O
int tvocPos = data.indexOf("TVOC=");
int co2Pos = data.indexOf("CO2=");
int ch2oPos = data.indexOf("CH2O=");
if (tvocPos >= 0) {
int tvocEnd = data.indexOf(',', tvocPos);
if (tvocEnd < 0) tvocEnd = data.length();
tvoc_ppb = data.substring(tvocPos + 5, tvocEnd).toFloat();
ys01Initialized = true;
}
if (co2Pos >= 0) {
int co2End = data.indexOf(',', co2Pos);
if (co2End < 0) co2End = data.length();
eco2_ppm = data.substring(co2Pos + 4, co2End).toFloat();
ys01Initialized = true;
}
if (ch2oPos >= 0) {
int ch2oEnd = data.indexOf(',', ch2oPos);
if (ch2oEnd < 0) ch2oEnd = data.length();
ech2o_ppb = data.substring(ch2oPos + 5, ch2oEnd).toFloat();
ys01Initialized = true;
}
if (ys01Initialized) {
Serial.printf(" YS01: TVOC=%.0f ppb, CO2=%.0f ppm, CH2O=%.0f ppb\n",
tvoc_ppb, eco2_ppm, ech2o_ppb);
}
}
}
delay(10);
}
}
void readAllSensors() {
Serial.println("\n📊 Branje senzorjev:");
readDHT22();
readLDR();
readSoilMoisture();
readDS18B20();
readYS01();
}
// ==================== POŠILJANJE PODATKOV ====================
void sendDataToMaster() {
// Preveri, ali so podatki smiselni (ne samo ničle)
// Če DHT22 ni inicializiran, uporabi privzete vrednosti
if (!dhtInitialized && airTemperature == 0 && airHumidity == 0) {
// Počakamo na naslednji cikel, da se senzorji inicializirajo
return;
}
// Format: temp,hum,0,light,soilTemp,soilMoisture,TVOC=xx,CO2=xx,CH2O=xx
// Pressure je 0 ker DHT22 ne meri tlaka
char buffer[256];
snprintf(buffer, sizeof(buffer),
"%.1f,%.1f,0.0,%d,%.1f,%d,TVOC=%.0f,CO2=%.0f,CH2O=%.0f",
airTemperature, airHumidity, lightPercent,
soilTemperature, soilMoisturePercent,
tvoc_ppb, eco2_ppm, ech2o_ppb);
Serial.printf("\n📡 Pošiljam podatke: %s\n", buffer);
esp_err_t result = esp_now_send(masterMAC, (uint8_t*)buffer, strlen(buffer));
if (result == ESP_OK) {
Serial.println(" ✅ Podatki poslani!");
} else {
Serial.printf(" ❌ Napaka pri pošiljanju: %d\n", result);
}
}
// ==================== INICIALIZACIJA SENZORJEV ====================
void initSensors() {
Serial.println("\n🔧 INICIALIZACIJA SENZORJEV");
// ===== DHT22 =====
Serial.println("\n Inicializiram DHT22...");
dht.begin();
delay(1000);
// Testno branje DHT22
float testH = dht.readHumidity();
float testT = dht.readTemperature();
if (!isnan(testT) && !isnan(testH)) {
dhtInitialized = true;
airTemperature = testT;
airHumidity = testH;
Serial.printf(" ✅ DHT22 inicializiran! T=%.1f°C, H=%.1f%%\n", testT, testH);
} else {
Serial.println(" ❌ DHT22 ni zaznan!");
Serial.println(" Preverite:");
Serial.println(" - Povezavo na pin 14");
Serial.println(" - Pull-up upor 4.7kΩ med DATA in 3.3V");
Serial.println(" - Napajanje (3.3V)");
dhtInitialized = false;
}
// ===== DS18B20 (temperatura zemlje) =====
Serial.println("\n Inicializiram DS18B20...");
pinMode(ONE_WIRE_BUS, INPUT_PULLUP);
soilTempSensor.begin();
int deviceCount = soilTempSensor.getDeviceCount();
if (deviceCount > 0) {
ds18b20Initialized = true;
Serial.printf(" ✅ DS18B20 inicializiran! (%d naprav)\n", deviceCount);
// Izpiši ROM naslove naprav
for (int i = 0; i < deviceCount; i++) {
DeviceAddress address;
if (soilTempSensor.getAddress(address, i)) {
Serial.print(" Naprava ");
Serial.print(i);
Serial.print(": ");
for (uint8_t j = 0; j < 8; j++) {
Serial.printf("%02X", address[j]);
if (j < 7) Serial.print(":");
}
Serial.println();
}
}
} else {
Serial.println(" ⚠️ DS18B20 ni najden - senzor temperature zemlje ne bo na voljo");
Serial.println(" (To ni kritično, če nimate priključenega senzorja)");
ds18b20Initialized = false;
}
// ===== LDR =====
Serial.println("\n Inicializiram LDR...");
pinMode(LDR_PIN, INPUT);
Serial.println(" ✅ LDR inicializiran!");
// ===== Senzor vlage tal =====
Serial.println("\n Inicializiram senzor vlage tal...");
pinMode(SOIL_MOISTURE_PIN, INPUT);
Serial.println(" ✅ Senzor vlage tal inicializiran!");
// ===== YS-Y01 V2 (TVOC/eCO2/eCH2O) =====
Serial.println("\n Inicializiram YS-Y01 V2...");
YS01.begin(9600, SERIAL_8N1, YS01_RX_PIN, YS01_TX_PIN);
Serial.printf(" ✅ YS-Y01 V2 inicializiran (UART2, RX=%d, TX=%d, 9600 baud)!\n", YS01_RX_PIN, YS01_TX_PIN);
// Pošlji začetni ukaz za YS01
YS01.print("AT+START\r\n");
delay(500);
}
// ==================== NALAGANJE KALIBRACIJSKIH VREDNOSTI ====================
void loadCalibration() {
Serial.println("\n🔧 Nalagam kalibracijske vrednosti...");
preferences.begin("module4-calib", true);
ldrMinADC = preferences.getInt("ldrMin", 500);
ldrMaxADC = preferences.getInt("ldrMax", 3000);
SOIL_DRY_VALUE = preferences.getInt("soilDry", 4095);
SOIL_WET_VALUE = preferences.getInt("soilWet", 1500);
preferences.end();
Serial.printf(" LDR kalibracija: Svetlo ADC=%d, Temno ADC=%d\n", ldrMinADC, ldrMaxADC);
Serial.printf(" Vlaga tal kalibracija: Suho ADC=%d, Mokro ADC=%d\n", SOIL_DRY_VALUE, SOIL_WET_VALUE);
}
// ==================== INICIALIZACIJA ESP-NOW ====================
void initESPNow() {
Serial.println("\n🔧 INICIALIZACIJA ESP-NOW");
WiFi.mode(WIFI_STA);
delay(100);
// Nastavi kanal na 1 (enako kot glavni sistem)
esp_wifi_set_promiscuous(true);
esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE);
esp_wifi_set_promiscuous(false);
Serial.println(" 📡 Kanal nastavljen na 1");
// Inicializiraj ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println(" ❌ Napaka pri inicializaciji ESP-NOW!");
return;
}
Serial.println(" ✅ ESP-NOW inicializiran!");
// Dodaj master kot peer
esp_now_peer_info_t peerInfo;
memset(&peerInfo, 0, sizeof(peerInfo));
memcpy(peerInfo.peer_addr, masterMAC, 6);
peerInfo.channel = 1;
peerInfo.encrypt = false;
peerInfo.ifidx = WIFI_IF_STA;
if (esp_now_add_peer(&peerInfo) == ESP_OK) {
Serial.println(" ✅ Peer (glavni sistem) dodan!");
Serial.print(" MAC naslov glavnega sistema: ");
for(int i = 0; i < 6; i++) {
Serial.printf("%02X", masterMAC[i]);
if(i < 5) Serial.print(":");
}
Serial.println();
} else {
Serial.println(" ❌ Napaka pri dodajanju peer-ja!");
}
}
// ==================== TESTNA FUNKCIJA ZA DHT22 ====================
void testDHT22() {
Serial.println("\n🔧 TEST DHT22 SENZORJA");
Serial.println(" Izvajam 5 zaporednih meritev...");
for (int i = 0; i < 5; i++) {
delay(2000);
float h = dht.readHumidity();
float t = dht.readTemperature();
if (!isnan(t) && !isnan(h)) {
Serial.printf(" Meritev %d: T=%.1f°C, H=%.1f%%\n", i+1, t, h);
} else {
Serial.printf(" Meritev %d: NAPAKA!\n", i+1);
}
}
}
// ==================== TESTNA FUNKCIJA ZA DS18B20 ====================
void testDS18B20() {
Serial.println("\n🔧 TEST DS18B20 SENZORJA");
if (!ds18b20Initialized) {
Serial.println(" DS18B20 ni inicializiran!");
return;
}
soilTempSensor.requestTemperatures();
float temp = soilTempSensor.getTempCByIndex(0);
if (temp != -127.00 && !isnan(temp)) {
Serial.printf(" Temperatura zemlje: %.1f°C\n", temp);
} else {
Serial.println(" Napaka pri branju DS18B20!");
}
}
// ==================== TESTNA FUNKCIJA ZA LDR ====================
void testLDR() {
Serial.println("\n🔧 TEST LDR SENZORJA");
int rawValue = analogRead(LDR_PIN);
Serial.printf(" ADC vrednost: %d\n", rawValue);
int percent = map(constrain(rawValue, 500, 3000), 500, 3000, 100, 0);
percent = constrain(percent, 0, 100);
Serial.printf(" Svetloba: %d%%\n", percent);
}
// ==================== TESTNA FUNKCIJA ZA SENZOR VLAGE TAL ====================
void testSoilMoisture() {
Serial.println("\n🔧 TEST SENZORJA VLAGE TAL");
int rawValue = analogRead(SOIL_MOISTURE_PIN);
Serial.printf(" ADC vrednost: %d\n", rawValue);
int percent = map(constrain(rawValue, 4095, 1500), 4095, 1500, 0, 100);
percent = constrain(percent, 0, 100);
Serial.printf(" Vlaga tal: %d%%\n", percent);
}
// ==================== TESTNA FUNKCIJA ZA YS01 ====================
void testYS01() {
Serial.println("\n🔧 TEST YS-Y01 V2 SENZORJA");
Serial.println(" Pošiljam ukaz AT+START...");
YS01.print("AT+START\r\n");
delay(500);
// Preberi odgovor
while (YS01.available()) {
String response = YS01.readStringUntil('\n');
if (response.length() > 0) {
Serial.printf(" Odgovor: %s\n", response.c_str());
}
}
Serial.println(" Pošiljam ukaz AT+DATA...");
YS01.print("AT+DATA\r\n");
delay(500);
while (YS01.available()) {
String response = YS01.readStringUntil('\n');
if (response.length() > 0) {
Serial.printf(" Podatki: %s\n", response.c_str());
}
}
}
// ==================== SETUP ====================
void setup() {
// ==================== 1. SERIAL INICIALIZACIJA ====================
Serial.begin(115200);
delay(1000);
Serial.println("\n\n╔════════════════════════════════════════════════════╗");
Serial.println("║ MODUL 4 - SENZORJI VITRINE (PRAVI SENZORJI) ║");
Serial.println("╚════════════════════════════════════════════════════╝\n");
// Izpiši MAC naslov
WiFi.mode(WIFI_STA);
delay(100);
Serial.print("📡 MAC naslov Modula 4: ");
Serial.println(WiFi.macAddress());
// ==================== 2. INICIALIZACIJA SENZORJEV ====================
initSensors();
// ==================== 3. TESTIRANJE SENZORJEV ====================
testDHT22();
testDS18B20();
testLDR();
testSoilMoisture();
testYS01();
// ==================== 4. NALOŽI KALIBRACIJSKE VREDNOSTI ====================
loadCalibration();
// ==================== 5. INICIALIZACIJA ESP-NOW ====================
initESPNow();
// ==================== 6. ZAČETNE MERITVE ====================
Serial.println("\n📊 Začetne meritve:");
delay(1000);
readAllSensors();
// ==================== 7. IZPIŠI STATUS ====================
Serial.println("\n📊 STATUS INICIALIZACIJE:");
Serial.printf(" DHT22: %s\n", dhtInitialized ? "✅ OK" : "❌ NEDOSEGLJIV");
Serial.printf(" DS18B20: %s\n", ds18b20Initialized ? "✅ OK" : "⚠️ OPCIONALEN");
Serial.printf(" YS01: %s\n", ys01Initialized ? "✅ OK" : "⚠️ OPCIONALEN");
Serial.printf(" LDR: ✅ OK\n");
Serial.printf(" Soil Moisture: ✅ OK\n");
// ==================== 8. ZAKLJUČEK SETUP ====================
Serial.println("\n✅ Modul 4 pripravljen!");
Serial.println("📡 Pošiljanje podatkov vsakih 10 sekund...\n");
lastSendTime = millis();
lastSensorRead = millis();
}
// ==================== LOOP ====================
void loop() {
unsigned long now = millis();
// Beri senzorje vsake 2 sekundi
if (now - lastSensorRead > SENSOR_READ_INTERVAL) {
readAllSensors();
lastSensorRead = now;
}
// Pošlji podatke vsakih 10 sekund
if (now - lastSendTime > SEND_INTERVAL) {
sendDataToMaster();
lastSendTime = now;
}
delay(100);
}Loading
esp32-s3-devkitc-1
esp32-s3-devkitc-1
GRETJE
HLAJENJE