Skip to content

Commit 8739cdb

Browse files
authored
feat: Introduce profiles (#175)
* feat: Add profile edit screen * fix: Fix merge errors * feat: Add new profile screen * fix: Fix PID heater * feat: Add profile progress * feat: Repair code after cherrypicking, finish touch ui, add migration * feat: Tune pump control, extend protocol * feat: Add functioning web ui * feat: Add web ui fixes, reflect profile on screen * feat: Add favorite function * fix: Fix communication * feat: Finalize profiles with pressure
1 parent 5b629cc commit 8739cdb

66 files changed

Lines changed: 6043 additions & 3442 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

icons/angle-left.svg

Lines changed: 2 additions & 0 deletions
Loading

icons/angle-right.svg

Lines changed: 2 additions & 0 deletions
Loading

icons/convert.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ function convert() {
2323

2424
convert "angle-down.svg" 40
2525
convert "angle-up.svg" 40
26+
convert "angle-left.svg" 40
27+
convert "angle-right.svg" 40
2628
convert "bluetooth-alt.svg" 20
2729
convert "check.svg" 40
2830
convert "coffee-bean.svg" 80
@@ -43,4 +45,6 @@ convert "wind.svg" 80
4345
convert "clock.svg" 40
4446
convert "thermometer-half.svg" 40
4547
convert "refresh.svg" 20
48+
convert "refresh.svg" 40
4649
convert "tap.svg" 60
50+
convert "settings.svg" 40

icons/settings.svg

Lines changed: 22 additions & 0 deletions
Loading

lib/GaggiMateController/src/GaggiMateController.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ void GaggiMateController::setup() {
3131
pressureSensor = new PressureSensor(_config.pressureSda, _config.pressureScl, [this](float pressure) { /* noop */ });
3232
}
3333
if (_config.capabilites.dimming) {
34-
pump = new DimmedPump(_config.pumpPin, _config.pumpSensePin);
34+
pump = new DimmedPump(_config.pumpPin, _config.pumpSensePin, pressureSensor);
3535
} else {
3636
pump = new SimplePump(_config.pumpPin, _config.pumpOn, _config.capabilites.ssrPump ? 1000.0f : 5000.0f);
3737
}
@@ -57,6 +57,20 @@ void GaggiMateController::setup() {
5757
this->valve->set(valve);
5858
this->heater->setSetpoint(heaterSetpoint);
5959
});
60+
_ble.registerAdvancedOutputControlCallback(
61+
[this](bool valve, float heaterSetpoint, bool pressureTarget, float pressure, float flow) {
62+
this->valve->set(valve);
63+
this->heater->setSetpoint(heaterSetpoint);
64+
if (!_config.capabilites.dimming) {
65+
return;
66+
}
67+
auto dimmedPump = static_cast<DimmedPump *>(pump);
68+
if (pressureTarget) {
69+
dimmedPump->setPressureTarget(pressure, flow);
70+
} else {
71+
dimmedPump->setFlowTarget(flow, pressure);
72+
}
73+
});
6074
_ble.registerAltControlCallback([this](bool state) { this->alt->set(state); });
6175
_ble.registerPidControlCallback([this](float Kp, float Ki, float Kd) { this->heater->setTunings(Kp, Ki, Kd); });
6276
_ble.registerPingCallback([this]() {

lib/GaggiMateController/src/peripherals/DimmedPump.cpp

Lines changed: 146 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,164 @@
22

33
#include <GaggiMateController.h>
44

5-
DimmedPump::DimmedPump(uint8_t ssr_pin, uint8_t sense_pin)
6-
: _ssr_pin(ssr_pin), _sense_pin(sense_pin), _psm(_sense_pin, _ssr_pin, 100, FALLING, 1, 4) {
5+
DimmedPump::DimmedPump(uint8_t ssr_pin, uint8_t sense_pin, PressureSensor *pressure_sensor)
6+
: _ssr_pin(ssr_pin), _sense_pin(sense_pin), _psm(_sense_pin, _ssr_pin, 100, FALLING, 1, 4), _pressureSensor(pressure_sensor) {
77
_psm.set(0);
8+
_pressureGains.push_back(0.002f);
9+
_pressureGains.push_back(0.005f);
10+
_pressureGains.push_back(0.01f);
11+
_pressureGains.push_back(0.02f);
12+
_pressureGains.push_back(0.03f);
13+
_pressureGains.push_back(0.15f);
14+
_pressureGains.push_back(0.20f);
15+
_pressureGains.push_back(0.15f);
16+
_pressureGains.push_back(0.1f);
17+
_pressureGains.push_back(0.09f);
18+
_pressureGains.push_back(0.085f);
19+
_pressureGains.push_back(0.08f);
20+
_pressureGains.push_back(0.07f);
821
}
922

10-
void DimmedPump::setup() { xTaskCreate(loopTask, "DimmedPump::loop", configMINIMAL_STACK_SIZE * 4, this, 1, &taskHandle); }
23+
void DimmedPump::setup() {
24+
_cps = _psm.cps();
25+
if (_cps > 70) {
26+
_psm.setDivider(2);
27+
_cps = _psm.cps();
28+
}
29+
xTaskCreate(loopTask, "DimmedPump::loop", configMINIMAL_STACK_SIZE * 4, this, 1, &taskHandle);
30+
}
1131

12-
void DimmedPump::loop() {}
32+
void DimmedPump::loop() {
33+
_currentPressure = _pressureSensor->getPressure();
34+
updatePower();
35+
}
36+
37+
void DimmedPump::calibrate() {
38+
_pressureGains.clear();
39+
_opvPressure = 0;
40+
float lastPressure = 0;
41+
float lastRoundedPressure = 0;
42+
_currentPressure = _pressureSensor->getPressure();
43+
_psm.set(10);
44+
vTaskDelay(100);
45+
do {
46+
vTaskDelay(100);
47+
lastRoundedPressure = round(_currentPressure - 0.5);
48+
lastPressure = _currentPressure;
49+
_currentPressure = _pressureSensor->getPressure();
50+
if (round(_currentPressure - 0.5) > lastRoundedPressure) {
51+
float gain = (_currentPressure - lastPressure) * 10.0f / (static_cast<float>(_cps) / 10.0f);
52+
ESP_LOGI("DimmedPump", "Gain: %.6f at %.6f bar", gain, round(_currentPressure - 0.5));
53+
_pressureGains.push_back(gain);
54+
}
55+
} while (_currentPressure > lastPressure - 0.1 || _currentPressure < 4.0f);
56+
_opvPressure = _currentPressure;
57+
58+
ESP_LOGI("DimmedPump", "Finished calibration");
59+
ESP_LOGI("DimmedPump", "Power line frequency: %d", _cps);
60+
ESP_LOGI("DimmedPump", "OPV Pressure: %.2f", _opvPressure);
61+
ESP_LOGI("DimmedPump", "Gains:");
62+
for (auto gain : _pressureGains) {
63+
ESP_LOGI("DimmedPump", " %.6f", gain);
64+
}
65+
_psm.set(0);
66+
}
1367

1468
void DimmedPump::setPower(float setpoint) {
1569
ESP_LOGV(LOG_TAG, "Setting power to %2f", setpoint);
16-
_power = setpoint;
17-
_psm.set(static_cast<int>(setpoint));
70+
_mode = ControlMode::POWER;
71+
_power = std::clamp(setpoint, 0.0f, 100.0f);
72+
_psm.set(static_cast<int>(_power));
1873
}
1974

2075
void DimmedPump::loopTask(void *arg) {
2176
auto *pump = static_cast<DimmedPump *>(arg);
2277
while (true) {
2378
pump->loop();
24-
vTaskDelay(10 / portTICK_PERIOD_MS);
79+
vTaskDelay(50 / portTICK_PERIOD_MS);
2580
}
2681
}
82+
83+
void DimmedPump::updatePower() {
84+
float newPower = _power;
85+
86+
switch (_mode) {
87+
case ControlMode::PRESSURE:
88+
newPower = calculatePowerForPressure(_targetPressure, _currentPressure, _flowLimit);
89+
ESP_LOGI("DimmedPump", "Calculating power for pressure: %.2f", newPower);
90+
break;
91+
92+
case ControlMode::FLOW:
93+
newPower = calculatePowerForFlow(_targetFlow, _currentPressure, _pressureLimit);
94+
break;
95+
96+
case ControlMode::POWER:
97+
_psm.set(static_cast<int>(_power));
98+
break;
99+
}
100+
101+
if (newPower != _power && _mode != ControlMode::POWER) {
102+
newPower = std::clamp(newPower, 0.0f, 100.0f);
103+
_power = 0.8f * _power + 0.2f * newPower;
104+
_psm.set(static_cast<int>(_power));
105+
}
106+
}
107+
108+
float DimmedPump::calculateFlowRate(float pressure) const {
109+
float flow = BASE_FLOW_RATE;
110+
float pressurePercentage = pressure / MAX_PRESSURE;
111+
return flow * pressurePercentage;
112+
}
113+
114+
float DimmedPump::calculatePowerForPressure(float targetPressure, float currentPressure, float flowLimit) {
115+
float error = targetPressure - currentPressure;
116+
float baseResponse = 0.0f;
117+
float pressureGain = _currentPressure - _lastPressure;
118+
float pressureLoss = _expectedPressureGain - pressureGain;
119+
float pressureLevel = std::clamp(round(_currentPressure), 0.0f, static_cast<float>(_pressureGains.size()));
120+
float pressureGainPerTick = _pressureGains[pressureLevel];
121+
float maxPressureGain = pressureGainPerTick * static_cast<float>(_cps) / 20.0f;
122+
ESP_LOGI("DimmedPump", "Pressure: %.2f, Gain: %.6f, Expected Gain: %.6f, Pressure Loss: %.6f, Error: %.6f, Per Tick: %.6f",
123+
currentPressure, pressureGain, _expectedPressureGain, pressureLoss, error, pressureGainPerTick);
124+
if (error + pressureLoss > maxPressureGain) {
125+
baseResponse = 100.0f;
126+
} else if (error + pressureLoss > 0.0f) {
127+
float desiredGain = std::clamp(error + pressureLoss, 0.0f, maxPressureGain);
128+
float gainRatio = desiredGain / maxPressureGain;
129+
baseResponse = gainRatio * 100.0f;
130+
}
131+
_lastPressure = currentPressure;
132+
_expectedPressureGain = baseResponse * static_cast<float>(_cps) / 100.0f / 20.0f * pressureGainPerTick;
133+
134+
if (flowLimit > 0.0f) {
135+
float maxFlowPower = calculatePowerForFlow(flowLimit, currentPressure, 100.0f);
136+
return std::min(baseResponse, maxFlowPower);
137+
}
138+
139+
ESP_LOGI("DimmedPump", "Return: %f", baseResponse);
140+
return baseResponse;
141+
}
142+
143+
float DimmedPump::calculatePowerForFlow(float targetFlow, float currentPressure, float pressureLimit) const {
144+
float maxFlow = calculateFlowRate(currentPressure) * _cps;
145+
float powerRatio = std::clamp(targetFlow / maxFlow, 0.0f, 1.0f);
146+
float basePower = powerRatio * 100.0f;
147+
148+
if (pressureLimit > 0 && currentPressure > pressureLimit) {
149+
return 0.0f;
150+
}
151+
152+
return basePower;
153+
}
154+
155+
void DimmedPump::setFlowTarget(float targetFlow, float pressureLimit) {
156+
_mode = ControlMode::FLOW;
157+
_targetFlow = targetFlow;
158+
_pressureLimit = pressureLimit;
159+
}
160+
161+
void DimmedPump::setPressureTarget(float targetPressure, float flowLimit) {
162+
_mode = ControlMode::PRESSURE;
163+
_targetPressure = targetPressure;
164+
_flowLimit = flowLimit;
165+
}

lib/GaggiMateController/src/peripherals/DimmedPump.h

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,56 @@
44
#include "Pump.h"
55
#include <Arduino.h>
66

7+
#include "PressureSensor.h"
8+
79
class DimmedPump : public Pump {
810
public:
9-
DimmedPump(uint8_t ssr_pin, uint8_t sense_pin);
11+
enum class ControlMode { POWER, PRESSURE, FLOW };
12+
13+
DimmedPump(uint8_t ssr_pin, uint8_t sense_pin, PressureSensor *pressureSensor);
1014
~DimmedPump() = default;
1115

1216
void setup() override;
1317
void loop() override;
18+
void calibrate();
1419
void setPower(float setpoint) override;
1520

21+
void setFlowTarget(float targetFlow, float pressureLimit);
22+
void setPressureTarget(float targetPressure, float flowLimit);
23+
void stop();
24+
void fullPower();
25+
1626
private:
1727
uint8_t _ssr_pin;
1828
uint8_t _sense_pin;
19-
float _power = 0.0f;
2029
PSM _psm;
30+
PressureSensor *_pressureSensor;
2131
xTaskHandle taskHandle;
2232

33+
ControlMode _mode = ControlMode::POWER;
34+
float _power = 0.0f;
35+
float _targetFlow = 0.0f;
36+
float _targetPressure = 0.0f;
37+
float _pressureLimit = 0.0f;
38+
float _flowLimit = 0.0f;
39+
float _currentPressure = 0.0f;
40+
float _lastPressure = 0.0f;
41+
float _expectedPressureGain = 0.0f;
42+
int _cps = MAX_FREQ;
43+
44+
float _opvPressure = 0.0f;
45+
std::vector<float> _pressureGains;
46+
47+
static constexpr float BASE_FLOW_RATE = 0.25f;
48+
static constexpr float MAX_PRESSURE = 15.0f;
49+
static constexpr float MAX_FREQ = 60.0f;
50+
51+
[[nodiscard]] float calculateFlowRate(float pressure) const;
52+
[[nodiscard]] float calculatePowerForPressure(float targetPressure, float currentPressure, float flowLimit);
53+
[[nodiscard]] float calculatePowerForFlow(float targetFlow, float currentPressure, float pressureLimit) const;
54+
void updatePower();
55+
void onPressureUpdate(float pressure);
56+
2357
const char *LOG_TAG = "DimmedPump";
2458
static void loopTask(void *arg);
2559
};

lib/GaggiMateController/src/peripherals/Heater.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
#include "Heater.h"
22
#include <Arduino.h>
3-
#include <algorithm>
4-
3+
#include <algorithm>
54

65
Heater::Heater(TemperatureSensor *sensor, uint8_t heaterPin, const heater_error_callback_t &error_callback,
76
const pid_result_callback_t &pid_callback)
8-
: sensor(sensor), heaterPin(heaterPin), taskHandle(nullptr), error_callback(error_callback),
9-
pid_callback(pid_callback) {
7+
: sensor(sensor), heaterPin(heaterPin), taskHandle(nullptr), error_callback(error_callback), pid_callback(pid_callback) {
108

119
simplePid = new SimplePID(&output, &temperature, &setpoint);
1210
autotuner = new Autotune();
@@ -119,8 +117,10 @@ void Heater::loopAutotune() {
119117
// simplePid->setSetpointRateLimits(-INFINITY, autotuner->getSystemGain() * 0.8);
120118
// simplePid->setSetpointFilterFrequency(autotuner->getCrossoverFreq()/2);
121119

122-
ESP_LOGI(LOG_TAG, "Autotuning finished: Kp=%.4f, Ki=%.4f, Kd=%.4f, Kff=%.4f\n", autotuner->getKp()*1000.0f, autotuner->getKi()*1000.0f, autotuner->getKd()*1000.0f, autotuner->getKff()*1000.0f);
123-
ESP_LOGI(LOG_TAG, "System delay: %.2f s, System gain: %.4f Setpoint Freq: %.4f Hz\n", autotuner->getSystemDelay(), autotuner->getSystemGain(), autotuner->getCrossoverFreq()/2);
120+
ESP_LOGI(LOG_TAG, "Autotuning finished: Kp=%.4f, Ki=%.4f, Kd=%.4f, Kff=%.4f\n", autotuner->getKp() * 1000.0f,
121+
autotuner->getKi() * 1000.0f, autotuner->getKd() * 1000.0f, autotuner->getKff() * 1000.0f);
122+
ESP_LOGI(LOG_TAG, "System delay: %.2f s, System gain: %.4f Setpoint Freq: %.4f Hz\n", autotuner->getSystemDelay(),
123+
autotuner->getSystemGain(), autotuner->getCrossoverFreq() / 2);
124124
}
125125

126126
float Heater::softPwm(uint32_t windowSize) {
@@ -151,7 +151,9 @@ float Heater::softPwm(uint32_t windowSize) {
151151
void Heater::plot(float optimumOutput, float outputScale, uint8_t everyNth) {
152152
if (plotCount >= everyNth) {
153153
plotCount = 1;
154-
ESP_LOGI(LOG_TAG, "Setpoint: %.2f, Input: %.2f, Output: %.2f, Kp: %.2f, Ki: %.2f, Kd: %.2f, Filtered Setpoint: %.2f", setpoint, temperature, optimumOutput * outputScale, simplePid->getKp(), simplePid->getKi(), simplePid->getKd(), simplePid->getSetpointFiltered());
154+
ESP_LOGI(LOG_TAG, "Setpoint: %.2f, Input: %.2f, Output: %.2f, Kp: %.2f, Ki: %.2f, Kd: %.2f, Filtered Setpoint: %.2f",
155+
setpoint, temperature, optimumOutput * outputScale, simplePid->getKp(), simplePid->getKi(), simplePid->getKd(),
156+
simplePid->getSetpointFiltered());
155157
} else
156158
plotCount++;
157159
}

0 commit comments

Comments
 (0)