From f41e525f5a24bd33a8490e1a558af3b9b6ebd95f Mon Sep 17 00:00:00 2001 From: Paul Blacknell Date: Mon, 9 Oct 2023 15:14:41 +0100 Subject: [PATCH] fix: account for MAX17043 alert status on start (#19708) --- tasmota/include/i18n.h | 1 + tasmota/my_user_config.h | 1 + .../tasmota_xsns_sensor/xsns_110_max17043.ino | 49 ++++++++++++++----- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/tasmota/include/i18n.h b/tasmota/include/i18n.h index 4f87a9cce149..0619aa0e1a03 100644 --- a/tasmota/include/i18n.h +++ b/tasmota/include/i18n.h @@ -238,6 +238,7 @@ #define D_JSON_MY "YaxisInduction" #define D_JSON_MZ "ZaxisInduction" #define D_JSON_MAGNETICFLD "MagneticInduction" +#define D_JSON_ALERT "Alert" #define D_JSON_BATTPERCENT "BatteryPercentage" #define D_RSLT_ENERGY "ENERGY" #define D_RSLT_HASS_STATE "HASS_STATE" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 33db2bdd1757..3f4d1980bf3d 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -716,6 +716,7 @@ // #define TC74_MAX_FAILCOUNT 8 // Maximum failed polls before it's marked inactive until reprobing later // #define USE_PCA9557 // [I2cDriver81] Enable PCA9557 8-bit I/O Expander (I2C addresses 0x18 - 0x1F) (+2k5 code) // #define USE_MAX17043 // [I2cDriver83] Enable MAX17043 fuel-gauge systems Lipo batteries sensor (I2C address 0x36) (+0k9 code) +// #define MAX17043_ALERT_THRESHOLD 32 // [I2cDriver83] Define the alert threshold for low battery level percentage 1-32 // #define USE_RTC_CHIPS // Enable RTC chip support and NTP server - Select only one // #define USE_DS3231 // [I2cDriver26] Enable DS3231 RTC (I2C address 0x68) (+1k2 code) diff --git a/tasmota/tasmota_xsns_sensor/xsns_110_max17043.ino b/tasmota/tasmota_xsns_sensor/xsns_110_max17043.ino index 542f27642649..f7a5e6abaf85 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_110_max17043.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_110_max17043.ino @@ -25,8 +25,11 @@ * * Battery voltage in Volt and State Of Charge (SOC) in percent are published via MQTT * - * The alert flag and alert threshold are not required for MQTT, the alert pin is not used - * by this sensor driver. + * The alert flag and alert threshold have been added to this sensor driver. Use + * Alert via as a 'low battery' or 'battery critical' binary sensor + * + * set MAX17043_ALERT_THRESHOLD to a percentage between 1-32 in my_user_config.h + * default is 32% per the legacy of this driver * * Tested module(s): * @@ -53,26 +56,43 @@ #define MAX17043_MODE_COMMAND_POWERONRESET 0x5400 #define MAX17043_MODE_COMMAND_QUICKSTART 0x4000 -#define MAX17043_CONFIG_POWER_UP_DEFAULT 0x971c -#define MAX17043_CONFIG_NO_COMPENSATION 0x9700 +#define MAX17043_CONFIG_POWER_UP_DEFAULT 0x971C +#define MAX17043_CONFIG_SAFE_MASK 0xFF1F // mask out sleep bit (7), unused bit (6) and alert bit (4) +#define MAX17043_CONFIG_ALERT_MASK 0x0020 // mask alert bit (4) + +#ifndef MAX17043_ALERT_THRESHOLD +#define MAX17043_ALERT_THRESHOLD 32 // legacy sensor code set this to 32% +#endif +#if MAX17043_ALERT_THRESHOLD<1 +#undef MAX17043_ALERT_THRESHOLD +#define MAX17043_ALERT_THRESHOLD 1 +#endif +#if MAX17043_ALERT_THRESHOLD>32 +#undef MAX17043_ALERT_THRESHOLD +#define MAX17043_ALERT_THRESHOLD 32 +#endif bool max17043 = false; int battery_latest = 101; +// set the lower 5 bits of config register to the 2's complement of MAX17043_ALERT_THRESHOLD +const uint16_t config_with_threshold = (MAX17043_CONFIG_POWER_UP_DEFAULT & 0xFFE0) | ((~MAX17043_ALERT_THRESHOLD+1) & 0x001F); + /*********************************************************************************************/ void Max17043Init(void) { + uint16_t config_reg; if (I2cSetDevice(MAX17043_ADDRESS)) { if (REASON_DEEP_SLEEP_AWAKE == ESP_ResetInfoReason()) { // if waking from deep sleep we assume the hardware design maintained power to the MAX17043 // retaining its model of the internal dynamics the battery - // if the hardware design doesn't (to conserve battery) then we lose some of + // if the hardware design doesn't (to conserve battery) then we lose many of // the benefits of the device anyway as it'll be re-learning from scratch every DeepSleepTime seconds. - // to confirm this is a MAX17043 - check for both the default (if the MAX17043 did lose it's power) - // or our setting if power was maintained - if (I2cRead16(MAX17043_ADDRESS, MAX17043_CONFIG) == MAX17043_CONFIG_NO_COMPENSATION - || I2cRead16(MAX17043_ADDRESS, MAX17043_CONFIG) == MAX17043_CONFIG_POWER_UP_DEFAULT) { + // confirm this is a MAX17043 + // mask out unpredictable bits on the config register + config_reg = I2cRead16(MAX17043_ADDRESS, MAX17043_CONFIG) & MAX17043_CONFIG_SAFE_MASK; + if (config_reg == MAX17043_CONFIG_POWER_UP_DEFAULT || config_reg == config_with_threshold) { max17043 = true; I2cSetActiveFound(MAX17043_ADDRESS, MAX17043_NAME); AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SNS: Waking from deep sleep - skipping " MAX17043_NAME " Power on Reset & Quick Start")); @@ -83,12 +103,16 @@ void Max17043Init(void) { I2cWrite16(MAX17043_ADDRESS, MAX17043_COMMAND, MAX17043_MODE_COMMAND_POWERONRESET); delay(10); - if (I2cRead16(MAX17043_ADDRESS, MAX17043_CONFIG) == MAX17043_CONFIG_POWER_UP_DEFAULT) { // Read the default to confirm this is a MAX17043 + // confirm this is a MAX17043 (must read after power on reset, as reset does just that to the config register) + // mask out unpredictable bits on the config register + config_reg = I2cRead16(MAX17043_ADDRESS, MAX17043_CONFIG) & MAX17043_CONFIG_SAFE_MASK; + if (config_reg == MAX17043_CONFIG_POWER_UP_DEFAULT) { I2cWrite16(MAX17043_ADDRESS, MAX17043_MODE, MAX17043_MODE_COMMAND_QUICKSTART); - I2cWrite16(MAX17043_ADDRESS, MAX17043_CONFIG, MAX17043_CONFIG_NO_COMPENSATION); + I2cWrite16(MAX17043_ADDRESS, MAX17043_CONFIG, config_with_threshold); delay(10); max17043 = true; I2cSetActiveFound(MAX17043_ADDRESS, MAX17043_NAME); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SNS: " MAX17043_NAME " Alert Threshold set to %d" D_UNIT_PERCENT), MAX17043_ALERT_THRESHOLD); } } } @@ -100,6 +124,7 @@ void Max17043Show(bool json) { uint16_t per = I2cRead16(MAX17043_ADDRESS, MAX17043_SOC); float percentage = (float)((per >> 8) + 0.003906f * (per & 0x00ff)); // Battery remaining charge in percent int battery_current; + bool alert = (MAX17043_CONFIG_ALERT_MASK == (I2cRead16(MAX17043_ADDRESS, MAX17043_CONFIG) & MAX17043_CONFIG_ALERT_MASK)); // During charging the percentage might be (slightly) above 100%. To avoid strange numbers // in the statistics the percentage provided by this driver will not go above 100% @@ -112,7 +137,7 @@ void Max17043Show(bool json) { battery_latest = battery_current; } if (json) { - ResponseAppend_P(PSTR(",\"" MAX17043_NAME "\":{\"" D_JSON_VOLTAGE "\":%3_f,\"" D_JSON_BATTPERCENT "\":%2_f}"), &voltage, &percentage ); + ResponseAppend_P(PSTR(",\"" MAX17043_NAME "\":{\"" D_JSON_VOLTAGE "\":%3_f,\"" D_JSON_BATTPERCENT "\":%2_f, \"" D_JSON_ALERT "\":%d}"), &voltage, &percentage, alert); #ifdef USE_WEBSERVER } else { WSContentSend_PD(PSTR("{s}" MAX17043_NAME " " D_VOLTAGE "{m}%1_f" D_UNIT_VOLT "{e}"), &voltage);