old codes
This commit is contained in:
759
old/nodemcu3.ino
Normal file
759
old/nodemcu3.ino
Normal file
@@ -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 <RH_ASK.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <Wire.h>
|
||||
#include "RTClib.h"
|
||||
//#include <RCSwitch.h>
|
||||
#include <SD.h>
|
||||
#include <SPI.h>
|
||||
#include <ESP8266HTTPClient.h>
|
||||
#include <WiFiClientSecureBearSSL.h>
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
|
||||
|
||||
|
||||
// ---------------- 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<NUM_ALLOWED;i++) if (id == ALLOWED_DEVICES[i]) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void resetFrame() {
|
||||
receivedKey = "";
|
||||
receivedHex = "";
|
||||
receivingPublicKey = true;
|
||||
receivedChars = 0;
|
||||
}
|
||||
|
||||
String dateTimeToISO(const DateTime &dt) {
|
||||
char buf[25];
|
||||
sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d",
|
||||
dt.year(), dt.month(), dt.day(),
|
||||
dt.hour(), dt.minute(), dt.second());
|
||||
return String(buf);
|
||||
}
|
||||
|
||||
String safeFileNameForNow() {
|
||||
if (rtcReady) {
|
||||
DateTime now = rtc.now();
|
||||
char fn[20];
|
||||
sprintf(fn, "%04d%02d%02d.txt", now.year(), now.month(), now.day());
|
||||
return String(fn);
|
||||
} else {
|
||||
unsigned long s = millis() / 1000UL;
|
||||
return String("t") + String(s) + ".txt";
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// ---------------- SD / config helpers ----------------
|
||||
// -------------------- loadConfigFromSD --------------------
|
||||
// -------------------- loadConfigFromSD --------------------
|
||||
void loadConfigFromSD() {
|
||||
if (!sdReady) {
|
||||
Serial.println("[CONFIG] SD not ready, skipping load");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("[CONFIG] Loading configuration from SD...");
|
||||
File f = SD.open(CONFIG_FILE, "r");
|
||||
if (!f) {
|
||||
Serial.println("[CONFIG] Config file not found, using defaults");
|
||||
return;
|
||||
}
|
||||
|
||||
while (f.available()) {
|
||||
String line = f.readStringUntil('\n');
|
||||
line.trim();
|
||||
if (line.length() == 0) continue;
|
||||
|
||||
Serial.print("[CONFIG] Line: ");
|
||||
Serial.println(line);
|
||||
|
||||
if (line.startsWith("save_interval_minutes=")) {
|
||||
saveIntervalMinutes = line.substring(strlen("save_interval_minutes=")).toInt();
|
||||
Serial.print("[CONFIG] Loaded save_interval_minutes = ");
|
||||
Serial.println(saveIntervalMinutes);
|
||||
}
|
||||
else if (line.startsWith("retention_days=")) {
|
||||
retentionDays = line.substring(strlen("retention_days=")).toInt();
|
||||
Serial.print("[CONFIG] Loaded retention_days = ");
|
||||
Serial.println(retentionDays);
|
||||
}
|
||||
else if (line.startsWith("wifi_ssid=")) {
|
||||
apSSID = line.substring(strlen("wifi_ssid="));
|
||||
Serial.print("[CONFIG] Loaded wifi_ssid = ");
|
||||
Serial.println(apSSID);
|
||||
}
|
||||
else if (line.startsWith("wifi_password=")) {
|
||||
apPassword = line.substring(strlen("wifi_password="));
|
||||
Serial.print("[CONFIG] Loaded wifi_password = ");
|
||||
Serial.println(apPassword);
|
||||
}
|
||||
else if (line.startsWith("sta_ssid=")) {
|
||||
staSSID = line.substring(strlen("sta_ssid="));
|
||||
Serial.print("[CONFIG] Loaded sta_ssid = ");
|
||||
Serial.println(staSSID);
|
||||
}
|
||||
else if (line.startsWith("sta_password=")) {
|
||||
staPassword = line.substring(strlen("sta_password="));
|
||||
Serial.print("[CONFIG] Loaded sta_password = ");
|
||||
Serial.println(staPassword);
|
||||
}
|
||||
else if (line.startsWith("sendIntervalMinutes=")) {
|
||||
sendIntervalMinutes = line.substring(strlen("sendIntervalMinutes=")).toInt();
|
||||
Serial.print("[CONFIG] Loaded sendIntervalMinutes = ");
|
||||
Serial.println(sendIntervalMinutes);
|
||||
}
|
||||
else {
|
||||
Serial.print("[CONFIG] Unknown line ignored: ");
|
||||
Serial.println(line);
|
||||
}
|
||||
}
|
||||
|
||||
f.close();
|
||||
Serial.println("[CONFIG] Finished loading configuration");
|
||||
}
|
||||
|
||||
// -------------------- saveConfigToSD --------------------
|
||||
void saveConfigToSD() {
|
||||
if (!sdReady) {
|
||||
Serial.println("[CONFIG] SD not ready, cannot save config");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("[CONFIG] Saving configuration to SD...");
|
||||
|
||||
// اول فایل قبلی رو پاک کن
|
||||
if (SD.exists(CONFIG_FILE)) {
|
||||
SD.remove(CONFIG_FILE);
|
||||
Serial.println("[CONFIG] Old config file removed");
|
||||
}
|
||||
|
||||
File f = SD.open(CONFIG_FILE, FILE_WRITE);
|
||||
if (!f) {
|
||||
Serial.println("[CONFIG] Failed to open config file for writing");
|
||||
return;
|
||||
}
|
||||
|
||||
// همه مقادیر رو یکجا مینویسیم
|
||||
f.print("save_interval_minutes=");
|
||||
f.println(saveIntervalMinutes);
|
||||
|
||||
f.print("retention_days=");
|
||||
f.println(retentionDays);
|
||||
|
||||
f.print("sendIntervalMinutes=");
|
||||
f.println(sendIntervalMinutes);
|
||||
|
||||
f.print("wifi_ssid=");
|
||||
f.println(apSSID);
|
||||
|
||||
f.print("wifi_password=");
|
||||
f.println(apPassword);
|
||||
|
||||
f.print("sta_ssid=");
|
||||
f.println(staSSID);
|
||||
|
||||
f.print("sta_password=");
|
||||
f.println(staPassword);
|
||||
|
||||
f.close();
|
||||
Serial.println("[CONFIG] Configuration saved successfully (file rewritten)");
|
||||
}
|
||||
|
||||
|
||||
void appendDataToSD(const String &line) {
|
||||
if (!sdReady) return;
|
||||
String fname = safeFileNameForNow();
|
||||
File f = SD.open(fname, FILE_WRITE);
|
||||
if (!f) f = SD.open(fname, "a");
|
||||
if (!f) return;
|
||||
f.println(line);
|
||||
f.close();
|
||||
}
|
||||
|
||||
uint64_t computeSDUsedBytes() {
|
||||
if (!sdReady) return 0;
|
||||
uint64_t used = 0;
|
||||
File root = SD.open("/");
|
||||
if (!root) return 0;
|
||||
File entry = root.openNextFile();
|
||||
while (entry) { if (!entry.isDirectory()) used += (uint64_t)entry.size(); entry.close(); entry = root.openNextFile(); }
|
||||
root.close();
|
||||
return used;
|
||||
}
|
||||
|
||||
void cleanupOldFilesOnSD() {
|
||||
if (!sdReady || !rtcReady) return;
|
||||
File root = SD.open("/");
|
||||
if (!root) return;
|
||||
File entry = root.openNextFile();
|
||||
DateTime now = rtc.now();
|
||||
while (entry) {
|
||||
String name = entry.name();
|
||||
if (name.length() && name[0] == '/') name = name.substring(1);
|
||||
if (name != String(CONFIG_FILE) && !entry.isDirectory()) {
|
||||
if (name.length() >= 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<deviceCount;i++) {
|
||||
if (lastRemoteData[i].deviceId==_remoteData.deviceId) {
|
||||
lastRemoteData[i]=_remoteData;
|
||||
updated=true; break;
|
||||
}
|
||||
}
|
||||
if (!updated && deviceCount<MAX_DEVICES) lastRemoteData[deviceCount++]=_remoteData;
|
||||
|
||||
if ((millis()-lastSaveMillis) >= 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<deviceCount;i++){ if(i) arr+=","; RemoteData d=lastRemoteData[i]; arr+="{\"device\":\""+d.deviceId+"\",\"soil\":"+String(d.soil)+",\"gas\":"+String(d.gas)+",\"temp\":"+String(d.temp)+",\"hum\":"+String(d.hum)+",\"time\":\""+d.timestamp+"\"}"; }
|
||||
arr+="]";
|
||||
response="{\"status\":\"ok\",\"data\":"+arr+"}"; break;
|
||||
}
|
||||
case 6: {
|
||||
if (!sdReady) { response = "{\"status\":\"error\",\"message\":\"SD not ready\"}"; break; }
|
||||
String name = getParamFromPath(path, "name");
|
||||
if (name.length() == 0) { response = "{\"status\":\"error\",\"message\":\"missing name\"}"; break; }
|
||||
File f = SD.open(name, "r");
|
||||
if (!f) { response = "{\"status\":\"error\",\"message\":\"file not found\"}"; break; }
|
||||
String content = "";
|
||||
while (f.available()) {
|
||||
char c = f.read();
|
||||
if (c == '"') content += "\""; else content += c;
|
||||
if (c == '}')
|
||||
{
|
||||
//content += c;
|
||||
content += ",";
|
||||
}
|
||||
}
|
||||
if (content.length() > 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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user