From 66a02f4584fd375c062f9da5652fcef534e3897b Mon Sep 17 00:00:00 2001 From: rahimi rahimi Date: Fri, 19 Dec 2025 11:50:13 +0330 Subject: [PATCH] old codes --- old/STM32-03/STM32-03.ino | 519 ++++++++++++++++++ old/Stm32Test1/Stm32Test1.ino | 210 ++++++++ old/newWifi/newWifi.ino | 156 ++++++ old/nodemcu3.ino | 759 ++++++++++++++++++++++++++ old/nodemcu3/nodemcu3.ino | 759 ++++++++++++++++++++++++++ old/nodmcu1/nodmcu1.ino | 716 ++++++++++++++++++++++++ old/nodmcu2/nodmcu2.ino | 928 ++++++++++++++++++++++++++++++++ old/reciver01/reciver01.ino | 196 +++++++ old/sender01/sender01.ino | 165 ++++++ old/sender02/sender02.ino | 132 +++++ old/stm32f103_2/stm32f103_2.ino | 307 +++++++++++ old/test1/test1.ino | 123 +++++ old/test2/test2.ino | 148 +++++ old/teststm03/teststm03.ino | 116 ++++ old/wifi1/wifi1.ino | 212 ++++++++ 15 files changed, 5446 insertions(+) create mode 100644 old/STM32-03/STM32-03.ino create mode 100644 old/Stm32Test1/Stm32Test1.ino create mode 100644 old/newWifi/newWifi.ino create mode 100644 old/nodemcu3.ino create mode 100644 old/nodemcu3/nodemcu3.ino create mode 100644 old/nodmcu1/nodmcu1.ino create mode 100644 old/nodmcu2/nodmcu2.ino create mode 100644 old/reciver01/reciver01.ino create mode 100644 old/sender01/sender01.ino create mode 100644 old/sender02/sender02.ino create mode 100644 old/stm32f103_2/stm32f103_2.ino create mode 100644 old/test1/test1.ino create mode 100644 old/test2/test2.ino create mode 100644 old/teststm03/teststm03.ino create mode 100644 old/wifi1/wifi1.ino diff --git a/old/STM32-03/STM32-03.ino b/old/STM32-03/STM32-03.ino new file mode 100644 index 0000000..04bed3a --- /dev/null +++ b/old/STM32-03/STM32-03.ino @@ -0,0 +1,519 @@ +#include +#include +#include +#include +#include +#include +#include + +// -------------------- پیکربندی حافظه SPI Flash -------------------- +#define FLASH_CS PA4 +#define FLASH_MOSI PA7 +#define FLASH_MISO PA6 +#define FLASH_SCK PA5 + +// کتابخانه جایگزین برای حافظه SPI +#include + +// -------------------- پیکربندی OLED -------------------- +#define SCREEN_WIDTH 128 +#define SCREEN_HEIGHT 64 +#define OLED_RESET -1 +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); + +// -------------------- پیکربندی سنسورها -------------------- +#define SOIL_PIN PA1 +#define MQ7_PIN PA2 +#define SDA_PIN PB9 +#define SCL_PIN PB8 + +BH1750 lightMeter; +Adafruit_SHT31 sht31 = Adafruit_SHT31(); + +// -------------------- پیکربندی EC200U -------------------- +#define PWRKEY_PIN PB5 +HardwareSerial EC200U(USART3); + +// -------------------- پارامترهای قابل تنظیم -------------------- +#define SENSOR_READ_INTERVAL 60000 // خواندن سنسورها هر 1 دقیقه + +// -------------------- ساختار تنظیمات -------------------- +struct DeviceConfig { + char signature[4]; + char apn[32]; + char serverUrl[64]; + char deviceName[16]; + char smsNumber[16]; + unsigned long webInterval; // دقیقه + unsigned long smsInterval; // دقیقه + unsigned long saveInterval; // ثانیه - فاصله ذخیره در قطعی + bool smsEnabled; + bool valid; +}; + +// -------------------- ساختار داده سنسورها -------------------- +struct SensorData { + float temperature; + float humidity; + int soilMoisture; + float coPPM; + float lightLux; + unsigned long timestamp; +}; + +// -------------------- متغیرهای سراسری -------------------- +DeviceConfig config; +SensorData currentData; +SensorData storedData; + +unsigned long lastSensorRead = 0; +unsigned long lastUpload = 0; +unsigned long lastSMS = 0; +unsigned long lastSave = 0; +bool networkConnected = false; +bool dataStored = false; +int displayMode = 0; +unsigned long lastDisplayChange = 0; + +// -------------------- توابع حافظه SPI Flash -------------------- +void initFlash() { + SPI.setMOSI(FLASH_MOSI); + SPI.setMISO(FLASH_MISO); + SPI.setSCLK(FLASH_SCK); + SPI.begin(); + + pinMode(FLASH_CS, OUTPUT); + digitalWrite(FLASH_CS, HIGH); + + delay(100); + + // مقداردهی اولیه SerialFlash + if (!SerialFlash.begin(FLASH_CS)) { + Serial1.println("❌ Flash init failed!"); + return; + } + + Serial1.println("✅ Flash OK"); + + // نمایش اطلاعات حافظه + SerialFlash::ID id; + SerialFlash.readID(&id); + Serial1.print("Flash ID: "); + Serial1.print(id.id, HEX); + Serial1.print(" Size: "); + Serial1.print(SerialFlash.capacity(id) / 1024); + Serial1.println("KB"); +} + +void readConfig() { + // ابتدا از EEPROM داخلی بخوان + EEPROM.get(0, config); + + // اگر تنظیمات معتبر نیست، از حافظه SPI بخوان + if (strcmp(config.signature, "CFG") != 0) { + if (SerialFlash.exists("config.bin")) { + SerialFlashFile file = SerialFlash.open("config.bin"); + if (file) { + file.read(&config, sizeof(DeviceConfig)); + file.close(); + Serial1.println("✅ Config read from SPI Flash"); + } + } + } + + // اگر هنوز تنظیمات معتبر نیست، مقادیر پیش‌فرض + if (strcmp(config.signature, "CFG") != 0) { + strcpy(config.signature, "CFG"); + strcpy(config.apn, "mcinet"); + strcpy(config.serverUrl, "https://ghback.nabaksoft.ir/api/Telemetry/AddData"); + strcpy(config.smsNumber, "+989120000000"); + strcpy(config.deviceName, "ST-"); + config.webInterval = 1; + config.smsInterval = 5; + config.saveInterval = 60; // پیش‌فرض 60 ثانیه + config.smsEnabled = false; + config.valid = false; + } +} + +void saveConfig() { + config.valid = true; + + // در EEPROM داخلی ذخیره کن + EEPROM.put(0, config); + EEPROM.commit(); + + // در حافظه SPI هم ذخیره کن + if (SerialFlash.exists("config.bin")) { + SerialFlash.remove("config.bin"); + } + + SerialFlashFile file = SerialFlash.create("config.bin", sizeof(DeviceConfig)); + if (file) { + file.write((byte*)&config, sizeof(DeviceConfig)); + file.close(); + Serial1.println("✅ Config saved to SPI Flash"); + } +} + +void saveDataToFlash() { + if (!dataStored) { + if (SerialFlash.exists("data.bin")) { + SerialFlash.remove("data.bin"); + } + dataStored = true; + } + + currentData.timestamp = millis(); + + SerialFlashFile file = SerialFlash.open("data.bin"); + if (!file) { + file = SerialFlash.create("data.bin", sizeof(SensorData)); + } + + if (file) { + file.seek(0); + file.write((byte*)¤tData, sizeof(SensorData)); + file.close(); + Serial1.println("💾 Data saved to flash"); + } +} + +void readDataFromFlash() { + if (SerialFlash.exists("data.bin")) { + SerialFlashFile file = SerialFlash.open("data.bin"); + if (file) { + file.read(&storedData, sizeof(SensorData)); + file.close(); + + // بررسی اعتبار داده + if (storedData.timestamp > 0) { + Serial1.println("📖 Stored data found"); + } + } + } +} + +void clearStoredData() { + if (SerialFlash.exists("data.bin")) { + SerialFlash.remove("data.bin"); + storedData.timestamp = 0; + dataStored = false; + } +} + +// -------------------- توابع EC200U -------------------- +bool sendAT(String cmd, uint16_t wait = 2000) { + Serial1.print(">> "); + Serial1.println(cmd); + EC200U.println(cmd); + + String response = ""; + unsigned long start = millis(); + + while (millis() - start < wait) { + while (EC200U.available()) { + char c = EC200U.read(); + response += c; + Serial1.write(c); + } + if (response.indexOf("OK") != -1) return true; + if (response.indexOf("ERROR") != -1) return false; + } + return false; +} + +bool waitForResponse(String expected, unsigned long timeout = 10000) { + unsigned long startTime = millis(); + String response = ""; + + while (millis() - startTime < timeout) { + while (EC200U.available()) { + char c = EC200U.read(); + response += c; + Serial1.write(c); + if (response.indexOf(expected) != -1) return true; + if (response.indexOf("ERROR") != -1) return false; + } + } + return false; +} + +bool sendSMS(String number, String message) { + if (!sendAT("AT+CMGF=1", 2000)) return false; + + String cmd = "AT+CMGS=\"" + number + "\""; + if (!sendAT(cmd, 2000)) return false; + + delay(100); + EC200U.print(message); + EC200U.write(26); + return waitForResponse("+CMGS:", 10000); +} + +void initEC200U() { + Serial1.println("🚀 Starting EC200U..."); + + digitalWrite(PWRKEY_PIN, HIGH); + delay(2000); + digitalWrite(PWRKEY_PIN, LOW); + delay(5000); + + if (!sendAT("AT", 3000)) { + Serial1.println("❌ EC200U not responding!"); + return; + } + + String apnCmd = "AT+CGDCONT=1,\"IP\",\"" + String(config.apn) + "\""; + sendAT(apnCmd, 2000); + + if (sendAT("AT+QIACT=1", 15000)) { + networkConnected = true; + Serial1.println("✅ Network connected"); + + // اگر داده ذخیره شده وجود دارد، ارسال کن + if (storedData.timestamp > 0) { + Serial1.println("📤 Sending stored data..."); + sendStoredData(); + } + } else { + networkConnected = false; + Serial1.println("❌ Network failed"); + } +} + +// -------------------- توابع سنسورها -------------------- +void readSensors() { + currentData.temperature = sht31.readTemperature(); + currentData.humidity = sht31.readHumidity(); + currentData.soilMoisture = readSoil(); + currentData.coPPM = MQ7_ReadPPM(); + currentData.lightLux = lightMeter.readLightLevel(); + + if (isnan(currentData.temperature)) currentData.temperature = -999; + if (isnan(currentData.humidity)) currentData.humidity = -999; + if (isnan(currentData.lightLux)) currentData.lightLux = 0; + + lastSensorRead = millis(); +} + +int readSoil() { + int adcValue = analogRead(SOIL_PIN); + const int adcDry = 4095; + const int adcWet = 1200; + + float soilPercent = (float)(adcDry - adcValue) / (adcDry - adcWet) * 100.0; + if (soilPercent > 100.0) soilPercent = 100.0; + if (soilPercent < 0.0) soilPercent = 0.0; + + return (int)soilPercent; +} + +float MQ7_ReadPPM() { + long sum = 0; + for (int i = 0; i < 10; i++) { + sum += analogRead(MQ7_PIN); + delay(5); + } + float adcValue = sum / 10.0; + float voltage = (adcValue / 4095.0) * 3.3; + + float ppm; + if (voltage < 0.1) ppm = 0; + else if (voltage < 0.2) ppm = 10 * (voltage / 0.2); + else if (voltage < 0.5) ppm = 50 + (voltage - 0.2) * 300; + else if (voltage < 1.0) ppm = 140 + (voltage - 0.5) * 800; + else if (voltage < 2.0) ppm = 500 + (voltage - 1.0) * 1500; + else ppm = 2000 + (voltage - 2.0) * 2000; + + if (ppm < 0) ppm = 0; + if (ppm > 10000) ppm = 10000; + + return ppm; +} + +// -------------------- توابع ارسال داده -------------------- +bool sendData(SensorData data) { + if (data.temperature == -999 || data.humidity == -999) return false; + + String dataStr = "temperatureC=" + String(data.temperature, 1) + + "&humidityPercent=" + String(data.humidity, 1) + + "&soilPercent=" + String(data.soilMoisture) + + "&gasPPM=" + String(data.coPPM, 0) + + "&lux=" + String(data.lightLux, 1); + + String url = String(config.serverUrl) + "?deviceName=" + String(config.deviceName) + "&" + dataStr; + + String httpCmd = "AT+QHTTPURL=" + String(url.length()) + ",80"; + if (!sendAT(httpCmd, 5000)) return false; + + delay(100); + EC200U.print(url); + + if (!waitForResponse("OK", 5000)) return false; + + return sendAT("AT+QHTTPGET=60", 15000); +} + +void sendStoredData() { + if (sendData(storedData)) { + Serial1.println("✅ Stored data sent successfully"); + clearStoredData(); + } +} + +// -------------------- توابع نمایش OLED -------------------- +void updateDisplay() { + if (millis() - lastDisplayChange > 5000) { + displayMode = (displayMode + 1) % 3; + lastDisplayChange = millis(); + } + + display.clearDisplay(); + display.setTextSize(1); + + switch(displayMode) { + case 0: + display.setTextSize(2); + display.setCursor(20, 10); + display.println("DEVICE"); + display.setCursor(30, 35); + display.println(config.deviceName); + break; + + case 1: + display.setCursor(0, 0); + display.print("T:"); + display.print(currentData.temperature, 1); + display.print("C "); + display.print("H:"); + display.print(currentData.humidity, 1); + display.println("%"); + + display.setCursor(0, 16); + display.print("S:"); + display.print(currentData.soilMoisture); + display.print("% "); + display.print("C:"); + display.print(currentData.coPPM, 0); + display.println("P"); + + display.setCursor(0, 32); + display.print("L:"); + display.print(currentData.lightLux, 0); + display.println("Lx"); + + display.setCursor(0, 48); + display.print(networkConnected ? "ONLINE" : "OFFLINE"); + if (dataStored) display.print(" *"); + break; + + case 2: + display.setTextSize(3); + display.setCursor(10, 25); + display.print(currentData.temperature, 1); + display.setTextSize(2); + display.setCursor(100, 30); + display.print("C"); + break; + } + display.display(); +} + +// -------------------- setup -------------------- +void setup() { + Serial1.begin(115200); + delay(1000); + + Serial1.println("\n\n🚀 System Starting..."); + + pinMode(PWRKEY_PIN, OUTPUT); + pinMode(SOIL_PIN, INPUT); + pinMode(MQ7_PIN, INPUT); + digitalWrite(PWRKEY_PIN, LOW); + + Wire.setSDA(SDA_PIN); + Wire.setSCL(SCL_PIN); + Wire.begin(); + + if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { + Serial1.println("❌ OLED failed!"); + } + + sht31.begin(0x44); + lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE); + + // مقداردهی حافظه + initFlash(); + readConfig(); + readDataFromFlash(); + + // اگر نام دستگاه تنظیم نشده، از UID استفاده کن + if (strlen(config.deviceName) < 3) { + uint32_t uid0 = *(uint32_t*)0x1FFFF7E8; + uint32_t uid1 = *(uint32_t*)0x1FFFF7EC; + uint32_t uid2 = *(uint32_t*)0x1FFFF7F0; + + sprintf(config.deviceName, "ST-%08X", (unsigned int)(uid0 ^ uid1 ^ uid2)); + saveConfig(); + } + + EC200U.begin(115200); + if (config.valid) { + initEC200U(); + } + + Serial1.println("✅ System Ready"); +} + +// -------------------- loop -------------------- +void loop() { + // خواندن سنسورها در بازه زمانی مشخص + if (millis() - lastSensorRead > SENSOR_READ_INTERVAL) { + readSensors(); + Serial1.println("📊 Sensors read"); + + // اگر شبکه وصل است، داده را ارسال کن + if (networkConnected) { + if (millis() - lastUpload > config.webInterval * 60000) { + if (sendData(currentData)) { + Serial1.println("✅ Web data sent"); + lastUpload = millis(); + } + } + } + // اگر شبکه قطع است، داده را ذخیره کن + else { + if (config.saveInterval > 0) { + if (millis() - lastSave > config.saveInterval * 1000) { + saveDataToFlash(); + lastSave = millis(); + } + } + + // ارسال SMS در صورت فعال بودن + if (config.smsEnabled && millis() - lastSMS > config.smsInterval * 60000) { + String smsMsg = String(config.deviceName) + + " T:" + String(currentData.temperature, 1) + + " H:" + String(currentData.humidity, 1) + + " S:" + String(currentData.soilMoisture) + "%"; + + if (sendSMS(config.smsNumber, smsMsg)) { + Serial1.println("✅ SMS sent"); + lastSMS = millis(); + } + } + } + } + + updateDisplay(); + + // تلاش برای اتصال مجدد شبکه + static unsigned long lastReconnect = 0; + if (!networkConnected && millis() - lastReconnect > 60000) { + initEC200U(); + lastReconnect = millis(); + } + + delay(1000); +} \ No newline at end of file diff --git a/old/Stm32Test1/Stm32Test1.ino b/old/Stm32Test1/Stm32Test1.ino new file mode 100644 index 0000000..98044f1 --- /dev/null +++ b/old/Stm32Test1/Stm32Test1.ino @@ -0,0 +1,210 @@ +#include +#include +#include +#include "DHT.h" + +// --------------------------- تنظیمات --------------------------- +#define DHTPIN A0 +#define DHTTYPE DHT22 +DHT dht(DHTPIN, DHTTYPE); + +#define SOIL_PIN A1 + +#define MQ7_PIN A2 +#define VREF 5.0 // ولتاژ مرجع ADC +#define ADC_MAX 4095.0 // برای STM32 (۱۲ بیتی) + +#define SDA_PIN PB9 +#define SCL_PIN PB8 +BH1750 lightMeter; + +// UART EC200U +HardwareSerial EC200U(1); +#define PWRKEY_PIN PB5 + +// ارسال هر n دقیقه +#define UPLOAD_INTERVAL_MIN 1 + +// ذخیره ساعت شبکه +String networkTime = ""; + +// --------------------------- توابع --------------------------- + +// روشن کردن ماژول EC200U +void powerEC200U() { + pinMode(PWRKEY_PIN, OUTPUT); + digitalWrite(PWRKEY_PIN, HIGH); + delay(1000); // نگه داشتن HIGH حدود 1 ثانیه برای روشن کردن + digitalWrite(PWRKEY_PIN, LOW); + delay(2000); // کمی صبر قبل از AT +} + +// ارسال دستور AT و نمایش پاسخ +void sendAT(String cmd, uint16_t wait = 1000) { + Serial.print(">> "); Serial.println(cmd); + EC200U.println(cmd); + unsigned long start = millis(); + while (millis() - start < wait) { + while (EC200U.available()) Serial.write(EC200U.read()); + } + Serial.println(); +} + +// آماده‌سازی ماژول و اینترنت +void initEC200U() { + Serial.println("🚀 Initializing EC200U..."); + sendAT("AT",1000); + sendAT("ATI",1000); + sendAT("AT+CPIN?",1000); + sendAT("AT+CSQ",1000); + sendAT("AT+CREG?",1000); + sendAT("AT+CGATT=1",2000); + sendAT("AT+CGDCONT=1,\"IP\",\"mcinet\"",1000); + sendAT("AT+QIACT=1",5000); + sendAT("AT+QIACT?",2000); + Serial.println("✅ EC200U Ready"); +} + +// خواندن ساعت شبکه +void getNetworkTime() { + sendAT("AT+QLTS=2", 3000); + networkTime = ""; + unsigned long t = millis(); + while (millis()-t < 3000) { + while(EC200U.available()) { + char c = EC200U.read(); + Serial.write(c); + networkTime += c; + } + } +} + +// خواندن سنسورها +float readDHT22() { return dht.readTemperature(); } +float readHumidity() { return dht.readHumidity(); } + +// رطوبت خاک به درصد +int readSoilPercent() { + int val = analogRead(SOIL_PIN); // 0-4095 + int perc = map(val, 3000, 1500, 0, 100); // خشک: 3000, خیس:1500 (تنظیم شود) + if(perc>100) perc=100; + if(perc<0) perc=0; + return perc; +} + +float readMQ7ppm() { + // --- 1. میانگین‌گیری چند قرائت برای پایداری --- + long sum = 0; + for (int i = 0; i < 10; i++) { + sum += analogRead(MQ7_PIN); + delay(5); + } + float adcValue = sum / 10.0; + + // --- 2. محاسبه ولتاژ خروجی --- + float voltage = (adcValue / ADC_MAX) * VREF; + + // --- 3. تبدیل تقریبی به ppm --- + // منحنی تجربی بر اساس تست ماژول‌های MQ7 آماده (ولتاژ به ppm CO) + // این ضرایب با ولتاژ 0.1V ~ 1V برای ppm=50~5000 کالیبره شده‌اند. + // اگر مقدار خروجی بیش از 4V باشد، سنسور اشباع است. + float ppm; + + if (voltage < 0.1) ppm = 0; // خیلی پاک + else if (voltage < 0.2) ppm = 10 * (voltage / 0.2); // محدوده پایین + else if (voltage < 0.5) ppm = 50 + (voltage - 0.2) * 300; // 50–140ppm + else if (voltage < 1.0) ppm = 140 + (voltage - 0.5) * 800; // تا حدود 500ppm + else if (voltage < 2.0) ppm = 500 + (voltage - 1.0) * 1500; // تا حدود 2000ppm + else ppm = 2000 + (voltage - 2.0) * 2000; // تا ~4000ppm + + // --- 4. محدود کردن مقدار --- + if (ppm < 0) ppm = 0; + if (ppm > 10000) ppm = 10000; + + // --- 5. نمایش برای دیباگ --- + Serial.print("MQ7 voltage: "); + Serial.print(voltage, 3); + Serial.print(" V, CO ≈ "); + Serial.print(ppm, 1); + Serial.println(" ppm"); + + return ppm; +} + + +float readLight() { return lightMeter.readLightLevel(); } + +// ارسال داده HTTP GET +void sendData(float temp, float hum, int soilPerc, float mq7ppm, float lux, String timeStr) { + String dataStr = String(temp,1) + "," + String(hum,1) + "," + String(soilPerc) + "," + String(mq7ppm,0) + "," + String(lux,1) + "," + timeStr; + // 'http://localhost:5064/api/Telemetry/AddData?deviceName=dr110&temperatureC=24.5&humidityPercent=26.3&soilPercent=12&gasPPM=2&lux=103' + String url = "http://nabaksoft.ir/api/Telemetry/AddData?deviceName=dr110&temperatureC="+String(temp,1) + +"&humidityPercent="+String(hum,1)+"&soilPercent="+String(soilPerc)+"&gasPPM="+String(mq7ppm,0)+"&lux="+String(lux,1); + + Serial.println("🌐 Sending data: " + dataStr); + + sendAT("AT+QHTTPURL=" + String(url.length()) + ",80", 500); + delay(500); + EC200U.print(url); + delay(1000); + sendAT("AT+QHTTPGET=80", 5000); + sendAT("AT+QHTTPREAD=80", 5000); +} + +// --------------------------- راه‌اندازی --------------------------- +void setup() { + Serial.begin(115200); + delay(1000); + Serial.println("🚀 STM32 + EC200U + Sensors"); + + // روشن کردن ماژول EC200U + powerEC200U(); + + // UART EC200U + EC200U.setRx(PA10); + EC200U.setTx(PA9); + EC200U.begin(115200); + delay(1000); + + // سنسورها + dht.begin(); + Wire.setSDA(SDA_PIN); + Wire.setSCL(SCL_PIN); + Wire.begin(); + if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) { + Serial.println("BH1750 Initialized successfully!"); + } else { + Serial.println("Error initializing BH1750!"); + } + + // آماده سازی ماژول و اینترنت + initEC200U(); + + // خواندن ساعت شبکه + getNetworkTime(); +} + +// --------------------------- حلقه اصلی --------------------------- +unsigned long lastUpload = 0; + +void loop() { + unsigned long now = millis(); + if (now - lastUpload > UPLOAD_INTERVAL_MIN*60UL*1000UL || lastUpload==0) { + // خواندن سنسورها + float temp = readDHT22(); + float hum = readHumidity(); + int soil = readSoilPercent(); + float mq7 = readMQ7ppm(); + float lux = readLight(); + + // دریافت ساعت شبکه + getNetworkTime(); + + // ارسال به سرور + sendData(temp, hum, soil, mq7, lux, networkTime); + + lastUpload = now; + } + + delay(500); +} diff --git a/old/newWifi/newWifi.ino b/old/newWifi/newWifi.ino new file mode 100644 index 0000000..521c20f --- /dev/null +++ b/old/newWifi/newWifi.ino @@ -0,0 +1,156 @@ +#include + +SoftwareSerial esp8266(4, 5); // RX, TX + +// صفحه پیش‌فرض HTML +const char* HTML_PAGE = "

Hello from ESP8266

"; + +void setup() { + Serial.begin(9600); + esp8266.begin(9600); + + delay(2000); // آماده‌سازی ESP + + // تنظیمات اولیه ESP8266 + sendCommand("AT", "OK", 2000); + sendCommand("ATE0", "OK", 2000); + sendCommand("AT+CWMODE=2", "OK", 2000); + sendCommand("AT+CWSAP=\"ESP8266_AP\",\"12345678\",1,0", "OK", 5000); + sendCommand("AT+CIPMUX=1", "OK", 3000); + sendCommand("AT+CIPSERVER=1,80", "OK", 3000); + + Serial.println(F("ESP8266 Ready. Connect to SSID: ESP8266_AP, Pass: 12345678")); + Serial.println(F("Then open http://192.168.4.1/ in your browser")); +} + +void loop() { + if (esp8266.available()) { + String line = esp8266.readStringUntil('\n'); + line.trim(); + if (line.length() == 0) return; + + Serial.println("[ESP8266] " + line); + + if (line.startsWith("+IPD,")) { + int len = 0; + int linkId = parseIPDLine(line, len); + if (linkId < 0) { + Serial.println("Failed to parse IPD line."); + return; + } + + drainPayload(len); + + // فراخوانی تابع پردازش و ارسال پاسخ + processAndSend(linkId, line); + } + } +} + +// =================== توابع کمکی =================== + +// تابع پردازش داده و ارسال پاسخ به کلاینت +void processAndSend(int linkId, const String &requestLine) { + String html; + + // بررسی پارامتر صفحه در URL + if (requestLine.indexOf("GET /?page=") != -1) { + int start = requestLine.indexOf("GET /?page=") + 10; + int end = requestLine.indexOf(" ", start); + int pageNum = requestLine.substring(start, end).toInt(); + + switch (pageNum) { + case 1: + html = "

صفحه ۱

"; + break; + case 2: + html = "

صفحه ۲

"; + break; + case 3: + html = "

صفحه ۳

"; + break; + default: + html = "

صفحه پیش‌فرض

"; + break; + } + } else { + html = HTML_PAGE; // صفحه پیش‌فرض + } + + // ساخت پاسخ HTTP + String response = "HTTP/1.1 200 OK\r\n"; + response += "Content-Type: text/html\r\n"; + response += "Content-Length: " + String(html.length()) + "\r\n"; + response += "Connection: close\r\n\r\n"; + response += html; + + // ارسال پاسخ + String cmd = "AT+CIPSEND=" + String(linkId) + "," + String(response.length()); + if (sendCommand(cmd, ">", 5000)) { + esp8266.print(response); + + if (waitFor("SEND OK", 5000)) { + Serial.println("Response sent to client."); + } else { + Serial.println("SEND OK not received (timeout)."); + } + } else { + Serial.println("CIPSEND prompt not received (timeout)."); + } + + // بستن کانکشن + String closeCmd = "AT+CIPCLOSE=" + String(linkId); + sendCommand(closeCmd, "OK", 2000); +} + +// استخراج linkId و len از خط +IPD +int parseIPDLine(const String& line, int &lenOut) { + int ipdPos = line.indexOf("+IPD,"); + if (ipdPos == -1) return -1; + + int firstComma = line.indexOf(',', ipdPos + 4); + int secondComma = line.indexOf(',', firstComma + 1); + if (firstComma == -1 || secondComma == -1) return -1; + + int colon = line.indexOf(':', secondComma + 1); + if (colon == -1) { + lenOut = line.substring(secondComma + 1).toInt(); + return line.substring(ipdPos + 4, firstComma).toInt(); + } else { + lenOut = line.substring(firstComma + 1, secondComma).toInt(); + return line.substring(ipdPos + 4, firstComma).toInt(); + } +} + +// پاک‌سازی payload بعد از +IPD +void drainPayload(int len) { + unsigned long t0 = millis(); + int remaining = len; + while (millis() - t0 < 1000 && remaining > 0) { + if (esp8266.available()) { + esp8266.read(); + remaining--; + } + } +} + +// ارسال فرمان AT و انتظار ACK +bool sendCommand(const String& cmd, const char* ack, unsigned long timeout) { + esp8266.println(cmd); + return waitFor(ack, timeout); +} + +// منتظر بودن برای وجود یک ACK/کلمه کلیدی تا مهلت معین +bool waitFor(const char* target, unsigned long timeout) { + unsigned long start = millis(); + String buffer = ""; + while (millis() - start < timeout) { + while (esp8266.available()) { + char c = esp8266.read(); + buffer += c; + if (buffer.indexOf(target) != -1) return true; + } + } + Serial.print("Timeout waiting for: "); Serial.println(target); + return false; +} diff --git a/old/nodemcu3.ino b/old/nodemcu3.ino new file mode 100644 index 0000000..2c75cdb --- /dev/null +++ b/old/nodemcu3.ino @@ -0,0 +1,759 @@ +// Clean, full sketch for ESP8266 (NodeMCU) +// - RCSwitch receiver on D5 +// - RTC DS3231 on I2C (SDA=D2, SCL=D1) +// - Optional SD on CS = D8 (GPIO15) +// - Always prints received RF data to Serial +// - Saves to SD every N minutes if SD present +// - Cleans files older than M days every 12 hours +// - getPageID(...) returns numeric page id; switch-case used +// - STA + periodic sending to server +// - API to set STA & send interval +#include +#include +#include +#include "RTClib.h" +//#include +#include +#include +#include +#include +#include + + + +// ---------------- CONFIG ---------------- +String apSSID = "ESP8266_AP"; +String apPassword = "12345678"; +WiFiServer server(80); + +// ---------------- HW ---------------- +RTC_DS3231 rtc; +bool rtcReady = false; + +//RCSwitch rx; +//const uint8_t RX_PIN = D1; +#define RF_RECEIVE_PIN D1 +RH_ASK driver(1200, RF_RECEIVE_PIN, -1, -1); + +#define LED_PIN 1 // TX = GPIO1 +#define NUM_LEDS 8 + +//Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800); + + +#define SD_CS_PIN D8 +bool sdReady = false; +const char* CONFIG_FILE = "config.txt"; + +const int buttonPin = 16; // D0 +bool wifiEnabled = true; +bool ConnectToModem = false; +bool buttonPressed = false; +int lastButtonState = HIGH; +unsigned long lastDebounceTime = 0; +const unsigned long debounceDelay = 50; + +// ---------------- Protocol & storage ---------------- +const String PRIVATE_KEY = "as23f"; +const String ALLOWED_DEVICES[] = {"dr142","abcde","fghij"}; +const int NUM_ALLOWED = 3; + +#define MAX_DEVICES 4 +struct RemoteData { + String deviceId; + int soil; + int gas; + int temp; + int hum; + unsigned long timestamp; +}; + +RemoteData lastRemoteData[MAX_DEVICES]; +/*struct DeviceData { + String deviceId; + int soil; + int gas; + float temp; + float hum; + String timestamp; +}; +DeviceData lastRemoteData[MAX_DEVICES];*/ +int deviceCount = 0; + +// RX frame parsing +String receivedKey = ""; +String receivedHex = ""; +bool receivingPublicKey = true; +int receivedChars = 0; +unsigned long lastReceiveTime = 0; +const unsigned long FRAME_TIMEOUT_MS = 500; +const int EXPECTED_PLAIN_LEN = 25; + +// ---------------- Settings (default) ---------------- +unsigned long saveIntervalMinutes = 5; +int retentionDays = 90; +unsigned long lastSaveMillis = 0; +unsigned long lastCleanupMillis = 0; + +// ---------------- WiFi client (STA) ---------------- +String staSSID = ""; +String staPassword = ""; +unsigned long lastSendMillis = 0; +unsigned long sendIntervalMinutes = 1; // پیش فرض + +// ---------------- Helpers ---------------- +bool isHexChar(char c) { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); +} + +bool isDeviceAllowed(const String &id) { + for (int i=0;i= 8 && isDigit(name[0])) { + int y = name.substring(0,4).toInt(); + int m = name.substring(4,6).toInt(); + int d = name.substring(6,8).toInt(); + if (y > 2000 && m>=1 && m<=12 && d>=1 && d<=31) { + DateTime fileDate(y,m,d,0,0,0); + TimeSpan diff = now - fileDate; + if (diff.days() > retentionDays) SD.remove(name); + } + } + } + entry.close(); + entry = root.openNextFile(); + } + root.close(); +} + +// ---------------- Remote receiver ---------------- +void processRemote() { + uint8_t buf[32]; // حداکثر طول بسته + uint8_t buflen = sizeof(buf); + + if (driver.recv(buf, &buflen)) { + buf[buflen] = '\0'; // تبدیل به رشته + String plain = String((char*)buf); + + Serial.print("[RX] Received: "); + Serial.println(plain); + + // 📌 فرض: فرمت مثل "dr142S0345G0123T0254H0456" + if (plain.length() >= 25) { + RemoteData _remoteData; + _remoteData.soil = plain.substring(6, 10).toInt(); + _remoteData.gas = plain.substring(11, 15).toInt(); + _remoteData.deviceId = plain.substring(0, 5); + _remoteData.temp = plain.substring(16, 20).toInt(); + _remoteData.hum = plain.substring(21, 25).toInt(); + _remoteData.timestamp = millis(); +bool updated=false; + for (int i=0;i= saveIntervalMinutes*60000UL) { + if (sdReady) { + String j="{\"device\":\""+_remoteData.deviceId+"\",\"soil\":"+String(_remoteData.soil)+",\"gas\":"+String(_remoteData.gas)+ + ",\"temp\":"+String(_remoteData.temp)+",\"hum\":"+String(_remoteData.hum)+",\"time\":\""+_remoteData.timestamp+"\"}"; + appendDataToSD(j); + Serial.println("[INFO] appended to SD"); + } + lastSaveMillis=millis(); + } + + + + // String logLine = plain + "," + String(millis()); + // saveToSD(logLine); + + //digitalWrite(LED_GREEN, HIGH); + delay(50); + //digitalWrite(LED_GREEN, LOW); + } + } +} + +// ---------------- Page mapping ---------------- +int getPageID(const String &page) { + if (page == "info") return 1; + if (page == "sensor") return 2; + if (page == "time") return 3; + if (page == "settime") return 4; + if (page == "lastremote") return 5; + if (page == "readfile") return 6; + if (page == "files") return 7; + if (page == "format") return 8; + if (page == "set_save_interval") return 9; + if (page == "set_retention_days") return 10; + if (page == "sd_status") return 11; + return 0; +} + +String urlDecode(const String &input) { + String s = input; + s.replace("+", " "); + for (int i = 0; i + 2 < s.length(); ++i) { + if (s[i] == '%') { + String hx = s.substring(i+1, i+3); + char c = (char) strtol(hx.c_str(), NULL, 16); + s = s.substring(0,i) + String(c) + s.substring(i+3); + } + } + return s; +} + +String getParamFromPath(const String &path, const String &key) { + int q = path.indexOf('?'); + if (q == -1) return ""; + String qstr = path.substring(q+1); + int start = 0; + while (start < qstr.length()) { + int amp = qstr.indexOf('&', start); + if (amp == -1) amp = qstr.length(); + int eq = qstr.indexOf('=', start); + if (eq != -1 && eq < amp) { + String k = qstr.substring(start, eq); + String v = qstr.substring(eq+1, amp); + if (k == key) return urlDecode(v); + } + start = amp + 1; + } + return ""; +} + +// ---------------- HTTP handler ---------------- +void handleClient(WiFiClient &client) { + String req = ""; + unsigned long start = millis(); + while (client.connected() && millis() - start < 1500) { + while (client.available()) { + char c = client.read(); + req += c; + if (req.endsWith("\r\n\r\n")) break; + } + if (req.endsWith("\r\n\r\n")) break; + } + if (req.length() == 0) return; + + int lineEnd = req.indexOf("\r\n"); + String firstLine = (lineEnd == -1) ? req : req.substring(0, lineEnd); + Serial.print("[HTTP] "); Serial.println(firstLine); + + String path = ""; + int sp1 = firstLine.indexOf(' '); + int sp2 = firstLine.indexOf(" HTTP/"); + if (sp1 != -1 && sp2 != -1) path = firstLine.substring(sp1+1, sp2); + + String page = getParamFromPath(path,"page"); + String response=""; + + // --- API: set STA --- + if(page=="set_sta") { + String ssid = getParamFromPath(path,"ssid"); + String pass = getParamFromPath(path,"pass"); + if(ssid.length()>0) { + staSSID=ssid; staPassword=pass; + ConnectToModem=WiFi.begin(staSSID.c_str(),staPassword.c_str()); + if(sdReady) saveConfigToSD(); + response="{\"status\":\"ok\",\"message\":\"STA updated, connecting...\"}"; + } else response="{\"status\":\"error\",\"message\":\"SSID missing\"}"; + client.println(F("HTTP/1.1 200 OK")); + client.println(F("Content-Type: application/json")); + client.print(F("Content-Length: ")); client.println(response.length()); + client.println(F("Connection: close")); client.println(); + client.println(response); + client.stop(); + return; + } + + // --- API: set send interval --- + if(page=="set_send_interval") { + String v = getParamFromPath(path,"minutes"); + int m=v.toInt(); + if(m>0) { + sendIntervalMinutes=m; + if(sdReady) saveConfigToSD(); + response="{\"status\":\"ok\",\"send_interval_minutes\":"+String(m)+"}"; + } else response="{\"status\":\"error\",\"message\":\"invalid minutes\"}"; + client.println(F("HTTP/1.1 200 OK")); + client.println(F("Content-Type: application/json")); + client.print(F("Content-Length: ")); client.println(response.length()); + client.println(F("Connection: close")); client.println(); + client.println(response); + client.stop(); + return; + } + + // --- old page switch --- + int pid = getPageID(page); + switch(pid) { + case 1: response="{\"status\":\"ok\",\"data\":\"ESP ready\"}"; break; + case 2: response="{\"status\":\"ok\",\"sensor\":"+String(analogRead(A0))+"}"; break; + case 3: response=rtcReady?"{\"status\":\"ok\",\"datetime\":\""+dateTimeToISO(rtc.now())+"\"}":"{\"status\":\"error\",\"message\":\"RTC not ready\"}"; break; + case 4: { + String iso=getParamFromPath(path,"iso"); + if(!rtcReady){ response="{\"status\":\"error\",\"message\":\"RTC not ready\"}"; break; } + if(iso.length()>=19){ + int y=iso.substring(0,4).toInt(), m=iso.substring(5,7).toInt(), d=iso.substring(8,10).toInt(); + int hh=iso.substring(11,13).toInt(), mm=iso.substring(14,16).toInt(), ss=iso.substring(17,19).toInt(); + rtc.adjust(DateTime(y,m,d,hh,mm,ss)); + response="{\"status\":\"ok\",\"datetime\":\""+dateTimeToISO(rtc.now())+"\"}"; + } else response="{\"status\":\"error\",\"message\":\"invalid iso\"}"; + break; + } + case 5: { + String arr="["; + for(int i=0;i 0) { + content.remove(content.length() - 3); + } + f.close(); + response = "{\"status\":\"ok\",\"content\":[" + content + "]}"; + + break; + } + case 7: { // files + if (!sdReady) { response = "{\"status\":\"error\",\"message\":\"SD not ready\"}"; break; } + File root = SD.open("/"); + String arr = "["; + bool first = true; + File entry = root.openNextFile(); + while (entry) { + String name = entry.name(); + if (name.length() && name[0] == '/') name = name.substring(1); + if (!first) arr += ","; + arr += "\"" + name + "\""; + first = false; + entry.close(); + entry = root.openNextFile(); + } + root.close(); + arr += "]"; + response = "{\"status\":\"ok\",\"files\":" + arr + "}"; + break; + } + case 8: { // format (remove all files except config) + if (!sdReady) { response = "{\"status\":\"error\",\"message\":\"SD not ready\"}"; break; } + File root = SD.open("/"); + File entry = root.openNextFile(); + while (entry) { + String name = entry.name(); + if (name.length() && name[0] == '/') name = name.substring(1); + if (name != String(CONFIG_FILE) && !entry.isDirectory()) SD.remove(name); + entry.close(); + entry = root.openNextFile(); + } + root.close(); + response = "{\"status\":\"ok\",\"message\":\"formatted (config preserved)\"}"; + break; + } + case 9: { // set_save_interval?min=NUM + String v = getParamFromPath(path, "min"); + int m = v.toInt(); + if (m <= 0) response = "{\"status\":\"error\",\"message\":\"invalid min\"}"; + else { + saveIntervalMinutes = (unsigned long)m; + if (sdReady) saveConfigToSD(); + response = "{\"status\":\"ok\",\"save_interval_minutes\":" + String(m) + "}"; + } + break; + } + case 10: { // set_retention_days?days=NUM + String v = getParamFromPath(path, "days"); + int d = v.toInt(); + if (d <= 0) response = "{\"status\":\"error\",\"message\":\"invalid days\"}"; + else { + retentionDays = d; + if (sdReady) saveConfigToSD(); + response = "{\"status\":\"ok\",\"retention_days\":" + String(d) + "}"; + } + break; + } + case 11: { // sd_status + if (!sdReady) response = "{\"status\":\"error\",\"message\":\"SD not ready\"}"; + else + { + uint64_t used = computeSDUsedBytes(); + //total/free not reliably available via SD.h on ESP8266 + response = "{\"status\":\"ok\",\"used_bytes\":" + String((unsigned long)used) + "}"; + } + break; + } + default: response = page.length()==0?"{\"status\":\"error\",\"message\":\"missing page\"}":"{\"status\":\"error\",\"message\":\"unknown page\"}"; break; + } + + client.println(F("HTTP/1.1 200 OK")); + client.println(F("Content-Type: application/json")); + client.print(F("Content-Length: ")); client.println(response.length()); + client.println(F("Connection: close")); + client.println(); + client.println(response); + delay(5); + client.stop(); + Serial.println("[HTTP] client disconnected"); +} +void setLed(uint8_t idx, bool condition, uint32_t colorTrue, uint32_t colorFalse) { + // if (condition) { + // strip.setPixelColor(idx, colorTrue); + // } else { + // strip.setPixelColor(idx, colorFalse); + // } +} +// ---------------- Setup & Loop ---------------- +void setup() { + Serial.begin(115200); delay(2000); + +//led + // strip.begin(); + // strip.show(); + + //چراغ اول روشن شود. یعنی دستگاه روشن است + // setLed(0, true, strip.Color(0,255,0), strip.Color(0,0,0)); + // strip.show(); + + pinMode(buttonPin, INPUT_PULLUP); + Wire.begin(D2,D3); + rtcReady=rtc.begin(); + if(rtcReady && rtc.lostPower()) rtc.adjust(DateTime(F(__DATE__),F(__TIME__))); + + if (!driver.init()) { + Serial.println("[ERR] RH_ASK init failed!"); + } else { + Serial.println("[INFO] RH_ASK ready"); + } + + // rx.enableReceive(digitalPinToInterrupt(RX_PIN)); + // rx.setProtocol(1); + // rx.setPulseLength(300); + Serial.println("[INFO] RCSwitch enabled on D5"); + + sdReady=SD.begin(SD_CS_PIN); + if(sdReady){ Serial.println("[INFO] SD ready"); loadConfigFromSD(); } + else Serial.println("[WARN] SD init failed"); + + if(wifiEnabled){ WiFi.softAP(apSSID,apPassword); server.begin(); Serial.print("AP IP: "); Serial.println(WiFi.softAPIP()); } + + if(staSSID.length()>0){ ConnectToModem=WiFi.begin(staSSID.c_str(),staPassword.c_str()); } + + lastSaveMillis=millis(); lastCleanupMillis=millis(); lastSendMillis=millis(); +} + +void loop() { + // ---------------- Button handling (toggle AP) ---------------- + int reading = digitalRead(buttonPin); + if (reading != lastButtonState) lastDebounceTime = millis(); + + if ((millis() - lastDebounceTime) > debounceDelay) { + if (reading == LOW && !buttonPressed) { + buttonPressed = true; + wifiEnabled = !wifiEnabled; + + if (wifiEnabled) { + WiFi.mode(WIFI_AP_STA); + WiFi.softAP(apSSID, apPassword); + server.begin(); + Serial.println("✅ AP enabled"); + Serial.print("IP: "); Serial.println(WiFi.softAPIP()); + } else { + WiFi.softAPdisconnect(true); + WiFi.mode(WIFI_STA); + Serial.println("❌ AP disabled"); + } + } + + if (reading == HIGH) buttonPressed = false; + } + lastButtonState = reading; + + // ---------------- HTTP server handling ---------------- + if (wifiEnabled) { + WiFiClient client = server.available(); + if (client) handleClient(client); + } + + // ---------------- Process RF data ---------------- + processRemote(); + + // ---------------- Periodic cleanup every 12 hours ---------------- + if ((millis() - lastCleanupMillis) >= (12UL * 60UL * 60UL * 1000UL)) { + cleanupOldFilesOnSD(); + lastCleanupMillis = millis(); + } + + // ---------------- Debug info before sending ---------------- + + + // ---------------- Periodic send to server ---------------- + // ---------------- Periodic send to server ---------------- +if (deviceCount > 0 && sendIntervalMinutes > 0) { + if (lastSendMillis == 0) lastSendMillis = millis(); + + if ((millis() - lastSendMillis) >= sendIntervalMinutes * 60000UL) { + Serial.println("[DEBUG] Entering send block"); + Serial.print("[DEBUG] WiFi.status: "); Serial.println(WiFi.status()); + + if (WiFi.status() == WL_CONNECTED) { + // Prepare JSON payload + String payload = "["; + for (int i = 0; i < deviceCount; i++) { + if (i) payload += ","; + RemoteData d = lastRemoteData[i]; + payload += "{\"device\":\"" + d.deviceId + "\",\"soil\":" + String(d.soil) + + ",\"gas\":" + String(d.gas) + ",\"temp\":" + String(d.temp) + + ",\"hum\":" + String(d.hum) + ",\"time\":\"" + d.timestamp + "\"}"; + } + payload += "]"; + + // Use WiFiClientSecure for HTTPS + WiFiClientSecure client; + client.setInsecure(); // SSL certificate not verified + HTTPClient http; + + // Use URL with www if nabaksoft.ir ریدایرکت می‌کند + String url = "https://www.nabaksoft.ir/greenhome/mygreenhome.php?aid="+PRIVATE_KEY+"&data=" + payload; + + http.begin(client, url); + http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); // Follow redirects automatically + + Serial.println("[HTTP] Sending data to server..."); + int httpCode = http.GET(); + + if (httpCode > 0) { + Serial.printf("[HTTP] Response code: %d\n", httpCode); + String resp = http.getString(); + Serial.printf("[HTTP] Server response: %s\n", resp.c_str()); + } else { + Serial.printf("[HTTP] Send failed, error: %s\n", http.errorToString(httpCode).c_str()); + } + + http.end(); + } else { + Serial.println("[HTTP] WiFi not connected, skipping send"); + } + + lastSendMillis = millis(); + } +} + //دریافت کننده فعال است؟ + // setLed(1, rtcReady, strip.Color(0,255,0), strip.Color(255,0,0)); + // //کارتخوان فعال است؟ + // setLed(2, sdReady, strip.Color(0,255,0), strip.Color(255,0,0)); + // //wifi فعال است؟ + // setLed(3, wifiEnabled, strip.Color(0,255,0), strip.Color(0,0,0)); + // //مودم فعال است یا خیر و اگر فعال است متصل است؟ + // if(staSSID.length()>0) + // setLed(4, ConnectToModem, strip.Color(0,255,0), strip.Color(255,0,0)); + // else + // setLed(4, true, strip.Color(0,0,0), strip.Color(0,0,0)); + + // strip.show(); +} + diff --git a/old/nodemcu3/nodemcu3.ino b/old/nodemcu3/nodemcu3.ino new file mode 100644 index 0000000..2c75cdb --- /dev/null +++ b/old/nodemcu3/nodemcu3.ino @@ -0,0 +1,759 @@ +// Clean, full sketch for ESP8266 (NodeMCU) +// - RCSwitch receiver on D5 +// - RTC DS3231 on I2C (SDA=D2, SCL=D1) +// - Optional SD on CS = D8 (GPIO15) +// - Always prints received RF data to Serial +// - Saves to SD every N minutes if SD present +// - Cleans files older than M days every 12 hours +// - getPageID(...) returns numeric page id; switch-case used +// - STA + periodic sending to server +// - API to set STA & send interval +#include +#include +#include +#include "RTClib.h" +//#include +#include +#include +#include +#include +#include + + + +// ---------------- CONFIG ---------------- +String apSSID = "ESP8266_AP"; +String apPassword = "12345678"; +WiFiServer server(80); + +// ---------------- HW ---------------- +RTC_DS3231 rtc; +bool rtcReady = false; + +//RCSwitch rx; +//const uint8_t RX_PIN = D1; +#define RF_RECEIVE_PIN D1 +RH_ASK driver(1200, RF_RECEIVE_PIN, -1, -1); + +#define LED_PIN 1 // TX = GPIO1 +#define NUM_LEDS 8 + +//Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800); + + +#define SD_CS_PIN D8 +bool sdReady = false; +const char* CONFIG_FILE = "config.txt"; + +const int buttonPin = 16; // D0 +bool wifiEnabled = true; +bool ConnectToModem = false; +bool buttonPressed = false; +int lastButtonState = HIGH; +unsigned long lastDebounceTime = 0; +const unsigned long debounceDelay = 50; + +// ---------------- Protocol & storage ---------------- +const String PRIVATE_KEY = "as23f"; +const String ALLOWED_DEVICES[] = {"dr142","abcde","fghij"}; +const int NUM_ALLOWED = 3; + +#define MAX_DEVICES 4 +struct RemoteData { + String deviceId; + int soil; + int gas; + int temp; + int hum; + unsigned long timestamp; +}; + +RemoteData lastRemoteData[MAX_DEVICES]; +/*struct DeviceData { + String deviceId; + int soil; + int gas; + float temp; + float hum; + String timestamp; +}; +DeviceData lastRemoteData[MAX_DEVICES];*/ +int deviceCount = 0; + +// RX frame parsing +String receivedKey = ""; +String receivedHex = ""; +bool receivingPublicKey = true; +int receivedChars = 0; +unsigned long lastReceiveTime = 0; +const unsigned long FRAME_TIMEOUT_MS = 500; +const int EXPECTED_PLAIN_LEN = 25; + +// ---------------- Settings (default) ---------------- +unsigned long saveIntervalMinutes = 5; +int retentionDays = 90; +unsigned long lastSaveMillis = 0; +unsigned long lastCleanupMillis = 0; + +// ---------------- WiFi client (STA) ---------------- +String staSSID = ""; +String staPassword = ""; +unsigned long lastSendMillis = 0; +unsigned long sendIntervalMinutes = 1; // پیش فرض + +// ---------------- Helpers ---------------- +bool isHexChar(char c) { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); +} + +bool isDeviceAllowed(const String &id) { + for (int i=0;i= 8 && isDigit(name[0])) { + int y = name.substring(0,4).toInt(); + int m = name.substring(4,6).toInt(); + int d = name.substring(6,8).toInt(); + if (y > 2000 && m>=1 && m<=12 && d>=1 && d<=31) { + DateTime fileDate(y,m,d,0,0,0); + TimeSpan diff = now - fileDate; + if (diff.days() > retentionDays) SD.remove(name); + } + } + } + entry.close(); + entry = root.openNextFile(); + } + root.close(); +} + +// ---------------- Remote receiver ---------------- +void processRemote() { + uint8_t buf[32]; // حداکثر طول بسته + uint8_t buflen = sizeof(buf); + + if (driver.recv(buf, &buflen)) { + buf[buflen] = '\0'; // تبدیل به رشته + String plain = String((char*)buf); + + Serial.print("[RX] Received: "); + Serial.println(plain); + + // 📌 فرض: فرمت مثل "dr142S0345G0123T0254H0456" + if (plain.length() >= 25) { + RemoteData _remoteData; + _remoteData.soil = plain.substring(6, 10).toInt(); + _remoteData.gas = plain.substring(11, 15).toInt(); + _remoteData.deviceId = plain.substring(0, 5); + _remoteData.temp = plain.substring(16, 20).toInt(); + _remoteData.hum = plain.substring(21, 25).toInt(); + _remoteData.timestamp = millis(); +bool updated=false; + for (int i=0;i= saveIntervalMinutes*60000UL) { + if (sdReady) { + String j="{\"device\":\""+_remoteData.deviceId+"\",\"soil\":"+String(_remoteData.soil)+",\"gas\":"+String(_remoteData.gas)+ + ",\"temp\":"+String(_remoteData.temp)+",\"hum\":"+String(_remoteData.hum)+",\"time\":\""+_remoteData.timestamp+"\"}"; + appendDataToSD(j); + Serial.println("[INFO] appended to SD"); + } + lastSaveMillis=millis(); + } + + + + // String logLine = plain + "," + String(millis()); + // saveToSD(logLine); + + //digitalWrite(LED_GREEN, HIGH); + delay(50); + //digitalWrite(LED_GREEN, LOW); + } + } +} + +// ---------------- Page mapping ---------------- +int getPageID(const String &page) { + if (page == "info") return 1; + if (page == "sensor") return 2; + if (page == "time") return 3; + if (page == "settime") return 4; + if (page == "lastremote") return 5; + if (page == "readfile") return 6; + if (page == "files") return 7; + if (page == "format") return 8; + if (page == "set_save_interval") return 9; + if (page == "set_retention_days") return 10; + if (page == "sd_status") return 11; + return 0; +} + +String urlDecode(const String &input) { + String s = input; + s.replace("+", " "); + for (int i = 0; i + 2 < s.length(); ++i) { + if (s[i] == '%') { + String hx = s.substring(i+1, i+3); + char c = (char) strtol(hx.c_str(), NULL, 16); + s = s.substring(0,i) + String(c) + s.substring(i+3); + } + } + return s; +} + +String getParamFromPath(const String &path, const String &key) { + int q = path.indexOf('?'); + if (q == -1) return ""; + String qstr = path.substring(q+1); + int start = 0; + while (start < qstr.length()) { + int amp = qstr.indexOf('&', start); + if (amp == -1) amp = qstr.length(); + int eq = qstr.indexOf('=', start); + if (eq != -1 && eq < amp) { + String k = qstr.substring(start, eq); + String v = qstr.substring(eq+1, amp); + if (k == key) return urlDecode(v); + } + start = amp + 1; + } + return ""; +} + +// ---------------- HTTP handler ---------------- +void handleClient(WiFiClient &client) { + String req = ""; + unsigned long start = millis(); + while (client.connected() && millis() - start < 1500) { + while (client.available()) { + char c = client.read(); + req += c; + if (req.endsWith("\r\n\r\n")) break; + } + if (req.endsWith("\r\n\r\n")) break; + } + if (req.length() == 0) return; + + int lineEnd = req.indexOf("\r\n"); + String firstLine = (lineEnd == -1) ? req : req.substring(0, lineEnd); + Serial.print("[HTTP] "); Serial.println(firstLine); + + String path = ""; + int sp1 = firstLine.indexOf(' '); + int sp2 = firstLine.indexOf(" HTTP/"); + if (sp1 != -1 && sp2 != -1) path = firstLine.substring(sp1+1, sp2); + + String page = getParamFromPath(path,"page"); + String response=""; + + // --- API: set STA --- + if(page=="set_sta") { + String ssid = getParamFromPath(path,"ssid"); + String pass = getParamFromPath(path,"pass"); + if(ssid.length()>0) { + staSSID=ssid; staPassword=pass; + ConnectToModem=WiFi.begin(staSSID.c_str(),staPassword.c_str()); + if(sdReady) saveConfigToSD(); + response="{\"status\":\"ok\",\"message\":\"STA updated, connecting...\"}"; + } else response="{\"status\":\"error\",\"message\":\"SSID missing\"}"; + client.println(F("HTTP/1.1 200 OK")); + client.println(F("Content-Type: application/json")); + client.print(F("Content-Length: ")); client.println(response.length()); + client.println(F("Connection: close")); client.println(); + client.println(response); + client.stop(); + return; + } + + // --- API: set send interval --- + if(page=="set_send_interval") { + String v = getParamFromPath(path,"minutes"); + int m=v.toInt(); + if(m>0) { + sendIntervalMinutes=m; + if(sdReady) saveConfigToSD(); + response="{\"status\":\"ok\",\"send_interval_minutes\":"+String(m)+"}"; + } else response="{\"status\":\"error\",\"message\":\"invalid minutes\"}"; + client.println(F("HTTP/1.1 200 OK")); + client.println(F("Content-Type: application/json")); + client.print(F("Content-Length: ")); client.println(response.length()); + client.println(F("Connection: close")); client.println(); + client.println(response); + client.stop(); + return; + } + + // --- old page switch --- + int pid = getPageID(page); + switch(pid) { + case 1: response="{\"status\":\"ok\",\"data\":\"ESP ready\"}"; break; + case 2: response="{\"status\":\"ok\",\"sensor\":"+String(analogRead(A0))+"}"; break; + case 3: response=rtcReady?"{\"status\":\"ok\",\"datetime\":\""+dateTimeToISO(rtc.now())+"\"}":"{\"status\":\"error\",\"message\":\"RTC not ready\"}"; break; + case 4: { + String iso=getParamFromPath(path,"iso"); + if(!rtcReady){ response="{\"status\":\"error\",\"message\":\"RTC not ready\"}"; break; } + if(iso.length()>=19){ + int y=iso.substring(0,4).toInt(), m=iso.substring(5,7).toInt(), d=iso.substring(8,10).toInt(); + int hh=iso.substring(11,13).toInt(), mm=iso.substring(14,16).toInt(), ss=iso.substring(17,19).toInt(); + rtc.adjust(DateTime(y,m,d,hh,mm,ss)); + response="{\"status\":\"ok\",\"datetime\":\""+dateTimeToISO(rtc.now())+"\"}"; + } else response="{\"status\":\"error\",\"message\":\"invalid iso\"}"; + break; + } + case 5: { + String arr="["; + for(int i=0;i 0) { + content.remove(content.length() - 3); + } + f.close(); + response = "{\"status\":\"ok\",\"content\":[" + content + "]}"; + + break; + } + case 7: { // files + if (!sdReady) { response = "{\"status\":\"error\",\"message\":\"SD not ready\"}"; break; } + File root = SD.open("/"); + String arr = "["; + bool first = true; + File entry = root.openNextFile(); + while (entry) { + String name = entry.name(); + if (name.length() && name[0] == '/') name = name.substring(1); + if (!first) arr += ","; + arr += "\"" + name + "\""; + first = false; + entry.close(); + entry = root.openNextFile(); + } + root.close(); + arr += "]"; + response = "{\"status\":\"ok\",\"files\":" + arr + "}"; + break; + } + case 8: { // format (remove all files except config) + if (!sdReady) { response = "{\"status\":\"error\",\"message\":\"SD not ready\"}"; break; } + File root = SD.open("/"); + File entry = root.openNextFile(); + while (entry) { + String name = entry.name(); + if (name.length() && name[0] == '/') name = name.substring(1); + if (name != String(CONFIG_FILE) && !entry.isDirectory()) SD.remove(name); + entry.close(); + entry = root.openNextFile(); + } + root.close(); + response = "{\"status\":\"ok\",\"message\":\"formatted (config preserved)\"}"; + break; + } + case 9: { // set_save_interval?min=NUM + String v = getParamFromPath(path, "min"); + int m = v.toInt(); + if (m <= 0) response = "{\"status\":\"error\",\"message\":\"invalid min\"}"; + else { + saveIntervalMinutes = (unsigned long)m; + if (sdReady) saveConfigToSD(); + response = "{\"status\":\"ok\",\"save_interval_minutes\":" + String(m) + "}"; + } + break; + } + case 10: { // set_retention_days?days=NUM + String v = getParamFromPath(path, "days"); + int d = v.toInt(); + if (d <= 0) response = "{\"status\":\"error\",\"message\":\"invalid days\"}"; + else { + retentionDays = d; + if (sdReady) saveConfigToSD(); + response = "{\"status\":\"ok\",\"retention_days\":" + String(d) + "}"; + } + break; + } + case 11: { // sd_status + if (!sdReady) response = "{\"status\":\"error\",\"message\":\"SD not ready\"}"; + else + { + uint64_t used = computeSDUsedBytes(); + //total/free not reliably available via SD.h on ESP8266 + response = "{\"status\":\"ok\",\"used_bytes\":" + String((unsigned long)used) + "}"; + } + break; + } + default: response = page.length()==0?"{\"status\":\"error\",\"message\":\"missing page\"}":"{\"status\":\"error\",\"message\":\"unknown page\"}"; break; + } + + client.println(F("HTTP/1.1 200 OK")); + client.println(F("Content-Type: application/json")); + client.print(F("Content-Length: ")); client.println(response.length()); + client.println(F("Connection: close")); + client.println(); + client.println(response); + delay(5); + client.stop(); + Serial.println("[HTTP] client disconnected"); +} +void setLed(uint8_t idx, bool condition, uint32_t colorTrue, uint32_t colorFalse) { + // if (condition) { + // strip.setPixelColor(idx, colorTrue); + // } else { + // strip.setPixelColor(idx, colorFalse); + // } +} +// ---------------- Setup & Loop ---------------- +void setup() { + Serial.begin(115200); delay(2000); + +//led + // strip.begin(); + // strip.show(); + + //چراغ اول روشن شود. یعنی دستگاه روشن است + // setLed(0, true, strip.Color(0,255,0), strip.Color(0,0,0)); + // strip.show(); + + pinMode(buttonPin, INPUT_PULLUP); + Wire.begin(D2,D3); + rtcReady=rtc.begin(); + if(rtcReady && rtc.lostPower()) rtc.adjust(DateTime(F(__DATE__),F(__TIME__))); + + if (!driver.init()) { + Serial.println("[ERR] RH_ASK init failed!"); + } else { + Serial.println("[INFO] RH_ASK ready"); + } + + // rx.enableReceive(digitalPinToInterrupt(RX_PIN)); + // rx.setProtocol(1); + // rx.setPulseLength(300); + Serial.println("[INFO] RCSwitch enabled on D5"); + + sdReady=SD.begin(SD_CS_PIN); + if(sdReady){ Serial.println("[INFO] SD ready"); loadConfigFromSD(); } + else Serial.println("[WARN] SD init failed"); + + if(wifiEnabled){ WiFi.softAP(apSSID,apPassword); server.begin(); Serial.print("AP IP: "); Serial.println(WiFi.softAPIP()); } + + if(staSSID.length()>0){ ConnectToModem=WiFi.begin(staSSID.c_str(),staPassword.c_str()); } + + lastSaveMillis=millis(); lastCleanupMillis=millis(); lastSendMillis=millis(); +} + +void loop() { + // ---------------- Button handling (toggle AP) ---------------- + int reading = digitalRead(buttonPin); + if (reading != lastButtonState) lastDebounceTime = millis(); + + if ((millis() - lastDebounceTime) > debounceDelay) { + if (reading == LOW && !buttonPressed) { + buttonPressed = true; + wifiEnabled = !wifiEnabled; + + if (wifiEnabled) { + WiFi.mode(WIFI_AP_STA); + WiFi.softAP(apSSID, apPassword); + server.begin(); + Serial.println("✅ AP enabled"); + Serial.print("IP: "); Serial.println(WiFi.softAPIP()); + } else { + WiFi.softAPdisconnect(true); + WiFi.mode(WIFI_STA); + Serial.println("❌ AP disabled"); + } + } + + if (reading == HIGH) buttonPressed = false; + } + lastButtonState = reading; + + // ---------------- HTTP server handling ---------------- + if (wifiEnabled) { + WiFiClient client = server.available(); + if (client) handleClient(client); + } + + // ---------------- Process RF data ---------------- + processRemote(); + + // ---------------- Periodic cleanup every 12 hours ---------------- + if ((millis() - lastCleanupMillis) >= (12UL * 60UL * 60UL * 1000UL)) { + cleanupOldFilesOnSD(); + lastCleanupMillis = millis(); + } + + // ---------------- Debug info before sending ---------------- + + + // ---------------- Periodic send to server ---------------- + // ---------------- Periodic send to server ---------------- +if (deviceCount > 0 && sendIntervalMinutes > 0) { + if (lastSendMillis == 0) lastSendMillis = millis(); + + if ((millis() - lastSendMillis) >= sendIntervalMinutes * 60000UL) { + Serial.println("[DEBUG] Entering send block"); + Serial.print("[DEBUG] WiFi.status: "); Serial.println(WiFi.status()); + + if (WiFi.status() == WL_CONNECTED) { + // Prepare JSON payload + String payload = "["; + for (int i = 0; i < deviceCount; i++) { + if (i) payload += ","; + RemoteData d = lastRemoteData[i]; + payload += "{\"device\":\"" + d.deviceId + "\",\"soil\":" + String(d.soil) + + ",\"gas\":" + String(d.gas) + ",\"temp\":" + String(d.temp) + + ",\"hum\":" + String(d.hum) + ",\"time\":\"" + d.timestamp + "\"}"; + } + payload += "]"; + + // Use WiFiClientSecure for HTTPS + WiFiClientSecure client; + client.setInsecure(); // SSL certificate not verified + HTTPClient http; + + // Use URL with www if nabaksoft.ir ریدایرکت می‌کند + String url = "https://www.nabaksoft.ir/greenhome/mygreenhome.php?aid="+PRIVATE_KEY+"&data=" + payload; + + http.begin(client, url); + http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); // Follow redirects automatically + + Serial.println("[HTTP] Sending data to server..."); + int httpCode = http.GET(); + + if (httpCode > 0) { + Serial.printf("[HTTP] Response code: %d\n", httpCode); + String resp = http.getString(); + Serial.printf("[HTTP] Server response: %s\n", resp.c_str()); + } else { + Serial.printf("[HTTP] Send failed, error: %s\n", http.errorToString(httpCode).c_str()); + } + + http.end(); + } else { + Serial.println("[HTTP] WiFi not connected, skipping send"); + } + + lastSendMillis = millis(); + } +} + //دریافت کننده فعال است؟ + // setLed(1, rtcReady, strip.Color(0,255,0), strip.Color(255,0,0)); + // //کارتخوان فعال است؟ + // setLed(2, sdReady, strip.Color(0,255,0), strip.Color(255,0,0)); + // //wifi فعال است؟ + // setLed(3, wifiEnabled, strip.Color(0,255,0), strip.Color(0,0,0)); + // //مودم فعال است یا خیر و اگر فعال است متصل است؟ + // if(staSSID.length()>0) + // setLed(4, ConnectToModem, strip.Color(0,255,0), strip.Color(255,0,0)); + // else + // setLed(4, true, strip.Color(0,0,0), strip.Color(0,0,0)); + + // strip.show(); +} + diff --git a/old/nodmcu1/nodmcu1.ino b/old/nodmcu1/nodmcu1.ino new file mode 100644 index 0000000..921744d --- /dev/null +++ b/old/nodmcu1/nodmcu1.ino @@ -0,0 +1,716 @@ +// Clean, full sketch for ESP8266 (NodeMCU) +// - RCSwitch receiver on D5 +// - RTC DS3231 on I2C (SDA=D2, SCL=D1) +// - Optional SD on CS = D8 (GPIO15) +// - Always prints received RF data to Serial +// - Saves to SD every N minutes if SD present +// - Cleans files older than M days every 12 hours +// - getPageID(...) returns numeric page id; switch-case used + +#include +#include +#include "RTClib.h" +#include +#include +#include +#include +// ---------------- CONFIG ---------------- +const char* ssid = "ESP8266_AP"; +const char* password = "12345678"; +WiFiServer server(80); + +// ---------------- HW ---------------- +#define LED_PIN 1 // TX = GPIO1 +#define NUM_LEDS 8 + +Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800); + +RTC_DS3231 rtc; +bool rtcReady = false; + +RCSwitch rx; // RCSwitch for RXB45 +const uint8_t RX_PIN = D1; + +#define SD_CS_PIN D8 // safe for boot (GPIO15) + +const int buttonPin = 16; // D0 + + + +bool sdReady = false; +const char* CONFIG_FILE = "config.txt"; +bool wifiEnabled = true; // وضعیت WiFi +bool buttonPressed = false; // وضعیت فشار داده شده +int lastButtonState = HIGH; +unsigned long lastDebounceTime = 0; +const unsigned long debounceDelay = 50; // 200ms برای حذف لرزش +// ---------------- Protocol & storage ---------------- +const String PRIVATE_KEY = "as23f"; // shared key +const String ALLOWED_DEVICES[] = {"dr142","abcde","fghij"}; +const int NUM_ALLOWED = 3; + +#define MAX_DEVICES 16 +struct DeviceData { + String deviceId; + int soil; + int gas; + float temp; + float hum; + String timestamp; +}; +DeviceData lastRemoteData[MAX_DEVICES]; +int deviceCount = 0; + +// RX frame parsing (same logic as earlier RCSwitch-based receiver) +String receivedKey = ""; +String receivedHex = ""; +bool receivingPublicKey = true; +int receivedChars = 0; +unsigned long lastReceiveTime = 0; +const unsigned long FRAME_TIMEOUT_MS = 500; +const int EXPECTED_PLAIN_LEN = 25; + +// ---------------- Settings (default) ---------------- +unsigned long saveIntervalMinutes = 5; // minutes (configurable) +int retentionDays = 90; // days (configurable) + +unsigned long lastSaveMillis = 0; +unsigned long lastCleanupMillis = 0; + +// ---------------- Helpers ---------------- +bool isHexChar(char c) { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); +} + +bool isDeviceAllowed(const String &id) { + for (int i=0;i= 8 && isDigit(name[0])) { + int y = name.substring(0,4).toInt(); + int m = name.substring(4,6).toInt(); + int d = name.substring(6,8).toInt(); + if (y > 2000 && m>=1 && m<=12 && d>=1 && d<=31) { + DateTime fileDate(y,m,d,0,0,0); + TimeSpan diff = now - fileDate; + if (diff.days() > retentionDays) { + SD.remove(name); + } + } + } + } + entry.close(); + entry = root.openNextFile(); + } + root.close(); +} + +// ---------------- Remote receiver (RCSwitch pulses) ---------------- +void processRemote() { + bool rxa=rx.available(); + //Serial.println("rxa:"+rxa); + if (rxa) { + unsigned long value = rx.getReceivedValue(); + unsigned int bitlen = rx.getReceivedBitlength(); + + // debug to ensure we see raw values + // Serial.print(F("[DEBUG] got value=")); + // Serial.print(value); + // Serial.print(F(" bits=")); + // Serial.println(bitlen); + + if (bitlen == 8) { + char c = (char)value; + if (receivingPublicKey) { + if (receivedKey.length() < 5) receivedKey += c; + if (receivedKey.length() == 5) { + receivingPublicKey = false; + Serial.println(F("[DEBUG] public key received -> switching to HEX")); + } + } else { + if (isHexChar(c)) receivedHex += c; + else { + // noise + Serial.print(F("[DEBUG] ignored non-hex char: 0x")); + Serial.println((int)(uint8_t)c, HEX); + } + } + receivedChars++; + lastReceiveTime = millis(); + } + + rx.resetAvailable(); + } + + // when frame timeout -> process + if (receivedChars >= 5 && (millis() - lastReceiveTime) > FRAME_TIMEOUT_MS) { + Serial.println(F("[DEBUG] frame timeout -> processing...")); + + if (receivedKey != PRIVATE_KEY) { + Serial.println(F("[WARN] key mismatch")); + resetFrame(); return; + } + if ((receivedHex.length() % 2) != 0) { + Serial.println(F("[WARN] odd hex length")); + resetFrame(); return; + } + + // hex -> bytes + String decoded; decoded.reserve(receivedHex.length()/2); + for (int i=0; i+1 < receivedHex.length(); i+=2) { + char hex2[3] = { receivedHex[i], receivedHex[i+1], '\0' }; + char b = (char) strtol(hex2, NULL, 16); + decoded += b; + } + + if (decoded.length() != EXPECTED_PLAIN_LEN) { + Serial.print(F("[WARN] decoded length != expected: ")); + Serial.println(decoded.length()); + resetFrame(); return; + } + + String plain = decryptData(decoded, PRIVATE_KEY); + // check format markers (positions 5,10,15,20 should be S,G,T,H) + if (plain.length() != EXPECTED_PLAIN_LEN || + plain[5] != 'S' || plain[10] != 'G' || plain[15] != 'T' || plain[20] != 'H') { + Serial.println(F("[WARN] format check failed")); + resetFrame(); return; + } + + String deviceId = plain.substring(0,5); + if (!isDeviceAllowed(deviceId)) { + Serial.print(F("[WARN] device not allowed: ")); Serial.println(deviceId); + resetFrame(); return; + } + + // parse values + int soil = plain.substring(6,10).toInt(); + int gas = plain.substring(11,15).toInt(); + float temp = plain.substring(16,20).toInt() / 10.0; + float hum = plain.substring(21,25).toInt() / 10.0; + + String ts; + if (rtcReady) ts = dateTimeToISO(rtc.now()); + else ts = String(millis()); + + // PRINT ALWAYS + Serial.print(F("[RX] device=")); Serial.print(deviceId); + Serial.print(F(" soil=")); Serial.print(soil); + Serial.print(F(" gas=")); Serial.print(gas); + Serial.print(F(" temp=")); Serial.print(temp); + Serial.print(F(" hum=")); Serial.print(hum); + Serial.print(F(" time=")); Serial.println(ts); + + // update array (replace if exists else append) + bool updated = false; + for (int i=0;i= (saveIntervalMinutes * 60000UL)) { + if (sdReady) { + // prepare JSON line + String j = "{\"device\":\"" + deviceId + "\",\"soil\":" + String(soil) + + ",\"gas\":" + String(gas) + ",\"temp\":" + String(temp) + + ",\"hum\":" + String(hum) + ",\"time\":\"" + ts + "\"}"; + appendDataToSD(j); + Serial.println(F("[INFO] appended to SD")); + } else { + Serial.println(F("[INFO] SD not ready, skipped save")); + } + lastSaveMillis = millis(); + } + + resetFrame(); + } +} + +// ---------------- Page mapping to integer (user requested) ---------------- +int getPageID(const String &page) { + if (page == "info") return 1; + if (page == "sensor") return 2; + if (page == "time") return 3; + if (page == "settime") return 4; + if (page == "lastremote") return 5; + if (page == "readfile") return 6; + if (page == "files") return 7; + if (page == "format") return 8; + if (page == "set_save_interval") return 9; + if (page == "set_retention_days") return 10; + if (page == "sd_status") return 11; + return 0; +} + +// URL-decode (simple) +String urlDecode(const String &input) { + String s = input; + s.replace("+", " "); + for (int i = 0; i + 2 < s.length(); ++i) { + if (s[i] == '%') { + String hx = s.substring(i+1, i+3); + char c = (char) strtol(hx.c_str(), NULL, 16); + s = s.substring(0,i) + String(c) + s.substring(i+3); + } + } + return s; +} + +String getParamFromPath(const String &path, const String &key) { + int q = path.indexOf('?'); + if (q == -1) return ""; + String qstr = path.substring(q+1); + int start = 0; + while (start < qstr.length()) { + int amp = qstr.indexOf('&', start); + if (amp == -1) amp = qstr.length(); + int eq = qstr.indexOf('=', start); + if (eq != -1 && eq < amp) { + String k = qstr.substring(start, eq); + String v = qstr.substring(eq+1, amp); + if (k == key) return urlDecode(v); + } + start = amp + 1; + } + return ""; +} + +// ---------------- HTTP handler ---------------- +void handleClient(WiFiClient &client) { + String req = ""; + unsigned long start = millis(); + while (client.connected() && millis() - start < 1500) { + while (client.available()) { + char c = client.read(); + req += c; + if (req.endsWith("\r\n\r\n")) break; + } + if (req.endsWith("\r\n\r\n")) break; + } + if (req.length() == 0) return; + + int lineEnd = req.indexOf("\r\n"); + String firstLine = (lineEnd == -1) ? req : req.substring(0, lineEnd); + Serial.print(F("[HTTP] ")); Serial.println(firstLine); + + // extract path, e.g. GET /?page=info HTTP/1.1 + String path = ""; + int sp1 = firstLine.indexOf(' '); + int sp2 = firstLine.indexOf(" HTTP/"); + if (sp1 != -1 && sp2 != -1) path = firstLine.substring(sp1+1, sp2); + + String page = getParamFromPath(path, "page"); + int pid = getPageID(page); + String response = ""; + + switch (pid) { + case 1: // info + response = "{\"status\":\"ok\",\"data\":\"ESP ready\"}"; + break; + case 2: // sensor (A0) + response = "{\"status\":\"ok\",\"sensor\":" + String(analogRead(A0)) + "}"; + break; + case 3: // time + if (!rtcReady) response = "{\"status\":\"error\",\"message\":\"RTC not ready\"}"; + else response = "{\"status\":\"ok\",\"datetime\":\"" + dateTimeToISO(rtc.now()) + "\"}"; + break; + case 4: { // settime (iso) + String iso = getParamFromPath(path, "iso"); + if (!rtcReady) { response = "{\"status\":\"error\",\"message\":\"RTC not ready\"}"; break; } + if (iso.length() >= 19) { + int y=iso.substring(0,4).toInt(), m=iso.substring(5,7).toInt(), d=iso.substring(8,10).toInt(); + int hh=iso.substring(11,13).toInt(), mm=iso.substring(14,16).toInt(), ss=iso.substring(17,19).toInt(); + rtc.adjust(DateTime(y,m,d,hh,mm,ss)); + response = "{\"status\":\"ok\",\"datetime\":\"" + dateTimeToISO(rtc.now()) + "\"}"; + } else response = "{\"status\":\"error\",\"message\":\"invalid iso\"}"; + break; + } + case 5: { // lastremote + String arr = "["; + for (int i=0;i 0) { + content.remove(content.length() - 3); + } + f.close(); + response = "{\"status\":\"ok\",\"content\":[" + content + "]}"; + + break; + } + case 7: { // files + if (!sdReady) { response = "{\"status\":\"error\",\"message\":\"SD not ready\"}"; break; } + File root = SD.open("/"); + String arr = "["; + bool first = true; + File entry = root.openNextFile(); + while (entry) { + String name = entry.name(); + if (name.length() && name[0] == '/') name = name.substring(1); + if (!first) arr += ","; + arr += "\"" + name + "\""; + first = false; + entry.close(); + entry = root.openNextFile(); + } + root.close(); + arr += "]"; + response = "{\"status\":\"ok\",\"files\":" + arr + "}"; + break; + } + case 8: { // format (remove all files except config) + if (!sdReady) { response = "{\"status\":\"error\",\"message\":\"SD not ready\"}"; break; } + File root = SD.open("/"); + File entry = root.openNextFile(); + while (entry) { + String name = entry.name(); + if (name.length() && name[0] == '/') name = name.substring(1); + if (name != String(CONFIG_FILE) && !entry.isDirectory()) SD.remove(name); + entry.close(); + entry = root.openNextFile(); + } + root.close(); + response = "{\"status\":\"ok\",\"message\":\"formatted (config preserved)\"}"; + break; + } + case 9: { // set_save_interval?min=NUM + String v = getParamFromPath(path, "min"); + int m = v.toInt(); + if (m <= 0) response = "{\"status\":\"error\",\"message\":\"invalid min\"}"; + else { + saveIntervalMinutes = (unsigned long)m; + if (sdReady) saveConfigToSD(); + response = "{\"status\":\"ok\",\"save_interval_minutes\":" + String(m) + "}"; + } + break; + } + case 10: { // set_retention_days?days=NUM + String v = getParamFromPath(path, "days"); + int d = v.toInt(); + if (d <= 0) response = "{\"status\":\"error\",\"message\":\"invalid days\"}"; + else { + retentionDays = d; + if (sdReady) saveConfigToSD(); + response = "{\"status\":\"ok\",\"retention_days\":" + String(d) + "}"; + } + break; + } + case 11: { // sd_status + if (!sdReady) response = "{\"status\":\"error\",\"message\":\"SD not ready\"}"; + else + { + uint64_t used = computeSDUsedBytes(); + //total/free not reliably available via SD.h on ESP8266 + response = "{\"status\":\"ok\",\"used_bytes\":" + String((unsigned long)used) + "}"; + } + break; + } + default: + if (page.length() == 0) response = "{\"status\":\"error\",\"message\":\"missing page\"}"; + else response = "{\"status\":\"error\",\"message\":\"unknown page\"}"; + break; + } + + client.println(F("HTTP/1.1 200 OK")); + client.println(F("Content-Type: application/json")); + client.print(F("Content-Length: ")); + client.println(response.length()); + client.println(F("Connection: close")); + client.println(); + client.println(response); + delay(5); + client.stop(); + Serial.println(F("[HTTP] client disconnected")); +} + +// ---------------- Setup & Loop ---------------- +void setup() { + Serial.begin(115200); + delay(2000); + + //led + strip.begin(); + strip.show(); + + //چراغ اول روشن شود. یعنی دستگاه روشن است + setLed(0, true, strip.Color(0,255,0), strip.Color(0,0,0)); + + + pinMode(buttonPin, INPUT_PULLUP); // کلید به GND وصل میشه + + Wire.begin(D2, D3); + rtcReady = rtc.begin(); + if (!rtcReady) Serial.println(F("RTC not found")); + else if (rtc.lostPower()) { + Serial.println(F("RTC lost power — setting to compile time")); + rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); + } + + // RCSwitch init + rx.enableReceive(digitalPinToInterrupt(RX_PIN)); // use interrupt on D1 + rx.setProtocol(1); + rx.setPulseLength(300); + Serial.println(F("[INFO] RCSwitch receiver enabled on D5")); + + // SD init + sdReady = SD.begin(SD_CS_PIN); + if (sdReady) { + Serial.println("[INFO] SD ready"); + //loadConfigFromSD(); + } else { + Serial.println("[WARN] SD init failed — will continue without SD"); + } + + // WiFi AP + server + //WiFi.softAP(ssid, password); + //server.begin(); + if (wifiEnabled) { + WiFi.softAP(ssid, password); + server.begin(); + Serial.print(F("AP: ")); Serial.println(ssid); + Serial.print(F("IP: ")); Serial.println(WiFi.softAPIP()); + } + lastSaveMillis = millis(); + lastCleanupMillis = millis(); +} + +void loop() { + int reading = digitalRead(buttonPin); + + if (reading != lastButtonState) { + lastDebounceTime = millis(); + } + + if ((millis() - lastDebounceTime) > debounceDelay) { + // تشخیص لبه فشار واقعی (HIGH → LOW) + if (reading == LOW && !buttonPressed) { + buttonPressed = true; // علامتگذاری فشار داده شده + wifiEnabled = !wifiEnabled; // تغییر وضعیت AP + + if (wifiEnabled) { + WiFi.mode(WIFI_AP_STA); + WiFi.softAP("ESP-Server", "12345678"); + Serial.println("✅ سرور (AP) فعال شد"); + Serial.print("IP سرور: "); + Serial.println(WiFi.softAPIP()); + } else { + WiFi.softAPdisconnect(true); + WiFi.mode(WIFI_STA); + Serial.println("❌ سرور (AP) غیرفعال شد"); + } + } + + // وقتی دکمه رها شد، آماده فشار بعدی + if (reading == HIGH) { + buttonPressed = false; + } + } + + lastButtonState = reading; +// int buttonState = digitalRead(buttonPin); +// if (buttonState == LOW && (millis() - lastDebounceTime) > debounceDelay) { +// lastDebounceTime = millis(); + +// wifiEnabled = !wifiEnabled; // تغییر وضعیت سرور + +// if (wifiEnabled) { +// WiFi.mode(WIFI_AP_STA); // مودم + AP +// WiFi.softAP("ESP-Server", "12345678"); // روشن کردن سرور +// Serial.println("✅ سرور (AP) فعال شد"); +// Serial.print("IP سرور: "); +// Serial.println(WiFi.softAPIP()); +// } else { +// WiFi.softAPdisconnect(true); // خاموش کردن AP +// WiFi.mode(WIFI_STA); // فقط مودم +// Serial.println("❌ سرور (AP) غیرفعال شد"); +// } +// } + + if (wifiEnabled) { + WiFiClient client = server.available(); + if (client) handleClient(client); + } + + processRemote(); + + // WiFiClient client = server.available(); + //if (client) handleClient(client); + + // periodic cleanup every 12 hours + if ((millis() - lastCleanupMillis) >= (12UL * 60UL * 60UL * 1000UL)) { + //cleanupOldFilesOnSD(); + lastCleanupMillis = millis(); + } + //---------------leds--------------------------------- + //دریافت کننده فعال است؟ + setLed(0, rtcReady, strip.Color(0,255,0), strip.Color(255,0,0)); + //کارتخوان فعال است؟ + setLed(0, sdReady, strip.Color(0,255,0), strip.Color(255,0,0)); + //wifi فعال است؟ + setLed(0, wifiEnabled, strip.Color(0,255,0), strip.Color(0,0,0)); + //مودم فعال است یا خیر و اگر فعال است متصل است؟ + setLed(0, wifiEnabled, strip.Color(0,255,0), strip.Color(0,0,0)); + + //---------------leds--------------------------------- +} \ No newline at end of file diff --git a/old/nodmcu2/nodmcu2.ino b/old/nodmcu2/nodmcu2.ino new file mode 100644 index 0000000..2ba5197 --- /dev/null +++ b/old/nodmcu2/nodmcu2.ino @@ -0,0 +1,928 @@ +// Clean, full sketch for ESP8266 (NodeMCU) +// - RCSwitch receiver on D5 +// - RTC DS3231 on I2C (SDA=D2, SCL=D1) +// - Optional SD on CS = D8 (GPIO15) +// - Always prints received RF data to Serial +// - Saves to SD every N minutes if SD present +// - Cleans files older than M days every 12 hours +// - getPageID(...) returns numeric page id; switch-case used +// - STA + periodic sending to server +// - API to set STA & send interval + +#include +#include +#include "RTClib.h" +#include +#include +#include +#include +#include +#include +#include + + +// ---------------- CONFIG ---------------- +String apSSID = "ESP8266_AP"; +String apPassword = "12345678"; +WiFiServer server(80); + +// ---------------- HW ---------------- +RTC_DS3231 rtc; +bool rtcReady = false; + +RCSwitch rx; +const uint8_t RX_PIN = D1; + +//-------------------------------------led---------------------------------- +#define LED_PIN 2 +#define NUM_LEDS 8 +uint32_t lastLedState[NUM_LEDS] = {0}; +// uint8_t currentLedIndex = 0; // LED فعلی برای ارسال +// bool ledUpdateNeeded = false; +uint32_t targetColors[NUM_LEDS]; // رنگ‌های هدف +Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800); +uint32_t On_color = strip.Color(0,255,127); +uint32_t off_color = strip.Color(0, 0, 0); +//uint32_t off_color = strip.Color(210, 105, 30); +uint32_t false_color = strip.Color(255, 255, 0); +uint32_t Ok_color = strip.Color(0,255,127); +uint32_t Red_color = strip.Color(255,0,0); +//----------------------------------------------------------------------- + + +#define SD_CS_PIN D8 +bool sdReady = false; +const char* CONFIG_FILE = "config.txt"; + +const int buttonPin = 16; // D0 +bool wifiEnabled = true; +bool StartConnectToModem = false; +bool buttonPressed = false; +int lastButtonState = HIGH; +unsigned long lastDebounceTime = 0; +const unsigned long debounceDelay = 50; + +// ---------------- Protocol & storage ---------------- +const String PRIVATE_KEY = "as23f"; +const String device_1 = "dr142"; +const String device_2 = "dv154"; + +uint8_t device1_recived=0; +uint8_t device2_recived=0; +//bool device2_recived=false; + +const String ALLOWED_DEVICES[] = {device_1,device_2}; +const int NUM_ALLOWED = 2; + +#define MAX_DEVICES 16 +struct DeviceData { + String deviceId; + int soil; + int gas; + float temp; + float hum; + String timestamp; +}; +DeviceData lastRemoteData[MAX_DEVICES]; +int deviceCount = 0; + +// RX frame parsing +String receivedKey = ""; +String receivedHex = ""; +bool receivingPublicKey = true; +int receivedChars = 0; +unsigned long lastReceiveTime = 0; +const unsigned long FRAME_TIMEOUT_MS = 500; +const int EXPECTED_PLAIN_LEN = 25; + +// ---------------- Settings (default) ---------------- +unsigned long saveIntervalMinutes = 5; +int retentionDays = 90; +unsigned long lastSaveMillis = 0; +unsigned long lastCleanupMillis = 0; +unsigned long lastCheckDevice = 0; + + +// ---------------- WiFi client (STA) ---------------- +String staSSID = ""; +String staPassword = ""; +unsigned long lastSendMillis = 0; +unsigned long sendIntervalMinutes = 1; // پیش فرض + +// ---------------- Helpers ---------------- +bool isHexChar(char c) { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); +} + +bool isDeviceAllowed(const String &id) { + for (int i=0;i= 8 && isDigit(name[0])) { + int y = name.substring(0,4).toInt(); + int m = name.substring(4,6).toInt(); + int d = name.substring(6,8).toInt(); + if (y > 2000 && m>=1 && m<=12 && d>=1 && d<=31) { + DateTime fileDate(y,m,d,0,0,0); + TimeSpan diff = now - fileDate; + if (diff.days() > retentionDays) SD.remove(name); + } + } + } + entry.close(); + entry = root.openNextFile(); + } + root.close(); +} + +// ---------------- Remote receiver ---------------- +void processRemote() { + if (rx.available()) { + unsigned long value = rx.getReceivedValue(); + unsigned int bitlen = rx.getReceivedBitlength(); + if (bitlen == 8) { + char c = (char)value; + if (receivingPublicKey) { + if (receivedKey.length() < 5) receivedKey += c; + if (receivedKey.length() == 5) receivingPublicKey = false; + } else { + if (isHexChar(c)) receivedHex += c; + } + receivedChars++; + lastReceiveTime = millis(); + } + rx.resetAvailable(); + } + + if (receivedChars >= 5 && (millis() - lastReceiveTime) > FRAME_TIMEOUT_MS) { + if (receivedKey != PRIVATE_KEY || (receivedHex.length() % 2) != 0) { resetFrame(); return; } + + String decoded; decoded.reserve(receivedHex.length()/2); + for (int i=0; i+1= saveIntervalMinutes*60000UL) { + if (sdReady) { + String j="{\"device\":\""+deviceId+"\",\"soil\":"+String(soil)+",\"gas\":"+String(gas)+ + ",\"temp\":"+String(temp)+",\"hum\":"+String(hum)+",\"time\":\""+ts+"\"}"; + appendDataToSD(j); + Serial.println("[INFO] appended to SD"); + } + lastSaveMillis=millis(); + } + + resetFrame(); + } +} + +// ---------------- Page mapping ---------------- +int getPageID(const String &page) { + if (page == "info") return 1; + if (page == "sensor") return 2; + if (page == "time") return 3; + if (page == "settime") return 4; + if (page == "lastremote") return 5; + if (page == "readfile") return 6; + if (page == "files") return 7; + if (page == "format") return 8; + if (page == "set_save_interval") return 9; + if (page == "set_retention_days") return 10; + if (page == "sd_status") return 11; + return 0; +} + +String urlDecode(const String &input) { + String s = input; + s.replace("+", " "); + for (int i = 0; i + 2 < s.length(); ++i) { + if (s[i] == '%') { + String hx = s.substring(i+1, i+3); + char c = (char) strtol(hx.c_str(), NULL, 16); + s = s.substring(0,i) + String(c) + s.substring(i+3); + } + } + return s; +} + +String getParamFromPath(const String &path, const String &key) { + int q = path.indexOf('?'); + if (q == -1) return ""; + String qstr = path.substring(q+1); + int start = 0; + while (start < qstr.length()) { + int amp = qstr.indexOf('&', start); + if (amp == -1) amp = qstr.length(); + int eq = qstr.indexOf('=', start); + if (eq != -1 && eq < amp) { + String k = qstr.substring(start, eq); + String v = qstr.substring(eq+1, amp); + if (k == key) return urlDecode(v); + } + start = amp + 1; + } + return ""; +} + +// ---------------- HTTP handler ---------------- +void handleClient() { + if (!wifiEnabled) + return; + WiFiClient client = server.available(); + if (!client) + return; + String req = ""; + unsigned long start = millis(); + while (client.connected() && millis() - start < 1500) { + while (client.available()) { + char c = client.read(); + req += c; + if (req.endsWith("\r\n\r\n")) break; + } + if (req.endsWith("\r\n\r\n")) break; + } + if (req.length() == 0) return; + + int lineEnd = req.indexOf("\r\n"); + String firstLine = (lineEnd == -1) ? req : req.substring(0, lineEnd); + Serial.print("[HTTP] "); Serial.println(firstLine); + + String path = ""; + int sp1 = firstLine.indexOf(' '); + int sp2 = firstLine.indexOf(" HTTP/"); + if (sp1 != -1 && sp2 != -1) path = firstLine.substring(sp1+1, sp2); + + String page = getParamFromPath(path,"page"); + String response=""; + + // --- API: set STA --- + if(page=="set_sta") { + String ssid = getParamFromPath(path,"ssid"); + String pass = getParamFromPath(path,"pass"); + if(ssid.length()>0) { + staSSID=ssid; staPassword=pass; + StartConnectToModem=WiFi.begin(staSSID.c_str(),staPassword.c_str()); + if(sdReady) saveConfigToSD(); + response="{\"status\":\"ok\",\"message\":\"STA updated, connecting...\"}"; + } else response="{\"status\":\"error\",\"message\":\"SSID missing\"}"; + client.println(F("HTTP/1.1 200 OK")); + client.println(F("Content-Type: application/json")); + client.print(F("Content-Length: ")); client.println(response.length()); + client.println(F("Connection: close")); client.println(); + client.println(response); + client.stop(); + return; + } + + // --- API: set send interval --- + if(page=="set_send_interval") { + String v = getParamFromPath(path,"minutes"); + int m=v.toInt(); + if(m>0) { + sendIntervalMinutes=m; + if(sdReady) saveConfigToSD(); + response="{\"status\":\"ok\",\"send_interval_minutes\":"+String(m)+"}"; + } else response="{\"status\":\"error\",\"message\":\"invalid minutes\"}"; + client.println(F("HTTP/1.1 200 OK")); + client.println(F("Content-Type: application/json")); + client.print(F("Content-Length: ")); client.println(response.length()); + client.println(F("Connection: close")); client.println(); + client.println(response); + client.stop(); + return; + } + + // --- old page switch --- + int pid = getPageID(page); + switch(pid) { + case 1: + response="{\"status\":\"ok\",\"data\":\"ESP ready,StartConnectToModem:"+String(StartConnectToModem)+",wifiEnabled:"+String(wifiEnabled)+"\"}"; break; + case 2: response="{\"status\":\"ok\",\"sensor\":"+String(analogRead(A0))+"}"; break; + case 3: response=rtcReady?"{\"status\":\"ok\",\"data\":\""+dateTimeToISO(rtc.now())+"\"}":"{\"status\":\"error\",\"message\":\"RTC not ready\"}"; break; + case 4: { + String iso=getParamFromPath(path,"iso"); + if(!rtcReady){ response="{\"status\":\"error\",\"message\":\"RTC not ready\"}"; break; } + if(iso.length()>=19){ + int y=iso.substring(0,4).toInt(), m=iso.substring(5,7).toInt(), d=iso.substring(8,10).toInt(); + int hh=iso.substring(11,13).toInt(), mm=iso.substring(14,16).toInt(), ss=iso.substring(17,19).toInt(); + rtc.adjust(DateTime(y,m,d,hh,mm,ss)); + response="{\"status\":\"ok\",\"data\":\""+dateTimeToISO(rtc.now())+"\"}"; + } else response="{\"status\":\"error\",\"message\":\"invalid iso\"}"; + break; + } + case 5: { + String arr="["; + for(int i=0;i 0) { + content.remove(content.length() - 3); + } + f.close(); + response = "{\"status\":\"ok\",\"content\":[" + content + "]}"; + + break; + } + case 7: { // files + if (!sdReady) { response = "{\"status\":\"error\",\"message\":\"SD not ready\"}"; break; } + File root = SD.open("/"); + String arr = "["; + bool first = true; + File entry = root.openNextFile(); + while (entry) { + String name = entry.name(); + if (name.length() && name[0] == '/') name = name.substring(1); + if (!first) arr += ","; + arr += "\"" + name + "\""; + first = false; + entry.close(); + entry = root.openNextFile(); + } + root.close(); + arr += "]"; + response = "{\"status\":\"ok\",\"files\":" + arr + "}"; + break; + } + case 8: { // format (remove all files except config) + if (!sdReady) { response = "{\"status\":\"error\",\"message\":\"SD not ready\"}"; break; } + File root = SD.open("/"); + File entry = root.openNextFile(); + while (entry) { + String name = entry.name(); + if (name.length() && name[0] == '/') name = name.substring(1); + if (name != String(CONFIG_FILE) && !entry.isDirectory()) SD.remove(name); + entry.close(); + entry = root.openNextFile(); + } + root.close(); + response = "{\"status\":\"ok\",\"message\":\"formatted (config preserved)\"}"; + break; + } + case 9: { // set_save_interval?min=NUM + String v = getParamFromPath(path, "min"); + int m = v.toInt(); + if (m <= 0) response = "{\"status\":\"error\",\"message\":\"invalid min\"}"; + else { + saveIntervalMinutes = (unsigned long)m; + if (sdReady) saveConfigToSD(); + response = "{\"status\":\"ok\",\"save_interval_minutes\":" + String(m) + "}"; + } + break; + } + case 10: { // set_retention_days?days=NUM + String v = getParamFromPath(path, "days"); + int d = v.toInt(); + if (d <= 0) response = "{\"status\":\"error\",\"message\":\"invalid days\"}"; + else { + retentionDays = d; + if (sdReady) saveConfigToSD(); + response = "{\"status\":\"ok\",\"retention_days\":" + String(d) + "}"; + } + break; + } + case 11: { // sd_status + if (!sdReady) response = "{\"status\":\"error\",\"message\":\"SD not ready\"}"; + else + { + uint64_t used = computeSDUsedBytes(); + //total/free not reliably available via SD.h on ESP8266 + response = "{\"status\":\"ok\",\"used_bytes\":" + String((unsigned long)used) + "}"; + } + break; + } + default: response = page.length()==0?"{\"status\":\"error\",\"message\":\"missing page\"}":"{\"status\":\"error\",\"message\":\"unknown page\"}"; break; + } + + client.println(F("HTTP/1.1 200 OK")); + client.println(F("Content-Type: application/json")); + client.print(F("Content-Length: ")); client.println(response.length()); + client.println(F("Connection: close")); + client.println(); + client.println(response); + delay(5); + client.stop(); + Serial.println("[HTTP] client disconnected"); +} + +time_t parseTimestamp(String ts) { + int year = ts.substring(0, 4).toInt(); + int month = ts.substring(5, 7).toInt(); + int day = ts.substring(8, 10).toInt(); + int hour = ts.substring(11, 13).toInt(); + int min = ts.substring(14, 16).toInt(); + int sec = ts.substring(17, 19).toInt(); + + tmElements_t tm; + tm.Year = year - 1970; + tm.Month = month; + tm.Day = day; + tm.Hour = hour; + tm.Minute = min; + tm.Second = sec; + + return makeTime(tm); +} +void checkDeviceData() { + time_t now = rtc.now().unixtime(); + int device1Index=-1; + int device2Index=-1; + for (int i = 0; i < MAX_DEVICES; i++) + { + if(i 0) { + time_t t = parseTimestamp(lastRemoteData[i].timestamp); + long diff = now - t; // اختلاف زمان به ثانیه + + if (diff < 60) { + device1_recived=2; + Serial.println(lastRemoteData[i].deviceId + " updated less than 60 seconds ago"); + } else { + device1_recived=1; + Serial.println(lastRemoteData[i].deviceId + "--- updated more than 60 seconds ago"); + } + } + else{ + device1_recived=1; + Serial.println(lastRemoteData[i].deviceId + "--- noDataRecive updated more than 60 seconds ago"); + } + } + if(device2Index==-1) + { + device2_recived=0;//دریافتی از دستگاه 2 نداشتیم + Serial.println(device_2 + " not exist"); + } + else + { + int i=device2Index; + if (lastRemoteData[i].timestamp.length() > 0) { + time_t t = parseTimestamp(lastRemoteData[i].timestamp); + long diff = now - t; // اختلاف زمان به ثانیه + + if (diff < 60) { + device2_recived=2; + Serial.println(lastRemoteData[i].deviceId + " updated less than 60 seconds ago"); + } else { + device2_recived=1; + Serial.println(lastRemoteData[i].deviceId + "--- updated more than 60 seconds ago"); + } + } + else{ + device1_recived=1; + Serial.println(lastRemoteData[i].deviceId + "--- noDataRecive updated more than 60 seconds ago"); + } + } +} +void setLed(uint8_t idx, bool condition, uint32_t colorTrue, uint32_t colorFalse) { + if (condition) { + strip.setPixelColor(idx, colorTrue); + } else { + strip.setPixelColor(idx, colorFalse); + } +} +// ---------------- Setup & Loop ---------------- +void startEsp() +{ + +} +void setup() { + + Serial.begin(115200); delay(100); + +//--------------------------------Start Led--------------------------------------------------------- + strip.begin(); + strip.show(); + + //چراغ اول روشن شود. یعنی دستگاه روشن است + //setLed(0, true, On_color, On_color); + //strip.show(); +//----------------------------------------------------------------------------------------- +//-------------------------------------Button Config---------------------------------------------------- + pinMode(buttonPin, INPUT_PULLUP); +//----------------------------------------------------------------------------------------- +//------------------------------------Start Clock----------------------------------------------------- + Wire.begin(D2,D3); + rtcReady=rtc.begin(); + if(rtcReady && rtc.lostPower()) rtc.adjust(DateTime(F(__DATE__),F(__TIME__))); +//----------------------------------------------------------------------------------------- + +//--------------------------------------Start Sdk--------------------------------------------------- + rx.enableReceive(digitalPinToInterrupt(RX_PIN)); + rx.setProtocol(1); + rx.setPulseLength(300); + Serial.println("[INFO] RCSwitch enabled on D1"); +//----------------------------------------------------------------------------------------- +//-----------------------------------------Start SD Card------------------------------------------------ + sdReady=SD.begin(SD_CS_PIN); + if(sdReady){ Serial.println("[INFO] SD ready"); loadConfigFromSD(); } + else Serial.println("[WARN] SD init failed"); +//----------------------------------------------------------------------------------------- +//-----------------------------------Start ESP------------------------------------------------------ + if(wifiEnabled){ WiFi.softAP(apSSID,apPassword,6); server.begin(); Serial.print("AP IP: "); Serial.println(WiFi.softAPIP()); } + + if(staSSID.length()>0){ StartConnectToModem=WiFi.begin(staSSID.c_str(),staPassword.c_str()); } +//----------------------------------------------------------------------------------------- + + lastSaveMillis=millis(); lastCleanupMillis=millis(); lastSendMillis=millis();lastCheckDevice=millis(); +} +void CheckWifiBtn() +{ +// ---------------- Button handling (toggle AP) ---------------- + int reading = digitalRead(buttonPin); + if (reading != lastButtonState) lastDebounceTime = millis(); + + if ((millis() - lastDebounceTime) > debounceDelay) { + if (reading == LOW && !buttonPressed) { + buttonPressed = true; + wifiEnabled = !wifiEnabled; + + if (wifiEnabled) { + WiFi.mode(WIFI_AP_STA); + WiFi.softAP(apSSID, apPassword,6); + server.begin(); + Serial.println("✅ AP enabled"); + Serial.print("IP: "); Serial.println(WiFi.softAPIP()); + } else { + WiFi.softAPdisconnect(true); + WiFi.mode(WIFI_STA); + Serial.println("❌ AP disabled"); + } + } + + if (reading == HIGH) buttonPressed = false; + } + lastButtonState = reading; +} +void SendDataToServer() +{ + if (deviceCount > 0 && sendIntervalMinutes > 0) { + if (lastSendMillis == 0) lastSendMillis = millis(); + + if ((millis() - lastSendMillis) >= sendIntervalMinutes * 60000UL) { + Serial.println("[DEBUG] Entering send block"); + Serial.print("[DEBUG] WiFi.status: "); Serial.println(WiFi.status()); + if (WiFi.status() == WL_CONNECTED) { + // Prepare JSON payload + String payload = "["; + for (int i = 0; i < deviceCount; i++) { + if (i) payload += ","; + DeviceData &d = lastRemoteData[i]; + payload += "{\"device\":\"" + d.deviceId + "\",\"soil\":" + String(d.soil) + + ",\"gas\":" + String(d.gas) + ",\"temp\":" + String(d.temp) + + ",\"hum\":" + String(d.hum) + ",\"time\":\"" + d.timestamp + "\"}"; + } + payload += "]"; + + // Use WiFiClientSecure for HTTPS + WiFiClientSecure client; + client.setInsecure(); // SSL certificate not verified + HTTPClient http; + + // Use URL with www if nabaksoft.ir ریدایرکت می‌کند + String url = "https://www.nabaksoft.ir/greenhome/mygreenhome.php?aid="+PRIVATE_KEY+"&data=" + payload; + + http.begin(client, url); + http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); // Follow redirects automatically + + Serial.println("[HTTP] Sending data to server..."); + int httpCode = http.GET(); + + if (httpCode > 0) { + Serial.printf("[HTTP] Response code: %d\n", httpCode); + String resp = http.getString(); + Serial.printf("[HTTP] Server response: %s\n", resp.c_str()); + } else { + Serial.printf("[HTTP] Send failed, error: %s\n", http.errorToString(httpCode).c_str()); + } + + http.end(); + } else { + Serial.println("[HTTP] WiFi not connected, skipping send"); + } + lastSendMillis = millis(); + } + } +} +void SetLedStates() +{ + //دریافت کننده فعال است؟ + /*setLed(1, rtcReady, Ok_color, off_color); + //کارتخوان فعال است؟ + setLed(2, sdReady, Ok_color, off_color); + //wifi فعال است؟ + setLed(3, wifiEnabled, Ok_color, off_color); + //مودم فعال است یا خیر و اگر فعال است متصل است؟ + if(staSSID.length()>0) + { + //اگر رمز دارد پس باید متصل بشه.اگر شده که سبز. اگر نشده قرمز + setLed(4, WiFi.status()==WL_CONNECTED, Ok_color, false_color); + } + else + setLed(4, true, off_color, off_color); + + setLed(5, true, off_color, off_color); + setLed(6, true, off_color, off_color); + setLed(7, true, off_color, off_color); + //شدت روشنایی + strip.setBrightness(20); + strip.show();*/ + int32_t colors[NUM_LEDS]; + colors[0] = On_color; // دستگاه روشن + colors[1] = rtcReady ? Ok_color : off_color; // وضعیت RTC + colors[2] = sdReady ? Ok_color : off_color; // وضعیت SD + colors[3] = wifiEnabled ? Ok_color : off_color; // وضعیت AP + colors[4] = (staSSID.length() > 0 && WiFi.status() == WL_CONNECTED) ? Ok_color : false_color; // STA + + colors[5] = (device1_recived==2)?Ok_color:(device1_recived==1?false_color:Red_color); + colors[6] = (device2_recived == 2)?Ok_color:(device2_recived==1?false_color:Red_color); + colors[7] = off_color; + + // بررسی اینکه آیا تغییری نسبت به وضعیت قبلی وجود دارد + bool changed = false; + for (int i = 0; i < NUM_LEDS; i++) { + if (colors[i] != lastLedState[i]) { + lastLedState[i] = colors[i]; + strip.setPixelColor(i, colors[i]); + changed = true; + } + } + + // فقط وقتی تغییر بوده، strip.show() اجرا شود + if (changed) { + strip.setBrightness(20); + strip.show(); // این تابع اکنون به حداقل فراخوانی کاهش یافته + } +} +void loop() { + + CheckWifiBtn(); + + // ---------------- HTTP server handling ---------------- + handleClient(); + + // ---------------- Process RF data ---------------- + processRemote(); + + //---------------- Periodic cleanup every 12 hours ---------------- + if ((millis() - lastCleanupMillis) >= (12UL * 60UL * 60UL * 1000UL)) { + cleanupOldFilesOnSD(); + lastCleanupMillis = millis(); + } +//هر یک دقیقه چک کنه وضعیت دو فرستنده چطور هست +if ((millis() - lastCheckDevice) >= (60UL * 1000UL)) { + checkDeviceData(); + lastCheckDevice = millis(); + } + + + // ---------------- Periodic send to server ---------------- + SendDataToServer(); + + SetLedStates(); +} + + +// if (wifiEnabled) { +// WiFiClient client = server.available(); +// if (client) handleClient(client); +// } \ No newline at end of file diff --git a/old/reciver01/reciver01.ino b/old/reciver01/reciver01.ino new file mode 100644 index 0000000..f4e72a0 --- /dev/null +++ b/old/reciver01/reciver01.ino @@ -0,0 +1,196 @@ +#include + +RCSwitch rx = RCSwitch(); + +// باید با فرستنده یکسان باشد +const String PRIVATE_KEY = "as23f"; + +// دستگاه‌های مجاز +const String ALLOWED_DEVICES[] = {"dr142", "abcde", "fghij"}; +const int NUM_ALLOWED_DEVICES = 3; + +// بافرهای دریافت +String receivedKey = ""; +String receivedHex = ""; + +// کنترل فریم +bool receivingPublicKey = true; +int receivedChars = 0; +unsigned long lastReceiveTime = 0; +const unsigned long TIMEOUT_MS = 500; + +// طول متن اصلی انتظار می‌رود 25 باشد +const int EXPECTED_PLAIN_LEN = 25; + +// XOR ساده +String decryptData(const String &data, const String &key) { + String out; + out.reserve(data.length()); + for (int i = 0; i < data.length(); i++) { + out += (char)(data[i] ^ key[i % key.length()]); + } + return out; +} + +bool isDeviceAllowed(const String &deviceId) { + for (int i = 0; i < NUM_ALLOWED_DEVICES; i++) { + if (deviceId == ALLOWED_DEVICES[i]) return true; + } + return false; +} + +static inline bool isHexChar(char c) { + return (c >= '0' && c <= '9') || + (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f'); +} + +void resetFrame() { + receivedKey = ""; + receivedHex = ""; + receivingPublicKey = true; + receivedChars = 0; +} + +void setup() { + Serial.begin(9600); + + rx.enableReceive(0); // interrupt 0 → پایه 2 در آردوینو UNO + rx.setProtocol(1); + rx.setPulseLength(300); + + resetFrame(); + + Serial.println(F("=== Receiver Started ===")); + Serial.print(F("Private Key: ")); Serial.println(PRIVATE_KEY); + Serial.print(F("Allowed IDs: ")); + for (int i = 0; i < NUM_ALLOWED_DEVICES; i++) { Serial.print(ALLOWED_DEVICES[i]); Serial.print(' '); } + Serial.println(); +} + +void loop() { + if (rx.available()) { + unsigned long value = rx.getReceivedValue(); + unsigned int bitlen = rx.getReceivedBitlength(); + + if (bitlen == 8) { + char c = (char)value; + + if (receivingPublicKey) { + if (receivedKey.length() < 5) { + receivedKey += c; + //Serial.print(F("Received key char: ")); Serial.println(c); + receivedChars++; + if (receivedKey.length() == 5) { + receivingPublicKey = false; + Serial.println(F("Now receiving encrypted HEX data...")); + } + } + } else { + // فقط کاراکتر HEX معتبر ذخیره شود + if (isHexChar(c)) { + receivedHex += c; + //Serial.print(F("Received HEX char: ")); Serial.println(c); + receivedChars++; + } else { + // نویز را رد کن + Serial.print(F("Ignored non-HEX char: 0x")); + Serial.println((int)(uint8_t)c, HEX); + } + } + + lastReceiveTime = millis(); + } + + rx.resetAvailable(); + } + + // اگر وقفه افتاد، پردازش کن + if (receivedChars >= 5 && (millis() - lastReceiveTime) > TIMEOUT_MS) { + Serial.println(F("=== Processing Data ===")); + Serial.print(F("Received Public Key: ")); Serial.println(receivedKey); + + if (receivedKey != PRIVATE_KEY) { + Serial.println(F("Key verification: FAILED")); + resetFrame(); + return; + } + Serial.println(F("Key verification: SUCCESS")); + + // طول HEX باید زوج باشد (هر دو کاراکتر → یک بایت) + if ((receivedHex.length() % 2) != 0) { + Serial.print(F("Odd HEX length: ")); Serial.println(receivedHex.length()); + resetFrame(); + return; + } + + // تبدیل HEX → بایت‌ها + String decoded; decoded.reserve(receivedHex.length() / 2); + for (int i = 0; i + 1 < receivedHex.length(); i += 2) { + char hex2[3] = { receivedHex[i], receivedHex[i+1], '\0' }; + char b = (char) strtol(hex2, NULL, 16); + decoded += b; + } + + Serial.print(F("Decoded length: ")); Serial.println(decoded.length()); + Serial.print(F("Decoded (raw XORed) bytes: ")); + for (int i = 0; i < decoded.length(); i++) { + Serial.print((int)(uint8_t)decoded[i]); Serial.print(' '); + } + Serial.println(); + + // باید دقیقاً به طول 25 بایت باشد + if (decoded.length() != EXPECTED_PLAIN_LEN) { + Serial.println(F("Unexpected decoded length (should be 25).")); + resetFrame(); + return; + } + + // رمزگشایی + String plain = decryptData(decoded, PRIVATE_KEY); + Serial.print(F("Decrypted Data: ")); Serial.println(plain); + + // اعتبارسنجی قالب + if (plain.length() != EXPECTED_PLAIN_LEN || + plain[5] != 'S' || plain[10] != 'G' || + plain[15] != 'T' || plain[20] != 'H') { + Serial.println(F("Format check failed.")); + resetFrame(); + return; + } + + String deviceId = plain.substring(0, 5); + Serial.print(F("Device ID: ")); Serial.println(deviceId); + + if (!isDeviceAllowed(deviceId)) { + Serial.println(F("Device authorization: FAILED")); + resetFrame(); + return; + } + + Serial.println(F("Device authorization: SUCCESS")); + + // پارس مقادیر + String sSoil = plain.substring(6, 10); // بین S و G + String sGas = plain.substring(11, 15); // بین G و T + String sTemp = plain.substring(16, 20); // بین T و H + String sHum = plain.substring(21, 25); // بعد از H + + int soilMoisture = sSoil.toInt(); + int gasValue = sGas.toInt(); + float temperature = sTemp.toInt() / 10.0; + float humidity = sHum.toInt() / 10.0; + + Serial.println(F("=== Authorized Data ===")); + Serial.print(F("Soil Moisture: ")); Serial.print(soilMoisture); + Serial.print(F(" - Gas Value : ")); Serial.print(gasValue); + Serial.print(F(" - Temperature : ")); Serial.print(temperature); Serial.print(F(" C")); + Serial.print(F(" - Humidity : ")); Serial.print(humidity); Serial.println(F(" %")); + Serial.println(F("=======================")); + + // آماده دریافت بعدی + resetFrame(); + } + + delay(5); +} diff --git a/old/sender01/sender01.ino b/old/sender01/sender01.ino new file mode 100644 index 0000000..cb0edb3 --- /dev/null +++ b/old/sender01/sender01.ino @@ -0,0 +1,165 @@ +#include +#include + +// پین‌ها +#define DHTPIN 2 +#define DHTTYPE DHT11 +#define SOIL_MOISTURE_PIN A3 +#define GAS_SENSOR_PIN A2 +#define RF_TRANSMIT_PIN 9 + +const float RL = 10.0; // مقاومت Load روی ماژول (کیلو اهم) +float R0 = 50; // بعد از کالیبراسیون مقدار واقعی جایگزین کنید +// متن ثابت و کلیدها + +const String PUBLIC_KEY = "as23f"; +const String DEVICE_ID = "dr142"; + +// اشیاء +DHT dht(DHTPIN, DHTTYPE); +RCSwitch tx = RCSwitch(); + +// زمان‌بندی +unsigned long lastSendTime = 0; +const unsigned long sendInterval = 10000; + +// تاخیر بین ارسال هر کاراکتر (ms) +const unsigned int INTER_CHAR_DELAY_MS = 1; + +// XOR ساده +String encryptData(const String &data, const String &key) { + String out; + out.reserve(data.length()); + for (int i = 0; i < data.length(); i++) { + out += (char)(data[i] ^ key[i % key.length()]); + } + return out; +} + +static inline void sendChar(uint8_t c) { + tx.send((unsigned long)c, 8); + delay(INTER_CHAR_DELAY_MS); +} + +static inline void sendHexByte(uint8_t b) { + char hex[3]; + sprintf(hex, "%02X", b); // حروف بزرگ + sendChar(hex[0]); + sendChar(hex[1]); +} + +void setup() { + Serial.begin(9600); + dht.begin(); + + tx.enableTransmit(RF_TRANSMIT_PIN); + tx.setProtocol(1); + tx.setPulseLength(300); + tx.setRepeatTransmit(3); + + Serial.println(F("=== Transmitter Started ===")); + Serial.print(F("Public Key: ")); Serial.println(PUBLIC_KEY); + Serial.print(F("Device ID : ")); Serial.println(DEVICE_ID); +} +int getSoilMoistureInt() { + int adcValue = analogRead(SOIL_MOISTURE_PIN); + // مقادیر کالیبراسیون: خاک خشک و خاک خیس + const int adcDry = 1023; // خاک کاملاً خشک + const int adcWet = 400; // خاک کاملاً خیس + + // محاسبه درصد رطوبت با یک رقم اعشار + float soilPercent = (float)(adcDry - adcValue) / (adcDry - adcWet) * 100.0; + + // محدود کردن بین 0 تا 100 + if (soilPercent > 100.0) soilPercent = 100.0; + if (soilPercent < 0.0) soilPercent = 0.0; + + // ضرب در 10 و تبدیل به عدد صحیح + int soilInt = (int)(soilPercent * 10 + 0.5); // +0.5 برای گرد کردن صحیح + return soilInt; +} + +int readGas() { + long sum = 0; + for (int i = 0; i < 5; i++) { + sum += analogRead(GAS_SENSOR_PIN); + delay(10); + } + float adcValue = sum / 5.0; // میانگین ADC + + float vrl = (adcValue / 1023.0) * 5.0; // ولتاژ خروجی + if (vrl < 0.001) vrl = 0.001; // جلوگیری از تقسیم بر صفر + + float Rs = (5.0 - vrl) * RL / vrl; // مقاومت سنسور (kΩ) + float ratio = Rs / R0; // نسبت Rs/R0 + + // ثابت‌های تقریبی از دیتاشیت MQ7 (CO curve) + float m = -0.77; + float b = 0.36; + + float ppm_log = (log10(ratio) - b) / m; + int ppm = round(pow(10, ppm_log)); + + return ppm; // خروجی اعشاری +} +void loop() { + // خواندن سنسورها + float temperature = dht.readTemperature(); + float humidity = dht.readHumidity(); + int soilMoisture = getSoilMoistureInt(); + int gasValue = readGas(); //analogRead(GAS_SENSOR_PIN); + + if (isnan(temperature) || isnan(humidity)) { + temperature = 0; humidity = 0; + } + + soilMoisture = constrain(soilMoisture, 0, 9999); + gasValue = constrain(gasValue, 0, 9999);//1023 + int tempInt = constrain((int)(temperature * 10), 0, 9999); // چهار رقمی + int humidityInt = constrain((int)(humidity * 10), 0, 9999); // چهار رقمی + + // ⚠️ خیلی مهم: ۲۶ بایت برای نَل ترمینیتور + char dataString[26]; + // قالب دقیقاً 25 کاراکتر تولید می‌کند: 5 + (S####) + (G####) + (T####) + (H####) + // 5 + 1+4 + 1+4 + 1+4 + 1+4 = 25 + int n = snprintf( + dataString, sizeof(dataString), + "%sS%04dG%04dT%04dH%04d", + DEVICE_ID.c_str(), soilMoisture, gasValue, tempInt, humidityInt + ); + + // اگر بنا به هر دلیلی طول غیرمنتظره شد، همین‌جا خروج + if (n != 25) { + Serial.print(F("Format length unexpected: ")); Serial.println(n); + delay(500); + return; + } + + String plain = String(dataString); + String enc = encryptData(plain, PUBLIC_KEY); + + if (millis() - lastSendTime >= sendInterval) { + Serial.println(F("=== Data to Send ===")); + Serial.print(F("Original: ")); Serial.println(plain); + Serial.print(F("Length : ")); Serial.println(plain.length()); + + // 1) ارسال 5 کاراکتر کلید عمومی + for (int i = 0; i < PUBLIC_KEY.length(); i++) { + sendChar((uint8_t)PUBLIC_KEY[i]); + } + + // 2) ارسال دیتای رمز شده به صورت HEX (هر بایت → دو کاراکتر) + Serial.print(F("Encrypted HEX: ")); + for (int i = 0; i < enc.length(); i++) { + uint8_t b = (uint8_t)enc[i]; + char hex[3]; sprintf(hex, "%02X", b); + Serial.print(hex); Serial.print(' '); + sendHexByte(b); + } + Serial.println(); + + lastSendTime = millis(); + } + + delay(100); +} diff --git a/old/sender02/sender02.ino b/old/sender02/sender02.ino new file mode 100644 index 0000000..5b208ac --- /dev/null +++ b/old/sender02/sender02.ino @@ -0,0 +1,132 @@ +#include +#include + +// پین‌ها +#define DHTPIN 2 +#define DHTTYPE DHT11 +#define SOIL_MOISTURE_PIN A3 +#define GAS_SENSOR_PIN A2 +#define RF_TRANSMIT_PIN 9 + +// متن ثابت و کلیدها +const String PUBLIC_KEY = "as23f"; +const String DEVICE_ID = "dr142"; + +// اشیاء +DHT dht(DHTPIN, DHTTYPE); +RCSwitch tx = RCSwitch(); + +// زمان‌بندی +unsigned long lastSendTime = 0; +const unsigned long sendInterval = 5000; + +// تاخیر بین ارسال هر کاراکتر (ms) +const unsigned int INTER_CHAR_DELAY_MS = 15; + +// شمارهٔ بسته (در صورت نیاز بعداً) +uint8_t seqNumber = 0; + +// XOR ساده +String encryptData(const String &data, const String &key) { + String out; + out.reserve(data.length()); + for (int i = 0; i < data.length(); i++) { + out += (char)(data[i] ^ key[i % key.length()]); + } + return out; +} + +static inline void sendChar(uint8_t c) { + tx.send((unsigned long)c, 8); + delay(INTER_CHAR_DELAY_MS); +} + +void setup() { + Serial.begin(9600); + dht.begin(); + + tx.enableTransmit(RF_TRANSMIT_PIN); + tx.setProtocol(1); + tx.setPulseLength(300); + tx.setRepeatTransmit(3); // کتابخانه هر بایت را 3 بار تکرار می‌کند + + Serial.println(F("=== Transmitter Started (with 1-byte checksum) ===")); + Serial.print(F("Public Key: ")); Serial.println(PUBLIC_KEY); + Serial.print(F("Device ID : ")); Serial.println(DEVICE_ID); + + randomSeed(analogRead(0)); // برای ایجاد تاخیر تصادفی احتمالی +} + +void loop() { + // خواندن سنسورها + float temperature = dht.readTemperature(); + float humidity = dht.readHumidity(); + int soilMoisture = analogRead(SOIL_MOISTURE_PIN); + int gasValue = analogRead(GAS_SENSOR_PIN); + + if (isnan(temperature) || isnan(humidity)) { + temperature = 0; humidity = 0; + } + + soilMoisture = constrain(soilMoisture, 0, 1023); + gasValue = constrain(gasValue, 0, 1023); + int tempInt = constrain((int)(temperature * 10), 0, 9999); // چهار رقمی + int humidityInt = constrain((int)(humidity * 10), 0, 9999); // چهار رقمی + + // قالب دقیقاً 25 کاراکتر تولید می‌کند: 5 + (S####) + (G####) + (T####) + (H####) + char dataString[26]; + int n = snprintf( + dataString, sizeof(dataString), + "%sS%04dG%04dT%04dH%04d", + DEVICE_ID.c_str(), soilMoisture, gasValue, tempInt, humidityInt + ); + + if (n != 25) { + Serial.print(F("Format length unexpected: ")); Serial.println(n); + delay(500); + return; + } + + String plain = String(dataString); + String enc = encryptData(plain, PUBLIC_KEY); // length 25, may contain non-printables + + if (millis() - lastSendTime >= sendInterval) { + Serial.println(F("=== Data to Send ===")); + Serial.print(F("Plain : ")); Serial.println(plain); + Serial.print(F("Enc : ")); + for (int i = 0; i < enc.length(); i++) { + uint8_t b = (uint8_t)enc[i]; + if (b < 0x10) Serial.print('0'); + Serial.print(b, HEX); Serial.print(' '); + } + Serial.println(); + + // ساخت packet: [PUBLIC_KEY(5)] + [ENC(25)] + [CHK(1)] => مجموع 31 بایت + const int PACKET_LEN = 31; + uint8_t packet[PACKET_LEN]; + + // PUBLIC_KEY (5 bytes) + for (int i = 0; i < 5; i++) packet[i] = (uint8_t)PUBLIC_KEY[i]; + + // ENC (25 bytes) + for (int i = 0; i < 25; i++) packet[5 + i] = (uint8_t)enc[i]; + + // محاسبه چک‌سام ساده (sum of bytes 0..29) & 0xFF + uint16_t sum = 0; + for (int i = 0; i < 30; i++) sum += packet[i]; + packet[30] = (uint8_t)(sum & 0xFF); + + // ارسال تمام بایت‌ها متوالی (فقط یک بار، بدون حلقهٔ 3تایی دستی) + for (int i = 0; i < PACKET_LEN; i++) { + sendChar(packet[i]); + } + + Serial.print(F("Checksum sent: 0x")); + if (packet[30] < 0x10) Serial.print('0'); + Serial.println(packet[30], HEX); + + lastSendTime = millis(); + } + + delay(100); +} diff --git a/old/stm32f103_2/stm32f103_2.ino b/old/stm32f103_2/stm32f103_2.ino new file mode 100644 index 0000000..3dcdfa4 --- /dev/null +++ b/old/stm32f103_2/stm32f103_2.ino @@ -0,0 +1,307 @@ +#include +#include +#include +#include +#include + +// ==================== پین‌ها ==================== +#define SOIL_MOISTURE_PIN PA1 +#define DHT11_PIN PA0 +#define SHT31_SCL PB6 +#define SHT31_SDA PB7 +#define OLED_SCL PB10 +#define OLED_SDA PB11 + +// ==================== OLED ==================== +#define SCREEN_WIDTH 128 +#define SCREEN_HEIGHT 64 +#define OLED_ADDRESS 0x3C + +TwoWire Wire2(OLED_SDA, OLED_SCL); +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire2, -1); + +// ==================== سنسورها ==================== +#define SHT31_ADDRESS 0x44 +Adafruit_SHT31 sht31(&Wire); +#define DHTTYPE DHT11 +DHT dht(DHT11_PIN, DHTTYPE); + +// ==================== کالیبراسیون ==================== +#define SOIL_WET_VALUE 520 +#define SOIL_DRY_VALUE 800 + +// ==================== متغیرها ==================== +int soilMoisturePercent = 0; +float dht11_temp = 0, dht11_humidity = 0; +float sht31_temp = 0, sht31_humidity = 0; +bool sht31Found = false; +unsigned long lastRead = 0; + +// ==================== تنظیمات نمایش ==================== +#define LARGE_FONT_SIZE 2 // فونت بزرگ برای اعداد +#define SMALL_FONT_SIZE 1 // فونت کوچک برای متن + +void setup() { + Serial1.begin(115200); + delay(100); + + Serial1.println("========================================"); + Serial1.println("STM32F103 - Three Sensor System"); + Serial1.println("========================================"); + + // I2C1 برای SHT31 + Wire.setSDA(SHT31_SDA); + Wire.setSCL(SHT31_SCL); + Wire.begin(); + + // I2C2 برای OLED + Wire2.begin(); + Wire2.setClock(400000); + + // سنسورها + pinMode(SOIL_MOISTURE_PIN, INPUT_ANALOG); + dht.begin(); + + // OLED + if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) { + Serial1.println("OLED initialization failed!"); + while (1); + } + + Serial1.println("OLED initialized successfully"); + + // SHT31 + sht31Found = sht31.begin(SHT31_ADDRESS); + if (!sht31Found) { + sht31Found = sht31.begin(0x45); // تست آدرس دیگر + } + + if (sht31Found) { + Serial1.println("SHT31 found!"); + } else { + Serial1.println("SHT31 not found!"); + } + + displayStartup(); +} + +void loop() { + if (millis() - lastRead >= 2000) { + lastRead = millis(); + readSensors(); + updateDisplay(); + printSerial(); + } + delay(100); +} + +void readSensors() { + // خاک - میانگین‌گیری برای دقت بیشتر + long soilSum = 0; + for (int i = 0; i < 5; i++) { + soilSum += analogRead(SOIL_MOISTURE_PIN); + delay(1); + } + int soilRaw = soilSum / 5; + + if (soilRaw <= SOIL_WET_VALUE) { + soilMoisturePercent = 100; + } else if (soilRaw >= SOIL_DRY_VALUE) { + soilMoisturePercent = 0; + } else { + soilMoisturePercent = map(soilRaw, SOIL_DRY_VALUE, SOIL_WET_VALUE, 0, 100); + } + soilMoisturePercent = constrain(soilMoisturePercent, 0, 100); + + // DHT11 + dht11_temp = dht.readTemperature(); + dht11_humidity = dht.readHumidity(); + if (isnan(dht11_temp) || isnan(dht11_humidity)) { + dht11_temp = dht11_humidity = -999; + } + + // SHT31 + if (sht31Found) { + sht31_temp = sht31.readTemperature(); + sht31_humidity = sht31.readHumidity(); + if (isnan(sht31_temp) || isnan(sht31_humidity)) { + sht31_temp = sht31_humidity = -999; + } + } +} + +void updateDisplay() { + display.clearDisplay(); + display.setTextColor(SSD1306_WHITE); + + // ==================== خط اول: خاک ==================== + // عنوان خاک + display.setTextSize(SMALL_FONT_SIZE); + display.setCursor(0, 0); + display.print("Soil:"); + + // مقدار خاک (بزرگ) + display.setTextSize(LARGE_FONT_SIZE); + if (soilMoisturePercent < 10) { + display.setCursor(35, 0); + } else if (soilMoisturePercent < 100) { + display.setCursor(25, 0); + } else { + display.setCursor(15, 0); + } + display.print(soilMoisturePercent); + + // علامت درصد + display.setTextSize(SMALL_FONT_SIZE); + display.print("%"); + + // ==================== خط دوم: DHT11 ==================== + // عنوان DHT11 + display.setTextSize(SMALL_FONT_SIZE); + display.setCursor(0, 20); + display.print("DHT:"); + + // دما DHT (بزرگ) + display.setTextSize(LARGE_FONT_SIZE); + if (dht11_temp != -999) { + if (dht11_temp >= 0 && dht11_temp < 10) { + display.setCursor(40, 20); + } else if (dht11_temp >= 10 && dht11_temp < 100) { + display.setCursor(30, 20); + } else { + display.setCursor(20, 20); + } + display.print(dht11_temp, 1); + } else { + display.setCursor(40, 20); + display.print("---"); + } + + // درجه سانتیگراد + display.setTextSize(SMALL_FONT_SIZE); + display.print("C"); + + // رطوبت DHT (بزرگ) + display.setTextSize(LARGE_FONT_SIZE); + display.setCursor(80, 20); + if (dht11_humidity != -999) { + if (dht11_humidity < 10) { + display.setCursor(85, 20); + } else if (dht11_humidity < 100) { + display.setCursor(80, 20); + } else { + display.setCursor(75, 20); + } + display.print(dht11_humidity, 0); + } else { + display.print("---"); + } + + // علامت درصد + display.setTextSize(SMALL_FONT_SIZE); + display.print("%"); + + // ==================== خط سوم: SHT31 ==================== + // عنوان SHT31 + display.setTextSize(SMALL_FONT_SIZE); + display.setCursor(0, 40); + display.print("SHT:"); + + // دما SHT (بزرگ) + display.setTextSize(LARGE_FONT_SIZE); + if (sht31Found && sht31_temp != -999) { + if (sht31_temp >= 0 && sht31_temp < 10) { + display.setCursor(40, 40); + } else if (sht31_temp >= 10 && sht31_temp < 100) { + display.setCursor(30, 40); + } else { + display.setCursor(20, 40); + } + display.print(sht31_temp, 1); + } else { + display.setCursor(40, 40); + display.print("---"); + } + + // درجه سانتیگراد + display.setTextSize(SMALL_FONT_SIZE); + display.print("C"); + + // رطوبت SHT (بزرگ) + display.setTextSize(LARGE_FONT_SIZE); + if (sht31Found && sht31_humidity != -999) { + if (sht31_humidity < 10) { + display.setCursor(85, 40); + } else if (sht31_humidity < 100) { + display.setCursor(80, 40); + } else { + display.setCursor(75, 40); + } + display.print(sht31_humidity, 0); + } else { + display.setCursor(80, 40); + display.print("---"); + } + + // علامت درصد + display.setTextSize(SMALL_FONT_SIZE); + display.print("%"); + + // ==================== خط جداساز ==================== + display.drawFastHLine(0, 15, 128, SSD1306_WHITE); // بین خاک و DHT + display.drawFastHLine(0, 35, 128, SSD1306_WHITE); // بین DHT و SHT + + display.display(); +} + +void printSerial() { + Serial1.print("Time: "); + Serial1.print(millis() / 1000); + Serial1.print("s | "); + + Serial1.print("Soil: "); + Serial1.print(soilMoisturePercent); + Serial1.print("% | "); + + Serial1.print("DHT: "); + if (dht11_temp != -999) { + Serial1.print(dht11_temp, 1); + Serial1.print("C "); + Serial1.print(dht11_humidity, 0); + Serial1.print("%"); + } else { + Serial1.print("---"); + } + + Serial1.print(" | "); + + Serial1.print("SHT: "); + if (sht31Found && sht31_temp != -999) { + Serial1.print(sht31_temp, 1); + Serial1.print("C "); + Serial1.print(sht31_humidity, 0); + Serial1.print("%"); + } else { + Serial1.print("---"); + } + + Serial1.println(); +} + +void displayStartup() { + display.clearDisplay(); + + // نمایش عنوان + display.setTextSize(LARGE_FONT_SIZE); + display.setCursor(15, 10); + display.println("SENSOR"); + display.setCursor(20, 30); + display.println("SYSTEM"); + + display.setTextSize(SMALL_FONT_SIZE); + display.setCursor(40, 50); + display.println("READY"); + + display.display(); + delay(1500); +} \ No newline at end of file diff --git a/old/test1/test1.ino b/old/test1/test1.ino new file mode 100644 index 0000000..93a651c --- /dev/null +++ b/old/test1/test1.ino @@ -0,0 +1,123 @@ +#include +#include + +// پین‌ها +#define DHTPIN 2 +#define DHTTYPE DHT11 +#define SOIL_MOISTURE_PIN A0 +#define GAS_SENSOR_PIN A1 +#define RF_TRANSMIT_PIN 9 + +// متن ثابت و کلیدها + +const String PUBLIC_KEY = "as23f"; +const String DEVICE_ID = "dr142"; + +// اشیاء +DHT dht(DHTPIN, DHTTYPE); +RCSwitch tx = RCSwitch(); + +// زمان‌بندی +unsigned long lastSendTime = 0; +const unsigned long sendInterval = 5000; + +// تاخیر بین ارسال هر کاراکتر (ms) +const unsigned int INTER_CHAR_DELAY_MS = 15; + +// XOR ساده +String encryptData(const String &data, const String &key) { + String out; + out.reserve(data.length()); + for (int i = 0; i < data.length(); i++) { + out += (char)(data[i] ^ key[i % key.length()]); + } + return out; +} + +static inline void sendChar(uint8_t c) { + tx.send((unsigned long)c, 8); + delay(INTER_CHAR_DELAY_MS); +} + +static inline void sendHexByte(uint8_t b) { + char hex[3]; + sprintf(hex, "%02X", b); // حروف بزرگ + sendChar(hex[0]); + sendChar(hex[1]); +} + +void setup() { + Serial.begin(9600); + dht.begin(); + + tx.enableTransmit(RF_TRANSMIT_PIN); + tx.setProtocol(1); + tx.setPulseLength(300); + tx.setRepeatTransmit(3); + + Serial.println(F("=== Transmitter Started ===")); + Serial.print(F("Public Key: ")); Serial.println(PUBLIC_KEY); + Serial.print(F("Device ID : ")); Serial.println(DEVICE_ID); +} + +void loop() { + // خواندن سنسورها + float temperature = dht.readTemperature(); + float humidity = dht.readHumidity(); + int soilMoisture = analogRead(SOIL_MOISTURE_PIN); + int gasValue = analogRead(GAS_SENSOR_PIN); + + if (isnan(temperature) || isnan(humidity)) { + temperature = 0; humidity = 0; + } + + soilMoisture = constrain(soilMoisture, 0, 1023); + gasValue = constrain(gasValue, 0, 1023); + int tempInt = constrain((int)(temperature * 10), 0, 9999); // چهار رقمی + int humidityInt = constrain((int)(humidity * 10), 0, 9999); // چهار رقمی + + // ⚠️ خیلی مهم: ۲۶ بایت برای نَل ترمینیتور + char dataString[26]; + // قالب دقیقاً 25 کاراکتر تولید می‌کند: 5 + (S####) + (G####) + (T####) + (H####) + // 5 + 1+4 + 1+4 + 1+4 + 1+4 = 25 + int n = snprintf( + dataString, sizeof(dataString), + "%sS%04dG%04dT%04dH%04d", + DEVICE_ID.c_str(), soilMoisture, gasValue, tempInt, humidityInt + ); + + // اگر بنا به هر دلیلی طول غیرمنتظره شد، همین‌جا خروج + if (n != 25) { + Serial.print(F("Format length unexpected: ")); Serial.println(n); + delay(500); + return; + } + + String plain = String(dataString); + String enc = encryptData(plain, PUBLIC_KEY); + + if (millis() - lastSendTime >= sendInterval) { + Serial.println(F("=== Data to Send ===")); + Serial.print(F("Original: ")); Serial.println(plain); + Serial.print(F("Length : ")); Serial.println(plain.length()); + + // 1) ارسال 5 کاراکتر کلید عمومی + for (int i = 0; i < PUBLIC_KEY.length(); i++) { + sendChar((uint8_t)PUBLIC_KEY[i]); + } + + // 2) ارسال دیتای رمز شده به صورت HEX (هر بایت → دو کاراکتر) + Serial.print(F("Encrypted HEX: ")); + for (int i = 0; i < enc.length(); i++) { + uint8_t b = (uint8_t)enc[i]; + char hex[3]; sprintf(hex, "%02X", b); + Serial.print(hex); Serial.print(' '); + sendHexByte(b); + } + Serial.println(); + + lastSendTime = millis(); + } + + delay(100); +} diff --git a/old/test2/test2.ino b/old/test2/test2.ino new file mode 100644 index 0000000..66a6d77 --- /dev/null +++ b/old/test2/test2.ino @@ -0,0 +1,148 @@ +#include +#define RX_PIN D3 // RX NodeMCU -> TX M66 +#define TX_PIN D4 // TX NodeMCU -> RX M66 + +SoftwareSerial M66(RX_PIN, TX_PIN); + +const String url = "http://amlakmodaberan.ir/1.html"; +// ========================= +// Timeout ها +// ========================= +const unsigned long AT_TIMEOUT = 15000; +const unsigned long HTTP_TIMEOUT = 30000; + +// ========================= +// ارسال دستور AT با انتظار پاسخ +// ========================= +bool sendAT(String cmd, String expected = "OK", unsigned long timeout = AT_TIMEOUT) { + Serial.print("[TX] "); Serial.println(cmd); + + while (M66.available()) M66.read(); // پاکسازی بافر + + M66.println(cmd); + + unsigned long start = millis(); + String response = ""; + + while (millis() - start < timeout) { + yield(); + while (M66.available()) { + char c = M66.read(); + response += c; + Serial.write(c); + + if (response.indexOf(expected) != -1) return true; + if (response.indexOf("ERROR") != -1 || response.indexOf("+CME ERROR") != -1) { + Serial.println("❌ Command failed"); + return false; + } + } + } + + Serial.println("⏱ Timeout waiting for response"); + return false; +} + +// ========================= +// راه‌اندازی GPRS و HTTP با QIREGAPP +// ========================= +bool initGPRS() { + Serial.println("=== Initializing GPRS ==="); + delay(2000); + + sendAT("ATE0"); + sendAT("AT+CMEE=2"); + sendAT("AT+CFUN=1"); + delay(2000); + + if (!sendAT("AT+CPIN?", "READY")) return false; + + // شبکه ثبت شده + for (int i = 0; i < 10; i++) { + if (sendAT("AT+CREG?", "+CREG: 0,1")) break; + delay(2000); + } + + if (!sendAT("AT+CGATT=1")) return false; + delay(5000); + + // reset context + sendAT("AT+QIFGCNT=0"); + + if (!sendAT("AT+QICSGP=1,\"mcinet\",\"\",\"\"")) return false; + + // فعال کردن QIREGAPP به جای QIACT + if (!sendAT("AT+QIREGAPP", "OK", 30000)) return false; + + // بررسی IP state + sendAT("AT+QISTAT", "STATE: IP GPRSACT"); + + // پیکربندی HTTP + sendAT("AT+QHTTPCFG=\"contextid\",1"); + sendAT("AT+QHTTPCFG=\"responseheader\",1"); + sendAT("AT+QHTTPCFG=\"timeout\",30000"); + sendAT("AT+QHTTPCFG=\"requestheader\",1"); + + Serial.println("✅ GPRS ready!"); + return true; +} + +// ========================= +// ارسال HTTP GET +// ========================= +bool sendHTTPRequest() { + Serial.println("=== Sending HTTP Request ==="); + + int len = url.length(); + + if (!sendAT("AT+QHTTPURL=" + String(len) + ",60", "CONNECT", 15000)) { + Serial.println("❌ URL setup failed"); + return false; + } + + M66.print(url); + delay(200); + M66.write(0x1A); // Ctrl+Z + delay(1500); + + if (!sendAT("AT+QHTTPGET=80", "OK", HTTP_TIMEOUT)) { + Serial.println("❌ HTTP GET failed"); + return false; + } + + if (!sendAT("AT+QHTTPREAD", "+QHTTPREAD:", HTTP_TIMEOUT)) { + Serial.println("⚠️ No HTTP response body"); + return false; + } + + Serial.println("✅ HTTP request done!"); + return true; +} + +// ========================= +// setup +// ========================= +void setup() { + Serial.begin(115200); + M66.begin(9600); + delay(2000); + + int retry = 0; + while (retry < 3) { + if (initGPRS()) { + if (sendHTTPRequest()) break; + else Serial.println("⚠️ HTTP failed, retrying..."); + } else { + Serial.println("❌ GPRS init failed, retrying..."); + } + retry++; + delay(5000); + } +} + +// ========================= +// loop +// ========================= +void loop() { + yield(); // جلوگیری از WDT +} diff --git a/old/teststm03/teststm03.ino b/old/teststm03/teststm03.ino new file mode 100644 index 0000000..accc4f0 --- /dev/null +++ b/old/teststm03/teststm03.ino @@ -0,0 +1,116 @@ +/* + MQ-7 Module - با ضرایب صحیح +*/ + +#include + +const uint8_t ADC_PIN = PA2; +const uint8_t LED_PIN = PC13; + +const float ADC_REF = 3.3; +const uint32_t ADC_MAX = 4095; +const float RL = 10000.0; +float R0 = -1.0; +const float CO_THRESHOLD = 50.0; + +// ضرایب صحیح برای MQ-7 و گاز CO +const float CO_A = 99.042; +const float CO_B = -1.518; + +float readVoltage() { + const int N = 10; + uint32_t sum = 0; + for (int i = 0; i < N; i++) { + sum += analogRead(ADC_PIN); + delay(3); + } + float adc_avg = sum / float(N); + return adc_avg * (ADC_REF / ADC_MAX); +} + +float calcRs(float Vout) { + if (Vout <= 0.001) return 1e6; + + // فرمول اصلاح شده: ما Vout را از سنسور می‌خوانیم که نسبت به 5V داخلی ماژول است + // بنابراین باید از 5.0 در فرمول استفاده کنیم، نه ADC_REF + return RL * (5.0 - Vout) / Vout; // این فرمول صحیح است +} + +float toRealPPM(float Rs) { + if (R0 <= 0) return -1; + float ratio = Rs / R0; + + // فرمول صحیح براساس دیتاشیت MQ-7 + float ppm = CO_A * pow(ratio, CO_B); + + return ppm; +} + +void calibrateR0() { + Serial1.println("=== Calibrating R0 in clean air ==="); + const int N = 50; + float sum_R0 = 0; + + for (int i = 0; i < N; i++) { + float V = readVoltage(); + float Rs = calcRs(V); + + // در هوای پاک: نسبت Rs/R0 ≈ 27.5 (طبق دیتاشیت) + // بنابراین: R0 = Rs / 27.5 + sum_R0 += Rs / 27.5; + + delay(100); + } + + R0 = sum_R0 / N; + Serial1.print("Calibration complete. R0 = "); + Serial1.println(R0, 2); +} + +void setup() { + Serial1.begin(115200); + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + + Serial1.println("MQ-7 CO Monitor - Waiting for warm up..."); + delay(30000); // 30 ثانیه پیش‌گرمایش + Serial1.println("Ready. Send 'c' to calibrate."); + calibrateR0(); +} + +void loop() { + if (Serial1.available()) { + char c = Serial1.read(); + if (c == 'c' || c == 'C') calibrateR0(); + } + + float V = readVoltage(); + float Rs = calcRs(V); + float ppm = toRealPPM(Rs); + + Serial1.print("Vout="); + Serial1.print(V, 3); + Serial1.print("V, Rs="); + Serial1.print(Rs, 1); + Serial1.print("Ω"); + + if (R0 > 0) { + Serial1.print(", Rs/R0="); + Serial1.print(Rs/R0, 3); + Serial1.print(", CO="); + Serial1.print(ppm, 1); + Serial1.println("ppm"); + + // هشدار + if (ppm > CO_THRESHOLD) { + digitalWrite(LED_PIN, HIGH); + Serial1.println("⚠️ WARNING: High CO level!"); + } else { + digitalWrite(LED_PIN, LOW); + } + } else { + Serial1.println(" [Not calibrated]"); + } + + delay(2000); +} \ No newline at end of file diff --git a/old/wifi1/wifi1.ino b/old/wifi1/wifi1.ino new file mode 100644 index 0000000..3f9c065 --- /dev/null +++ b/old/wifi1/wifi1.ino @@ -0,0 +1,212 @@ +#include +#include +#include "RTClib.h" +#include +#include + +// تعریف نام مستعار برای حل مشکل تداخل +using SDLibFile = File; + +SoftwareSerial espSerial(4, 5); +const int chipSelect = 10; +RTC_DS3231 rtc; + +// کاهش مصرف حافظه با استفاده از PROGMEM +const char daysOfTheWeek[7][4] PROGMEM = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + +// پیش‌تعریف توابع +bool saveDataToFile(const char* filename, const char* data, bool append = true); +bool formatSDCard(); +void sendCommand(const char* cmd, int delayTime); +void sendHTTPResponse(int connectionId, const char* content); +const char* readSensorData(); +const char* handleSaveData(const char* query); +const char* handleReadData(const char* query); +const char* handleFormatCard(); + +void setup() { + Serial.begin(9600); + + // راه اندازی کارت SD + if (!SD.begin(chipSelect)) { + Serial.println(F("SD Card Error!")); + } else { + Serial.println(F("SD Card OK")); + } + + espSerial.begin(9600); + + // راه اندازی RTC + if (!rtc.begin()) { + Serial.println(F("RTC Error!")); + while (1); + } + + if (rtc.lostPower()) { + rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); + } + + delay(1000); + Serial.println(F("Initializing ESP...")); + + // کاهش دستورات ESP + const char* commands[] = { + "AT", "AT+RST", "AT+CWMODE=2", + "AT+CWSAP=\"ESP_CTRL\",\"12345678\",1,3", + "AT+CIPMUX=1", "AT+CIPSERVER=1,80" + }; + + for (int i = 0; i < 6; i++) { + sendCommand(commands[i], 1000); + } + + Serial.println(F("AP Ready!")); +} + +void loop() { + checkESP(); + delay(1000); +} + +void sendCommand(const char* cmd, int delayTime) { + Serial.print(F("Sending: ")); + Serial.println(cmd); + espSerial.println(cmd); + + delay(delayTime); +} + +void sendHTTPResponse(int connectionId, const char* content) { + char response[512]; + snprintf(response, sizeof(response), + "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n%s", + content); + + char cmd[50]; + snprintf(cmd, sizeof(cmd), "AT+CIPSEND=%d,%d", connectionId, strlen(response)); + + sendCommand(cmd, 50); + sendCommand(response, 100); + + snprintf(cmd, sizeof(cmd), "AT+CIPCLOSE=%d", connectionId); + sendCommand(cmd, 50); +} + +void checkESP() { + static char buffer[128]; + static int index = 0; + + while (espSerial.available()) { + char c = espSerial.read(); + if (index < sizeof(buffer) - 1) { + buffer[index++] = c; + } + + if (c == '\n') { + buffer[index] = '\0'; + + if (strstr(buffer, "+IPD") != NULL) { + int connId = atoi(&buffer[5]); + handleRequest(connId, buffer); + } + + index = 0; + } + } +} + +void handleRequest(int connectionId, char* request) { + char* getStart = strstr(request, "GET /"); + if (!getStart) return; + + char* pathStart = getStart + 5; + char* pathEnd = strchr(pathStart, ' '); + if (!pathEnd) return; + + char path[32] = {0}; + strncpy(path, pathStart, min((int)(pathEnd - pathStart), 31)); + + char* query = strchr(path, '?'); + if (query) { + *query = '\0'; + query++; + } + + Serial.print(F("Path: ")); + Serial.println(path); + + const char* response; + + if (strcmp(path, "se") == 0) { + response = readSensorData(); + } + else if (strcmp(path, "save") == 0) { + response = handleSaveData(query); + } + else if (strcmp(path, "format") == 0) { + response = handleFormatCard(); + } + else { + response = "Available endpoints: /se, /save, /format"; + } + + sendHTTPResponse(connectionId, response); +} + +const char* readSensorData() { + static char buffer[64]; + DateTime now = rtc.now(); + + snprintf(buffer, sizeof(buffer), "Temp: %.1fC, Time: %02d:%02d:%02d", + rtc.getTemperature(), now.hour(), now.minute(), now.second()); + + return buffer; +} + +const char* handleSaveData(const char* query) { + if (query && strlen(query) > 0) { + if (saveDataToFile("data.txt", query, true)) { + return "Data saved"; + } + return "Save error"; + } + return "No data"; +} + +const char* handleFormatCard() { + return formatSDCard() ? "Formatted" : "Format error"; +} + +bool saveDataToFile(const char* filename, const char* data, bool append) { + SDLibFile dataFile; + + if (append) { + dataFile = SD.open(filename, FILE_WRITE); + } else { + if (SD.exists(filename)) { + SD.remove(filename); + } + dataFile = SD.open(filename, FILE_WRITE); + } + + if (!dataFile) return false; + + bool result = dataFile.println(data); + dataFile.close(); + + return result; +} + +bool formatSDCard() { + // فقط حذف فایل‌های اصلی + const char* files[] = {"data.txt", "test.txt"}; + + for (int i = 0; i < 2; i++) { + if (SD.exists(files[i])) { + SD.remove(files[i]); + } + } + + // تست نوشتن + return saveDataToFile("test.txt", "Formatted", false); +} \ No newline at end of file