Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HX711 absolute weight conversion #15292

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions tasmota/xsns_34_hx711.ino
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
#define D_JSON_WEIGHT_CHANGE "WeightChange"
#define D_JSON_WEIGHT_RAW "WeightRaw"
#define D_JSON_WEIGHT_DELTA "WeightDelta"
#define D_JSON_WEIGHT_ABSCONV_A "WeightAbsConvA"
#define D_JSON_WEIGHT_ABSCONV_B "WeightAbsConvB"

enum HxCalibrationSteps { HX_CAL_END, HX_CAL_LIMBO, HX_CAL_FINISH, HX_CAL_FAIL, HX_CAL_DONE, HX_CAL_FIRST, HX_CAL_RESET, HX_CAL_START };

Expand All @@ -73,6 +75,8 @@ struct HX {
long offset = 0;
long scale = 1;
long weight_diff = 0;
long absconv_a = 0;
long absconv_b = 0;
uint8_t type = 1;
uint8_t sample_count = 0;
uint8_t calibrate_step = HX_CAL_END;
Expand Down Expand Up @@ -195,6 +199,8 @@ void SetWeightDelta()
* Sensor34 8 0 - Disable JSON weight change message
* Sensor34 8 1 - Enable JSON weight change message
* Sensor34 9 <weight code> - Set minimum delta to trigger JSON message
* Sensor34 10 <value A> - Set A = a * 10^9 for raw to absolute weight conversion: y=a*x+b
* Sensor34 11 <value B> - Set B = b * 10^6 for raw to absolute weight conversion: y=a*x+b
\*********************************************************************************************/

bool HxCommand(void)
Expand Down Expand Up @@ -259,8 +265,21 @@ bool HxCommand(void)
break;
case 9: // WeightDelta
if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings->weight_change = strtol(ArgV(argument, 2), nullptr, 10);
SetWeightDelta();
Settings->weight_change = strtol(ArgV(argument, 2), nullptr, 10);
SetWeightDelta();
}
show_parms = true;
break;
case 10: // AbsoluteConversion, A
if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings->weight_absconv_a = strtol(ArgV(argument, 2), nullptr, 10);
Hx.absconv_a = Settings->weight_absconv_a;
}
show_parms = true;
case 11: // AbsoluteConversion, B
if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings->weight_absconv_b = strtol(ArgV(argument, 2), nullptr, 10);
Hx.absconv_b = Settings->weight_absconv_b;
}
show_parms = true;
break;
Expand All @@ -272,9 +291,11 @@ bool HxCommand(void)
char item[33];
dtostrfd((float)Settings->weight_item / 10, 1, item);
Response_P(PSTR("{\"Sensor34\":{\"" D_JSON_WEIGHT_REF "\":%d,\"" D_JSON_WEIGHT_CAL "\":%d,\"" D_JSON_WEIGHT_MAX "\":%d,\""
D_JSON_WEIGHT_ITEM "\":%s,\"" D_JSON_WEIGHT_CHANGE "\":\"%s\",\"" D_JSON_WEIGHT_DELTA "\":%d}}"),
Settings->weight_reference, Settings->weight_calibration, Settings->weight_max * 1000,
item, GetStateText(Settings->SensorBits1.hx711_json_weight_change), Settings->weight_change);
D_JSON_WEIGHT_ITEM "\":%s,\"" D_JSON_WEIGHT_CHANGE "\":\"%s\",\"" D_JSON_WEIGHT_DELTA "\":%d,\""
D_JSON_WEIGHT_ABSCONV_A "\":%d,\"" D_JSON_WEIGHT_ABSCONV_B "\":%d}}"),
Settings->weight_reference, Settings->weight_calibration, Settings->weight_max * 1000,
item, GetStateText(Settings->SensorBits1.hx711_json_weight_change), Settings->weight_change,
Settings->weight_absconv_a, Settings->weight_absconv_b);
}

return serviced;
Expand All @@ -301,11 +322,13 @@ void HxInit(void)

SetWeightDelta();

if (HxIsReady(8 * HX_TIMEOUT)) { // Can take 600 milliseconds after power on
if (HxIsReady(8 * HX_TIMEOUT)) { // Can take 600 milliseconds after power on
if (!Settings->weight_max) { Settings->weight_max = HX_MAX_WEIGHT / 1000; }
if (!Settings->weight_calibration) { Settings->weight_calibration = HX_SCALE; }
if (!Settings->weight_reference) { Settings->weight_reference = HX_REFERENCE; }
Hx.scale = Settings->weight_calibration;
if (Settings->weight_absconv_a) { Hx.absconv_a = Settings->weight_absconv_a; }
if (Settings->weight_absconv_b) { Hx.absconv_b = Settings->weight_absconv_b; }
HxRead();
HxResetPart();
Hx.type = 1;
Expand Down Expand Up @@ -451,6 +474,9 @@ void HxShow(bool json)
}
weight = (float)Hx.weight / 1000; // kilograms
}
if (Hx.absconv_a != 0 && Hx.absconv_b != 0) {
weight = (float)Hx.absconv_a / 1e9 * Hx.raw + (float)Hx.absconv_b / 1e6;
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I right in the conclusion that using the raw value here makes current calibration efforts useless? How do you define the absconv parameters? By trial and error?

Copy link
Author

@ThomDietrich ThomDietrich Apr 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No you are correct. No offense, but I didn't find the implemented calibration combined with taring the weight upon startup useful for my use case (and wonder in which use case it is). The strategy I follow is to take a few raw weights for known masses, then run a simple linear regression, e.g. here: https://mycurvefit.com to get to the absconv parameters of y=ax+b.
It's not as integrated but is a good deterministic process. Let me know if you believe we should have a discussion about a different path!

Copy link
Owner

@arendst arendst Apr 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My implemented use case is based on a commercial kitchen scale like the Ikea one.

After power on the user adds an empty dish, selects the reset button to zero the result and then is able to weigh anything he adds to the dish. Hence the zero button in the GUI.

There are ofcourse other uses which may use your suggested solution.

As your implementation doesn't interfere with mine I'll add it now so users can get some experience with it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting element you brought up!

USE_HX711_GUI is not defined for FIRMWARE_SENSORS. As a result I did never see this "zero button in GUI" you refered to. Maybe this should be changed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arendst ping in case you missed this.

char weight_chr[33];
dtostrfd(weight, Settings->flag2.weight_resolution, weight_chr);

Expand Down