diff --git a/data/html/index.html b/data/html/index.html
index 3fe5e1888..0d4e9a12a 100644
--- a/data/html/index.html
+++ b/data/html/index.html
@@ -113,7 +113,7 @@
|
diff --git a/data/js/app.js b/data/js/app.js
index 180f4f1e5..9e25dcbef 100644
--- a/data/js/app.js
+++ b/data/js/app.js
@@ -9,6 +9,7 @@ const vueApp = Vue.createApp({
showPostSucceeded: false
}
},
+ el: '#calibrationForm',
methods: {
fetchParameters() {
fetch("/parameters")
@@ -72,6 +73,11 @@ const vueApp = Vue.createApp({
4: 'Scale Parameters'
}
return sectionNames[sectionId]
+ },
+ confirmSubmission() {
+ if(confirm('Are you sure you want to toggle the calibration?')) {
+ this.$el.submit();
+ }
}
},
computed: {
diff --git a/platformio.ini b/platformio.ini
index c6a40e474..f1f383ff4 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -35,4 +35,4 @@ debug_init_break = tbreak setup
monitor_port = socket://silvia.local:23
upload_protocol = espota
upload_port = silvia.local
-upload_flags = --auth=otapass
\ No newline at end of file
+upload_flags = --auth=otapass
diff --git a/src/EmbeddedWebserver.h b/src/EmbeddedWebserver.h
index a32dd193d..d9a840109 100644
--- a/src/EmbeddedWebserver.h
+++ b/src/EmbeddedWebserver.h
@@ -282,7 +282,7 @@ void serverSetup() {
int calibrate = flipUintValue(calibrationON);
setCalibration(calibrate);
- debugPrintf("Toggle tare mode: %i \n", calibrate);
+ debugPrintf("Toggle calibration mode: %i \n", calibrate);
request->redirect("/");
});
diff --git a/src/Storage.cpp b/src/Storage.cpp
index c3f0ba00e..e80a3fd69 100644
--- a/src/Storage.cpp
+++ b/src/Storage.cpp
@@ -38,7 +38,11 @@ typedef struct __attribute__((packed)) {
uint8_t freeToUse6[21];
uint8_t pidBdOn;
double pidKpBd;
+ #if SINGLE_HX711 == 1
uint8_t freeToUse7[2];
+ #else
+ float scale2Calibration;
+ #endif
double pidTnBd;
uint8_t freeToUse8[2];
double pidTvBd;
@@ -87,7 +91,8 @@ static const sto_data_t itemDefaults PROGMEM = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, // free to use
0, // STO_ITEM_USE_PID_BD
AGGBKP, // STO_ITEM_PID_KP_BD
- {0xFF, 0xFF}, // free to use
+ SCALE2_CALIBRATION_FACTOR, //STO_ITEM_SCALE2_CALIBRATION_FACTOR
+ // {0xFF, 0xFF}, // free to use
AGGBTN, // STO_ITEM_PID_TN_BD
{0xFF, 0xFF}, // free to use
AGGBTV, // STO_ITEM_PID_TV_BD
@@ -279,6 +284,13 @@ static inline int32_t getItemAddr(sto_item_id_t itemId, uint16_t* maxItemSize =
size = STRUCT_MEMBER_SIZE(sto_data_t,scaleCalibration);
break;
+ #if SINGLE_HX711 == 0
+ case STO_ITEM_SCALE2_CALIBRATION_FACTOR:
+ addr = offsetof(sto_data_t,scale2Calibration );
+ size = STRUCT_MEMBER_SIZE(sto_data_t,scale2Calibration);
+ break;
+ #endif
+
case STO_ITEM_SCALE_KNOWN_WEIGHT:
addr = offsetof(sto_data_t,scaleKnownWeight );
size = STRUCT_MEMBER_SIZE(sto_data_t,scaleKnownWeight);
diff --git a/src/Storage.h b/src/Storage.h
index 6f12e28e8..a00202ae4 100644
--- a/src/Storage.h
+++ b/src/Storage.h
@@ -43,6 +43,9 @@ typedef enum
STO_ITEM_STANDBY_MODE_ON, // Enable tandby mode
STO_ITEM_STANDBY_MODE_TIME, // Time until heater is turned off
STO_ITEM_SCALE_CALIBRATION_FACTOR, // Calibration factor for scale
+ #if SINGLE_HX711 == 0
+ STO_ITEM_SCALE2_CALIBRATION_FACTOR, // Calibration factor for scale 2
+ #endif
STO_ITEM_SCALE_KNOWN_WEIGHT, // Calibration weight for scale
STO_ITEM_RESERVED_30, // reserved
STO_ITEM_RESERVED_21, // reserved
diff --git a/src/brewvoid.h b/src/brewvoid.h
index 8e5aebaf2..69a224e6e 100644
--- a/src/brewvoid.h
+++ b/src/brewvoid.h
@@ -62,6 +62,9 @@ boolean brewPIDDisabled = false; // is PID disabled for delay
const unsigned long intervalWeight = 200; // weight scale
unsigned long previousMillisScale; // initialisation at the end of init()
HX711_ADC LoadCell(PIN_HXDAT, PIN_HXCLK);
+ #if SINGLE_HX711 == 0
+ HX711_ADC LoadCell2(PIN_HXDAT2, PIN_HXCLK);
+ #endif
#endif
/**
@@ -439,11 +442,7 @@ void brew() {
break;
case 41: // waiting time brew
- if (timeBrewed > totalBrewTime || (weightBrew > (weightSetpoint - scaleDelayValue))) {
- brewCounter = kBrewFinished;
- }
-
- if (timeBrewed > totalBrewTime) {
+ if (weightBrew > (weightSetpoint - scaleDelayValue)) {
brewCounter = kBrewFinished;
}
diff --git a/src/defaults.h b/src/defaults.h
index 84f667f84..0e9925e91 100644
--- a/src/defaults.h
+++ b/src/defaults.h
@@ -24,6 +24,9 @@ int writeSysParamsToStorage(void);
#define TEMPOFFSET 0 // brew temperature setpoint
#define STEAMSETPOINT 120 // steam temperature setpoint
#define SCALE_CALIBRATION_FACTOR 1.00 // Raw data is divided by this value to convert to readable data
+#if SINGLE_HX711 == 0
+#define SCALE2_CALIBRATION_FACTOR 1.00 // Raw data is divided by this value to convert to readable data
+#endif
#define SCALE_KNOWN_WEIGHT 267.00 // Calibration weight for scale (weight of the tray)
#define AGGKP 62 // PID Kp (regular phase)
#define AGGTN 52 // PID Tn (regular phase)
diff --git a/src/display.h b/src/display.h
index 3979dfd79..d15401e59 100644
--- a/src/display.h
+++ b/src/display.h
@@ -246,7 +246,7 @@ void displayShottimer(void) {
u8g2.print(timeBrewed / 1000, 1);
u8g2.print("s");
u8g2.setCursor(64, 38);
- u8g2.print(weightBrew, 0);
+ u8g2.print(weightBrew, 1);
u8g2.print("g");
u8g2.setFont(u8g2_font_profont11_tf);
displayWaterIcon(119, 1);
@@ -261,8 +261,8 @@ void displayShottimer(void) {
u8g2.print(lastBrewTime/1000, 1);
u8g2.print("s");
u8g2.setCursor(64, 38);
- u8g2.print(weightBrew, 0);
- u8g2.print(" g");
+ u8g2.print(weightBrew, 1);
+ u8g2.print("g");
u8g2.setFont(u8g2_font_profont11_tf);
displayWaterIcon(119, 1);
u8g2.sendBuffer();
diff --git a/src/main.cpp b/src/main.cpp
index 8535f838a..0b1937381 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -45,6 +45,12 @@ hw_timer_t *timer = NULL;
#endif
#if (BREWMODE == 2 || ONLYPIDSCALE == 1)
+ #define HX711_ADC_config_h
+ #define SAMPLES 32
+ #define IGN_HIGH_SAMPLE 1
+ #define IGN_LOW_SAMPLE 1
+ #define SCK_DELAY 1
+ #define SCK_DISABLE_INTERRUPTS 0
#include
#endif
@@ -177,6 +183,9 @@ double brewTempOffset = TEMPOFFSET;
double setpoint = brewSetpoint;
double steamSetpoint = STEAMSETPOINT;
float scaleCalibration = SCALE_CALIBRATION_FACTOR;
+#if SINGLE_HX711 == 0
+float scale2Calibration = SCALE_CALIBRATION_FACTOR;
+#endif
float scaleKnownWeight = SCALE_KNOWN_WEIGHT;
uint8_t usePonM = 0; // 1 = use PonM for cold start PID, 0 = use normal PID for cold start
double steamKp = STEAMKP;
@@ -241,6 +250,9 @@ SysPara sysParaWeightSetpoint(&weightSetpoint, WEIGHTSETPOINT_MIN, WEIGH
SysPara sysParaStandbyModeOn(&standbyModeOn, 0, 1, STO_ITEM_STANDBY_MODE_ON);
SysPara sysParaStandbyModeTime(&standbyModeTime, STANDBY_MODE_TIME_MIN, STANDBY_MODE_TIME_MAX, STO_ITEM_STANDBY_MODE_TIME);
SysPara sysParaScaleCalibration(&scaleCalibration, -100000, 100000, STO_ITEM_SCALE_CALIBRATION_FACTOR);
+#if SINGLE_HX711 == 0
+SysPara sysParaScale2Calibration(&scale2Calibration, -100000, 100000, STO_ITEM_SCALE2_CALIBRATION_FACTOR);
+#endif
SysPara sysParaScaleKnownWeight(&scaleKnownWeight, 0, 2000, STO_ITEM_SCALE_KNOWN_WEIGHT);
// Other variables
@@ -2008,7 +2020,7 @@ void setup() {
};
editableVars["SCALE_CALIBRATION"] = {
- .displayName = F("Calibration factor"),
+ .displayName = F("Calibration factor scale 1"),
.hasHelpText = false,
.helpText = "",
.type = kFloat,
@@ -2019,6 +2031,21 @@ void setup() {
.maxValue = 100000,
.ptr = (void *)&scaleCalibration
};
+
+ #if SINGLE_HX711 == 0
+ editableVars["SCALE2_CALIBRATION"] = {
+ .displayName = F("Calibration factor scale 2"),
+ .hasHelpText = false,
+ .helpText = "",
+ .type = kFloat,
+ .section = sScaleSection,
+ .position = 32,
+ .show = [] { return true; },
+ .minValue = -100000,
+ .maxValue = 100000,
+ .ptr = (void *)&scale2Calibration
+ };
+ #endif
#endif
editableVars["VERSION"] = {
@@ -2062,6 +2089,9 @@ void setup() {
if (ONLYPIDSCALE == 1 || BREWMODE == 2) {
mqttVars["weightSetpoint"] = []{ return &editableVars.at("SCALE_WEIGHTSETPOINT"); };
mqttVars["scaleCalibration"] = []{ return &editableVars.at("SCALE_CALIBRATION"); };
+ #if SINGLE_HX711 == 0
+ mqttVars["scale2Calibration"] = []{ return &editableVars.at("SCALE2_CALIBRATION"); };
+ #endif
mqttVars["scaleKnownWeight"] = []{ return &editableVars.at("SCALE_KNOWN_WEIGHT"); };
mqttVars["tareON"] = []{ return &editableVars.at("TARE_ON"); };
mqttVars["calibrationON"] = []{ return &editableVars.at("CALIBRATION_ON"); };
@@ -2219,6 +2249,11 @@ void setup() {
temperature -= brewTempOffset;
+ // Init Scale by BREWMODE 2 or SHOTTIMER 2
+ #if (BREWMODE == 2 || ONLYPIDSCALE == 1)
+ initScale();
+ #endif
+
// Initialisation MUST be at the very end of the init(), otherwise the
// time comparision in loop() will have a big offset
unsigned long currentTime = millis();
@@ -2236,11 +2271,6 @@ void setup() {
previousMillisPressure = currentTime;
#endif
- // Init Scale by BREWMODE 2 or SHOTTIMER 2
- #if (BREWMODE == 2 || ONLYPIDSCALE == 1)
- initScale();
- #endif
-
setupDone = true;
enableTimer1();
@@ -2648,6 +2678,9 @@ int readSysParamsFromStorage(void) {
if (sysParaStandbyModeOn.getStorage() != 0) return -1;
if (sysParaStandbyModeTime.getStorage() != 0) return -1;
if (sysParaScaleCalibration.getStorage() != 0) return -1;
+ #if SINGLE_HX711 == 0
+ if (sysParaScale2Calibration.getStorage() != 0) return -1;
+ #endif
if (sysParaScaleKnownWeight.getStorage() != 0) return -1;
return 0;
@@ -2686,6 +2719,9 @@ int writeSysParamsToStorage(void) {
if (sysParaStandbyModeOn.setStorage() != 0) return -1;
if (sysParaStandbyModeTime.setStorage() != 0) return -1;
if (sysParaScaleCalibration.setStorage() != 0) return -1;
+ #if SINGLE_HX711 == 0
+ if (sysParaScale2Calibration.setStorage() != 0) return -1;
+ #endif
if (sysParaScaleKnownWeight.setStorage() != 0) return -1;
return storageCommit();
diff --git a/src/scalevoid.h b/src/scalevoid.h
index 26752bc16..3cc05bfbd 100644
--- a/src/scalevoid.h
+++ b/src/scalevoid.h
@@ -8,42 +8,45 @@
#if (BREWMODE == 2 || ONLYPIDSCALE == 1)
-void calibrate() {
- calibrationON = 0;
- LoadCell.setCalFactor(1.0);
+void calibrate(HX711_ADC loadCell, int pin, sto_item_id_t name, float *calibration) {
+ loadCell.setCalFactor(1.0);
u8g2.clearBuffer();
u8g2.drawStr(0, 22, "Calibration coming up");
- u8g2.drawStr(0, 32, "Empty the scale");
+ u8g2.drawStr(0, 32, "Empty scale ");
+ u8g2.print(pin, 0);
u8g2.sendBuffer();
- debugPrintf("Taking scale zero point\n");
- LoadCell.update();
- LoadCell.tare();
- delay(2000);
- debugPrintf("Put load on scale\n");
+ debugPrintf("Taking scale %d to zero point\n", pin);
+ loadCell.update();
+ loadCell.tare();
+ debugPrintf("Put load on scale %d within the next 10 seconds\n", pin);
u8g2.clearBuffer();
u8g2.drawStr(2, 2, "Calibration in progress.");
u8g2.drawStr(2, 12, "Place known weight");
u8g2.drawStr(2, 22, "on scale in next");
- u8g2.drawStr(2, 32," 10 seconds");
+ u8g2.drawStr(2, 32,"10 seconds");
u8g2.drawStr(2, 42, number2string(scaleKnownWeight));
u8g2.sendBuffer();
delay(10000);
debugPrintf("Taking scale load point\n");
- LoadCell.refreshDataSet();
- scaleCalibration = LoadCell.getNewCalibration(scaleKnownWeight);
- LoadCell.setCalFactor(scaleCalibration);
- debugPrintf("New calibration: %f\n", scaleCalibration);
+ // increase scale samples temporarily to ensure a stable reading
+ loadCell.setSamplesInUse(128);
+ loadCell.refreshDataSet();
+ *calibration = loadCell.getNewCalibration(scaleKnownWeight);
+ loadCell.setSamplesInUse(SCALE_SAMPLES);
+ debugPrintf("New calibration: %f\n", *calibration);
u8g2.sendBuffer();
- writeSysParamsToStorage();
+ storageSet(name, *calibration, true);
u8g2.clearBuffer();
u8g2.drawStr(2, 2, "Calibration done!");
u8g2.drawStr(2, 12, "New calibration:");
- u8g2.drawStr(2, 22, number2string(scaleCalibration));
+ u8g2.drawStr(2, 22, number2string(*calibration));
u8g2.sendBuffer();
- delay(5000);
-
+ delay(2000);
}
+float w1 = 0.0;
+float w2 = 0.0;
+
/**
* @brief Check measured weight
*/
@@ -55,19 +58,38 @@ void checkWeight() {
return;
}
+ // check for new data/start next conversion:
if (LoadCell.update()) newDataReady = true;
+ #if SINGLE_HX711 == 0
+ // weirdly, the library examples do not check for updates on the second cell before getting the values...
+ LoadCell2.update();
+ #endif
if (newDataReady) {
if (currentMillisScale - previousMillisScale >= intervalWeight) {
- previousMillisScale = currentMillisScale;
- weight = LoadCell.getData();
- newDataReady = 0;
+ previousMillisScale = currentMillisScale;
+ newDataReady = false;
+ w1 = LoadCell.getData();
+
+ #if SINGLE_HX711 == 0
+ w2 = LoadCell2.getData();
+ // debugPrintf("Current weight: %.2f from %.2f and %.2f\n", weight, w1, w2);
+ #endif
}
}
+ #if SINGLE_HX711 == 0
+ weight = w1 + w2;
+ #else
+ weight = w1;
+ #endif
+
if (calibrationON) {
- while (!LoadCell.update());
- calibrate();
+ calibrate(LoadCell, PIN_HXDAT, STO_ITEM_SCALE_CALIBRATION_FACTOR, &scaleCalibration);
+ #if SINGLE_HX711 == 0
+ calibrate(LoadCell2, PIN_HXDAT2, STO_ITEM_SCALE2_CALIBRATION_FACTOR, &scale2Calibration);
+ #endif
+ calibrationON = 0;
}
if (tareON) {
@@ -79,6 +101,11 @@ void checkWeight() {
delay(2000);
u8g2.sendBuffer();
LoadCell.tare();
+ LoadCell.setCalFactor(scaleCalibration);
+ #if SINGLE_HX711 == 0
+ LoadCell2.setCalFactor(scale2Calibration);
+ LoadCell2.tare();
+ #endif
u8g2.drawStr(0, 32, "done");
u8g2.sendBuffer();
delay(2000);
@@ -86,50 +113,67 @@ void checkWeight() {
}
-/**
- * @brief Initialize scale
- */
void initScale() {
- readSysParamsFromStorage();
- LoadCell.begin(128);
- long stabilizingtime = 5000; // tare preciscion can be improved by adding a few seconds of stabilizing time
+ boolean shouldCalibrate = calibrationON;
+
+ LoadCell.begin();
+ #if SINGLE_HX711 == 0
+ LoadCell2.begin();
+ #endif
+ // u8g2.clearBuffer();
+ // u8g2.drawStr(0, 2, "Taring scale");
+ // u8g2.drawStr(0, 12, "remove any load!");
+ // u8g2.drawStr(0, 22, "....");
+ // u8g2.sendBuffer();
+ // delay(2000);
+
+ unsigned long stabilizingtime = 5000; // tare preciscion can be improved by adding a few seconds of stabilizing time
boolean _tare = true; //set this to false if you don't want tare to be performed in the next step
- u8g2.clearBuffer();
- u8g2.drawStr(0, 2, "Taring scale,");
- u8g2.drawStr(0, 12, "remove any load!");
- u8g2.drawStr(0, 22, "....");
- u8g2.sendBuffer();
- delay(2000);
- LoadCell.startMultiple(stabilizingtime, _tare);
- delay(5000);
+
+ #if SINGLE_HX711 == 1
+ while(!LoadCell.startMultiple(stabilizingtime, _tare));
+ #else
+ byte loadCellReady = 0;
+ byte loadCell2Ready = 0;
+ // run startup, stabilization and tare, both modules simultaniously
+ // this parallel start seems to be the most important part to get accurate readings with two HX711s connected
+ while ((loadCellReady + loadCell2Ready) < 2) {
+ if (!loadCellReady) loadCellReady = LoadCell.startMultiple(stabilizingtime, _tare);
+ if (!loadCell2Ready) loadCell2Ready = LoadCell2.startMultiple(stabilizingtime, _tare);
+ }
+ #endif
if (LoadCell.getTareTimeoutFlag() || LoadCell.getSignalTimeoutFlag() ) {
- debugPrintf("Timeout, check MCU>HX711 wiring and pin designations");
+ debugPrintf("Timeout, check MCU>HX711 wiring for scale");
u8g2.drawStr(0, 32, "failed!");
u8g2.drawStr(0, 42, "Scale not working..."); // scale timeout will most likely trigger after OTA update, but will still work after boot
u8g2.sendBuffer();
- scaleFailure = true;
delay(5000);
+ scaleFailure = true;
+ return;
}
- else {
- if (calibrationON) {
- LoadCell.setCalFactor(1.0);
- while (!LoadCell.update());
- calibrate();
- LoadCell.setSamplesInUse(SCALE_SAMPLES);
- u8g2.drawStr(0, 52, "done.");
- delay(2000);
- }
- else {
- LoadCell.setCalFactor(scaleCalibration); // set calibration factor (float)
- LoadCell.setSamplesInUse(SCALE_SAMPLES);
- u8g2.drawStr(0, 42, number2string(scaleCalibration));
- u8g2.drawStr(0, 52, "done.");
- u8g2.sendBuffer();
- delay(2000);
- }
+
+ #if SINGLE_HX711 == 0
+ if (LoadCell2.getTareTimeoutFlag() || LoadCell2.getSignalTimeoutFlag() ) {
+ debugPrintf("Timeout, check MCU>HX711 wiring for scale 2");
+ u8g2.drawStr(0, 32, "failed!");
+ u8g2.drawStr(0, 42, "Scale not working..."); // scale timeout will most likely trigger after OTA update, but will still work after boot
+ u8g2.sendBuffer();
+ delay(5000);
+ scaleFailure = true;
+ return;
}
+ #endif
+
+ LoadCell.setCalFactor(scaleCalibration);
+ LoadCell.setSamplesInUse(SCALE_SAMPLES);
+ #if SINGLE_HX711 == 0
+ LoadCell2.setCalFactor(scale2Calibration);
+ LoadCell2.setSamplesInUse(SCALE_SAMPLES);
+ #endif
+
+ calibrationON = 0;
}
/**
@@ -138,7 +182,7 @@ void initScale() {
void shottimerscale() {
switch (shottimerCounter) {
case 10: // waiting step for brew switch turning on
- if (preinfusionpause == 0 || preinfusion == 0) {
+ if (preinfusionPause == 0 || preinfusion == 0) {
if (timeBrewed > 0) {
weightPreBrew = weight;
shottimerCounter = 20;
@@ -146,7 +190,7 @@ void shottimerscale() {
} else {
if (timeBrewed > preinfusion*1000) {
weightPreBrew = weight;
- shottimercounter = 20;
+ shottimerCounter = 20;
}
}
diff --git a/src/userConfig_sample.h b/src/userConfig_sample.h
index 0246fc26b..dd720a7fe 100644
--- a/src/userConfig_sample.h
+++ b/src/userConfig_sample.h
@@ -66,6 +66,7 @@ enum MACHINE {
// Brew Scale
#define SCALE_SAMPLES 2 // Load cell sample rate
+#define SINGLE_HX711 0 // 1 = Only a single HX711 with two channels, 0 = one HX711 per load cell
// Backflush values
#define FILLTIME 5000 // time in ms the pump is running