// ==================== MODUL 2 - NAMAKALNI SEMIST ====================
#include <esp_now.h>
#include <WiFi.h>
// ==================== PIN DEFINICIJE ====================
#define FLOW_SENSOR_1_PIN 18
#define FLOW_SENSOR_2_PIN 19
#define FLOW_SENSOR_3_PIN 21
// Releji - uporabite MOSFET module, ne direktnih relejev!
#define RELAY_1_PIN 4
#define RELAY_2_PIN 5
#define RELAY_3_PIN 6
#define STATUS_LED 2
// ==================== KONFIGURACIJA ====================
#define MODULE_ID 2
#define MODULE_TYPE 2
uint8_t masterMAC[] = {0xB4, 0x3A, 0x45, 0xF3, 0xEB, 0xF0};
const unsigned long SEND_INTERVAL = 10000; // 10 sekund
#define PULSES_PER_LITER 450
#define FLOW_UPDATE_INTERVAL 2000
// ==================== STRUKTURE ====================
enum ModuleType { MODULE_WEATHER = 1, MODULE_IRRIGATION = 2, MODULE_SHADE_MOTOR = 3 };
enum ErrorCode { ERR_NONE = 0, ERR_SENSOR_FLOW_1 = 10, ERR_SENSOR_FLOW_2 = 11, ERR_SENSOR_FLOW_3 = 12 };
struct ModuleData {
uint8_t moduleId;
ModuleType moduleType;
unsigned long timestamp;
ErrorCode errorCode;
float batteryVoltage;
struct {
float flowRate1, flowRate2, flowRate3;
float totalFlow1, totalFlow2, totalFlow3;
bool relay1State, relay2State, relay3State;
} irrigation;
};
struct CommandData {
uint8_t targetModuleId;
uint8_t command;
float param1;
float param2;
};
// ==================== GLOBALNE SPREMENLJIVKE ====================
ModuleData sendData;
CommandData receivedCommand;
unsigned long lastSendTime = 0;
unsigned long lastFlowUpdate = 0;
unsigned long oldTime = 0;
volatile unsigned long pulseCount1 = 0, pulseCount2 = 0, pulseCount3 = 0;
float flowRate1 = 0, flowRate2 = 0, flowRate3 = 0;
float totalFlow1 = 0, totalFlow2 = 0, totalFlow3 = 0;
bool relay1State = false, relay2State = false, relay3State = false;
// ==================== ESP-NOW CALLBACKI ====================
void onDataSent(const esp_now_send_info_t *send_info, esp_now_send_status_t status) {
digitalWrite(STATUS_LED, HIGH);
delay(5);
digitalWrite(STATUS_LED, LOW);
}
void onDataRecv(const esp_now_recv_info_t *recv_info, const uint8_t *incomingData, int len) {
if (len == sizeof(CommandData)) {
memcpy(&receivedCommand, incomingData, sizeof(receivedCommand));
if (receivedCommand.targetModuleId == MODULE_ID) {
switch(receivedCommand.command) {
case 1: // SET_RELAY
setRelay((int)receivedCommand.param1, (bool)receivedCommand.param2);
break;
case 2: // RESET_FLOW_TOTALS
resetFlowTotals();
break;
}
}
}
}
// ==================== INTERRUPT HANDLERJI ====================
void IRAM_ATTR pulseCounter1() { pulseCount1++; }
void IRAM_ATTR pulseCounter2() { pulseCount2++; }
void IRAM_ATTR pulseCounter3() { pulseCount3++; }
// ==================== FUNKCIJE ZA ZMANJŠANO PORABO ====================
void goToSleep() {
sendData.timestamp = millis();
esp_now_send(masterMAC, (uint8_t *)&sendData, sizeof(sendData));
delay(50);
esp_sleep_enable_timer_wakeup(5 * 1000000);
esp_light_sleep_start();
}
// ==================== FUNKCIJE ZA FLOW SENZORJE ====================
void initializeFlowSensors() {
Serial.println("Inicializacija flow senzorjev...");
pinMode(FLOW_SENSOR_1_PIN, INPUT_PULLUP);
pinMode(FLOW_SENSOR_2_PIN, INPUT_PULLUP);
pinMode(FLOW_SENSOR_3_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(FLOW_SENSOR_1_PIN), pulseCounter1, FALLING);
attachInterrupt(digitalPinToInterrupt(FLOW_SENSOR_2_PIN), pulseCounter2, FALLING);
attachInterrupt(digitalPinToInterrupt(FLOW_SENSOR_3_PIN), pulseCounter3, FALLING);
oldTime = millis();
lastFlowUpdate = millis();
}
void updateFlowSensors() {
unsigned long now = millis();
if (now - lastFlowUpdate < FLOW_UPDATE_INTERVAL) return;
float timeInSeconds = (now - oldTime) / 1000.0;
if (timeInSeconds > 0) {
flowRate1 = (pulseCount1 / (float)PULSES_PER_LITER) / (timeInSeconds / 60.0);
flowRate2 = (pulseCount2 / (float)PULSES_PER_LITER) / (timeInSeconds / 60.0);
flowRate3 = (pulseCount3 / (float)PULSES_PER_LITER) / (timeInSeconds / 60.0);
totalFlow1 += (pulseCount1 / (float)PULSES_PER_LITER);
totalFlow2 += (pulseCount2 / (float)PULSES_PER_LITER);
totalFlow3 += (pulseCount3 / (float)PULSES_PER_LITER);
pulseCount1 = pulseCount2 = pulseCount3 = 0;
oldTime = now;
}
lastFlowUpdate = now;
}
void resetFlowTotals() {
totalFlow1 = totalFlow2 = totalFlow3 = 0;
pulseCount1 = pulseCount2 = pulseCount3 = 0;
}
// ==================== FUNKCIJE ZA RELEJE ====================
void initializeRelays() {
Serial.println("Inicializacija relejev...");
pinMode(RELAY_1_PIN, OUTPUT);
pinMode(RELAY_2_PIN, OUTPUT);
pinMode(RELAY_3_PIN, OUTPUT);
digitalWrite(RELAY_1_PIN, LOW);
digitalWrite(RELAY_2_PIN, LOW);
digitalWrite(RELAY_3_PIN, LOW);
relay1State = relay2State = relay3State = false;
}
void setRelay(int relayNum, bool state) {
int pin;
bool* relayState;
switch(relayNum) {
case 1: pin = RELAY_1_PIN; relayState = &relay1State; break;
case 2: pin = RELAY_2_PIN; relayState = &relay2State; break;
case 3: pin = RELAY_3_PIN; relayState = &relay3State; break;
default: return;
}
digitalWrite(pin, state ? HIGH : LOW);
*relayState = state;
digitalWrite(STATUS_LED, HIGH);
delay(20);
digitalWrite(STATUS_LED, LOW);
}
// ==================== SETUP ====================
void setup() {
pinMode(STATUS_LED, OUTPUT);
digitalWrite(STATUS_LED, HIGH);
delay(100);
Serial.begin(115200);
delay(500);
Serial.println("\n\n=========================================");
Serial.println("MODUL 2 - NAMAKALNI SISTEM (KANAL 1)");
Serial.println("=========================================");
// ========== ZMANJŠAJ CPU FREKVENCO ==========
setCpuFrequencyMhz(80);
Serial.println("CPU frekvenca: 80MHz");
// ========== INICIALIZACIJA WIFI - KANAL 1 ==========
Serial.println("\n--- WiFi inicializacija ---");
WiFi.mode(WIFI_STA);
WiFi.setTxPower(WIFI_POWER_5dBm);
WiFi.setChannel(1); // KANAL 1 (isti kot glavni sistem)
WiFi.disconnect();
delay(100);
Serial.print("MAC naslov: ");
Serial.println(WiFi.macAddress());
Serial.print("Nastavljen kanal: ");
Serial.println(WiFi.channel());
// ========== INICIALIZACIJA ESP-NOW ==========
Serial.println("\n--- ESP-NOW inicializacija ---");
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");
esp_now_register_send_cb(esp_now_send_cb_t(onDataSent));
esp_now_register_recv_cb(esp_now_recv_cb_t(onDataRecv));
// Dodaj peer - KANAL 1
Serial.print("Dodajanje master peerja... ");
esp_now_peer_info_t peerInfo;
memset(&peerInfo, 0, sizeof(peerInfo));
memcpy(peerInfo.peer_addr, masterMAC, 6);
peerInfo.channel = 1; // KANAL 1
peerInfo.encrypt = false;
peerInfo.ifidx = WIFI_IF_STA;
esp_err_t addResult = esp_now_add_peer(&peerInfo);
if (addResult == ESP_OK) {
Serial.println("OK");
} else if (addResult == ESP_ERR_ESPNOW_EXIST) {
Serial.println("že obstaja");
} else {
Serial.printf("NAPAKA (koda: %d)\n", addResult);
}
// ========== INICIALIZACIJA STROJNE OPREME ==========
initializeRelays();
initializeFlowSensors();
// ========== KONFIGURACIJA PODATKOV ==========
sendData.moduleId = MODULE_ID;
sendData.moduleType = MODULE_IRRIGATION;
sendData.errorCode = ERR_NONE;
sendData.batteryVoltage = 0;
Serial.println("\n=== MODUL 2 PRIPRAVLJEN ===");
Serial.println("Kanal: 1 (isti kot glavni sistem)");
Serial.println("=========================================\n");
// Utripni LED za uspešen zagon
digitalWrite(STATUS_LED, LOW);
delay(500);
for(int i = 0; i < 3; i++) {
digitalWrite(STATUS_LED, HIGH);
delay(100);
digitalWrite(STATUS_LED, LOW);
delay(100);
}
}
// ==================== LOOP ====================
void loop() {
unsigned long now = millis();
// ========== 1. PREVERI IN POPRAVI KANAL NA 1 ==========
static unsigned long lastChannelCheck = 0;
if (now - lastChannelCheck > 10000) { // Vsakih 10 sekund
int currentChannel = WiFi.channel();
if (currentChannel != 1) {
Serial.printf("⚠ Kanal je %d, nastavljam na 1...\n", currentChannel);
WiFi.setChannel(1);
delay(50);
if (WiFi.channel() == 1) {
Serial.println("✓ Kanal uspešno nastavljen na 1");
} else {
Serial.printf("✗ Napaka pri nastavljanju kanala (trenutno: %d)\n", WiFi.channel());
}
}
lastChannelCheck = now;
}
// ========== 2. PREVERI ALI PEER OBSTAJA ==========
static unsigned long lastPeerCheck = 0;
if (now - lastPeerCheck > 30000) { // Vsakih 30 sekund
if (!esp_now_is_peer_exist(masterMAC)) {
Serial.println("⚠ Peer ne obstaja - ponovno dodajanje...");
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");
}
}
lastPeerCheck = now;
}
// ========== 3. POSODABLJANJE FLOW SENZORJEV ==========
updateFlowSensors();
// ========== 4. POSODABLJANJE PODATKOV ZA POŠILJANJE ==========
sendData.irrigation.flowRate1 = flowRate1;
sendData.irrigation.flowRate2 = flowRate2;
sendData.irrigation.flowRate3 = flowRate3;
sendData.irrigation.totalFlow1 = totalFlow1;
sendData.irrigation.totalFlow2 = totalFlow2;
sendData.irrigation.totalFlow3 = totalFlow3;
sendData.irrigation.relay1State = relay1State;
sendData.irrigation.relay2State = relay2State;
sendData.irrigation.relay3State = relay3State;
// ========== 5. POŠILJANJE PODATKOV ==========
if (now - lastSendTime >= SEND_INTERVAL) {
sendData.timestamp = now;
Serial.println("\n--- Pošiljanje podatkov ---");
Serial.printf("Flow 1: %.2f L/min (skupaj: %.1f L)\n", flowRate1, totalFlow1);
Serial.printf("Flow 2: %.2f L/min (skupaj: %.1f L)\n", flowRate2, totalFlow2);
Serial.printf("Flow 3: %.2f L/min (skupaj: %.1f L)\n", flowRate3, totalFlow3);
Serial.printf("Releji: R1=%s, R2=%s, R3=%s\n",
relay1State ? "ON" : "OFF",
relay2State ? "ON" : "OFF",
relay3State ? "ON" : "OFF");
Serial.printf("Kanal: %d\n", WiFi.channel());
if (esp_now_is_peer_exist(masterMAC)) {
esp_err_t result = esp_now_send(masterMAC, (uint8_t *)&sendData, sizeof(sendData));
if (result == ESP_OK) {
Serial.println("✓ USPEŠNO poslano");
digitalWrite(STATUS_LED, HIGH);
delay(10);
digitalWrite(STATUS_LED, LOW);
} else {
Serial.printf("✗ NAPAKA pri pošiljanju (koda: %d)\n", result);
for(int i = 0; i < 3; i++) {
digitalWrite(STATUS_LED, HIGH);
delay(50);
digitalWrite(STATUS_LED, LOW);
delay(50);
}
}
} else {
Serial.println("✗ Peer ne obstaja!");
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 dodan, poskušam znova...");
esp_err_t retry = esp_now_send(masterMAC, (uint8_t *)&sendData, sizeof(sendData));
if (retry == ESP_OK) {
Serial.println(" ✓ Poslano po ponovnem dodajanju");
digitalWrite(STATUS_LED, HIGH);
delay(50);
digitalWrite(STATUS_LED, LOW);
}
}
}
lastSendTime = now;
}
delay(50);
}
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