diff --git a/tasmota/include/tasmota.h b/tasmota/include/tasmota.h index ba9645e9b..1df0aa1f0 100644 --- a/tasmota/include/tasmota.h +++ b/tasmota/include/tasmota.h @@ -515,10 +515,10 @@ enum DevGroupShareItem { DGR_SHARE_POWER = 1, DGR_SHARE_LIGHT_BRI = 2, DGR_SHARE enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER, SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_SHUTTER, - SRC_THERMOSTAT, SRC_CHAT, SRC_TCL, SRC_BERRY, SRC_FILE, SRC_SSERIAL, SRC_USBCONSOLE, SRC_SO47, SRC_MAX }; + SRC_THERMOSTAT, SRC_CHAT, SRC_TCL, SRC_BERRY, SRC_FILE, SRC_SSERIAL, SRC_USBCONSOLE, SRC_SO47, SRC_SENSOR, SRC_MAX }; const char kCommandSource[] PROGMEM = "I|MQTT|Restart|Button|Switch|Backlog|Serial|WebGui|WebCommand|WebConsole|PulseTimer|" "Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote|Shutter|" - "Thermostat|Chat|TCL|Berry|File|SSerial|UsbConsole|SO47"; + "Thermostat|Chat|TCL|Berry|File|SSerial|UsbConsole|SO47|Sensor"; const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 }; diff --git a/tasmota/tasmota_xsns_sensor/xsns_110_max17043.ino b/tasmota/tasmota_xsns_sensor/xsns_110_max17043.ino index 7c97be17e..3e9a64a74 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_110_max17043.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_110_max17043.ino @@ -1,7 +1,8 @@ /* xsns_110_max17043.ino - Support for MAX17043 fuel-gauge systems Lipo batteries for Tasmota - Copyright (C) 2023 Vincent de Groot + Copyright (c) 2023 Vincent de Groot + Copyright (c) 2023 Paul Blacknell This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -40,6 +41,8 @@ #define XSNS_110 110 #define XI2C_83 83 // See I2CDEVICES.md +#define MAX17043_NAME "MAX17043" + #define MAX17043_ADDRESS 0x36 #define MAX17043_VCELL 0x02 #define MAX17043_SOC 0x04 @@ -48,39 +51,74 @@ #define MAX17043_CONFIG 0x0c #define MAX17043_COMMAND 0xfe +#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 + bool max17043 = false; +int battery_latest = 101; /*********************************************************************************************/ void Max17043Init(void) { if (I2cSetDevice(MAX17043_ADDRESS)) { - I2cWrite16(MAX17043_ADDRESS, MAX17043_COMMAND, 0x5400); // Power on reset - delay(10); - if (I2cRead16(MAX17043_ADDRESS, MAX17043_CONFIG) == 0x971c) { // Default 0x971c - I2cWrite16(MAX17043_ADDRESS, MAX17043_MODE, 0x4000); // Quick start - I2cWrite16(MAX17043_ADDRESS, MAX17043_CONFIG, 0x9700); + 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 + // 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) { + 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")); + } + } else { + // otherwise perform a full Power on Reset (which is the same as disconnecting power) + // and a Quick Start which essentially does the same but handles a noisy power up sequence + + I2cWrite16(MAX17043_ADDRESS, MAX17043_COMMAND, MAX17043_MODE_COMMAND_POWERONRESET); delay(10); - max17043 = true; - I2cSetActiveFound(MAX17043_ADDRESS, "MAX17043"); + if (I2cRead16(MAX17043_ADDRESS, MAX17043_CONFIG) == MAX17043_CONFIG_POWER_UP_DEFAULT) { // Read the default to confirm this is a MAX17043 + I2cWrite16(MAX17043_ADDRESS, MAX17043_MODE, MAX17043_MODE_COMMAND_QUICKSTART); + I2cWrite16(MAX17043_ADDRESS, MAX17043_CONFIG, MAX17043_CONFIG_NO_COMPENSATION); + delay(10); + max17043 = true; + I2cSetActiveFound(MAX17043_ADDRESS, MAX17043_NAME); + } } } } + void Max17043Show(bool json) { float voltage = (1.25f * (float)(I2cRead16(MAX17043_ADDRESS, MAX17043_VCELL) >> 4)) / 1000.0; // Battery voltage in Volt 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; // 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% if (percentage > 100.0) { percentage = 100.0; } + + // only update the system percentage if it's changed + battery_current = int(round(percentage)); + if (battery_latest != battery_current) { + char cmnd[30]; + sprintf(cmnd, "%s %d", D_CMND_ZIGBEE_BATTPERCENT, battery_current); + ExecuteCommand(cmnd, SRC_SENSOR); + battery_latest = battery_current; + } if (json) { - ResponseAppend_P(PSTR(",\"MAX17043\":{\"" 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}"), &voltage, &percentage ); #ifdef USE_WEBSERVER } else { -// WSContentSend_Voltage("MAX17043", voltage); - WSContentSend_PD(PSTR("{s}MAX17043 " D_VOLTAGE "{m}%1_f" D_UNIT_VOLT "{e}"), &voltage); - WSContentSend_PD(PSTR("{s}MAX17043 " D_BATTERY_CHARGE "{m}%1_f %% {e}"), &percentage); + WSContentSend_PD(PSTR("{s}" MAX17043_NAME " " D_VOLTAGE "{m}%1_f" D_UNIT_VOLT "{e}"), &voltage); + WSContentSend_PD(PSTR("{s}" MAX17043_NAME " " D_BATTERY_CHARGE "{m}%1_f " D_UNIT_PERCENT " {e}"), &percentage); #endif } }