CCCPaste

Sensor Control rev_38

/********* Pleasedontcode.com **********

	Pleasedontcode thanks you for automatic code generation! Enjoy your code!

	- Terms and Conditions:
	You have a non-exclusive, revocable, worldwide, royalty-free license
	for personal and commercial use. Attribution is optional; modifications
	are allowed, but you're responsible for code maintenance. We're not
	liable for any loss or damage. For full terms,
	please visit pleasedontcode.com/termsandconditions.

	- Project: Sensor Control
	- Source Code compiled for: ESP32 DevKit V1
	- Source Code created on: 2024-10-21 11:43:18

********* Pleasedontcode.com **********/

/****** SYSTEM REQUIREMENTS *****/
/****** SYSTEM REQUIREMENT 1 *****/
	/* merge code. */
/****** END SYSTEM REQUIREMENTS *****/


/* START CODE */

/****** DEFINITION OF LIBRARIES *****/
#include 
#include "ACS712.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "X9C10X.h"

/****** FUNCTION PROTOTYPES *****/
void setup(void);
void loop(void);

// Access Point credentials
char ssid[] = "pleasedontcode.com";        // your network SSID (name)
char pass[] = "prova1234";        // your network password (use for WPA, or use as key for WEP)

// Create an instance of the web server
AsyncWebServer server(80);

TinyGPSPlus gps;

#define VELOCITA_SOGLIA_HIGH 75.0 //km/h
#define VELOCITA_SOGLIA_LOW 65.0 //km/h
#define VELOCITA_SOGLIA_0A_HIGH  20.0 //km/h - soglia sotto 15km/h si spegne l'erogazione corrente
#define VELOCITA_SOGLIA_0A_LOW  10.0 //km/h

//PINS
const int water_level_pin = 18;
const int voltage_pin     = 35;
const int current_pin     = 34;
const int tempSensor1_pin = 33;
const int tempSensor2_pin = 32;
const int ONE_WIRE_BUS_Temp1 = 19; //sonda temp 1
const int ONE_WIRE_BUS_Temp2 = 21; //sonda temp 2
const int DIGPOT_INC      = 4;    // pin INC - X9C103S
const int DIGPOT_UD       = 5;    // pin UD - X9C103S
const int DIGPOT_CS       = 15;   // pin CS - X9C103S

const float PWM_output_percentage_0A = 0.0; //0%
const float PWM_output_percentage_9A = 20.0; //20% --> 1V/5V
const float PWM_output_percentage_5A = 13.0; //13% --> 0,65V/5V

// DATI globali da trasferire
float PWM_output_percentage = 0.0;
float velocita = 0.0;
float voltage_output_value = 0.0;
bool waterLevelEmpty = true;
float voltage = 0.0;
float current = 0.0;
float temperature1 = 0.0;
float temperature2 = 0.0;
unsigned long powerOnTime = 0; //minutes

boolean startRegeneration = false;
unsigned int set_current  = 0;
unsigned int set_timer    = 0;

// configurazione ACS712 da 30A
unsigned int ADC_Offset = 1930;
ACS712  ACS(current_pin, 3.3, 4095, 40); // pin 34 per acquisizione sensore corrente; l'alimentazione sensore è 3.3V

X9C10X pot(10000);  //  10KΩ  - potenziometro digitale X9C103S da 10kΩ

void printWiFiStatus();
void printWebPage();
void checkClientRequest(String currentLine);

bool ReplyWebPageContent = true;
bool ReplyResetTime = false;
bool postUpdateData = false;

static const int GPSBaud = 9600;
#define ss Serial2

unsigned long TEMPO_ATTESA_VISUALIZZAZIONE_VELOCITA = 300;
unsigned long SpeedShowTimer = 0;

// Counter to track seconds
unsigned long secondsCounter            = 0;
unsigned long previousMillis            = millis(); // Variable to store the previous millis value
unsigned long currentMillis             = millis();
unsigned long minutesCounter            = 0;

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire1(ONE_WIRE_BUS_Temp1);
OneWire oneWire2(ONE_WIRE_BUS_Temp2);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensor1(&oneWire1);
DallasTemperature sensor2(&oneWire2);

/****** DEFINITION OF ANALOG INPUTS CHARACTERISTIC CURVES *****/
const uint8_t SEGMENT_POINTS_voltage_Temperature = 10;
const float voltage_Temperature_lookup[2][SEGMENT_POINTS_voltage_Temperature] =
{
    {0.0, 1.2, 1.9, 5.0, 10.0, 14.5, 17.0, 20.0, 30.0, 35.0}, // corrente [V]
    {0.0, 5.0, 7.0, 13.0, 22.0, 29.0, 33.0, 37.0, 56.0, 65.0} // percentuale [°C]
};

// Initialize SPIFFS for file storage
void initSPIFFS() {
  if (!SPIFFS.begin(true)) {
    Serial.println("An error occurred while mounting SPIFFS");
    return;
  }
  Serial.println("SPIFFS mounted successfully");
}

void setup() {
  // Start Serial for debugging
  Serial.begin(115200);
  delay(1000);
  Serial.println("ciao");

  pot.begin(DIGPOT_INC, DIGPOT_UD, DIGPOT_CS);  //  pulse, direction, select // INC = 4, UD = 5, CS = 15
  
  //NON TOGLIERE - SERVE PER NON FAR SBARELLARE LA MACCHINA
  for(int i=0; i<10;i++)
  {
    setCurrentOutput(0);
    delay(20);
    setCurrentOutput(100);
    delay(20);
  }
  
  setCurrentOutput(PWM_output_percentage);
  readMinutesCounterFromEEPROM();
  
  ss.begin(GPSBaud);
  Serial.println("ciao2");

  sensor1.begin(); 
  sensor2.begin(); 

  smartDelay(1000);
  
  ACS.setMidPoint(ADC_Offset); 

  Serial.println(F("Access Point Web Server"));

  // Initialize SPIFFS
  initSPIFFS();

  WiFi.mode(WIFI_AP); // Set the ESP32 to access point mode
  if (!WiFi.softAP(ssid, pass)) {
    Serial.println("Soft AP creation failed.");
    while(1);
  }

  // Print the IP address of the access point
  IPAddress IP = WiFi.softAPIP();
  Serial.print("Access Point IP Address: ");
  Serial.println(IP);

  // Serve the JPEG image
  server.on("/background.jpg", HTTP_GET, [](AsyncWebServerRequest *request){
    Serial.println("0");
    request->send(SPIFFS, "/background.jpg", "image/jpeg");
  });

  // Serve the HTML page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    Serial.println("1");
    request->send(SPIFFS, "/index.html", "text/html");
  });

  server.on("/UPDATEDATA", HTTP_POST, [](AsyncWebServerRequest *request) {
    // Log post request handling
    //Serial.println("postUpdateData");

    // Allocate a temporary JsonDocument
    StaticJsonDocument<512> doc;

    // Gather data and populate JSON
    updateData(doc);

    // Convert the JSON document to string and send it in response
    String response;
    serializeJsonPretty(doc, response);

    request->send(200, "application/json", response);
  });

  // Start the server
  server.begin();
}

void loop() {
  // No logic in the loop; the server works asynchronously
  readGPSAndCheckSpeed();
  readCurrent();
  readVoltage();
  readWaterTank();
  readTemp1();
  readTemp2();
  updateMinutesCounter();
  checkRegeneration();
}

// The updateData function to generate the JSON payload
void updateData(JsonDocument &doc) {
  if (velocita > 0.0) {
    doc["speed"] = String(velocita) + String(F(" km/h"));
  } else {
    doc["speed"] = String(F("ERROR"));
  }
  doc["voltageCommandOut"] = String(F("Tensione uscita comando: ")) + String(voltage_output_value) + String(F("/3.3 [V]"));
  doc["percentageCommandOut"] = String(F("Uscita comando PWM: ")) + String(PWM_output_percentage) + String(F(" [%]"));
  doc["waterTankLevel"] = waterLevelEmpty ? String(F("VUOTO")) : String(F("PIENO"));
  doc["powerOnTime"] = String(powerOnTime) + String(F(" min"));
  doc["current"] = String(current) + String(F(" A"));
  doc["voltage"] = String(voltage) + String(F(" V"));
  doc["temperature1"] = String(temperature1) + String(F(" °C"));
  doc["temperature2"] = String(temperature2) + String(F(" °C"));
  doc["set_timer"] = String(F("Timer : ")) + String(set_timer) + String(F(" min"));
}

void checkRegeneration() {
  if(set_timer == 0) {
    startRegeneration = false;
  }
}

void readMinutesCounterFromEEPROM() {
  // Read the counter value from EEPROM
  unsigned long max_minutesCounter = 0UL - 1UL;
  
  EEPROM.begin(sizeof(powerOnTime));
  EEPROM.get(0, powerOnTime);

  if(powerOnTime == max_minutesCounter) {
    powerOnTime = 0;
    Serial.println("Minutes Counter reinitialized");
    saveMinutesCounterInEEPROM();
  }
  
  Serial.print("powerOnTime: ");
  Serial.println(powerOnTime);
}

void updateMinutesCounter() {
  currentMillis = millis();
  if((currentMillis - previousMillis) > 1000) {
    previousMillis = currentMillis;
    secondsCounter++;
    if(secondsCounter % 60 == 0) {
      secondsCounter = 0;
      minutesCounter++;
      powerOnTime++;
      if(minutesCounter % 10 == 0) { //salva contatore in EEPROM ogni 10 minuti
        saveMinutesCounterInEEPROM();
      }
      Serial.print("cumulatedMinutesCounter:");
      Serial.println(powerOnTime);
      if(set_timer > 0) {
        set_timer--;
      }
    }
  }    
}

void saveMinutesCounterInEEPROM()  {
  EEPROM.put(0, powerOnTime);
  EEPROM.commit();
} 

void readGPSAndCheckSpeed() {
  if(startRegeneration == false) {
    while (ss.available() > 0) {
      if (gps.encode(ss.read())) {
        checkSpeed();
      }
    }

    if (millis() > 5000 && gps.charsProcessed() < 10) {
      velocita = -1.0;
      PWM_output_percentage = PWM_output_percentage_0A;
      setCurrentOutput(PWM_output_percentage);
    }
  } else {
    PWM_output_percentage = lookup_phyData_from_voltage(set_current, SEGMENT_POINTS_voltage_Temperature, &(voltage_Temperature_lookup[0][0]));
    setCurrentOutput(PWM_output_percentage);
  }
}

void setCurrentOutput(float PWM_outputPercentage) {
  pot.setPosition(PWM_outputPercentage);   //  position
  voltage_output_value = PWM_outputPercentage * 5.0 / 100.0;  
}

void readCurrent() { 
  int mA = ACS.mA_DC(30); //30 acquisizioni di media
  float tempCurrent = float(mA) / 1000;
  current = current * 0.7 + tempCurrent * 0.3;
}

void readVoltage() {
  float adc_voltage = 0.0;
  float R1 = 30000.0;
  float R2 = 7500.0; 
  float ref_voltage = 3.3;

  float adc_value = analogRead(voltage_pin);
  adc_voltage  = (adc_value * ref_voltage) / 4096.0;
  voltage = adc_voltage * (R1 + R2) / R2;
}

void readWaterTank() {
  waterLevelEmpty = digitalRead(water_level_pin);
}

void checkSpeed() {
  if (gps.location.isValid()) {
    velocita = gps.speed.kmph();
    if(millis() - SpeedShowTimer > TEMPO_ATTESA_VISUALIZZAZIONE_VELOCITA) {
      if(velocita > VELOCITA_SOGLIA_HIGH) {
        PWM_output_percentage = PWM_output_percentage_9A;
        setCurrentOutput(PWM_output_percentage);
      } else if(velocita > VELOCITA_SOGLIA_0A_HIGH && velocita < VELOCITA_SOGLIA_LOW) {
        PWM_output_percentage = PWM_output_percentage_5A;
        setCurrentOutput(PWM_output_percentage);
      } else if(velocita < VELOCITA_SOGLIA_0A_LOW) {
        PWM_output_percentage = PWM_output_percentage_0A;
        setCurrentOutput(PWM_output_percentage);
      }
      SpeedShowTimer = millis();
    }
  } else {
    Serial.println(F("NO GPS FIX!"));
    velocita = -1.0;
    PWM_output_percentage = PWM_output_percentage_0A;
    setCurrentOutput(PWM_output_percentage);
  }
}

void readTemp1() {
    sensor1.requestTemperatures(); // Send the command to get temperatures
    temperature1 = sensor1.getTempCByIndex(0);
    if(temperature1 == DEVICE_DISCONNECTED_C) {
      temperature1 = -100;
    }  
}

void readTemp2() {
    sensor2.requestTemperatures(); // Send the command to get temperatures
    temperature2 = sensor2.getTempCByIndex(0);
    if(temperature2 == DEVICE_DISCONNECTED_C) {
      temperature2 = -100;
    }  
}

float lookup_phyData_from_voltage(float voltage, int segment_points, const float* voltage_phyData_lookup) {
    uint8_t index = 0;
    const float *voltagePointer = &voltage_phyData_lookup[0];
    const float *phyDataPointer = &voltage_phyData_lookup[segment_points];

    voltage = min(voltage, voltagePointer[segment_points-1]);
    voltage = max(voltage, voltagePointer[0]);

    while(voltagePointer[index] <= voltage && index < segment_points) {
        index++;
    }

    if(index == 0) {
        return map_f(voltage, voltagePointer[0], voltagePointer[1], phyDataPointer[0], phyDataPointer[1]);
    } else if(index == segment_points) {
        return map_f(voltage, voltagePointer[segment_points-2], voltagePointer[segment_points-1], phyDataPointer[segment_points-2], phyDataPointer[segment_points-1]);
    } else {
        return map_f(voltage, voltagePointer[index-1], voltagePointer[index], phyDataPointer[index-1], phyDataPointer[index]);
    }
}

float map_f(float x, float in_min, float in_max, float out_min, float out_max) {
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

static void smartDelay(unsigned long ms) {
  unsigned long start = millis();
  do {
    while (ss.available())
      gps.encode(ss.read());
  } while (millis() - start < ms);
}

void resetDataRegeneration() {
  PWM_output_percentage = PWM_output_percentage_0A;
  setCurrentOutput(PWM_output_percentage);
  startRegeneration = false;
  set_current = 0;
  set_timer = 0;
}

void extractSubstring(String str, char delimiter)  {
  int startIndex = 0;
  int endIndex = str.indexOf(delimiter);
  int counter = 0;

  while(endIndex != -1) {
    String part = str.substring(startIndex, endIndex);
    Serial.println(part);
    if(counter == 0) {
      counter++; // qui c'è 'POST'
    } else if (counter == 1) {
      set_current = part.toInt();
      counter++;
    } else if (counter == 2) {
      set_timer = part.toInt();
      counter++;
    }
    startIndex = endIndex + 1;
    endIndex = str.indexOf(delimiter, startIndex);
  }
}

/* END CODE */