// ==================== MODUL 1 - VREMENSKI MODUL ZUNANJI (POPRAVLJEN) ====================
#include <esp_now.h>
#include <esp_wifi.h> // DODANO! Potrebno za esp_wifi_set_promiscuous in esp_wifi_set_channel
#include <WiFi.h>
#include <Wire.h>
#include <Adafruit_AHTX0.h>
#include <Adafruit_BMP280.h>
#include <Preferences.h>
// ==================== PIN DEFINICIJE ====================
#define I2C_SDA 4
#define I2C_SCL 5
#define LDR_PIN 6
#define STATUS_LED 2
#define MODULE_ID 1
// ===== PRAVILEN MAC NASLOV GLAVNEGA SISTEMA (IZ LOGA GLAVNEGA ESP) =====
// MAC naslov glavnega ESPja iz loga: B4:3A:45:F3:EB:F0
uint8_t masterMAC[] = {0xB4, 0x3A, 0x45, 0xF3, 0xEB, 0xF0};
const unsigned long SEND_INTERVAL = 5000;
// ==================== STRUKTURE ====================
struct ModuleData {
uint8_t moduleId;
uint8_t moduleType;
unsigned long timestamp;
uint8_t errorCode;
float batteryVoltage;
float temperature;
float humidity;
float pressure;
float lux;
float bmpTemperature;
};
struct CommandData {
uint8_t targetModuleId;
uint8_t command;
float param1;
float param2;
};
// ==================== GLOBALNE SPREMENLJIVKE ====================
ModuleData sendData;
Adafruit_AHTX0 aht;
Adafruit_BMP280 bmp;
Preferences preferences;
int ldrMinADC = 500;
int ldrMaxADC = 3000;
// ==================== SETUP ====================
void setup() {
Serial.begin(115200);
delay(2000);
Serial.println("\n\n=========================================");
Serial.println("MODUL 1 - VREMENSKI MODUL (POPRAVLJEN)");
Serial.println("=========================================");
pinMode(STATUS_LED, OUTPUT);
digitalWrite(STATUS_LED, LOW);
// ===== 1. WIFI INICIALIZACIJA =====
Serial.println("\n--- Inicializacija WiFi ---");
WiFi.mode(WIFI_STA);
delay(100);
String mac = WiFi.macAddress();
Serial.printf("📡 Moj MAC naslov: %s\n", mac.c_str());
if (mac == "00:00:00:00:00:00" || mac == "FF:FF:FF:FF:FF:FF") {
Serial.println("⚠ Neveljaven MAC! Poskus ponovne inicializacije...");
WiFi.mode(WIFI_OFF);
delay(500);
WiFi.mode(WIFI_STA);
delay(500);
mac = WiFi.macAddress();
Serial.printf("📡 Nov MAC naslov: %s\n", mac.c_str());
}
// 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");
// ===== 2. ESP-NOW INICIALIZACIJA =====
Serial.println("\n--- Inicializacija ESP-NOW ---");
if (esp_now_init() != ESP_OK) {
Serial.println("❌ ESP-NOW napaka!");
while(1) {
digitalWrite(STATUS_LED, HIGH);
delay(500);
digitalWrite(STATUS_LED, LOW);
delay(500);
}
}
Serial.println("✅ ESP-NOW inicializiran");
// Registriraj callback za prejemanje ukazov
esp_now_register_recv_cb(onDataRecv);
// ===== 3. DODAJ MASTER PEER (z uporabo PRAVILNEGA MAC naslova) =====
Serial.println("\n--- Dodajanje master peer-ja ---");
// Izpiši MAC naslov na katerega bomo pošiljali
Serial.printf("📡 Pošiljam na MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
masterMAC[0], masterMAC[1], masterMAC[2],
masterMAC[3], masterMAC[4], masterMAC[5]);
esp_now_peer_info_t peerInfo;
memset(&peerInfo, 0, sizeof(peerInfo));
memcpy(peerInfo.peer_addr, masterMAC, 6);
peerInfo.channel = 1; // Kanal 1 (enako kot glavni sistem)
peerInfo.encrypt = false;
peerInfo.ifidx = WIFI_IF_STA;
if (esp_now_add_peer(&peerInfo) == ESP_OK) {
Serial.println("✅ Master peer dodan!");
} else {
Serial.println("❌ Napaka pri dodajanju peer-ja!");
Serial.println(" Preverite, ali je MAC naslov pravilen.");
}
// ===== 4. SENZORJI =====
Serial.println("\n--- Inicializacija senzorjev ---");
Wire.begin(I2C_SDA, I2C_SCL);
Wire.setClock(100000);
delay(100);
if (!aht.begin()) {
Serial.println("❌ AHT20 napaka!");
} else {
Serial.println("✅ AHT20 OK");
}
if (!bmp.begin(0x76) && !bmp.begin(0x77)) {
Serial.println("❌ BMP280 napaka!");
} else {
Serial.println("✅ BMP280 OK");
}
pinMode(LDR_PIN, INPUT);
// Naloži kalibracijo
preferences.begin("ldr-calib", true);
ldrMinADC = preferences.getInt("min_adc", 500);
ldrMaxADC = preferences.getInt("max_adc", 3000);
preferences.end();
// Pripravi podatke
sendData.moduleId = MODULE_ID;
sendData.moduleType = 1; // MODULE_WEATHER
sendData.batteryVoltage = 0;
sendData.errorCode = 0;
Serial.println("\n✅ Modul 1 pripravljen!");
Serial.printf("📡 Moj MAC: %s\n", WiFi.macAddress().c_str());
Serial.printf("📡 Pošiljam na MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
masterMAC[0], masterMAC[1], masterMAC[2],
masterMAC[3], masterMAC[4], masterMAC[5]);
Serial.println("📡 Kanal: 1");
Serial.println("📡 Pošiljanje podatkov vsakih 5 sekund...\n");
// Utripni LED za potrditev zagona
for(int i = 0; i < 3; i++) {
digitalWrite(STATUS_LED, HIGH);
delay(100);
digitalWrite(STATUS_LED, LOW);
delay(100);
}
}
// ==================== FUNKCIJA ZA POŠILJANJE PODATKOV ====================
void sendSensorData() {
sendData.timestamp = millis();
sendData.errorCode = 0;
// Preveri, ali so podatki veljavni
if (isnan(sendData.temperature) || sendData.temperature < -40 || sendData.temperature > 80) {
sendData.errorCode = 1; // ERR_SENSOR_AHT
sendData.temperature = 0;
}
if (isnan(sendData.humidity) || sendData.humidity < 0 || sendData.humidity > 100) {
sendData.errorCode = 1;
sendData.humidity = 0;
}
if (isnan(sendData.pressure) || sendData.pressure < 800 || sendData.pressure > 1100) {
sendData.errorCode = 2; // ERR_SENSOR_BMP
sendData.pressure = 1013.25;
}
Serial.printf("📡 Pošiljam: T=%.1f°C, H=%.1f%%, P=%.1fhPa, Lux=%.0f\n",
sendData.temperature, sendData.humidity, sendData.pressure, sendData.lux);
// Pošlji podatke na master MAC
esp_err_t result = esp_now_send(masterMAC, (uint8_t*)&sendData, sizeof(sendData));
if (result == ESP_OK) {
digitalWrite(STATUS_LED, HIGH);
delay(10);
digitalWrite(STATUS_LED, LOW);
Serial.println(" ✅ Poslano!");
} else {
Serial.printf(" ❌ Napaka pri pošiljanju: %d\n", result);
// Če peer ne obstaja, ga poskusimo ponovno dodati
if (result == ESP_ERR_ESPNOW_NOT_FOUND) {
Serial.println(" → Peer ne obstaja, poskusim ponovno dodati...");
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 ponovno dodan!");
} else {
Serial.println(" ❌ Napaka pri ponovnem dodajanju peer-ja!");
}
}
}
}
// ==================== FUNKCIJA ZA BRANJE SENZORJEV ====================
void readSensors() {
sensors_event_t humidity, temp;
if (aht.getEvent(&humidity, &temp)) {
sendData.temperature = temp.temperature;
sendData.humidity = humidity.relative_humidity;
}
sendData.pressure = bmp.readPressure() / 100.0F;
sendData.bmpTemperature = bmp.readTemperature();
// LDR - pretvori ADC v lux
int adcValue = analogRead(LDR_PIN);
if (ldrMaxADC > ldrMinADC) {
int percent = map(adcValue, ldrMinADC, ldrMaxADC, 100, 0);
percent = constrain(percent, 0, 100);
sendData.lux = map(percent, 0, 100, 0, 20000);
} else {
sendData.lux = 0;
}
}
// ==================== GLAVNA ZANKA ====================
void loop() {
static unsigned long lastSend = 0;
static unsigned long lastRead = 0;
unsigned long now = millis();
// Branje senzorjev vsake 2 sekundi
if (now - lastRead >= 2000) {
readSensors();
lastRead = now;
}
// Pošiljanje vsakih 5 sekund
if (now - lastSend >= SEND_INTERVAL) {
sendSensorData();
lastSend = now;
}
delay(10);
}
// ==================== CALLBACK ZA PREJEM UKAZOV ====================
void onDataRecv(const esp_now_recv_info_t *recv_info, const uint8_t *incomingData, int len) {
if (len == sizeof(CommandData)) {
CommandData cmd;
memcpy(&cmd, incomingData, sizeof(cmd));
if (cmd.targetModuleId == MODULE_ID) {
Serial.printf("📡 Prejet ukaz: cmd=%d, p1=%.1f, p2=%.1f\n",
cmd.command, cmd.param1, cmd.param2);
if (cmd.command == 10) { // CALIB_DARK
int darkADC = analogRead(LDR_PIN);
ModuleData response;
response.moduleId = MODULE_ID;
response.moduleType = 1;
response.errorCode = 100; // CALIB_DARK
response.lux = darkADC;
esp_now_send(recv_info->src_addr, (uint8_t*)&response, sizeof(response));
Serial.printf(" 🌑 Temna vrednost: %d\n", darkADC);
}
else if (cmd.command == 11) { // CALIB_BRIGHT
int brightADC = analogRead(LDR_PIN);
ModuleData response;
response.moduleId = MODULE_ID;
response.moduleType = 1;
response.errorCode = 101; // CALIB_BRIGHT
response.lux = brightADC;
esp_now_send(recv_info->src_addr, (uint8_t*)&response, sizeof(response));
Serial.printf(" ☀️ Svetla vrednost: %d\n", brightADC);
}
else if (cmd.command == 12) { // CALIB_CONFIRM
ldrMinADC = (int)cmd.param1;
ldrMaxADC = (int)cmd.param2;
preferences.begin("ldr-calib", false);
preferences.putInt("min_adc", ldrMinADC);
preferences.putInt("max_adc", ldrMaxADC);
preferences.end();
Serial.printf(" 💾 Kalibracija shranjena: min=%d, max=%d\n", ldrMinADC, ldrMaxADC);
}
else if (cmd.command == 20) { // CMD_SET_MASTER_MAC
// Ukaz za nastavitev MAC naslova masterja
memcpy(masterMAC, recv_info->src_addr, 6);
Serial.printf(" 🎯 Master MAC nastavljen na: %02X:%02X:%02X:%02X:%02X:%02X\n",
masterMAC[0], masterMAC[1], masterMAC[2],
masterMAC[3], masterMAC[4], masterMAC[5]);
// Ponovno dodaj peer z novim MAC naslovom
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;
esp_now_add_peer(&peerInfo);
}
}
}
// Izpiši MAC naslov pošiljatelja za debug
Serial.printf("📡 Prejeto od: %02X:%02X:%02X:%02X:%02X:%02X (len=%d)\n",
recv_info->src_addr[0], recv_info->src_addr[1],
recv_info->src_addr[2], recv_info->src_addr[3],
recv_info->src_addr[4], recv_info->src_addr[5], len);
}
Senzor Pin na modulu Povezava
AHT20 VIN 3.3V 3.3V
AHT20 GND GND GND
AHT20 SDA GPIO4 SDA
AHT20 SCL GPIO5 SCL
BMP280 VIN 3.3V 3.3V
BMP280 GND GND GND
BMP280 SDA GPIO4 SDA
BMP280 SCL GPIO5 SCL
LDR en konec 3.3V 3.3V
LDR drug konec GPIO6 A0
10k upor GPIO6 -> GND Pull-down