m1cr0lab-esp32 / remote-control-with-websocket

ESP32 Remote Control with WebSocket
MIT License
37 stars 20 forks source link

Can you point me in the right direction please? #39

Open Baart-CY opened 7 months ago

Baart-CY commented 7 months ago

My project is an ESP32 controller for our hot tub. I am using 4 solid state relays to supply power to the circ pump, heater, control panel, and lights - not the underwater lights, they are controlled by the spa control panel. What it does so far is;

On boot, it connects to the WiFi and gets the correct time from a time server. This connection is then closed so WiFi can be used solely for remote control of the unit - initially turning on and off the lights and the control panel. Ultimately, I want to be able to be able to alter the circ pump on/off times and the water temperature set point. Currently, these are hard coded into the sketch. Every loop, it checks to see if there is a client and handles it if there is and every 30 seconds, it checks the time and the water temperature, taking action if the water is more than 0.5° below set point or turning off the heater is the set point has been reached and also running the circ pump if the time is between on and off settings. The circ pump must be run if the heater is turned on.

The web controller for the control panel and lights are taken from a RNT tutorial but I take on board your comments about 'netter ways to do things' - I know my code could be much better, I could have defined a relay class similar to your LED class and specified the pin number, state etc. and ultimately, I will do but we've already had a couple of days in the high twenties, I want to get the hot tub filled soon!

So there are two things I would like to do, improve the webserver method using websockets so I can also interactively display things like air temperature, pressure and humidity as well as water temperature as well as being able to set control board and lights on and off. And the second thing is OTA updates with the ESP32 being inside the hot tub casing, it is important. My problem is that when I try changing the wevserver methods or add OTA (ElegantOTA) and I have to change from, for example, webserver server(80 to WiFiserver server(80) I get problems such as webserver has no member named xxx

So, I need to use a library which will allow me to get the time from a time server, run an ESP32 webserver, AND do OTA updates and my other problem is that while I am a fairly experienced coder in other things ESP32 related, I simply do not have a clue about webserving!

Here is my full code so far. I would really appreciate some advice and pointers to where I can learn what I need to develop this further.

#include <Arduino.h>
#include <WiFi.h>
#include <ElegantOTA.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <ESP32Time.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>

#define lightsPin   12 //red
#define powerPin    18 //white
#define heaterPin   13 //green 
#define pumpPin     19 //yellow 
#define ONE_WIRE_BUS 8
#define ssid      "Steve"
#define password  "jguWzfc76i"

WiFiUDP ntpUDP;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
WiFiServer server(80);
ESP32Time rtc(7200);
NTPClient timeClient(ntpUDP);

String header;
long currentTime = millis();
long lastTempTime = 0; 
long timeSync;
long previousTime = 0; 
const long timeoutTime = 2000;
int yy,mm,dd,hh,mn,ss;
bool started=true;
String formattedDate;
String timeStamp;
char timeStr[6];

char tempstr[20];
char labtxt[9];
char tmp[5];
float airTemperature, pressure, humidity,wt,sp;
char settings[20];
int hStart,mStart,hSTop,mStop;
int hOn,hOff,mOn,mOff,hNow,mNow;
String outputcontrolState = "off";
String outputlightsState = "off";
boolean power = false;
boolean control = false;
boolean lights = false;
boolean timeron = true;
boolean circon = false;
boolean heateron = false;
unsigned long ota_progress_millis = 0;
const int led = 13;

void setup()
{  
  String dateSubStr;
  Serial.begin(115200);
  delay(3000);
  hOn=13;
  mOn=0;
  hOff=18;
  mOff=30;
  sp=36; 

  pinMode(powerPin,OUTPUT);
  pinMode(pumpPin,OUTPUT);
  pinMode(heaterPin,OUTPUT);
  pinMode(lightsPin,OUTPUT);
  digitalWrite(powerPin,LOW);
  digitalWrite(pumpPin,LOW);
  digitalWrite(heaterPin,LOW);
  digitalWrite(lightsPin,LOW);

  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }

  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.println("Getting time from NTP Server");
  // get time and set the RTC
  timeClient.begin();
  timeClient.setTimeOffset(0);
  while(!timeClient.update()) timeClient.forceUpdate();
  formattedDate = timeClient.getFormattedDate();
  timeClient.end();
  dateSubStr = formattedDate.substring(0,4);
  yy=dateSubStr.toInt();
  dateSubStr = formattedDate.substring(5,7);
  mm=dateSubStr.toInt();
  dateSubStr = formattedDate.substring(8,10);
  dd=dateSubStr.toInt();
  dateSubStr = formattedDate.substring(11,13);
  hh=dateSubStr.toInt();
  dateSubStr = formattedDate.substring(14,16);
  mn=dateSubStr.toInt();
  dateSubStr = formattedDate.substring(17,20);
  ss=dateSubStr.toInt();

  Serial.print("Setting time and date to : ");
  Serial.println(formattedDate);
  rtc.setTime(ss, mn, hh, dd, mm, yy); 
  server.begin();
  Serial.println("HTTP server started");

  sensors.begin();
}

void loop()
{
  if ((millis() - lastTempTime > 1000UL * 30) || started==true)
  {
    started=false;
    sensors.requestTemperatures(); // Send the command to get temperatures
    wt = sensors.getTempCByIndex(0);
    hNow = rtc.getHour(true);
    mNow = rtc.getMinute();
    sprintf(timeStr,"%2d:%02d",hNow,mNow);
    Serial.print("Time          ");
    Serial.println(timeStr);
    Serial.print("Water temp    ");
    Serial.println(wt);
    Serial.print("Set Point     ");
    Serial.println(sp);

    if(hNow==hOn && mNow >= mOn) circon=true;
    else if(hNow==hOn && mNow>=mOn) circon=true;
    else if(hNow<hOn)circon=false;
    else if(hNow>hOff)circon=false;
    else if(hNow==hOff && mNow>=mOff)circon=false;

    if(circon==true) Serial.println("Circ ON - timer");
    else Serial.println("Circ NOT On - timer");

    if(wt<(sp-0.5))
    {
      Serial.println("Heater ON, Circ ON");
      heateron=true;
      circon=true;
    }
    else if (wt>=sp)
    {
      Serial.println("Heater OFF");
      heateron=false;
    }

    if(heateron==true)
    {
      digitalWrite(heaterPin,HIGH);
      digitalWrite(pumpPin,HIGH);
      circon=true;
    } 
    else digitalWrite(heaterPin,LOW);

    if(circon==true) digitalWrite(pumpPin,HIGH);
    else digitalWrite(pumpPin,LOW);
    lastTempTime=millis(); 
  }
  WiFiClient client = server.available();   

  if (client) 
  {                             
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");
    String currentLine = "";      
    while (client.connected() && currentTime - previousTime <= timeoutTime) 
    {  
      currentTime = millis();
      if (client.available()) 
      {         
        char c = client.read();         
        Serial.write(c);                
        header += c;
        if (c == '\n') 
        {
          if (currentLine.length() == 0) 
          {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            if (header.indexOf("GET /lights/on") >= 0) 
            {
              Serial.println("Lights on");
              lights = "on";
              digitalWrite(lightsPin, HIGH);
            }
            else if (header.indexOf("GET /lights/off") >= 0) 
            {
              Serial.println("Lights off");
              lights = "off";
              digitalWrite(lightsPin, LOW);
            }
            else if (header.indexOf("GET /power/on") >= 0) 
            {
              Serial.println("Power on");
              power = true;
              digitalWrite(powerPin, HIGH);
            }
            else if (header.indexOf("GET /power/off") >= 0) 
            {
              Serial.println("Power off");
              power = true;
              digitalWrite(powerPin, LOW);
            }

            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println(".button2 {background-color: #555555;}</style></head>");

            client.println("<body><h1>Hot Tub Control</h1>");

            sprintf(tempstr,"<p>Water temperature  %4.1f°C</p>",wt);
            client.println(tempstr);

            client.println("<p>Lights</p>");
            if (lights==false) client.println("<p><a href=\"/lights/on\"><button class=\"button\">ON</button></a></p>");
            else client.println("<p><a href=\"/lights/off\"><button class=\"button button2\">OFF</button></a></p>");

            client.println("<p>Power</p>");
            if (power==false) client.println("<p><a href=\"/power/on\"><button class=\"button\">ON</button></a></p>");
            else client.println("<p><a href=\"/power/off\"><button class=\"button button2\">OFF</button></a></p>");

            client.println("</body></html>");
            client.println();
            break;
          }
          else currentLine = "";

        } 
        else if (c != '\r') currentLine += c;

      }
    }
    header = "";
      client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Thanks, Steve (Cyprus)