From 1f3bb675ba428486ddfa14d1e56e47ed83f26410 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 9 Apr 2022 18:24:37 +0200 Subject: [PATCH] HX711 redesign (#13986) - Add HX711 command ``Sensor34 10 0|1|`` to set HX711 fixed tare (0 = use auto tare, 1 = use calibrated tare, Any other value is user selected tare) - HX711 removed command ``Sensor34 7`` as now active tare is persistent resulting in calculated current weight - Changed HX711 commands ``Sensor34 11 `` and ``Sensor34 12 `` to use HX711 absolute weight conversion (#15292) --- CHANGELOG.md | 14 +++- RELEASENOTES.md | 6 +- tasmota/settings.h | 7 +- tasmota/settings.ino | 7 ++ tasmota/tasmota_version.h | 2 +- tasmota/xsns_34_hx711.ino | 171 +++++++++++++++++++++----------------- 6 files changed, 121 insertions(+), 86 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c7c204a0..363838e36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,12 +3,20 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Development -## [11.0.0.6] +## [11.0.0.7] ### Added -- Commands ``Sensor34 10 `` and ``Sensor34 11 `` to use HX711 absolute weight conversion (#15292) +- HX711 command ``Sensor34 10 0|1|`` to set HX711 fixed tare (0 = use auto tare, 1 = use calibrated tare, Any other value is user selected tare) ### Changed -- NeoPool: boost command with redox control state, relay and aux detail display +- HX711 removed command ``Sensor34 7`` as now active tare is persistent resulting in calculated current weight +- HX711 commands ``Sensor34 11 `` and ``Sensor34 12 `` to use HX711 absolute weight conversion (#15292) + +## [11.0.0.6] 20220409 +### Added +- HX711 commands ``Sensor34 10 `` and ``Sensor34 11 `` to use HX711 absolute weight conversion (#15292) + +### Changed +- NeoPool boost command with redox control state, relay and aux detail display ### Fixed - NeoPool filtration state and speed display diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 34ef99c74..3fe9132a7 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -103,7 +103,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v11.0.0.6 +## Changelog v11.0.0.7 ### Added - Command ``SetOption135 1`` to disable LVGL splash screen - Command ``SetOption136 1`` to disable single sensor reports from Tuya devices while keeping teleperiod reports [#15216](https://github.com/arendst/Tasmota/issues/15216) @@ -112,7 +112,8 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo - Command ``RfTimeout 100..60000`` to disable duplicate RfReceive. Default 1000 [#15061](https://github.com/arendst/Tasmota/issues/15061) - Command ``IfxSensor 1`` to send non-teleperiod data to influxdb - Commands ``Sensor12 D0 .. D5, S0 .. S5`` allowing differential or single-ended modes [#15001](https://github.com/arendst/Tasmota/issues/15001) -- Commands ``Sensor34 10 `` and ``Sensor34 11 `` to use HX711 absolute weight conversion [#15292](https://github.com/arendst/Tasmota/issues/15292) +- HX711 command ``Sensor34 10 0|1|`` to set HX711 fixed tare (0 = use auto tare, 1 = use calibrated tare, Any other value is user selected tare) +- HX711 commands ``Sensor34 11 `` and ``Sensor34 12 `` to use HX711 absolute weight conversion [#15292](https://github.com/arendst/Tasmota/issues/15292) - NeoPool commands ``NPpHMin``, ``NPpHMax``, ``NPpH``, ``NPRedox``, ``NPHydrolysis``, ``NPIonization``, ``NPChlorine`` and ``NPControl`` [#15015](https://github.com/arendst/Tasmota/issues/15015) - NeoPool system voltages display - TasmotaSerial implement ``end()`` @@ -139,6 +140,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo - Extent number of pulsetimers from 8 to 32 [#8266](https://github.com/arendst/Tasmota/issues/8266) - Consolidate three RTC chip drivers (DS3231, BM8563, PCF85363) into one driver updating RTC as soon as possible after restart - Removed command ``Sensor33`` and replaced by ``RtcNtpserver`` +- HX711 removed command ``Sensor34 7`` as now active tare is persistent resulting in calculated current weight - Remove support for Internet Explorer by allowing ECMAScript6 syntax using less JavaScript code bytes [#15280](https://github.com/arendst/Tasmota/issues/15280) - DS3231 I2C address define ``USE_RTC_ADDR`` into ``DS3231_ADDRESS`` - Display of energy values in GUI use columns when define ``USE_ENERGY_COLUMN_GUI`` is enabled (default) diff --git a/tasmota/settings.h b/tasmota/settings.h index 1acf9d376..b179e0e14 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -486,9 +486,7 @@ typedef struct { int32_t energy_kWhtoday_ph[3]; // 314 int32_t energy_kWhyesterday_ph[3]; // 320 int32_t energy_kWhtotal_ph[3]; // 32C - - uint8_t free_338[4]; // 338 - + int32_t weight_user_tare; // 338 uint8_t web_time_start; // 33C uint8_t web_time_end; // 33D uint8_t sserial_config; // 33E @@ -647,8 +645,9 @@ typedef struct { uint32_t ipv4_rgx_subnetmask; // 55C uint16_t pwm_value_ext[16-5]; // 560 Extension to pwm_value to store up to 16 PWM for ESP32. This array stores values 5..15 - uint8_t free_576[6]; // 576 + uint8_t free_576[2]; // 576 + int32_t weight_offset; // 578 uint16_t pulse_timer[MAX_PULSETIMERS]; // 57C SysMBitfield1 flag2; // 5BC uint32_t pulse_counter[MAX_COUNTERS]; // 5C0 diff --git a/tasmota/settings.ino b/tasmota/settings.ino index eb76cf664..1b4c2763c 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -1520,6 +1520,13 @@ void SettingsDelta(void) { Settings->weight_absconv_a = 0; Settings->weight_absconv_b = 0; } + if (Settings->version < 0x0B000007) { // 11.0.0.7 + Settings->weight_user_tare = 0; + Settings->weight_offset = 0; +#ifdef USE_HX711 + Settings->weight_offset = Settings->energy_frequency_calibration * Settings->weight_calibration; +#endif + } Settings->version = VERSION; SettingsSave(1); diff --git a/tasmota/tasmota_version.h b/tasmota/tasmota_version.h index f5c1f170e..43aa751a5 100644 --- a/tasmota/tasmota_version.h +++ b/tasmota/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x0B000006; // 11.0.0.6 +const uint32_t VERSION = 0x0B000007; // 11.0.0.7 #endif // _TASMOTA_VERSION_H_ diff --git a/tasmota/xsns_34_hx711.ino b/tasmota/xsns_34_hx711.ino index 332c98c7e..8a051949a 100644 --- a/tasmota/xsns_34_hx711.ino +++ b/tasmota/xsns_34_hx711.ino @@ -53,12 +53,14 @@ #define HX_GAIN_64 3 // Channel A, gain factor 64 #define D_JSON_WEIGHT_RAW "WeightRaw" +#define D_JSON_WEIGHT_RAW_ABS "AbsRaw" #define D_JSON_WEIGHT_REF "Ref" #define D_JSON_WEIGHT_CAL "Cal" #define D_JSON_WEIGHT_MAX "Max" #define D_JSON_WEIGHT_ITEM "Item" #define D_JSON_WEIGHT_CHANGE "Change" #define D_JSON_WEIGHT_DELTA "Delta" +#define D_JSON_WEIGHT_TARE "Tare" #define D_JSON_WEIGHT_ABSC_A "AbsConvA" #define D_JSON_WEIGHT_ABSC_B "AbsConvB" @@ -68,8 +70,10 @@ const char kHxCalibrationStates[] PROGMEM = D_HX_CAL_FAIL "|" D_HX_CAL_DONE "|" struct HX { long reads[HX_SAMPLES]; - long weight = 0; + long raw_empty = 0; + long raw_absolute; long raw = 0; + long weight = 0; long last_weight = 0; long offset = 0; long scale = 1; @@ -134,15 +138,11 @@ long HxRead(void) { /*********************************************************************************************/ -void HxResetPart(void) { - Hx.tare_flg = true; - Hx.sample_count = 0; - Hx.last_weight = 0; -} - -void HxReset(void) { - HxResetPart(); - Settings->energy_frequency_calibration = 0; +void HxTareInit(void) { + Hx.offset = (Settings->weight_user_tare != 0) ? Settings->weight_user_tare * Hx.scale : Settings->weight_offset; + if (0 == Hx.offset) { + Hx.tare_flg = true; + } } void HxCalibrationStateTextJson(uint8_t msg_id) { @@ -174,23 +174,24 @@ void SetWeightDelta(void) { /*********************************************************************************************\ * Supported commands for Sensor34: * + * Sensor34 - Show current settings * Sensor34 1 - Reset display to 0 * Sensor34 2 - Start calibration * Sensor34 2 - Set reference weight and start calibration - * Sensor34 3 - Show reference weight in gram * Sensor34 3 - Set reference weight - * Sensor34 4 - Show calibrated scale value * Sensor34 4 - Set calibrated scale value - * Sensor34 5 - Show max weight in gram * Sensor34 5 - Set max weight - * Sensor34 6 - Show item weight in decigram * Sensor34 6 - Set item weight - * Sensor34 7 - Save current weight to be used as start weight on restart + * Sensor34 7 - Save current weight to be used as start weight on restart (removed v11.0.0.7) * Sensor34 8 0 - Disable JSON weight change message * Sensor34 8 1 - Enable JSON weight change message * Sensor34 9 - Set minimum delta to trigger JSON message - * Sensor34 10 - Set A = a * 10^9 for raw to absolute weight conversion: y=a*x+b - * Sensor34 11 - Set B = b * 10^6 for raw to absolute weight conversion: y=a*x+b + * Sensor34 10 0 - Disable fixed tare and enable auto tare + * Sensor34 10 1 - Set fixed tare offset using current calibrated raw weight value + * Sensor34 10 - Set fixed tare offset + * Sensor34 11 0 - Disable absolute weight conversion + * Sensor34 11 - Set A = a * 10^9 for raw to absolute weight conversion: y=a*x+b + * Sensor34 12 - Set B = b * 10^6 for raw to absolute weight conversion: y=a*x+b \*********************************************************************************************/ bool HxCommand(void) { @@ -207,17 +208,21 @@ bool HxCommand(void) { switch (XdrvMailbox.payload) { case 1: // Reset scale - HxReset(); - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, "Reset"); + if (0 == Settings->weight_user_tare) { + Hx.tare_flg = true; + Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, "Reset"); + } show_parms = false; break; case 2: // Calibrate if (any_value) { Settings->weight_reference = value; } - Hx.scale = 1; - HxReset(); + Hx.scale = 1; // Uncalibrated + Hx.sample_count = 0; + Hx.offset = 0; // Disable tare while calibrating Hx.calibrate_step = HX_CAL_START; Hx.calibrate_timer = 1; - HxCalibrationStateTextJson(3); +// HxCalibrationStateTextJson(3); // D_HX_CAL_REMOVE + HxCalibrationStateTextJson(2); // D_HX_CAL_REMOVE show_parms = false; break; case 3: // WeightRef to user reference @@ -237,11 +242,11 @@ bool HxCommand(void) { Settings->weight_item = (unsigned long)(CharToFloat(ArgV(argument, 2)) * 10); } break; - case 7: // WeightSave - Settings->energy_frequency_calibration = Hx.weight; - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, PSTR(D_JSON_DONE)); - show_parms = false; - break; +// case 7: // WeightSave +// Settings->energy_frequency_calibration = Hx.weight; +// Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, PSTR(D_JSON_DONE)); +// show_parms = false; +// break; case 8: // Json on weight change if (any_value) { Settings->SensorBits1.hx711_json_weight_change = value &1; } break; @@ -251,10 +256,17 @@ bool HxCommand(void) { SetWeightDelta(); } break; - case 10: // AbsoluteConversion, A + case 10: // Fixed (user) tare + if (any_value) { + Settings->weight_user_tare = (1 == value) ? Hx.raw : value; + HxTareInit(); + Hx.weight_diff = Hx.weight_delta +1; // Force display of current weight + } + break; + case 11: // AbsoluteConversion, A if (any_value) { Settings->weight_absconv_a = value; } break; - case 11: // AbsoluteConversion, B + case 12: // AbsoluteConversion, B if (any_value) { Settings->weight_absconv_b = value; } break; } @@ -264,10 +276,10 @@ bool HxCommand(void) { 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,\"" - D_JSON_WEIGHT_ABSC_A "\":%d,\"" D_JSON_WEIGHT_ABSC_B "\":%d}}"), + D_JSON_WEIGHT_TARE "\":%d,\"" D_JSON_WEIGHT_ABSC_A "\":%d,\"" D_JSON_WEIGHT_ABSC_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); + Settings->weight_user_tare, Settings->weight_absconv_a, Settings->weight_absconv_b); } return serviced; @@ -297,8 +309,8 @@ void HxInit(void) { if (!Settings->weight_calibration) { Settings->weight_calibration = HX_SCALE; } if (!Settings->weight_reference) { Settings->weight_reference = HX_REFERENCE; } Hx.scale = Settings->weight_calibration; + HxTareInit(); HxRead(); - HxResetPart(); Hx.type = 1; } } @@ -328,45 +340,44 @@ void HxEvery100mSecond(void) { for (uint32_t i = 2; i < HX_SAMPLES -2; i++) { sum_raw += Hx.reads[i]; } - long average = sum_raw / (HX_SAMPLES -4); // grams + Hx.raw_absolute = sum_raw / (HX_SAMPLES -4); // Uncalibrated value + Hx.raw = Hx.raw_absolute / Hx.scale; // grams - if ((Hx.reads[0] < (average -4)) || (Hx.reads[9] > (average +4))) { - AddLog(LOG_LEVEL_DEBUG, PSTR("HX7: Range %d"), Hx.reads[9] - Hx.reads[0]); -// return; // Consider to drop samples with too much deviation (will fail too on quick load changes like filling a barrel!) - } - - long value = average - Hx.offset; // grams - Hx.weight = value / Hx.scale; // grams - Hx.raw = average / Hx.scale; - if (Hx.weight < 0) { - if (Settings->energy_frequency_calibration) { - long difference = Settings->energy_frequency_calibration + Hx.weight; - Hx.last_weight = difference; - if (difference < 0) { HxReset(); } // Cancel last weight as there seems to be no more weight on the scale - } - Hx.weight = 0; - } else { - Hx.last_weight = Settings->energy_frequency_calibration; - } - - if (Hx.tare_flg) { + if ((0 == Settings->weight_user_tare) && Hx.tare_flg) { // Reset scale based on current load Hx.tare_flg = false; - Hx.offset = average; // grams + Settings->weight_offset = Hx.raw_absolute; // Save for restart use + Hx.offset = Hx.raw_absolute; + } + + long value = Hx.raw_absolute - Hx.offset; // Uncalibrated value + Hx.weight = value / Hx.scale; // grams + if (Hx.weight < 0) { // We currently do not support negative weight + Hx.weight = 0; } if (Hx.calibrate_step) { Hx.calibrate_timer--; +// AddLog(LOG_LEVEL_DEBUG, PSTR("HX7: Step %d, weight %d, last %d, raw %d, empty %d"), Hx.calibrate_step, Hx.weight, Hx.last_weight, Hx.raw, Hx.raw_empty); + if (HX_CAL_START == Hx.calibrate_step) { // Skip reset just initiated - Hx.calibrate_step--; + if (0 == Hx.offset) { + Hx.calibrate_step--; // HX_CAL_RESET + Hx.last_weight = Hx.weight; // Uncalibrated value + Hx.raw_empty = Hx.raw; + } Hx.calibrate_timer = HX_CAL_TIMEOUT * (10 / HX_SAMPLES); } else if (HX_CAL_RESET == Hx.calibrate_step) { // Wait for stable reset if (Hx.calibrate_timer) { - if (Hx.weight < (long)Settings->weight_reference) { - Hx.calibrate_step--; + if (Hx.weight < Hx.last_weight -100) { // Load decrease detected + Hx.last_weight = Hx.weight; + Hx.raw_empty = Hx.raw; +// HxCalibrationStateTextJson(2); // D_HX_CAL_REFERENCE + } + else if (Hx.weight > Hx.last_weight +100) { // Load increase detected + Hx.calibrate_step--; // HX_CAL_FIRST Hx.calibrate_timer = HX_CAL_TIMEOUT * (10 / HX_SAMPLES); - HxCalibrationStateTextJson(2); } } else { Hx.calibrate_step = HX_CAL_FAIL; @@ -374,41 +385,46 @@ void HxEvery100mSecond(void) { } else if (HX_CAL_FIRST == Hx.calibrate_step) { // Wait for first reference weight if (Hx.calibrate_timer) { - if (Hx.weight > (long)Settings->weight_reference) { - Hx.calibrate_step--; + if (Hx.weight > Hx.last_weight +100) { + Hx.calibrate_step--; // HX_CAL_DONE } } else { Hx.calibrate_step = HX_CAL_FAIL; } } else if (HX_CAL_DONE == Hx.calibrate_step) { // Second stable reference weight - if (Hx.weight > (long)Settings->weight_reference) { + if (Hx.weight > Hx.last_weight +100) { Hx.calibrate_step = HX_CAL_FINISH; // Calibration done - Settings->weight_calibration = Hx.weight / Settings->weight_reference; + Settings->weight_offset = Hx.raw_empty; + Hx.offset = Hx.raw_empty; + Settings->weight_calibration = (Hx.weight - Hx.raw_empty) / Settings->weight_reference; // 1 gram Hx.weight = 0; // Reset calibration value - HxCalibrationStateTextJson(1); + HxCalibrationStateTextJson(1); // D_HX_CAL_DONE } else { Hx.calibrate_step = HX_CAL_FAIL; } } - if (HX_CAL_FAIL == Hx.calibrate_step) { // Calibration failed - Hx.calibrate_step--; - Hx.tare_flg = true; // Perform a reset using old scale - HxCalibrationStateTextJson(0); + Hx.calibrate_step--; // HX_CAL_FINISH + HxTareInit(); + HxCalibrationStateTextJson(0); // D_HX_CAL_FAIL } if (HX_CAL_FINISH == Hx.calibrate_step) { // Calibration finished - Hx.calibrate_step--; + Hx.calibrate_step--; // HX_CAL_LIMBO Hx.calibrate_timer = 3 * (10 / HX_SAMPLES); Hx.scale = Settings->weight_calibration; - } + if (Settings->weight_user_tare != 0) { // Re-enable fixed tare if needed + Settings->weight_user_tare = Hx.raw_empty / Hx.scale; + HxTareInit(); + } + + } if (!Hx.calibrate_timer) { Hx.calibrate_step = HX_CAL_END; // End of calibration + Hx.weight_diff = Hx.weight_delta +2; } } else { - Hx.weight += Hx.last_weight; // grams - if (Settings->SensorBits1.hx711_json_weight_change) { if (abs(Hx.weight - Hx.weight_diff) > Hx.weight_delta) { // Use weight_delta threshold to decrease "ghost" weights Hx.weight_diff = Hx.weight; @@ -428,7 +444,6 @@ void HxEvery100mSecond(void) { } void HxSaveBeforeRestart(void) { - Settings->energy_frequency_calibration = Hx.weight; Hx.sample_count = HX_SAMPLES +1; // Stop updating Hx.weight } @@ -448,8 +463,9 @@ void HxShow(bool json) { float weight = 0; if (Hx.calibrate_step < HX_CAL_FAIL) { if ((Settings->weight_absconv_a != 0) && (Settings->weight_absconv_b != 0)) { - weight = (float)Settings->weight_absconv_a / 1e9 * Hx.raw + (float)Settings->weight_absconv_b / 1e6; - } else { + weight = (float)Settings->weight_absconv_a / 1e9 * Hx.raw_absolute + (float)Settings->weight_absconv_b / 1e6; + } + else { if (Hx.weight && Settings->weight_item) { count = (Hx.weight * 10) / Settings->weight_item; if (count > 1) { @@ -463,7 +479,8 @@ void HxShow(bool json) { dtostrfd(weight, Settings->flag2.weight_resolution, weight_chr); if (json) { - ResponseAppend_P(PSTR(",\"HX711\":{\"" D_JSON_WEIGHT "\":%s%s,\"" D_JSON_WEIGHT_RAW "\":%d}"), weight_chr, scount, Hx.raw); + ResponseAppend_P(PSTR(",\"HX711\":{\"" D_JSON_WEIGHT "\":%s%s,\"" D_JSON_WEIGHT_RAW "\":%d,\"" D_JSON_WEIGHT_RAW_ABS "\":%d}"), + weight_chr, scount, Hx.raw, Hx.raw_absolute); #ifdef USE_WEBSERVER } else { WSContentSend_PD(HTTP_HX711_WEIGHT, weight_chr); @@ -582,7 +599,9 @@ bool Xsns34(uint8_t function) { break; #ifdef USE_HX711_GUI case FUNC_WEB_ADD_MAIN_BUTTON: - WSContentSend_P(HTTP_BTN_MENU_MAIN_HX711); + if (0 == Settings->weight_user_tare) { // Allow reset scale when no user tare is defined + WSContentSend_P(HTTP_BTN_MENU_MAIN_HX711); + } break; case FUNC_WEB_ADD_BUTTON: WSContentSend_P(HTTP_BTN_MENU_HX711);