Uploaded C++ code of project
parent
6ee020a4d4
commit
c8d7fed5f5
@ -0,0 +1,495 @@
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <Wire.h>
|
||||
#include <INA226.h>
|
||||
#include <ESP8266HTTPClient.h>
|
||||
|
||||
const int redPin = 12; // Red
|
||||
const int greenPin = 13; // Green
|
||||
const int bluePin = 14; // Blue
|
||||
|
||||
const int warning = 16;
|
||||
const int pwmResolution = 1024;
|
||||
|
||||
TwoWire Wire_;
|
||||
|
||||
// INA226 instances
|
||||
INA226 redINA(0x45, &Wire_); // 1000101
|
||||
INA226 blueINA(0x41, &Wire_); // 1000100
|
||||
INA226 greenINA(0x44, &Wire_); // 1000001
|
||||
|
||||
const char *ssid = "dlink-AB48";
|
||||
const char *password = "mjjbk74568";
|
||||
|
||||
// Array to store slave IP addresses
|
||||
const char* slaveIPs[] = {
|
||||
"192.168.129.119", // Slave 1
|
||||
};
|
||||
const int NUM_SLAVES = sizeof(slaveIPs) / sizeof(slaveIPs[0]);
|
||||
|
||||
int redValue = 0;
|
||||
int greenValue = 0;
|
||||
int blueValue = 0;
|
||||
float brightness = 100.0;
|
||||
bool rainbowActive = false;
|
||||
unsigned long lastRainbowUpdate = 0;
|
||||
int currentHue = 0;
|
||||
|
||||
// New variables for current monitoring
|
||||
float redCurrent = 0;
|
||||
float greenCurrent = 0;
|
||||
float blueCurrent = 0;
|
||||
unsigned long lastCurrentUpdate = 0;
|
||||
|
||||
ESP8266WebServer server(80);
|
||||
WiFiClient wifiClient;
|
||||
|
||||
|
||||
void handleSetRGB() {
|
||||
if (server.hasArg("r") && server.hasArg("g") && server.hasArg("b")) {
|
||||
redValue = server.arg("r").toInt();
|
||||
greenValue = server.arg("g").toInt();
|
||||
blueValue = server.arg("b").toInt();
|
||||
rainbowActive = false;
|
||||
|
||||
// Set master LED
|
||||
setRGB(redValue, greenValue, blueValue, brightness);
|
||||
|
||||
// Propagate to slaves
|
||||
String url = String("/set_rgb?r=") + redValue +
|
||||
String("&g=") + greenValue +
|
||||
String("&b=") + blueValue;
|
||||
propagateToSlaves(url);
|
||||
|
||||
server.send(200, "text/plain", "RGB updated");
|
||||
} else {
|
||||
server.send(400, "text/plain", "Missing RGB arguments");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Modified handleSetBrightness to propagate to slaves
|
||||
void handleSetBrightness() {
|
||||
if (server.hasArg("value")) {
|
||||
brightness = server.arg("value").toFloat();
|
||||
setRGB(redValue, greenValue, blueValue, brightness);
|
||||
|
||||
// Propagate to slaves
|
||||
String url = String("/set_brightness?value=") + brightness;
|
||||
propagateToSlaves(url);
|
||||
|
||||
server.send(200, "text/plain", "Brightness updated");
|
||||
} else {
|
||||
server.send(400, "text/plain", "Missing brightness argument");
|
||||
}
|
||||
}
|
||||
|
||||
// Modified handleRainbow to propagate to slaves
|
||||
void handleRainbow() {
|
||||
if (server.hasArg("state")) {
|
||||
rainbowActive = server.arg("state") == "true";
|
||||
if (!rainbowActive) {
|
||||
setRGB(redValue, greenValue, blueValue, brightness);
|
||||
}
|
||||
|
||||
// Propagate to slaves
|
||||
String url = String("/rainbow?state=") + server.arg("state");
|
||||
propagateToSlaves(url);
|
||||
}
|
||||
server.send(200, "text/plain", rainbowActive ? "Rainbow started" : "Rainbow stopped");
|
||||
}
|
||||
|
||||
// New function to propagate commands to slaves
|
||||
void propagateToSlaves(String endpoint) {
|
||||
HTTPClient http;
|
||||
for (int i = 0; i < NUM_SLAVES; i++) {
|
||||
String url = String("http://") + slaveIPs[i] + endpoint;
|
||||
http.begin(wifiClient, url);
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode != HTTP_CODE_OK) {
|
||||
Serial.printf("Failed to propagate to slave %s: %d\n", slaveIPs[i], httpCode);
|
||||
}
|
||||
http.end();
|
||||
}
|
||||
}
|
||||
|
||||
void handleGetCurrents() {
|
||||
String json = "{\"red\":" + String(redCurrent, 3) +
|
||||
",\"green\":" + String(greenCurrent, 3) +
|
||||
",\"blue\":" + String(blueCurrent, 3) +
|
||||
",\"total\":" + String(redCurrent + greenCurrent + blueCurrent, 3) +
|
||||
",\"redBusV\":" + String(redINA.getBusVoltage(), 3) +
|
||||
",\"greenBusV\":" + String(greenINA.getBusVoltage(), 3) +
|
||||
",\"blueBusV\":" + String(blueINA.getBusVoltage(), 3) +
|
||||
"}";
|
||||
server.send(200, "application/json", json);
|
||||
}
|
||||
|
||||
void scanI2CBus(TwoWire &wire) {
|
||||
Serial.println("Scanning I2C Bus...");
|
||||
for (uint8_t address = 1; address < 127; ++address) {
|
||||
wire.beginTransmission(address);
|
||||
if (wire.endTransmission() == 0) {
|
||||
Serial.print("Device found at address 0x");
|
||||
Serial.println(address, HEX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initializeINA226(INA226 &sensor, const char* name) {
|
||||
if (!sensor.begin()) {
|
||||
Serial.print("INA226 initialization failed for ");
|
||||
Serial.println(name);
|
||||
} else {
|
||||
Serial.print("INA226 initialized for ");
|
||||
Serial.println(name);
|
||||
}
|
||||
|
||||
if (strcmp(name, "RED") == 0) {
|
||||
sensor.setMaxCurrentShunt(0.4, 0.09);
|
||||
} else if (strcmp(name, "GREEN") == 0) {
|
||||
sensor.setMaxCurrentShunt(0.35, 0.18);
|
||||
} else if (strcmp(name, "BLUE") == 0) {
|
||||
sensor.setMaxCurrentShunt(0.35, 0.18);
|
||||
} else {
|
||||
// Default case for unknown names
|
||||
sensor.setMaxCurrentShunt(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
analogWriteRange(pwmResolution);
|
||||
Serial.println("Initializing RGB LED Controller with Current Monitoring");
|
||||
|
||||
|
||||
pinMode(redPin, OUTPUT);
|
||||
pinMode(greenPin, OUTPUT);
|
||||
pinMode(bluePin, OUTPUT);
|
||||
setRGB(redValue, greenValue, blueValue, brightness);
|
||||
|
||||
delay(100);
|
||||
Wire_.begin(5, 4);
|
||||
delay(200);
|
||||
scanI2CBus(Wire_);
|
||||
delay(200); // Extended delay
|
||||
initializeINA226(redINA, "RED");
|
||||
delay(200);
|
||||
initializeINA226(greenINA, "GREEN");
|
||||
delay(200);
|
||||
initializeINA226(blueINA, "BLUE");
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(1000);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println("Connected to Wi-Fi");
|
||||
Serial.print("IP Address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
server.on("/", handleRoot);
|
||||
server.on("/set_rgb", handleSetRGB);
|
||||
server.on("/set_brightness", handleSetBrightness);
|
||||
server.on("/rainbow", handleRainbow);
|
||||
server.on("/get_currents", handleGetCurrents);
|
||||
|
||||
server.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
server.handleClient();
|
||||
|
||||
unsigned long currentMillis = millis();
|
||||
|
||||
// Current measurement update (every 100ms)
|
||||
if (currentMillis - lastCurrentUpdate >= 100) {
|
||||
// Get current readings from all sensors
|
||||
redCurrent = redINA.getCurrent_mA();
|
||||
greenCurrent = greenINA.getCurrent_mA();
|
||||
blueCurrent = blueINA.getCurrent_mA();
|
||||
lastCurrentUpdate = currentMillis;
|
||||
}
|
||||
|
||||
// Rainbow animation update (every 20ms)
|
||||
if (rainbowActive && (currentMillis - lastRainbowUpdate >= 20)) {
|
||||
float r, g, b;
|
||||
hsvToRgb(currentHue, 1.0, brightness / 100.0, r, g, b);
|
||||
setRGB((int)(r * 255), (int)(g * 255), (int)(b * 255), brightness);
|
||||
currentHue = (currentHue + 1) % 360;
|
||||
lastRainbowUpdate = currentMillis;
|
||||
}
|
||||
}
|
||||
|
||||
void hsvToRgb(int hue, float saturation, float value, float &r, float &g, float &b) {
|
||||
float c = value * saturation;
|
||||
float x = c * (1 - abs(fmod(hue / 60.0, 2) - 1));
|
||||
float m = value - c;
|
||||
|
||||
if (hue >= 0 && hue < 60) {
|
||||
r = c; g = x; b = 0;
|
||||
} else if (hue >= 60 && hue < 120) {
|
||||
r = x; g = c; b = 0;
|
||||
} else if (hue >= 120 && hue < 180) {
|
||||
r = 0; g = c; b = x;
|
||||
} else if (hue >= 180 && hue < 240) {
|
||||
r = 0; g = x; b = c;
|
||||
} else if (hue >= 240 && hue < 300) {
|
||||
r = x; g = 0; b = c;
|
||||
} else {
|
||||
r = c; g = 0; b = x;
|
||||
}
|
||||
|
||||
r += m; g += m; b += m;
|
||||
}
|
||||
|
||||
int mapDutyCycle(int value, float brightness) {
|
||||
float adjusted = value * (brightness / 100.0);
|
||||
return (int)(adjusted * pwmResolution / 255.0);
|
||||
}
|
||||
|
||||
void setRGB(int red, int green, int blue, float brightness) {
|
||||
analogWrite(redPin, mapDutyCycle(red, brightness));
|
||||
analogWrite(greenPin, mapDutyCycle(green, brightness));
|
||||
analogWrite(bluePin, mapDutyCycle(blue, brightness));
|
||||
}
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
|
||||
// [Previous ESP8266 setup code remains the same until handleRoot()]
|
||||
|
||||
void handleRoot() {
|
||||
String html = R"rawliteral(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>RGB Control</title>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.14/vue.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-color/2.8.1/vue-color.min.js"></script>
|
||||
<style>
|
||||
@import url(https://fonts.googleapis.com/css?family=Barlow);
|
||||
* { font-family: "Barlow"; box-sizing: border-box; }
|
||||
body {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background: #f0f0f0;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.page-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 2rem;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.container {
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||
width: 500px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.current-monitor {
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||
width: 500px;
|
||||
}
|
||||
.current-display {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.current-item {
|
||||
padding: 1rem;
|
||||
border-radius: 10px;
|
||||
color: white;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.current-red { background: linear-gradient(to right, #ff0000, #ff4444); }
|
||||
.current-green { background: linear-gradient(to right, #00ff00, #44ff44); }
|
||||
.current-blue { background: linear-gradient(to right, #0000ff, #4444ff); }
|
||||
.current-total {
|
||||
background: linear-gradient(to right, #666, #999);
|
||||
font-weight: bold;
|
||||
}
|
||||
.vc-chrome {
|
||||
width: 100% !important;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
.controls {
|
||||
width: 100%;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.brightness-control {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
.brightness-control input {
|
||||
width: 100%;
|
||||
}
|
||||
.color-preview {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
border-radius: 10px;
|
||||
margin: 1rem 0;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container,
|
||||
.current-monitor {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
}
|
||||
.page-container {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
new Vue({
|
||||
el: "#app",
|
||||
components: {
|
||||
'chrome-picker': VueColor.Chrome
|
||||
},
|
||||
data: {
|
||||
color: {
|
||||
hex: "#000000",
|
||||
rgba: { r: 0, g: 0, b: 0, a: 1 }
|
||||
},
|
||||
brightness: 0,
|
||||
rainbow: false,
|
||||
currents: {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateColor(color) {
|
||||
this.color = color;
|
||||
const { r, g, b } = color.rgba;
|
||||
fetch(`/set_rgb?r=${r}&g=${g}&b=${b}`);
|
||||
},
|
||||
updateBrightness() {
|
||||
fetch(`/set_brightness?value=${this.brightness}`);
|
||||
},
|
||||
toggleRainbow() {
|
||||
fetch(`/rainbow?state=${this.rainbow}`);
|
||||
},
|
||||
async updateCurrents() {
|
||||
try {
|
||||
const response = await fetch('/get_currents');
|
||||
this.currents = await response.json();
|
||||
} catch (error) {
|
||||
console.error('Error fetching currents:', error);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// Send initial state to the server
|
||||
const { r, g, b } = this.color.rgba;
|
||||
fetch(`/set_rgb?r=${r}&g=${g}&b=${b}`);
|
||||
fetch(`/set_brightness?value=${this.brightness}`);
|
||||
setInterval(this.updateCurrents, 200);
|
||||
},
|
||||
computed: {
|
||||
previewStyle() {
|
||||
const { r, g, b } = this.color.rgba;
|
||||
const brightness = this.brightness / 100;
|
||||
return {
|
||||
backgroundColor: `rgba(${r}, ${g}, ${b}, ${brightness})`,
|
||||
boxShadow: `0 0 15px rgba(${r}, ${g}, ${b}, ${brightness})`
|
||||
};
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="page-container">
|
||||
<div class="container">
|
||||
<h1 class="title">RGB Control</h1>
|
||||
|
||||
<div class="color-preview" :style="previewStyle"></div>
|
||||
|
||||
<chrome-picker
|
||||
:value="color"
|
||||
@input="updateColor"
|
||||
:disable-alpha="true"
|
||||
></chrome-picker>
|
||||
|
||||
<div class="controls">
|
||||
<div class="brightness-control">
|
||||
<p>Brightness: {{ brightness }}%</p>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
v-model="brightness"
|
||||
@change="updateBrightness"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rainbow-toggle">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="rainbow"
|
||||
@change="toggleRainbow"
|
||||
/>
|
||||
Rainbow Animation
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="current-monitor">
|
||||
<h2>Current Monitor</h2>
|
||||
<div class="current-display">
|
||||
<div class="current-item current-red">
|
||||
<span>Red LED:</span>
|
||||
<span>{{ currents.red.toFixed(2) }} mA</span>
|
||||
</div>
|
||||
<div class="current-item current-green">
|
||||
<span>Green LED:</span>
|
||||
<span>{{ currents.green.toFixed(2) }} mA</span>
|
||||
</div>
|
||||
<div class="current-item current-blue">
|
||||
<span>Blue LED:</span>
|
||||
<span>{{ currents.blue.toFixed(2) }} mA</span>
|
||||
</div>
|
||||
<div class="current-item current-total">
|
||||
<span>Total Current:</span>
|
||||
<span>{{ currents.total.toFixed(2) }} mA</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)rawliteral";
|
||||
|
||||
server.send(200, "text/html", html);
|
||||
}
|
@ -0,0 +1,453 @@
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <Wire.h>
|
||||
#include <INA226.h>
|
||||
|
||||
|
||||
const int redPin = 12; // Red
|
||||
const int greenPin = 13; // Green
|
||||
const int bluePin = 14; // Blue
|
||||
|
||||
const int warning = 16;
|
||||
const int pwmResolution = 1024;
|
||||
|
||||
TwoWire Wire_;
|
||||
|
||||
// WiFi Configuration
|
||||
const char *ap_ssid = "RGB_Controller"; // Name of the WiFi network to create
|
||||
const char *ap_password = "12345678"; // Password for the WiFi network
|
||||
IPAddress local_ip(192,168,4,1); // Static IP address for the access point
|
||||
IPAddress gateway(192,168,4,1); // Gateway (same as static IP)
|
||||
IPAddress subnet(255,255,255,0); // Subnet mask
|
||||
|
||||
// INA226 instances
|
||||
INA226 redINA(0x45, &Wire_); // 1000101
|
||||
INA226 blueINA(0x41, &Wire_); // 1000100
|
||||
INA226 greenINA(0x44, &Wire_); // 1000001
|
||||
|
||||
|
||||
ESP8266WebServer server(80);
|
||||
|
||||
int redValue = 0;
|
||||
int greenValue = 0;
|
||||
int blueValue = 0;
|
||||
float brightness = 100.0;
|
||||
bool rainbowActive = false;
|
||||
unsigned long lastRainbowUpdate = 0;
|
||||
int currentHue = 0;
|
||||
|
||||
// New variables for current monitoring
|
||||
float redCurrent = 0;
|
||||
float greenCurrent = 0;
|
||||
float blueCurrent = 0;
|
||||
unsigned long lastCurrentUpdate = 0;
|
||||
|
||||
void handleSetRGB() {
|
||||
if (server.hasArg("r") && server.hasArg("g") && server.hasArg("b")) {
|
||||
redValue = server.arg("r").toInt();
|
||||
greenValue = server.arg("g").toInt();
|
||||
blueValue = server.arg("b").toInt();
|
||||
rainbowActive = false; // Stop rainbow when setting manual color
|
||||
setRGB(redValue, greenValue, blueValue, brightness);
|
||||
server.send(200, "text/plain", "RGB updated");
|
||||
} else {
|
||||
server.send(400, "text/plain", "Missing RGB arguments");
|
||||
}
|
||||
delay(10);
|
||||
}
|
||||
|
||||
void handleSetBrightness() {
|
||||
if (server.hasArg("value")) {
|
||||
brightness = server.arg("value").toFloat();
|
||||
setRGB(redValue, greenValue, blueValue, brightness);
|
||||
server.send(200, "text/plain", "Brightness updated");
|
||||
} else {
|
||||
server.send(400, "text/plain", "Missing brightness argument");
|
||||
}
|
||||
}
|
||||
|
||||
void handleRainbow() {
|
||||
if (server.hasArg("state")) {
|
||||
rainbowActive = server.arg("state") == "true";
|
||||
if (!rainbowActive) {
|
||||
// Restore the last manual color when rainbow is turned off
|
||||
setRGB(redValue, greenValue, blueValue, brightness);
|
||||
}
|
||||
}
|
||||
server.send(200, "text/plain", rainbowActive ? "Rainbow started" : "Rainbow stopped");
|
||||
}
|
||||
|
||||
|
||||
void handleGetCurrents() {
|
||||
String json = "{\"red\":" + String(redCurrent, 3) +
|
||||
",\"green\":" + String(greenCurrent, 3) +
|
||||
",\"blue\":" + String(blueCurrent, 3) +
|
||||
",\"total\":" + String(redCurrent + greenCurrent + blueCurrent, 3) +
|
||||
",\"redBusV\":" + String(redINA.getBusVoltage(), 3) +
|
||||
",\"greenBusV\":" + String(greenINA.getBusVoltage(), 3) +
|
||||
",\"blueBusV\":" + String(blueINA.getBusVoltage(), 3) +
|
||||
"}";
|
||||
server.send(200, "application/json", json);
|
||||
}
|
||||
|
||||
void scanI2CBus(TwoWire &wire) {
|
||||
Serial.println("Scanning I2C Bus...");
|
||||
for (uint8_t address = 1; address < 127; ++address) {
|
||||
wire.beginTransmission(address);
|
||||
if (wire.endTransmission() == 0) {
|
||||
Serial.print("Device found at address 0x");
|
||||
Serial.println(address, HEX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initializeINA226(INA226 &sensor, const char* name) {
|
||||
if (!sensor.begin()) {
|
||||
Serial.print("INA226 initialization failed for ");
|
||||
Serial.println(name);
|
||||
} else {
|
||||
Serial.print("INA226 initialized for ");
|
||||
Serial.println(name);
|
||||
}
|
||||
|
||||
if (strcmp(name, "RED") == 0) {
|
||||
sensor.setMaxCurrentShunt(0.4, 0.09);
|
||||
} else if (strcmp(name, "GREEN") == 0) {
|
||||
sensor.setMaxCurrentShunt(0.35, 0.18);
|
||||
} else if (strcmp(name, "BLUE") == 0) {
|
||||
sensor.setMaxCurrentShunt(0.35, 0.18);
|
||||
} else {
|
||||
// Default case for unknown names
|
||||
sensor.setMaxCurrentShunt(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
analogWriteRange(pwmResolution);
|
||||
Serial.println("Initializing RGB LED Controller with Current Monitoring");
|
||||
|
||||
pinMode(redPin, OUTPUT);
|
||||
pinMode(greenPin, OUTPUT);
|
||||
pinMode(bluePin, OUTPUT);
|
||||
setRGB(redValue, greenValue, blueValue, brightness);
|
||||
|
||||
// Initialize I2C and INA226 sensors
|
||||
delay(100);
|
||||
Wire_.begin(5, 4);
|
||||
delay(200);
|
||||
scanI2CBus(Wire_);
|
||||
delay(200);
|
||||
initializeINA226(redINA, "RED");
|
||||
delay(200);
|
||||
initializeINA226(greenINA, "GREEN");
|
||||
delay(200);
|
||||
initializeINA226(blueINA, "BLUE");
|
||||
|
||||
// Configure ESP8266 as Access Point
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.softAPConfig(local_ip, gateway, subnet);
|
||||
WiFi.softAP(ap_ssid, ap_password);
|
||||
|
||||
Serial.println("WiFi Access Point Created");
|
||||
Serial.print("SSID: ");
|
||||
Serial.println(ap_ssid);
|
||||
Serial.print("Password: ");
|
||||
Serial.println(ap_password);
|
||||
Serial.print("IP Address: ");
|
||||
Serial.println(local_ip);
|
||||
|
||||
server.on("/", handleRoot);
|
||||
server.on("/set_rgb", handleSetRGB);
|
||||
server.on("/set_brightness", handleSetBrightness);
|
||||
server.on("/rainbow", handleRainbow);
|
||||
server.on("/get_currents", handleGetCurrents);
|
||||
|
||||
server.begin();
|
||||
Serial.println("HTTP server started");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
server.handleClient();
|
||||
|
||||
unsigned long currentMillis = millis();
|
||||
|
||||
// Current measurement update (every 100ms)
|
||||
if (currentMillis - lastCurrentUpdate >= 100) {
|
||||
// Get current readings from all sensors
|
||||
redCurrent = redINA.getCurrent_mA();
|
||||
greenCurrent = greenINA.getCurrent_mA();
|
||||
blueCurrent = blueINA.getCurrent_mA();
|
||||
lastCurrentUpdate = currentMillis;
|
||||
}
|
||||
|
||||
// Rainbow animation update (every 20ms)
|
||||
if (rainbowActive && (currentMillis - lastRainbowUpdate >= 20)) {
|
||||
float r, g, b;
|
||||
hsvToRgb(currentHue, 1.0, brightness / 100.0, r, g, b);
|
||||
setRGB((int)(r * 255), (int)(g * 255), (int)(b * 255), brightness);
|
||||
currentHue = (currentHue + 1) % 360;
|
||||
lastRainbowUpdate = currentMillis;
|
||||
}
|
||||
}
|
||||
|
||||
void hsvToRgb(int hue, float saturation, float value, float &r, float &g, float &b) {
|
||||
float c = value * saturation;
|
||||
float x = c * (1 - abs(fmod(hue / 60.0, 2) - 1));
|
||||
float m = value - c;
|
||||
|
||||
if (hue >= 0 && hue < 60) {
|
||||
r = c; g = x; b = 0;
|
||||
} else if (hue >= 60 && hue < 120) {
|
||||
r = x; g = c; b = 0;
|
||||
} else if (hue >= 120 && hue < 180) {
|
||||
r = 0; g = c; b = x;
|
||||
} else if (hue >= 180 && hue < 240) {
|
||||
r = 0; g = x; b = c;
|
||||
} else if (hue >= 240 && hue < 300) {
|
||||
r = x; g = 0; b = c;
|
||||
} else {
|
||||
r = c; g = 0; b = x;
|
||||
}
|
||||
|
||||
r += m; g += m; b += m;
|
||||
}
|
||||
|
||||
int mapDutyCycle(int value, float brightness) {
|
||||
float adjusted = value * (brightness / 100.0);
|
||||
return (int)(adjusted * pwmResolution / 255.0);
|
||||
}
|
||||
|
||||
void setRGB(int red, int green, int blue, float brightness) {
|
||||
analogWrite(redPin, mapDutyCycle(red, brightness));
|
||||
analogWrite(greenPin, mapDutyCycle(green, brightness));
|
||||
analogWrite(bluePin, mapDutyCycle(blue, brightness));
|
||||
}
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
|
||||
// [Previous ESP8266 setup code remains the same until handleRoot()]
|
||||
|
||||
void handleRoot() {
|
||||
String html = R"rawliteral(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>RGB Control</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background: #f0f0f0;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.page-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
gap: 20px;
|
||||
}
|
||||
.card {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.color-preview {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
border-radius: 8px;
|
||||
margin: 10px 0;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
.color-inputs {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.color-input {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.color-input label {
|
||||
margin-bottom: 5px;
|
||||
color: #666;
|
||||
}
|
||||
input[type="range"] {
|
||||
width: 100%;
|
||||
margin: 10px 0;
|
||||
}
|
||||
input[type="number"] {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.current-item {
|
||||
padding: 10px;
|
||||
margin: 5px 0;
|
||||
border-radius: 5px;
|
||||
color: white;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.red { background: linear-gradient(to right, #ff0000, #ff4444); }
|
||||
.green { background: linear-gradient(to right, #00ff00, #44ff44); }
|
||||
.blue { background: linear-gradient(to right, #0000ff, #4444ff); }
|
||||
.total { background: linear-gradient(to right, #666, #999); }
|
||||
.checkbox-wrapper {
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page-container">
|
||||
<div class="card">
|
||||
<h2>RGB Control</h2>
|
||||
<div class="color-preview" id="colorPreview"></div>
|
||||
|
||||
<div class="color-inputs">
|
||||
<div class="color-input">
|
||||
<label>Red</label>
|
||||
<input type="range" id="redSlider" min="0" max="255" value="0">
|
||||
<input type="number" id="redValue" min="0" max="255" value="0">
|
||||
</div>
|
||||
<div class="color-input">
|
||||
<label>Green</label>
|
||||
<input type="range" id="greenSlider" min="0" max="255" value="0">
|
||||
<input type="number" id="greenValue" min="0" max="255" value="0">
|
||||
</div>
|
||||
<div class="color-input">
|
||||
<label>Blue</label>
|
||||
<input type="range" id="blueSlider" min="0" max="255" value="0">
|
||||
<input type="number" id="blueValue" min="0" max="255" value="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="brightness-control">
|
||||
<label>Brightness</label>
|
||||
<input type="range" id="brightnessSlider" min="0" max="100" value="100">
|
||||
<span id="brightnessValue">100%</span>
|
||||
</div>
|
||||
|
||||
<div class="checkbox-wrapper">
|
||||
<label>
|
||||
<input type="checkbox" id="rainbowToggle">
|
||||
Rainbow Mode
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Current Monitor</h2>
|
||||
<div id="currentDisplay">
|
||||
<div class="current-item red">
|
||||
<span>Red LED:</span>
|
||||
<span id="redCurrent">0.00 mA</span>
|
||||
</div>
|
||||
<div class="current-item green">
|
||||
<span>Green LED:</span>
|
||||
<span id="greenCurrent">0.00 mA</span>
|
||||
</div>
|
||||
<div class="current-item blue">
|
||||
<span>Blue LED:</span>
|
||||
<span id="blueCurrent">0.00 mA</span>
|
||||
</div>
|
||||
<div class="current-item total">
|
||||
<span>Total Current:</span>
|
||||
<span id="totalCurrent">0.00 mA</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Color control elements
|
||||
const redSlider = document.getElementById('redSlider');
|
||||
const greenSlider = document.getElementById('greenSlider');
|
||||
const blueSlider = document.getElementById('blueSlider');
|
||||
const redValue = document.getElementById('redValue');
|
||||
const greenValue = document.getElementById('greenValue');
|
||||
const blueValue = document.getElementById('blueValue');
|
||||
const brightnessSlider = document.getElementById('brightnessSlider');
|
||||
const brightnessValue = document.getElementById('brightnessValue');
|
||||
const colorPreview = document.getElementById('colorPreview');
|
||||
const rainbowToggle = document.getElementById('rainbowToggle');
|
||||
|
||||
// Current monitoring elements
|
||||
const redCurrent = document.getElementById('redCurrent');
|
||||
const greenCurrent = document.getElementById('greenCurrent');
|
||||
const blueCurrent = document.getElementById('blueCurrent');
|
||||
const totalCurrent = document.getElementById('totalCurrent');
|
||||
|
||||
// Sync sliders with number inputs
|
||||
function syncInputs(slider, value) {
|
||||
slider.oninput = () => {
|
||||
value.value = slider.value;
|
||||
updateColor();
|
||||
};
|
||||
value.oninput = () => {
|
||||
slider.value = value.value;
|
||||
updateColor();
|
||||
};
|
||||
}
|
||||
|
||||
syncInputs(redSlider, redValue);
|
||||
syncInputs(greenSlider, greenValue);
|
||||
syncInputs(blueSlider, blueValue);
|
||||
|
||||
// Update color preview and send to ESP
|
||||
function updateColor() {
|
||||
const r = redSlider.value;
|
||||
const g = greenSlider.value;
|
||||
const b = blueSlider.value;
|
||||
const brightness = brightnessSlider.value / 100;
|
||||
|
||||
colorPreview.style.backgroundColor =
|
||||
`rgba(${r}, ${g}, ${b}, ${brightness})`;
|
||||
|
||||
fetch(`/set_rgb?r=${r}&g=${g}&b=${b}`);
|
||||
}
|
||||
|
||||
// Brightness control
|
||||
brightnessSlider.oninput = () => {
|
||||
const value = brightnessSlider.value;
|
||||
brightnessValue.textContent = value + '%';
|
||||
fetch(`/set_brightness?value=${value}`);
|
||||
updateColor();
|
||||
};
|
||||
|
||||
// Rainbow mode
|
||||
rainbowToggle.onchange = () => {
|
||||
fetch(`/rainbow?state=${rainbowToggle.checked}`);
|
||||
};
|
||||
|
||||
// Update current readings
|
||||
function updateCurrents() {
|
||||
fetch('/get_currents')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
redCurrent.textContent = data.red.toFixed(2) + ' mA';
|
||||
greenCurrent.textContent = data.green.toFixed(2) + ' mA';
|
||||
blueCurrent.textContent = data.blue.toFixed(2) + ' mA';
|
||||
totalCurrent.textContent = data.total.toFixed(2) + ' mA';
|
||||
});
|
||||
}
|
||||
|
||||
// Update currents every 200ms
|
||||
setInterval(updateCurrents, 200);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)rawliteral";
|
||||
|
||||
server.send(200, "text/html", html);
|
||||
}
|
Loading…
Reference in New Issue