// Если кому в друг окажется полезным, оставляю ссылки на статьи которые читал при написании: // https://randomnerdtutorials.com/esp32-ds18b20-temperature-arduino-ide/ // https://randomnerdtutorials.com/esp32-esp8266-web-server-http-authentication/ // https://alexgyver.ru/gyverpid/ // // By SVSD_VAL #define STASSID "FiWii" #define STAPSK "EnterToTheHomeWorld" #ifdef ESP32 #include #include #else #include #include #include #include #include #endif #include //Ticker Library #include #include #define ONE_WIRE_BUS D2 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); const char index_html[] PROGMEM = R"rawliteral( Esp32 online

Управление уф-камерой

Описание Состояние
Состояние установки N/A
Текущий ШИМ N/A
Кол-во авто-перезапусков N/A / N/A
Текущее время работы N/A
Целевое время работы N/A
Дата выемки N/A
Текущая температура N/A
Целевая температура N/A
Минимальная температура N/A
Максимальная температура N/A

Управление:


Описание Состояние
Целевое время работы (в часах)
Целевая температура
Максимальная температура
Минимальная температура
Дата выемки
)rawliteral"; const char* http_username = "admin"; const char* http_password = "admin123"; String temperatureC = ""; // Replace with your network credentials const char* ssid = STASSID; const char* password = STAPSK; short cur_state = 0; uint64_t work_time = 0; unsigned long target_worktime=0; unsigned long restart_cnt = 0; float cur_temp = 0.0f; float max_temp=16.1f; float min_temp=10.0f; float target_temp=15.3f; String last_date = "..."; int cur_pwm=0; // Timer variables unsigned long last_sensor_time = 0; unsigned long last_halt_time = 0; unsigned long last_pid_time = 0; // Время (мс) которе должно пройти после сбоя (cur_state = -1 ) что бы попытаться запустить повторно #define restart_delay 600000 // Интервал (мс) считывания показания с датчика температуры #define sensor_timer_delay 2000 // Интервал (мс) обработки PID'a #define pid_timer_delay 200 // Светодиод отображения рабочего состояния. #define LED LED_BUILTIN // Пин состояния работы #define power_pin D8 // Пин ШИМ'а #define pwm_pin D7 // Стандартный порт http сервера #define http_port 80 AsyncWebServer server(http_port); float pid_integral=0; int computePID(float input, float setpoint, float kp, float ki, float kd, float dt, int minOut, int maxOut) { float err = setpoint - input; float pid_integral = 0, prevErr = 0; pid_integral = constrain(pid_integral + (float)err * dt * ki, minOut, maxOut); float D = (err - prevErr) / dt; prevErr = err; return constrain(err * kp + pid_integral + D * kd, minOut, maxOut); } float readDSTemperatureC() { sensors.requestTemperatures(); float tempC = sensors.getTempCByIndex(0); if(tempC == -127.00) { Serial.println("!!Failed to read from DS18B20 sensor!!"); } Serial.print("Temperature Celsius: "); Serial.println(tempC); return tempC; } // Формат строки возврата текущего состояния. String formatJson(){ char s[350]; unsigned long rst_time = 0; if (cur_state== -1) { if ( millis() < last_halt_time ) { rst_time = (last_halt_time - millis()) / 1000; } } snprintf_P(s, sizeof(s), PSTR("{'cur_state' : %i, 'work_time' : %i, 'cur_temp' : %0.2f, 'restart_cnt' : %i, 'date' : '%s', 'max_temp' : %.2f, 'min_temp': %.2f, 'target_temp' : %.2f, 'target_worktime' : %i, 'cur_pwm' : %i, 'rst_time' : %i }"), cur_state,work_time,cur_temp,restart_cnt,last_date,max_temp,min_temp,target_temp,target_worktime,cur_pwm, rst_time ); return String(s); } Ticker blinker; void onTimer(){ if ( cur_state ){ digitalWrite(LED, !digitalRead(LED)); // Добавляем 1 секунду к работе work_time+=1; } } void wshutdown(int state=0){ Serial.println("shutdown"); cur_state= state; cur_pwm=0; pid_integral=0; analogWrite(pwm_pin, 255-cur_pwm); digitalWrite(LED, 1); } void wstartup(){ cur_state = 1; restart_cnt = 0; cur_pwm = 0; work_time = 0; analogWrite(pwm_pin, 255-cur_pwm); digitalWrite(LED, 0); } void setup(){ // Serial port for debugging purposes Serial.begin(115200); Serial.println(); pinMode(power_pin , OUTPUT); pinMode(pwm_pin , OUTPUT); analogWrite(pwm_pin, 255); analogWriteFreq(100); pinMode(LED , OUTPUT); digitalWrite(LED , 0); // Start up the DS18B20 library sensors.begin(); cur_temp = readDSTemperatureC(); // Connect to Wi-Fi WiFi.begin(ssid, password); Serial.println("Connecting to WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); // Print ESP Local IP Address Serial.println(WiFi.localIP()); // Route for root / web page server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/html", index_html); }); server.on("/temperaturec", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/plain", temperatureC.c_str()); }); server.on("/get_stat", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "Content-type:application/json;charset=utf-8", formatJson().c_str()); }); server.on("/apply", HTTP_POST, [](AsyncWebServerRequest *request){ if(!request->authenticate(http_username, http_password)) { Serial.print("request Authentication != Login:"); Serial.print(http_username); Serial.print(" password:"); Serial.print(http_password); return request->requestAuthentication(); } int paramsNr = request->params(); Serial.println(paramsNr); int ishalt=0; for(int i=0;igetParam(i); if ( p->name() == "btn-stop" ){ wshutdown(0); ishalt=1; Serial.println('!Stop'); } } if (ishalt==0) { for(int i=0;igetParam(i); Serial.print(p->name()); Serial.print("->"); Serial.println(p->value()); Serial.println(); if ( p->name() == "itarget_worktime" ){ Serial.print("setup target_worktime = "); target_worktime = p->value().toInt(); Serial.println(target_worktime); } else if ( p->name() == "itarget_temp" ){ Serial.print("setup target_temp = "); target_temp = p->value().toFloat(); Serial.println(target_temp); } else if ( p->name() == "imin_temp" ){ Serial.print("setup min_temp = "); min_temp = p->value().toFloat(); Serial.println(min_temp); } else if ( p->name() == "imax_temp" ){ Serial.print("setup max_temp = "); max_temp = p->value().toFloat(); Serial.println(max_temp); } else if ( p->name() == "idate" ){ Serial.print("setup date = "); last_date = p->value(); Serial.println(last_date); } else if ( p->name() == "btn-start" ){ Serial.println("starting up"); wstartup(); }; } }; request->redirect("/"); }); server.on("/setpin", HTTP_GET, [](AsyncWebServerRequest *request){ int paramsNr = request->params(); Serial.println(paramsNr); for(int i=0;igetParam(i); Serial.print(p->name()); Serial.print("->"); Serial.println(p->value()); Serial.println(); Serial.print("int value: "); int x = p->value().toInt(); Serial.println(x); pinMode(x, OUTPUT); if ( p->name() == "pin_on" ){ Serial.print("set pin on"); digitalWrite( x , HIGH); }; if ( p->name() == "pin_off" ){ Serial.print("set pin off"); digitalWrite( x , LOW); }; } //request->send_P(200, "text/plain", "OK"); request->redirect("/"); }); // Start server server.begin(); digitalWrite(LED , 1); blinker.attach(1, onTimer); } void loop(){ // Получение температуры if ( millis() > last_sensor_time ) { cur_temp = readDSTemperatureC(); temperatureC = String(cur_temp); last_sensor_time = millis() + sensor_timer_delay; } // Расчёт PID if ( millis() > last_pid_time ) { if ( cur_state == 1 ) { unsigned long pidTime= millis() - last_pid_time; cur_pwm = computePID( target_temp , cur_temp , 50.0, 10.0, 1.0, pidTime * 0.01f , 0, 255 ) ; analogWrite(pwm_pin , 255-cur_pwm); } last_pid_time = millis() + pid_timer_delay; } if ( cur_state == 1 ) { // Проверка на минимальную температуру if (( cur_temp > max_temp ) || ( cur_temp < min_temp )) { wshutdown( -1 ); last_halt_time=millis() + restart_delay; } // Проверка на время if (work_time > target_worktime * 3600) { wshutdown( 0 ); last_halt_time=millis() + restart_delay; } } // Перезапуск по времени. if ( cur_state == -1 ){ if (millis() > last_halt_time){ cur_state=1; restart_cnt+=1; } } // Указание текущего состояния пина работы. if ( cur_state == 1 ){ digitalWrite(power_pin, 1); } else { digitalWrite(power_pin, 0); } }