added first iteration of a calibration menu to the webui
This commit is contained in:
@@ -75,6 +75,20 @@ const char* channelUnits[NUM_CHANNELS] = {
|
|||||||
"" // Reserved
|
"" // Reserved
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// -------------------------------
|
||||||
|
// Channel labels ESPUI
|
||||||
|
// -------------------------------
|
||||||
|
const char* channelDropdownLabels[NUM_CHANNELS] = {
|
||||||
|
"CH0 (CPU Load)",
|
||||||
|
"CH1 (CPU Temp)",
|
||||||
|
"CH2 (RAM Usage)",
|
||||||
|
"CH3 (GPU Load)",
|
||||||
|
"CH4 (GPU Temp)",
|
||||||
|
"CH5 (VRAM Usage)",
|
||||||
|
"CH6 (Reserved 6)",
|
||||||
|
"CH7 (Reserved 7)"
|
||||||
|
};
|
||||||
|
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
// Calibration tables
|
// Calibration tables
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
@@ -113,6 +127,20 @@ unsigned long lastFadeTime = 0;
|
|||||||
// -------------------------------
|
// -------------------------------
|
||||||
uint16_t portInput; // ID of the UDP port Number control
|
uint16_t portInput; // ID of the UDP port Number control
|
||||||
|
|
||||||
|
// --- Calibration UI Controls ---
|
||||||
|
uint16_t calChannelDropdown;
|
||||||
|
uint16_t calLabel;
|
||||||
|
uint16_t calInputs[5];
|
||||||
|
uint16_t calTestValueInput;
|
||||||
|
uint16_t calTestButton;
|
||||||
|
uint16_t calSaveButton;
|
||||||
|
uint16_t calReleaseButton;
|
||||||
|
uint16_t calOverrideSwitch;
|
||||||
|
|
||||||
|
uint8_t selectedCalChannel = 0;
|
||||||
|
bool overrideActive[NUM_CHANNELS] = {false};
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
// Calibration interpolation
|
// Calibration interpolation
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
@@ -133,6 +161,112 @@ float applyCalibration(uint8_t ch, float logicalDuty) {
|
|||||||
return calibratedPoints[ch][4];
|
return calibratedPoints[ch][4];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------
|
||||||
|
// Calibration UI helpers & callbacks
|
||||||
|
// -------------------------------
|
||||||
|
void refreshCalibrationUI() {
|
||||||
|
String label = "CH" + String(selectedCalChannel) + " (" + channelLabels[selectedCalChannel] + ")";
|
||||||
|
ESPUI.updateControlValue(calLabel, label);
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
ESPUI.updateControlValue(calInputs[i], String(calibratedPoints[selectedCalChannel][i], 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void calChannelCallback(Control *sender, int type) {
|
||||||
|
// Turn override OFF when switching channels
|
||||||
|
for (int ch = 0; ch < NUM_CHANNELS; ch++) {
|
||||||
|
overrideActive[ch] = false;
|
||||||
|
}
|
||||||
|
ESPUI.updateControlValue(calOverrideSwitch, "0");
|
||||||
|
|
||||||
|
selectedCalChannel = sender->value.toInt();
|
||||||
|
Serial.print("Calibration channel changed to ");
|
||||||
|
Serial.println(selectedCalChannel);
|
||||||
|
|
||||||
|
refreshCalibrationUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void calPointCallback(Control *sender, int type) {
|
||||||
|
int index = sender->id - calInputs[0];
|
||||||
|
if (index >= 0 && index < 5) {
|
||||||
|
float val = sender->value.toFloat();
|
||||||
|
calibratedPoints[selectedCalChannel][index] = val;
|
||||||
|
Serial.printf("Cal[%d][%d] = %.2f\n", selectedCalChannel, index, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void calTestCallback(Control *sender, int type) {
|
||||||
|
if (!overrideActive[selectedCalChannel]) return;
|
||||||
|
|
||||||
|
float logical = sender->value.toFloat(); // 0–100 integer
|
||||||
|
|
||||||
|
if (logical < 0) logical = 0;
|
||||||
|
if (logical > 100) logical = 100;
|
||||||
|
|
||||||
|
float calibrated = applyCalibration(selectedCalChannel, logical);
|
||||||
|
int duty = (int)((calibrated / 100.0f) * ((1 << pwmResolution) - 1));
|
||||||
|
|
||||||
|
ledcWrite(pwmPins[selectedCalChannel], duty);
|
||||||
|
|
||||||
|
Serial.printf("Override update CH%d: logical=%.2f calibrated=%.2f duty=%d\n",
|
||||||
|
selectedCalChannel, logical, calibrated, duty);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calSaveCallback(Control *sender, int type) {
|
||||||
|
Serial.printf("Saving calibration for CH%d...\n", selectedCalChannel);
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
String key = "cal_" + String(selectedCalChannel) + "_" + String(i);
|
||||||
|
prefs.putFloat(key.c_str(), calibratedPoints[selectedCalChannel][i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("Calibration saved.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void calReleaseOverrideCallback(Control *sender, int type) {
|
||||||
|
Serial.println("Manual override released for all channels.");
|
||||||
|
|
||||||
|
for (int ch = 0; ch < NUM_CHANNELS; ch++) {
|
||||||
|
overrideActive[ch] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void calOverrideSwitchCallback(Control *sender, int type) {
|
||||||
|
bool enabled = sender->value.toInt() == 1;
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
Serial.println("Override enabled.");
|
||||||
|
|
||||||
|
// Enable override only for the selected channel
|
||||||
|
for (int ch = 0; ch < NUM_CHANNELS; ch++) {
|
||||||
|
overrideActive[ch] = (ch == selectedCalChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Immediately apply the test value
|
||||||
|
float logical = ESPUI.getControl(calTestValueInput)->value.toFloat();
|
||||||
|
if (logical < 0) logical = 0;
|
||||||
|
if (logical > 100) logical = 100;
|
||||||
|
|
||||||
|
float calibrated = applyCalibration(selectedCalChannel, logical);
|
||||||
|
int duty = (int)((calibrated / 100.0f) * ((1 << pwmResolution) - 1));
|
||||||
|
ledcWrite(pwmPins[selectedCalChannel], duty);
|
||||||
|
|
||||||
|
Serial.printf("Override driving CH%d: logical=%.2f calibrated=%.2f duty=%d\n",
|
||||||
|
selectedCalChannel, logical, calibrated, duty);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Serial.println("Override disabled. Returning to UDP control.");
|
||||||
|
|
||||||
|
// Disable all overrides
|
||||||
|
for (int ch = 0; ch < NUM_CHANNELS; ch++) {
|
||||||
|
overrideActive[ch] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
// Setup
|
// Setup
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
@@ -176,6 +310,15 @@ void setup() {
|
|||||||
prefs.begin("analogmon", false);
|
prefs.begin("analogmon", false);
|
||||||
udpPort = prefs.getInt("udpPort", listenPort);
|
udpPort = prefs.getInt("udpPort", listenPort);
|
||||||
|
|
||||||
|
// Load calibration from flash (if present)
|
||||||
|
for (int ch = 0; ch < NUM_CHANNELS; ch++) {
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
String key = "cal_" + String(ch) + "_" + String(i);
|
||||||
|
float val = prefs.getFloat(key.c_str(), calibratedPoints[ch][i]);
|
||||||
|
calibratedPoints[ch][i] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start UDP with runtime port
|
// Start UDP with runtime port
|
||||||
udp.begin(udpPort);
|
udp.begin(udpPort);
|
||||||
Serial.print("Listening on UDP port ");
|
Serial.print("Listening on UDP port ");
|
||||||
@@ -280,71 +423,103 @@ void setup() {
|
|||||||
tabLighting
|
tabLighting
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// -------------------------------
|
||||||
|
// Calibration tab UI
|
||||||
|
// -------------------------------
|
||||||
|
|
||||||
|
// Channel selector
|
||||||
|
calChannelDropdown = ESPUI.addControl(
|
||||||
|
ControlType::Select,
|
||||||
|
"Selected Channel",
|
||||||
|
"0",
|
||||||
|
ControlColor::Peterriver,
|
||||||
|
tabCalibration,
|
||||||
|
calChannelCallback
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add options 0–7
|
||||||
|
for (int i = 0; i < NUM_CHANNELS; i++) {
|
||||||
|
char value[8];
|
||||||
|
snprintf(value, sizeof(value), "%d", i);
|
||||||
|
|
||||||
|
ESPUI.addControl(
|
||||||
|
ControlType::Option,
|
||||||
|
channelDropdownLabels[i], // static label
|
||||||
|
value, // static-ish value (OK)
|
||||||
|
ControlColor::None,
|
||||||
|
calChannelDropdown
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ESPUI.addControl(
|
ESPUI.addControl(
|
||||||
ControlType::Separator,
|
ControlType::Separator,
|
||||||
"CH0 (CPU Load)",
|
"",
|
||||||
"",
|
"",
|
||||||
ControlColor::None,
|
ControlColor::None,
|
||||||
tabCalibration
|
tabCalibration
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Calibration inputs
|
||||||
|
const char* calNames[5] = {"0%", "25%", "50%", "75%", "100%"};
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
calInputs[i] = ESPUI.addControl(
|
||||||
|
ControlType::Number,
|
||||||
|
calNames[i],
|
||||||
|
String(calibratedPoints[0][i], 2),
|
||||||
|
ControlColor::Wetasphalt,
|
||||||
|
tabCalibration,
|
||||||
|
calPointCallback
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ESPUI.addControl(
|
ESPUI.addControl(
|
||||||
ControlType::Separator,
|
ControlType::Separator,
|
||||||
"CH1 (CPU Temp)",
|
"",
|
||||||
"",
|
"",
|
||||||
ControlColor::None,
|
ControlColor::None,
|
||||||
tabCalibration
|
tabCalibration
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Test value input
|
||||||
|
calTestValueInput = ESPUI.addControl(
|
||||||
|
ControlType::Slider,
|
||||||
|
"Test Value",
|
||||||
|
"50",
|
||||||
|
ControlColor::Carrot,
|
||||||
|
tabCalibration,
|
||||||
|
calTestCallback
|
||||||
|
);
|
||||||
|
|
||||||
|
calOverrideSwitch = ESPUI.addControl(
|
||||||
|
ControlType::Switcher,
|
||||||
|
"Override",
|
||||||
|
"0", // default OFF
|
||||||
|
ControlColor::Alizarin,
|
||||||
|
tabCalibration,
|
||||||
|
calOverrideSwitchCallback
|
||||||
|
);
|
||||||
|
|
||||||
ESPUI.addControl(
|
ESPUI.addControl(
|
||||||
ControlType::Separator,
|
ControlType::Separator,
|
||||||
"CH2 (RAM Usage)",
|
"",
|
||||||
"",
|
"",
|
||||||
ControlColor::None,
|
ControlColor::None,
|
||||||
tabCalibration
|
tabCalibration
|
||||||
);
|
);
|
||||||
|
|
||||||
ESPUI.addControl(
|
// Save button
|
||||||
ControlType::Separator,
|
calSaveButton = ESPUI.addControl(
|
||||||
"CH3 (GPU Load)",
|
ControlType::Button,
|
||||||
"",
|
"Save Calibration",
|
||||||
ControlColor::None,
|
"Save",
|
||||||
tabCalibration
|
ControlColor::Emerald,
|
||||||
);
|
tabCalibration,
|
||||||
|
calSaveCallback
|
||||||
ESPUI.addControl(
|
|
||||||
ControlType::Separator,
|
|
||||||
"CH4 (GPU Temp)",
|
|
||||||
"",
|
|
||||||
ControlColor::None,
|
|
||||||
tabCalibration
|
|
||||||
);
|
|
||||||
|
|
||||||
ESPUI.addControl(
|
|
||||||
ControlType::Separator,
|
|
||||||
"CH5 (VRAM Usage)",
|
|
||||||
"",
|
|
||||||
ControlColor::None,
|
|
||||||
tabCalibration
|
|
||||||
);
|
|
||||||
|
|
||||||
ESPUI.addControl(
|
|
||||||
ControlType::Separator,
|
|
||||||
"CH6 (Reserved 6)",
|
|
||||||
"",
|
|
||||||
ControlColor::None,
|
|
||||||
tabCalibration
|
|
||||||
);
|
|
||||||
|
|
||||||
ESPUI.addControl(
|
|
||||||
ControlType::Separator,
|
|
||||||
"CH7 (Reserved 7)",
|
|
||||||
"",
|
|
||||||
ControlColor::None,
|
|
||||||
tabCalibration
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Start ESPUI
|
// Start ESPUI
|
||||||
|
ESPUI.sliderContinuous = true; // <‑‑ enables live slider updates
|
||||||
ESPUI.begin("Analog Monitor UI");
|
ESPUI.begin("Analog Monitor UI");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,9 +549,11 @@ void loop() {
|
|||||||
|
|
||||||
// Start a new slew toward the target
|
// Start a new slew toward the target
|
||||||
for (int ch = 0; ch < NUM_CHANNELS; ch++) {
|
for (int ch = 0; ch < NUM_CHANNELS; ch++) {
|
||||||
|
if (!overrideActive[ch]) { // <‑‑ NEW
|
||||||
targetDuty[ch] = values[ch];
|
targetDuty[ch] = values[ch];
|
||||||
slewStartDuty[ch] = currentDuty[ch];
|
slewStartDuty[ch] = currentDuty[ch];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
slewStartTime = millis();
|
slewStartTime = millis();
|
||||||
lastPacketTime = millis();
|
lastPacketTime = millis();
|
||||||
|
|
||||||
@@ -407,15 +584,17 @@ void loop() {
|
|||||||
if (progress > 1.0f) progress = 1.0f;
|
if (progress > 1.0f) progress = 1.0f;
|
||||||
|
|
||||||
for (int ch = 0; ch < NUM_CHANNELS; ch++) {
|
for (int ch = 0; ch < NUM_CHANNELS; ch++) {
|
||||||
|
|
||||||
|
if (!overrideActive[ch]) {
|
||||||
float newDuty = slewStartDuty[ch] + (targetDuty[ch] - slewStartDuty[ch]) * progress;
|
float newDuty = slewStartDuty[ch] + (targetDuty[ch] - slewStartDuty[ch]) * progress;
|
||||||
currentDuty[ch] = newDuty;
|
currentDuty[ch] = newDuty;
|
||||||
|
|
||||||
float calibratedDuty = applyCalibration(ch, newDuty);
|
float calibratedDuty = applyCalibration(ch, newDuty);
|
||||||
int duty = (int)((calibratedDuty / 100.0f) * ((1 << pwmResolution) - 1));
|
int duty = (int)((calibratedDuty / 100.0f) * ((1 << pwmResolution) - 1));
|
||||||
|
|
||||||
ledcWrite(pwmPins[ch], duty);
|
ledcWrite(pwmPins[ch], duty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -------- Watchdog fade-to-zero --------
|
// -------- Watchdog fade-to-zero --------
|
||||||
if (millis() - lastPacketTime > watchdogTimeout) {
|
if (millis() - lastPacketTime > watchdogTimeout) {
|
||||||
|
|||||||
Reference in New Issue
Block a user