Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <Arduino.h>
- #include "CountUpDownTimer.h"
- #include <PID_v1.h>
- #include <ESP8266WiFi.h>
- #include <ESP8266WiFiMulti.h>
- #include <WebSocketsServer.h>
- #include <ESP8266WebServer.h>
- #include <ESP8266mDNS.h>
- #include <Hash.h>
- #include <FS.h>
- #include "max6675.h"
- #include <SPI.h>
- #define OUT_PIN1 5
- #define OUT_PIN2 16
- #define OUT_ENABLE 15
- int dataSendTime = 5; // Refresh client data every x seconds (websocket)
- int WindowSize = 5000;
- unsigned long windowStartTime;
- ESP8266WiFiMulti WiFiMulti;
- ESP8266WebServer server = ESP8266WebServer(80);
- WebSocketsServer webSocket = WebSocketsServer(81);
- File fsUploadFile;
- const char* ssid = "mySSID";
- const char* password = "mypassword";
- const char* host = "smartOven";
- CountUpDownTimer Timer(UP, LOW); // Default precision is HIGH, but you can change it to also be LOW
- CountUpDownTimer dataTimer(UP, LOW);
- uint16_t iTimerSetpoint = 60;
- uint16_t iTemp1Setpoint = 25;
- uint16_t iTemp2Setpoint = 25;
- String stTimeActual = "60";
- double dTempActual1 = 75.0;
- double dTempActual2 = 75.0;
- bool bStart = false;
- int outState1 = 0; // current state of the OUT
- int lastOutState1 = 0; // previous state of the OUT
- int outState2 = 0; // current state of the OUT
- int lastOutState2 = 0; // previous state of the OUT
- // SPI hardware
- int thermoCS1 = 13;
- int thermoSO1 = 12;
- int thermoSCK1 = 14;
- // SPI Software
- int thermoCS2 = 0;
- int thermoSO2 = 4;
- int thermoSCK2 = 2;
- MAX6675 thermocouple1;
- MAX6675 thermocouple2;
- //Specify the links and initial tuning parameters
- double Kp1 ; double Ki1 ; double Kd1 ;
- double Setpoint1, Input1, OutputPID1;
- PID myPID1(&Input1, &OutputPID1, &Setpoint1, Kp1, Ki1, Kd1, DIRECT);
- //Specify the links and initial tuning parameters
- double Kp2 ; double Ki2 ; double Kd2 ;
- double Setpoint2, Input2, OutputPID2;
- PID myPID2(&Input2, &OutputPID2, &Setpoint2, Kp2, Ki2, Kd2, DIRECT);
- // *********************************** //
- // FUNCTIONS Prototype //
- // *********************************** //
- String getContentType(String filename);
- bool handleFileRead(String path);
- void handleFileUpload(void);
- void handleFileDelete(void);
- void handleFileCreate(void);
- void handleFileList(void);
- void loadPIDConfig(void);
- void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) ;
- // Setup nodeMCU
- void setup() {
- pinMode(OUT_PIN1, OUTPUT);
- pinMode(OUT_PIN2, OUTPUT);
- pinMode(OUT_ENABLE, OUTPUT);
- digitalWrite(OUT_PIN1, LOW);
- digitalWrite(OUT_PIN2, LOW);
- digitalWrite(OUT_ENABLE, LOW);
- Serial.flush();
- Serial.begin(115200);
- delay(10);
- SPIFFS.begin();
- for(uint8_t t = 4; t > 0; t--) {
- Serial.printf("[SETUP] BOOT WAIT %d...\n", t);
- Serial.flush();
- delay(1000);
- }
- WiFiMulti.addAP(ssid, password);
- Serial.print("Connecting WiFi ");
- Serial.println(ssid);
- while(WiFiMulti.run() != WL_CONNECTED) {
- delay(100);
- Serial.print(".");
- }
- Serial.println();
- Serial.print("WiFi connected. IP address: ");
- Serial.println(WiFi.localIP());
- // start webSocket server
- webSocket.begin();
- webSocket.onEvent(webSocketEvent);
- //WEBSERVER INIT
- //list directory
- server.on("/list", HTTP_GET, handleFileList);
- //load editor
- server.on("/edit", HTTP_GET, [](){ if(!handleFileRead("/edit.htm")) server.send(404, "text/plain", "FileNotFound"); });
- //create file
- server.on("/edit", HTTP_PUT, handleFileCreate);
- //delete file
- server.on("/edit", HTTP_DELETE, handleFileDelete);
- //first callback is called after the request has ended with all parsed arguments
- //second callback handles file uploads at that location
- server.on("/edit", HTTP_POST, [](){ server.send(200, "text/plain", ""); }, handleFileUpload);
- //called when the url is not defined here -> index.html (use it to load content from SPIFFS)
- server.onNotFound([](){ if(!handleFileRead(server.uri())) server.send(404, "text/plain", "FileNotFound"); });
- server.begin();
- Serial.println("HTTP server started");
- // Add service to MDNS
- MDNS.begin(host);
- MDNS.addService("http", "tcp", 80);
- MDNS.addService("ws", "tcp", 81);
- Serial.println("MDNSP services started");
- dataTimer.SetStopTime(0, 0, dataSendTime );
- dataTimer.StartTimer();
- windowStartTime = millis();
- //tell the PID to range between 0 and the full window size
- myPID1.SetOutputLimits(0, WindowSize);
- myPID1.SetMode(AUTOMATIC);
- myPID2.SetOutputLimits(0, WindowSize);
- myPID2.SetMode(AUTOMATIC);
- Serial.println("Reading PID constant...");
- loadPIDConfig();
- myPID1.SetTunings(Kp1, Ki1, Kd1);
- myPID2.SetTunings(Kp2, Ki2, Kd2);
- Serial.print("PID 1 parameter(Kp, Ki, Kd): ");
- Serial.println(String(myPID1.GetKp(), 1) + " " + String(myPID1.GetKi(), 1) + " " + String(myPID1.GetKd(), 1));
- Serial.print("PID 2 parameter(Kp, Ki, Kd): ");
- Serial.println(String(myPID2.GetKp(), 1) + " " + String(myPID2.GetKi(), 1) + " " + String(myPID2.GetKd(), 1));
- //SPI.begin();
- thermocouple1.begin(thermoSCK1, thermoCS1, thermoSO1);
- Serial.print("Temperatura 1 attuale: ");
- Serial.println(String(thermocouple1.readCelsius(), 2)+ (char)176 + "C");
- thermocouple2.begin(thermoSCK2, thermoCS2, thermoSO2);
- Serial.print("Temperatura 2 attuale: ");
- Serial.println(String(thermocouple2.readCelsius(), 2)+ (char)176 + "C");
- }
- void loop() {
- webSocket.loop();
- server.handleClient();
- myPID1.Compute();
- myPID2.Compute();
- // run the timer
- Timer.Timer();
- dataTimer.Timer();
- if (dataTimer.TimeCheck(0, 0, dataSendTime) ) {
- if (dataTimer.TimeHasChanged() ) {
- dTempActual1 = thermocouple1.readCelsius();
- dTempActual2 = thermocouple2.readCelsius();
- // update client data evry x seconds (via webSocket)
- stTimeActual = String(Timer.ShowMinutes(), DEC) + "':" + String(Timer.ShowSeconds(), DEC) + "\"";
- webSocket.broadcastTXT( "##" + String(iTemp2Setpoint, DEC) +';'+ String(iTemp1Setpoint, DEC) +';'+ String(iTimerSetpoint, DEC) +';'+
- String(dTempActual2, 2) + ';' + String(dTempActual1, 2) + ';' + stTimeActual);
- }
- dataTimer.StartTimer();
- }
- // Check if cooking timer has gone
- if (Timer.TimeCheck(0, iTimerSetpoint, 0) ) {
- bStart = false;
- if (Timer.TimeHasChanged() ) {
- Serial.print("Cooking time: ");
- Serial.print(Timer.ShowHours());
- Serial.print(":");
- Serial.print(Timer.ShowMinutes());
- Serial.print(":");
- Serial.println(Timer.ShowSeconds());
- }
- }
- Input1 = dTempActual1;
- Setpoint1 = iTemp1Setpoint;
- Input2 = dTempActual2;
- Setpoint2 = iTemp2Setpoint;
- /*
- Serial.print(OutputPID1);
- Serial.print("; ");
- Serial.println(OutputPID2);
- /************************************************
- * turn the output pin on/off based on pid output
- ************************************************/
- if (bStart==true) {
- unsigned long now = millis();
- if (now - windowStartTime > WindowSize) {
- //time to shift the Relay Window
- windowStartTime += WindowSize;
- }
- if (OutputPID1 > now - windowStartTime){
- digitalWrite(OUT_PIN1, HIGH);
- // Serial.println("High " + String(OutputPID1));
- }
- else { digitalWrite(OUT_PIN1, LOW); }
- if (OutputPID2 > now - windowStartTime) { digitalWrite(OUT_PIN2, HIGH); }
- else { digitalWrite(OUT_PIN2, LOW); }
- } else {
- digitalWrite(OUT_PIN1, LOW);
- digitalWrite(OUT_PIN2, LOW);
- }
- // compare the OUT to its previous state
- outState1 = digitalRead(OUT_PIN1);
- if (outState1 != lastOutState1) {
- webSocket.broadcastTXT( "@@" + String(outState1*30)+ ';' + String(outState2*30));
- lastOutState1 = outState1;
- }
- outState2 = digitalRead(OUT_PIN2);
- if (outState2 != lastOutState2) {
- webSocket.broadcastTXT( "@@" + String(outState1*30)+ ';' + String(outState2*30));
- lastOutState2 = outState2;
- }
- }
- // *********************************** //
- // FUNCTIONS //
- // *********************************** //
- String getValue(String data, char separator, int index){
- int found = 0;
- int strIndex[] = {0, -1};
- int maxIndex = data.length()-1;
- for(int i=0; i<=maxIndex && found<=index; i++){
- if(data.charAt(i)==separator || i==maxIndex){
- found++;
- strIndex[0] = strIndex[1]+1;
- strIndex[1] = (i == maxIndex) ? i+1 : i;
- }
- }
- return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
- }
- // Websocket messages
- void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) {
- switch(type) {
- case WStype_DISCONNECTED:{
- Serial.printf("[%u] Disconnected!\n", num);
- break;
- }
- case WStype_CONNECTED:{
- IPAddress ip = webSocket.remoteIP(num);
- Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
- webSocket.sendTXT(num, "Connected");
- delay(20);
- // if heating tell to the client we are busy
- if (bStart)
- webSocket.sendTXT( num, "State: RUN");
- webSocket.sendTXT( num, "Clients: " + String(num));
- dTempActual1 = thermocouple1.readCelsius();
- dTempActual2 = thermocouple2.readCelsius();
- // update client data evry x seconds (via webSocket)
- stTimeActual = String(Timer.ShowMinutes(), DEC) + "':" + String(Timer.ShowSeconds(), DEC) + "\"";
- webSocket.sendTXT( num, "##" + String(iTemp2Setpoint, DEC) +';'+ String(iTemp1Setpoint, DEC) +';'+ String(iTimerSetpoint, DEC) +';'+
- String(dTempActual2, 2) + ';' + String(dTempActual1, 2) + ';' + stTimeActual);
- webSocket.sendTXT( num, "!!" + String(myPID1.GetKp(), 1) + ";" + String(myPID1.GetKi(), 1) + ";" + String(myPID1.GetKd(), 1) + ';' +
- String(myPID2.GetKp(), 1) + ";" + String(myPID2.GetKi(), 1) + ";" + String(myPID2.GetKd(), 1) + ';' + String(WindowSize));
- break;
- }
- case WStype_TEXT:{
- Serial.printf("[%u] get Text: %s\n", num, payload);
- if(payload[0] == '#') {
- String stData = (const char*) payload + 3;
- if(payload[1]=='1'){
- iTemp1Setpoint = stData.toInt();
- Serial.printf("Set Temperature 1: %d\n", iTemp1Setpoint);
- webSocket.sendTXT(num, "Setpoint T1: " + String(iTemp1Setpoint, DEC));
- }
- if(payload[1]=='2'){
- iTemp2Setpoint = stData.toInt();
- Serial.printf("Set Temperature 2: %d\n", iTemp2Setpoint);
- webSocket.sendTXT(num, "Setpoint T2: " + String(iTemp2Setpoint, DEC));
- }
- }
- if(payload[0] == '%') {
- String stData = (const char*) payload + 1;
- iTimerSetpoint = stData.toInt();;
- Serial.printf("Set Timer: %d\n", iTimerSetpoint);
- Timer.SetStopTime(0, (uint32_t) iTimerSetpoint,0);
- webSocket.sendTXT(num, "Setpoint Time: " + String(iTimerSetpoint, DEC));
- }
- if(payload[2]== 'A') {
- Timer.SetStopTime(0, (uint32_t) iTimerSetpoint,0);
- Timer.StartTimer();
- Serial.printf("Start heating at %d\xB0C / %d\xB0C. Timer: %d min\n", iTemp1Setpoint, iTemp2Setpoint, iTimerSetpoint);
- bStart = true;
- }
- if(payload[2] == 'O') {
- Timer.StopTimer();
- Serial.println("Stop heating");
- bStart = false;
- }
- if(payload[0] == '!') {
- String str;
- String stData = (const char*) payload + 2;
- Kp1 = getValue(stData, ';', 0).toFloat();
- Ki1 = getValue(stData, ';', 1).toFloat();
- Kd1 = getValue(stData, ';', 2).toFloat();
- myPID1.SetTunings(Kp1, Ki1, Kd1);
- str = String(myPID1.GetKp(), 1) + " " + String(myPID1.GetKi(), 1) + " " + String(myPID1.GetKd(), 1);
- Serial.print("Update PID 1 parameter(Kp, Ki, Kd). New values: ");
- Serial.println(str);
- webSocket.sendTXT(num, "PID 1 parameter updated: " + str );
- Kp2 = getValue(stData, ';', 3).toFloat();
- Ki2 = getValue(stData, ';', 4).toFloat();
- Kd2 = getValue(stData, ';', 5).toFloat();
- myPID2.SetTunings(Kp2, Ki2, Kd2);
- str = String(myPID2.GetKp(), 1) + " " + String(myPID2.GetKi(), 1) + " " + String(myPID2.GetKd(), 1);
- Serial.print("Update PID 2 parameter(Kp, Ki, Kd). New values: ");
- Serial.println(str);
- webSocket.sendTXT(num, "PID 2 parameter updated: " + str );
- // Store new values in FS
- savePIDConfig();
- WindowSize = getValue(stData, ';', 6).toInt();
- Serial.print("Update windows output size. New values: ");
- Serial.println(getValue(stData, ';', 6));
- }
- break;
- }
- }
- }
- void loadPIDConfig(void) {
- File configFile = SPIFFS.open("/PID.ini", "r");
- if (!configFile) {
- Serial.println("File doesn't exist yet. Creating it");
- // open the file in write mode
- File f = SPIFFS.open("/PID.ini", "w");
- if (!f) { Serial.println(" file creation failed"); }
- // no cinfigFile: set default values
- Kp1 = 1.0; Ki1 = 2.0; Kd1 = 0.3;
- Kp2 = 1.0; Ki2 = 2.0; Kd2 = 0.3;
- // now write two lines in key/value style with end-of-line characters
- f.println(String(Kp1, 1)); f.println(String(Ki1, 1)); f.println(String(Kd1, 1));
- f.println(String(Kp2, 1)); f.println(String(Ki2, 1)); f.println(String(Kd2, 1));
- } else {
- // we could open the file
- Serial.println("File opened. Reading...");
- for (int i=1; i<=6; i++){
- //Lets read line by line from the file
- String line = configFile.readStringUntil('\n');
- switch (i) {
- case 1: Kp1 = line.toFloat();
- case 2: Ki1 = line.toFloat();
- case 3: Kd1 = line.toFloat();
- case 4: Kp2 = line.toFloat();
- case 5: Ki2 = line.toFloat();
- case 6: Kd2 = line.toFloat();
- }
- }
- }
- configFile.close();
- }
- void savePIDConfig(void) {
- File configFile = SPIFFS.open("/PID.ini", "w");
- if (!configFile) {
- Serial.println("File doesn't exist yet. Creating it");
- // open the file in write mode
- } else {
- // now write two lines in key/value style with end-of-line characters
- configFile.println(String(Kp1, 1));
- configFile.println(String(Ki1, 1));
- configFile.println(String(Kd1, 1));
- configFile.println(String(Kp2, 1));
- configFile.println(String(Ki2, 1));
- configFile.println(String(Kd2, 1));
- }
- configFile.close();
- }
- // Web server file handler
- String getContentType(String filename){
- if(server.hasArg("download")) return "application/octet-stream";
- else if(filename.endsWith(".htm")) return "text/html";
- else if(filename.endsWith(".html")) return "text/html";
- else if(filename.endsWith(".ini")) return "text/html";
- else if(filename.endsWith(".css")) return "text/css";
- else if(filename.endsWith(".js")) return "application/javascript";
- else if(filename.endsWith(".png")) return "image/png";
- else if(filename.endsWith(".gif")) return "image/gif";
- else if(filename.endsWith(".jpg")) return "image/jpeg";
- else if(filename.endsWith(".ico")) return "image/x-icon";
- else if(filename.endsWith(".xml")) return "text/xml";
- else if(filename.endsWith(".pdf")) return "application/x-pdf";
- else if(filename.endsWith(".zip")) return "application/x-zip";
- else if(filename.endsWith(".gz")) return "application/x-gzip";
- return "text/plain";
- }
- bool handleFileRead(String path){
- Serial.println("handleFileRead: " + path);
- if(path.endsWith("/")) path += "index.htm";
- String contentType = getContentType(path);
- String pathWithGz = path + ".gz";
- if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){
- if(SPIFFS.exists(pathWithGz))
- path += ".gz";
- File file = SPIFFS.open(path, "r");
- size_t sent = server.streamFile(file, contentType);
- file.close();
- return true;
- }
- return false;
- }
- void handleFileUpload(){
- if(server.uri() != "/edit") return;
- HTTPUpload& upload = server.upload();
- if(upload.status == UPLOAD_FILE_START){
- String filename = upload.filename;
- if(!filename.startsWith("/")) filename = "/"+filename;
- Serial.print("handleFileUpload Name: "); Serial.println(filename);
- fsUploadFile = SPIFFS.open(filename, "w");
- filename = String();
- } else if(upload.status == UPLOAD_FILE_WRITE){
- //Serial.print("handleFileUpload Data: "); Serial.println(upload.currentSize);
- if(fsUploadFile)
- fsUploadFile.write(upload.buf, upload.currentSize);
- } else if(upload.status == UPLOAD_FILE_END){
- if(fsUploadFile)
- fsUploadFile.close();
- Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize);
- }
- }
- void handleFileDelete(){
- if(server.args() == 0) return server.send(500, "text/plain", "BAD ARGS");
- String path = server.arg(0);
- Serial.println("handleFileDelete: " + path);
- if(path == "/")
- return server.send(500, "text/plain", "BAD PATH");
- if(!SPIFFS.exists(path))
- return server.send(404, "text/plain", "FileNotFound");
- SPIFFS.remove(path);
- server.send(200, "text/plain", "");
- path = String();
- }
- void handleFileCreate(){
- if(server.args() == 0)
- return server.send(500, "text/plain", "BAD ARGS");
- String path = server.arg(0);
- Serial.println("handleFileCreate: " + path);
- if(path == "/")
- return server.send(500, "text/plain", "BAD PATH");
- if(SPIFFS.exists(path))
- return server.send(500, "text/plain", "FILE EXISTS");
- File file = SPIFFS.open(path, "w");
- if(file)
- file.close();
- else
- return server.send(500, "text/plain", "CREATE FAILED");
- server.send(200, "text/plain", "");
- path = String();
- }
- void handleFileList() {
- if(!server.hasArg("dir")) {server.send(500, "text/plain", "BAD ARGS"); return;}
- String path = server.arg("dir");
- Serial.println("handleFileList: " + path);
- Dir dir = SPIFFS.openDir(path);
- path = String();
- String output = "[";
- while(dir.next()){
- File entry = dir.openFile("r");
- if (output != "[") output += ',';
- bool isDir = false;
- output += "{\"type\":\"";
- output += (isDir)?"dir":"file";
- output += "\",\"name\":\"";
- output += String(entry.name()).substring(1);
- output += "\"}";
- entry.close();
- }
- output += "]";
- server.send(200, "text/json", output);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement