0% found this document useful (0 votes)
9 views14 pages

ESP32 Power Monitoring System Code

This document contains code for an ESP32-based power monitoring system that measures voltage, current, and power, and provides a web interface for monitoring and controlling a relay. It includes HTML and JavaScript for the frontend display, as well as backend logic for handling ADC readings and relay control. The system operates as a WiFi access point, allowing users to access the monitoring interface via a web browser.

Uploaded by

Anushka Gupta
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views14 pages

ESP32 Power Monitoring System Code

This document contains code for an ESP32-based power monitoring system that measures voltage, current, and power, and provides a web interface for monitoring and controlling a relay. It includes HTML and JavaScript for the frontend display, as well as backend logic for handling ADC readings and relay control. The system operates as a WiFi access point, allowing users to access the monitoring interface via a web browser.

Uploaded by

Anushka Gupta
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

#include <WiFi.

h>

#include <WebServer.h>

#define VOLTAGE_PIN 32

#define CURRENT_PIN 34

#define RELAY_PIN 5

#define HOLD_LOW_SWITCH_PIN 2 // Manual override (Force LOW)

float sensorMaxVoltage = 25.0;

int adcMax = 4095;

float refVoltage = 3.3;

float ACS_Zero = 0;

float ACS_Sensitivity = 0.100;

WebServer server(80);

const char MAIN_page[] PROGMEM = R"=====(

<!DOCTYPE html>

<html>

<head>

<title>ESP32 Power Monitor</title>

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<style>

body {

font-family: Arial, sans-serif;

background: #121212;

color: #E5E5E5;

text-align: center;
margin: 0;

padding: 0;

.container {

width: 100%;

margin: 0 auto;

padding-bottom: 40px;

/* TOP CARD */

.card {

width: 350px;

margin: 25px auto;

padding: 24px;

background: #1E1E1E;

border-radius: 18px;

box-shadow: 0 6px 18px rgba(0,0,0,0.55);

.valueBox {

font-size: 26px;

margin: 10px;

color: #FFFFFF;

/* SWITCH */

.toggle {

width: 62px;

height: 34px;

position: relative;
display: inline-block;

.toggle input { display:none; }

.slider {

position:absolute; cursor:pointer; top:0; left:0; right:0; bottom:0;

background:#3A3A3A; border-radius:34px; transition: .3s;

.slider:before {

position:absolute; content:""; height:26px; width:26px;

left:4px; bottom:4px;

background:white; border-radius:50%; transition:.3s;

input:checked + .slider { background:#0A84FF; }

input:checked + .slider:before { transform: translateX(26px); }

/* GRAPH ROW — default desktop mode */

.graphRow {

display: flex;

flex-wrap: wrap;

gap: 20px;

width: 100%;

justify-content: space-between;

padding: 10px 20px;

box-sizing: border-box;

/* GRAPH CARD — desktop = 1/3 width */


.graphCard {

background: #1E1E1E;

border-radius: 18px;

padding: 16px;

flex: 1;

min-width: 260px;

max-width: 33%;

box-shadow: 0 6px 18px rgba(0,0,0,0.45);

.smallLabel {

margin-bottom: 10px;

font-size: 15px;

color: #BFBFBF;

/* CANVAS */

canvas {

width: 100%;

height: 180px;

background: #121212;

border-radius: 12px;

box-shadow: inset 0 4px 8px rgba(0,0,0,0.6);

/* MOBILE MODE (<768px) → stack vertically */

@media (max-width: 768px) {

.graphRow {

flex-direction: column;

padding: 10px 12px;

}
.graphCard {

max-width: 100%;

width: 100%;

/* SMALL PHONES (<480px) */

@media (max-width: 480px) {

.graphCard {

padding: 14px;

canvas {

height: 160px;

</style>

<script>

// DATA ARRAYS

const maxPoints = 40;

let voltHistory = new Array(maxPoints).fill(0);

let currHistory = new Array(maxPoints).fill(0);

let powerHistory = new Array(maxPoints).fill(0);

// ------------------------------------------------------

// DRAW SIMPLE LINE CHART

// ------------------------------------------------------

function drawLineChart(canvasId, data, color, unit) {


const canvas = [Link](canvasId);

const ctx = [Link]('2d');

const w = [Link];

const h = [Link];

[Link](0,0,w,h);

[Link] = '#121212';

[Link](0,0,w,h);

// GRID

[Link] = '#222';

[Link] = 1;

for (let i=0;i<=4;i++) {

let y = i*(h/4);

[Link]();

[Link](0,y);

[Link](w,y);

[Link]();

// RANGE

let maxVal = [Link](...data);

let minVal = [Link](...data);

if (maxVal === minVal) { maxVal += 1; minVal -= 1; }

const step = w / ([Link] - 1);

// LINE

[Link]();

[Link] = 2.4;
[Link] = color;

for (let i=0;i<[Link];i++){

const x = i * step;

const y = h - ((data[i] - minVal) / (maxVal - minVal)) * h;

if (i === 0) [Link](x,y);

else [Link](x,y);

[Link]();

// POINTS

[Link] = color;

for (let i=0;i<[Link];i++){

const x = i * step;

const y = h - ((data[i] - minVal) / (maxVal - minVal)) * h;

[Link]();

[Link](x,y,2,0,[Link]*2);

[Link]();

// LABELS

[Link] = '#BFBFBF';

[Link] = '12px Arial';

[Link](unit + " max: " + [Link](2), 5, 12);

[Link]("min: " + [Link](2), 5, h - 5);

// ------------------------------------------------------

// UPDATE UI

// ------------------------------------------------------

function updateUI(v, c, p, relayOn) {


[Link]("volt").innerText = [Link](2);

[Link]("curr").innerText = [Link](2);

[Link]("pow").innerText = [Link](2);

[Link]("relayState").checked = !!relayOn;

[Link](); [Link](); [Link]();

[Link](v); [Link](c); [Link](p);

drawLineChart("voltCanvas", voltHistory, "#0A84FF", "V");

drawLineChart("currCanvas", currHistory, "#00D17A", "A");

drawLineChart("powerCanvas", powerHistory, "#FFCE44", "W");

// ------------------------------------------------------

// FETCH JSON FROM ESP32

// ------------------------------------------------------

function fetchValues() {

fetch("/values")

.then(r => [Link]())

.then(data => {

updateUI(

parseFloat([Link]),

parseFloat([Link]),

parseFloat([Link]),

[Link] == 1

);

});

function toggleRelay() {
fetch("/toggle").then(() => setTimeout(fetchValues, 200));

// ------------------------------------------------------

// PAGE LOAD

// ------------------------------------------------------

[Link] = function() {

const ids = ["voltCanvas","currCanvas","powerCanvas"];

// Auto-size canvases to actual displayed width

[Link](id => {

let c = [Link](id);

let displayWidth = [Link];

[Link] = displayWidth;

[Link] = 180;

});

fetchValues();

setInterval(fetchValues, 1000);

};

</script>

</head>

<body>

<div class="container">

<div class="card">

<h2>ESP32 Power Monitor</h2>


<div class="valueBox">Voltage: <span id="volt">--</span> V</div>

<div class="valueBox">Current: <span id="curr">--</span> A</div>

<div class="valueBox">Power: <span id="pow">--</span> W</div>

<h3>Relay Control</h3>

<label class="toggle">

<input type="checkbox" id="relayState" onclick="toggleRelay()">

<span class="slider"></span>

</label>

</div>

<!-- RESPONSIVE FULL-WIDTH GRAPH ROW -->

<div class="graphRow">

<div class="graphCard">

<div class="smallLabel">Voltage (V)</div>

<canvas id="voltCanvas"></canvas>

</div>

<div class="graphCard">

<div class="smallLabel">Current (A)</div>

<canvas id="currCanvas"></canvas>

</div>

<div class="graphCard">

<div class="smallLabel">Power (W)</div>

<canvas id="powerCanvas"></canvas>

</div>

</div>
</div>

</body>

</html>

)=====";

// ---------- AVERAGE ADC ----------

int readADC(int pin) {

long sum = 0;

for (int i = 0; i < 100; i++) {

sum += analogRead(pin);

delayMicroseconds(200);

return sum / 100;

// ---------- CALIBRATION ----------

void calibrateACS() {

long sum = 0;

for (int i = 0; i < 500; i++) {

sum += analogRead(CURRENT_PIN);

delay(2);

float raw = sum / 500.0;

ACS_Zero = (raw * refVoltage) / adcMax;

// ---------- HOLD-LOW SWITCH ----------

bool checkHoldLowSwitch() {
if (digitalRead(HOLD_LOW_SWITCH_PIN) == HIGH) {

digitalWrite(RELAY_PIN, LOW); // force LOW (ON)

return true;

} else {

return false;

// ---------- AUTO-OFF WHEN CURRENT = 0 ----------

void handleAutoCurrentOff(float current) {

// placeholder - disabled by default

// if (current <= 0.01) {

// digitalWrite(RELAY_PIN, HIGH); // OFF

// }

// ========= WEB HANDLERS =========

void handleRoot() {

server.send_P(200, "text/html", MAIN_page);

void handleValues() {

// Read voltage

int rawVolt = readADC(VOLTAGE_PIN);

float voltageOut = (rawVolt * refVoltage) / adcMax;

float voltage = voltageOut * (sensorMaxVoltage / refVoltage);

// Read current

int rawCurrent = readADC(CURRENT_PIN);

float voltageACS = (rawCurrent * refVoltage) / adcMax;


float current = (voltageACS - ACS_Zero) / ACS_Sensitivity;

if (current < 0.01) current = 0;

float power = voltage * current;

// Apply logic

if (!checkHoldLowSwitch()) {

handleAutoCurrentOff(current);

int relayPhysical = digitalRead(RELAY_PIN);

// We define relayOn = 1 if physical pin is LOW (assuming LOW energizes relay)

int relayOn = (relayPhysical == LOW) ? 1 : 0;

String json = "{";

json += "\"voltage\":" + String(voltage, 2) + ",";

json += "\"current\":" + String(current, 2) + ",";

json += "\"power\":" + String(power, 2) + ",";

json += "\"relay\":" + String(relayOn);

json += "}";

[Link](200, "application/json", json);

void handleToggle() {

int state = digitalRead(RELAY_PIN);

// toggle: if currently HIGH (OFF) -> set LOW (ON), else set HIGH (OFF)

if (state == HIGH) digitalWrite(RELAY_PIN, LOW); else digitalWrite(RELAY_PIN, HIGH);

[Link](200, "text/plain", "OK");

// ---------- SETUP ----------


void setup() {

[Link](115200);

delay(1000);

pinMode(RELAY_PIN, OUTPUT);

pinMode(HOLD_LOW_SWITCH_PIN, INPUT_PULLDOWN);

digitalWrite(RELAY_PIN, HIGH); // Relay OFF initially

calibrateACS();

// ---- WiFi ----

[Link]("Starting WiFi Access Point...");

[Link]("ESP32-PowerMonitor", "12345678"); // You can change both

[Link]("AP IP Address: ");

[Link]([Link]());

// Web routes

[Link]("/", handleRoot);

[Link]("/values", handleValues);

[Link]("/toggle", handleToggle);

[Link]();

// ---------- LOOP ----------

void loop() {

[Link]();

Common questions

Powered by AI

The data fetching and UI update process involves sending a request to the '/values' endpoint, which returns the current sensor measurements as a JSON object. This data is then used to update the on-page elements displaying voltage, current, and power, and plots these values on respective charts. This continuous fetch cycle is triggered on page load and repeats every second, ensuring the user sees near real-time data. This process is crucial for maintaining timely and accurate monitoring of electric parameters .

The "Hold Low Switch" is used as a manual override to force the relay into a LOW state, essentially turning it ON. The system checks the switch's state regularly, and if it is detected to be HIGH, it forces the relay to LOW, overriding automated or remote control .

Programmatically, the relay state is controlled through a toggle switch on the web interface, which sends requests to change the relay state. Manually, the relay can be controlled using the "Hold Low Switch", which forces it to a LOW state. The relay logic assumes the relay is LOW when ON and HIGH when OFF .

The UI's minimalist design with concise data presentation aids in quickly interpreting electrical metrics. The use of color-coded line charts enhances comprehension of trends. However, the interface's reliance on real-time updates without historical data storage or analysis could limit long-term trend analysis. Including features like historical data downloads may enhance interpretability for more informed decision-making .

ACS_Sensitivity, set to 0.100, defines the sensitivity of the current sensor in volts per ampere. It is used in the calculation of the current by dividing the adjusted voltage measurement by this sensitivity to convert it into amperes. It ensures that the current readings are accurately translated from the sensed voltage drop across the ACS line .

The power calculation involves multiplying the measured voltage by current. While straightforward, this method assumes linearity and no phase shift between current and voltage, which may not always be accurate in AC systems. Further improvements might include factoring in real-time compensation for phase differences or using RMS values for better accuracy in AC power calculation .

The line chart visualizes the history of voltage, current, and power measurements, allowing for easy tracking of trends over time. The design includes responsiveness to adjust the charts based on screen size, with styles for desktop and mobile views. Canvas elements are auto-sized to fit their display width, ensuring clarity across devices .

The web interface provides a dynamically updating visualization of voltage, current, and power measurements using line charts. It displays real-time data in a responsive design optimized for various screen sizes. Users can also control a relay through a toggle switch on the interface .

The ESP32 Power Monitor calibrates current readings by averaging ADC values from the current sensor over multiple readings during setup. It calculates ACS_Zero, the offset voltage, based on these average measurements to ensure accuracy .

The web server hosted on the ESP32 facilitates interaction between the hardware and the user via the web interface. It serves the HTML page, handles routing requests for data, toggles relay states, and delivers real-time sensor measurements. This server functionality enables remote monitoring and control of electrical parameters .

You might also like