From ba101a01c1a410a48cbbefd6283f8025a07a962e Mon Sep 17 00:00:00 2001 From: Axel Gembe Date: Sun, 13 Jul 2025 17:58:05 +0700 Subject: [PATCH 1/3] apc_modbus: Add CHRG and DISCHRG status We use the acceptable input flag and the current battery level to determine if the device status is charging or discharging. Signed-off-by: Axel Gembe --- NEWS.adoc | 1 + drivers/apc_modbus.c | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/NEWS.adoc b/NEWS.adoc index d060e40a3f..4e4759ae41 100644 --- a/NEWS.adoc +++ b/NEWS.adoc @@ -138,6 +138,7 @@ https://github.com/networkupstools/nut/milestone/9 * The time stamp and inter-frame delay accounting was fixed, alleviating one of the problems reported in issue #2609. [PR #2982] * Fix missing variables due to mismatching format string. [PR #3013] + * Add CHRG and DISCHRG status. [PR #3014] - `bcmxcp` driver updates: * The latching on to a previous replace battery status was fixed, with its diff --git a/drivers/apc_modbus.c b/drivers/apc_modbus.c index 19d8788725..90953d5385 100644 --- a/drivers/apc_modbus.c +++ b/drivers/apc_modbus.c @@ -88,6 +88,7 @@ static int is_usb = 0; static int is_open = 0; static double power_nominal; static double realpower_nominal; +static double battery_charge; static int64_t last_send_time = 0; /* Function declarations */ @@ -850,7 +851,7 @@ static apc_modbus_register_t apc_modbus_register_map_status[] = { static apc_modbus_register_t apc_modbus_register_map_dynamic[] = { { "battery.runtime", 128, 2, APC_VT_UINT, 0, NULL, "%" PRIu64, 0, NULL }, - { "battery.charge", 130, 1, APC_VT_UINT, 0, &_apc_modbus_double_conversion, "%.2f", 9, NULL }, + { "battery.charge", 130, 1, APC_VT_UINT, 0, &_apc_modbus_double_conversion, "%.2f", 9, &battery_charge }, { "battery.voltage", 131, 1, APC_VT_INT, 0, &_apc_modbus_double_conversion, "%.2f", 5, NULL }, { "battery.date.maintenance", 133, 1, APC_VT_UINT, 0, &_apc_modbus_date_conversion, NULL, 0, NULL }, { "battery.temperature", 135, 1, APC_VT_INT, 0, &_apc_modbus_double_conversion, "%.2f", 7, NULL }, @@ -1532,16 +1533,24 @@ void upsdrv_updateinfo(void) /* Dynamic Data */ if (_apc_modbus_read_registers(modbus_ctx, 128, 32, regbuf)) { + _apc_modbus_process_registers(apc_modbus_register_map_dynamic, regbuf, 32, 128); + /* InputStatus_BF, 1 register */ _apc_modbus_to_uint64(®buf[22], 1, &value); + if (value & (1 << 0)) { + // Acceptable input + if (battery_charge < 100.0) { + status_set("CHRG"); + } + } else { + status_set("DISCHRG"); + } if (value & (1 << 5)) { status_set("BOOST"); } if (value & (1 << 6)) { status_set("TRIM"); } - - _apc_modbus_process_registers(apc_modbus_register_map_dynamic, regbuf, 32, 128); } else { dstate_datastale(); return; From 647d9c0ecfc751a3051344c00af105894ce7cc94 Mon Sep 17 00:00:00 2001 From: Axel Gembe Date: Sun, 13 Jul 2025 19:37:09 +0700 Subject: [PATCH 2/3] apc_modbus: Fix battery system error decoding --- drivers/apc_modbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/apc_modbus.c b/drivers/apc_modbus.c index 90953d5385..94d7bd1ae7 100644 --- a/drivers/apc_modbus.c +++ b/drivers/apc_modbus.c @@ -1514,7 +1514,7 @@ void upsdrv_updateinfo(void) } /* BatterySystemError_BF, 1 register */ - _apc_modbus_to_uint64(®buf[18], 1, &value); + _apc_modbus_to_uint64(®buf[22], 1, &value); if (value & (1 << 1)) { /* NeedsReplacement */ status_set("RB"); } From 21a5af3c24b61bc9a0f198dd87a29f95e970b77c Mon Sep 17 00:00:00 2001 From: Axel Gembe Date: Mon, 14 Jul 2025 23:30:32 +0700 Subject: [PATCH 3/3] chrg --- drivers/apc_modbus.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/apc_modbus.c b/drivers/apc_modbus.c index 94d7bd1ae7..5d0660b389 100644 --- a/drivers/apc_modbus.c +++ b/drivers/apc_modbus.c @@ -1461,6 +1461,8 @@ void upsdrv_initinfo(void) void upsdrv_updateinfo(void) { uint16_t regbuf[32]; + uint64_t ups_status; + uint64_t bat_system_err; uint64_t value; if (!is_open) { @@ -1478,32 +1480,32 @@ void upsdrv_updateinfo(void) /* Status Data */ if (_apc_modbus_read_registers(modbus_ctx, 0, 27, regbuf)) { /* UPSStatus_BF, 2 registers */ - _apc_modbus_to_uint64(®buf[0], 2, &value); - if (value & (1 << 1)) { + _apc_modbus_to_uint64(®buf[0], 2, &ups_status); + if (ups_status & (1 << 1)) { status_set("OL"); } - if (value & (1 << 2)) { + if (ups_status & (1 << 2)) { status_set("OB"); } - if (value & (1 << 3)) { + if (ups_status & (1 << 3)) { status_set("BYPASS"); } - if (value & (1 << 4)) { + if (ups_status & (1 << 4)) { status_set("OFF"); } - if (value & (1 << 5)) { + if (ups_status & (1 << 5)) { alarm_set("General fault"); } - if (value & (1 << 6)) { + if (ups_status & (1 << 6)) { alarm_set("Input not acceptable"); } - if (value & (1 << 7)) { + if (ups_status & (1 << 7)) { status_set("TEST"); } - if (value & (1 << 13)) { + if (ups_status & (1 << 13)) { buzzmode_set("vendor:apc:HE"); /* High efficiency / ECO mode*/ } - if (value & (1 << 21)) { + if (ups_status & (1 << 21)) { status_set("OVER"); } @@ -1514,8 +1516,8 @@ void upsdrv_updateinfo(void) } /* BatterySystemError_BF, 1 register */ - _apc_modbus_to_uint64(®buf[22], 1, &value); - if (value & (1 << 1)) { /* NeedsReplacement */ + _apc_modbus_to_uint64(®buf[22], 1, &bat_system_err); + if (bat_system_err & (1 << 1)) { /* NeedsReplacement */ status_set("RB"); } @@ -1525,6 +1527,17 @@ void upsdrv_updateinfo(void) status_set("CAL"); } + /* No battery error ? */ + if (bat_system_err == 0) { + if (ups_status & (1 << 1)) { + status_set("CHRG"); + } + if (ups_status & (1 << 2)) { + status_set("DISCHRG"); + } + + } + _apc_modbus_process_registers(apc_modbus_register_map_status, regbuf, 27, 0); } else { dstate_datastale();