Skip to content

ECOmode-auto-addon2-todo#2956

Merged
jimklimov merged 47 commits intonetworkupstools:masterfrom
masterwishx:ECOmode-auto-addon2-todo
Jul 18, 2025
Merged

ECOmode-auto-addon2-todo#2956
jimklimov merged 47 commits intonetworkupstools:masterfrom
masterwishx:ECOmode-auto-addon2-todo

Conversation

@masterwishx
Copy link
Copy Markdown
Contributor

@masterwishx masterwishx commented May 14, 2025

Signed-off-by: DaRK AnGeL 28630321+masterwishx@users.noreply.github.com

To continue work for #2949 :

To make automatic ECO Mode commands:

experimental.ecomode.start.auto
experimental.ecomode.stop.auto

that run Bypass On then ECO Mode Enable and back instead of users are run two separate commands or variables :

bypass.start + experimental.ecomode.enable
bypass.stop + experimental.ecomode.disable

or

 Enable bypass mode:
upsrw -u admin -p pass -s input.bypass.switch.on=on eaton

Enable ECO mode:
upsrw -u admin -p pass -s input.eco.switchable=enable eaton

Disable bypass mode:
upsrw -u admin -p pass -s input.bypass.switch.off=off eaton

Disable ECO mode:
upsrw -u admin -p pass -s input.eco.switchable=normal eaton

…p.auto"

Signed-off-by: DaRK AnGeL <28630321+masterwishx@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

@masterwishx masterwishx left a comment

Choose a reason for hiding this comment

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

@jimklimov i made the new pr for aecomode auto ,we need to confirm what best name for commands :
if you think auto not good , maybe :

experimental.bypass.ecomode.start
experimental.bypass.ecomode.stop

@masterwishx masterwishx changed the title added cmd "experimental.ecomode.start.auto" "experimental.ecomode.stop.auto" ECOmode-auto-addon2-todo May 14, 2025
@jimklimov
Copy link
Copy Markdown
Member

Yes, if they are one-time commands that take effect when issued (and not a toggle for UPS to auto-change modes later based on environmental circumstances and this choice of strategy, like e.g. trim/boost happens automatically to compensate for input voltage outside low/high thresholds), then *.start and *.stop variants are better.

…l.ecomode.start[stop].auto`

Signed-off-by: DaRK AnGeL <28630321+masterwishx@users.noreply.github.com>
@masterwishx
Copy link
Copy Markdown
Contributor Author

@ZivertX can you please test this pr : https://github.com/masterwishx/nut/tree/ECOmode-auto-addon2-todo when you will have time ?

This will run bypass + ecomode on/off by one command:

experimental.bypass.ecomode.start
experimental.bypass.ecomode.stop 

Please check (by ups screen or so) that bypass was enabled before ECO mode when on , also when off, bypass was disabled before exit from ecomode.

Also Please include debug Logs.
Thanks

@jimklimov jimklimov added Eaton USB ECO/ESS/HE/ABM modes Non-trivial power supply management modes (ECO, ESS, HE, ABM etc.) labels May 18, 2025
@jimklimov jimklimov added this to the 2.8.4 milestone May 18, 2025
@ZivertX
Copy link
Copy Markdown

ZivertX commented May 19, 2025

experimental.bypass.ecomode.start
experimental.bypass.ecomode.stop 

Built your version (ECOmode-auto-addon2-todo)

driver.version: 2.8.2.2824.348-3172+g327e51e24

  1. UPS doesn't go into bypass mode, but switches to ECO

experimental.bypass.ecomode.start.log

  1. UPS doesn't do anything, ECO mode still active

experimental.bypass.ecomode.stop.log

@masterwishx
Copy link
Copy Markdown
Contributor Author

  1. UPS doesn't go into bypass mode, but switches to ECO

Thanks will try to fix it

@masterwishx
Copy link
Copy Markdown
Contributor Author

driver.version: 2.8.2.

@jimklimov should it be 2.8.3 ?

@masterwishx
Copy link
Copy Markdown
Contributor Author

driver.version: 2.8.2

why not in 2.8.3 ?

@masterwishx
Copy link
Copy Markdown
Contributor Author

May 19 16:42:46 nut usbhid-ups[929]: [D2] entering main_instcmd(experimental.bypass.ecomode.start, (null)) for [eaton] on socket 10
May 19 16:42:46 nut usbhid-ups[929]: [D2] shared main_instcmd() does not handle command experimental.bypass.ecomode.start, proceeding to driver-specific handler
May 19 16:42:46 nut usbhid-ups[929]: [D1] instcmd(experimental.bypass.ecomode.start, [NULL])
May 19 16:42:46 nut usbhid-ups[929]: [D3] instcmd: using Path 'UPS.PowerConverter.Input.[5].Switchable'
May 19 16:42:46 nut usbhid-ups[929]: [D3] hu_find_valinfo: no matching HID value for this INFO_* value (1)

@jimklimov

nut/drivers/mge-hid.c

Lines 2167 to 2170 in 06d1032

{ "experimental.bypass.ecomode.start", 0, 0, "UPS.PowerConverter.Input.[5].Switchable", NULL, "1", HU_TYPE_CMD, eaton_input_eco_mode_auto_on_off_info },
/* Command to switch from ECO(HE) Mode with switch from Automatic Bypass Mode on before */
{ "experimental.bypass.ecomode.stop", 0, 0, "UPS.PowerConverter.Input.[5].Switchable", NULL, "0", HU_TYPE_CMD, eaton_input_eco_mode_auto_on_off_info },

We still have error when sending function in last setting of cmd instead of NULL?

can HU_TYPE_CMD_PARAM_REQUIRED instead of HU_TYPE_CMD can help here ?

@jimklimov
Copy link
Copy Markdown
Member

Regarding "2.8.2" - these strings from git describe depend on known git tags (probably had no git pull --tags after 2.8.3 release).

can HU_TYPE_CMD_PARAM_REQUIRED instead of HU_TYPE_CMD help here ?

No, it should require that you pass an argument (e.g. as upscmd usp@host cmd arg IIRC) if there is no (null) default in the table.

Here it finds "1" but then for some reason fails to use it. Can't say more ATM, am on phone in a bus...

@masterwishx
Copy link
Copy Markdown
Contributor Author

Here it finds "1" but then for some reason fails to use it. Can't say more ATM, am on phone in a bus...

I will try to dig it out, but if you will have time to help here will be cool, not shure how it should work as we don't have any command with function in last parametr instead of Null. :(

@jimklimov
Copy link
Copy Markdown
Member

jimklimov commented May 20, 2025

Digging a bit :)

For reference, definitions of mapping table elements (as of latest commit in this PR branch) are:

  • info_lkp_t (for info lookup helper methods):

    nut/drivers/usbhid-ups.h

    Lines 79 to 84 in 06d1032

    typedef struct {
    const long hid_value; /* HID value */
    const char *nut_value; /* NUT value */
    const char *(*fun)(double hid_value); /* optional HID to NUT mapping */
    double (*nuf)(const char *nut_value); /* optional NUT to HID mapping */
    } info_lkp_t;
  • hid_info_t (for the main mapping table):

    nut/drivers/usbhid-ups.h

    Lines 176 to 192 in 06d1032

    typedef struct {
    const char *info_type; /* NUT variable name */
    int info_flags; /* NUT flags (to set in addinfo) */
    int info_len; /* if ST_FLAG_STRING: length of the string */
    /* if HU_TYPE_CMD: command value */
    const char *hidpath; /* Full HID Object path (or NULL for server side vars) */
    HIDData_t *hiddata; /* Full HID Object data (for caching purpose, filled at runtime) */
    const char *dfl; /* if HU_FLAG_ABSENT: default value ; format otherwise */
    unsigned long hidflags; /* driver's own flags */
    info_lkp_t *hid2info; /* lookup table between HID and NUT values */
    /* if HU_FLAG_ENUM is set, hid2info is also used
    * as enumerated values (dstate_addenum()) */
    /* char *info_HID_format; *//* FFE: HID format for complex values */
    /* interpreter interpret; *//* FFE: interpreter fct, NULL if not needed */
    /* void *next; *//* next hid_info_t */
    } hid_info_t;

For INSTCMD we are interested in such hid_info_t entries that include HU_TYPE_CMD in their hidflags.

They may have a default dfl command argument (if not NULL); in our two entries they do, "0" and "1" as strings that are later converted to numbers:

nut/drivers/mge-hid.c

Lines 2166 to 2169 in 06d1032

/* Command to switch ECO(HE) Mode with switch to Automatic Bypass Mode on before */
{ "experimental.bypass.ecomode.start", 0, 0, "UPS.PowerConverter.Input.[5].Switchable", NULL, "1", HU_TYPE_CMD, eaton_input_eco_mode_auto_on_off_info },
/* Command to switch from ECO(HE) Mode with switch from Automatic Bypass Mode on before */
{ "experimental.bypass.ecomode.stop", 0, 0, "UPS.PowerConverter.Input.[5].Switchable", NULL, "0", HU_TYPE_CMD, eaton_input_eco_mode_auto_on_off_info },

They may also refer to a further table info_lkp_t *hid2info (if not NULL).

The lookup fault in your log:

May 19 16:42:46 nut usbhid-ups[929]: [D2] entering main_instcmd(experimental.bypass.ecomode.start, (null)) for [eaton] on socket 10
May 19 16:42:46 nut usbhid-ups[929]: [D2] shared main_instcmd() does not handle command experimental.bypass.ecomode.start, proceeding to driver-specific handler
May 19 16:42:46 nut usbhid-ups[929]: [D1] instcmd(experimental.bypass.ecomode.start, [NULL])
May 19 16:42:46 nut usbhid-ups[929]: [D3] instcmd: using Path 'UPS.PowerConverter.Input.[5].Switchable'
May 19 16:42:46 nut usbhid-ups[929]: [D3] hu_find_valinfo: no matching HID value for this INFO_* value (1)

...seems to come from code path at

nut/drivers/usbhid-ups.c

Lines 914 to 931 in 06d1032

/* Check if the item is an instant command */
if (!(hidups_item->hidflags & HU_TYPE_CMD)) {
upsdebugx(2, "instcmd: %s is not an instant command", cmdname);
return STAT_INSTCMD_INVALID;
}
/* If extradata is empty, use the default value from the HID-to-NUT table */
val = extradata ? extradata : hidups_item->dfl;
if (!val && hidups_item->hidflags & HU_FLAG_PARAM_REQUIRED) {
upsdebugx(2, "instcmd: %s requires an explicit or default parameter", cmdname);
return STAT_INSTCMD_CONVERSION_FAILED;
}
/* Lookup the new value if needed */
if (hidups_item->hid2info != NULL) {
/* item->nuf() is expected to handle NULL if it must */
value = hu_find_valinfo(hidups_item->hid2info, val);
} else {

...and specifically it fails in hu_find_valinfo() at the last quoted line. That method looks into an info_lkp_t *hid2info (treated as a single element if (hid2info->fun != NULL), or a lookup array while info_lkp->nut_value != NULL otherwise... for apparently static lookups for) as seen at

nut/drivers/usbhid-ups.c

Lines 2636 to 2663 in 06d1032

/* find the HID Item value matching that NUT value */
/* useful for set with value lookup... */
static long hu_find_valinfo(info_lkp_t *hid2info, const char* value)
{
info_lkp_t *info_lkp;
/* if a conversion function is defined, use 'value' as argument for it */
if (hid2info->nuf != NULL) {
double hid_value;
hid_value = hid2info->nuf(value);
upsdebugx(5, "hu_find_valinfo: found %g (value: %s)", hid_value, value);
return hid_value;
}
for (info_lkp = hid2info; info_lkp->nut_value != NULL; info_lkp++) {
if (!(strcmp(info_lkp->nut_value, value))) {
upsdebugx(5,
"hu_find_valinfo: found %s (value: %ld)",
info_lkp->nut_value, info_lkp->hid_value);
return info_lkp->hid_value;
}
}
upsdebugx(3,
"hu_find_valinfo: no matching HID value for this INFO_* value (%s)",
value);
return -1;
}

So apparently all other command cases which used some mapping function worked with a trivial mapping table of one or two info_lkp_t entries, one with a non-trivial nuf (which takes the given char* argument which may be NULL generally, and returns a double number... then converted to a long :\ ), and maybe a NULL,NULL,... sentinel as the other entry just in case - making a separate table for each unique function. And if there was no nuf in that (or no fun in the inverse hu_find_infoval()), the several couples of number(hid_value)+string(nut_value) had roles to play instead.

  • fun(): double arg => char* return
  • nuf(): char* arg => double(=>long) return

In your case, the eaton_input_eco_mode_auto_on_off_info[] mapping at

nut/drivers/mge-hid.c

Lines 1216 to 1222 in 06d1032

/* High Efficiency (aka ECO) mode for auto start/stop commands */
static info_lkp_t eaton_input_eco_mode_auto_on_off_info[] = {
{ 0, "normal", eaton_input_eco_mode_auto_off_fun, NULL },
{ 1, "ECO", eaton_input_eco_mode_auto_on_fun, NULL },
{ 2, "ESS", NULL, NULL },
{ 0, NULL, NULL, NULL }
};

...defines two fun entries (apparently only the first would get used) but not nuf.

With current code structure, which apparently ignores fun/nuf in non-first entries, this requires that you split your function-oriented tables into several single-entry mappings (maybe with a sentinel to avoid overflows just in case), possibly defining both one fun and one nuf in that first entry for the opposite use-cases, and keep function-less mappings for the fixed string<->number lookups.

Thanks for making me dig into this - now I think this problem seems to impact your other tables with fun entries not at the first spot, e.g.

  • eaton_input_eco_mode_on_off_info[] at

    nut/drivers/mge-hid.c

    Lines 1016 to 1022 in 06d1032

    /* High Efficiency (aka ECO) mode, Energy Saver System (aka ESS) mode makes sense for UPS like (93PM G2, 9395P) */
    static info_lkp_t eaton_input_eco_mode_on_off_info[] = {
    { 0, "normal", NULL, NULL },
    { 1, "ECO", eaton_input_eco_mode_check_range, NULL }, /* NOTE: "ECO" = tested on 9SX model and working fine, 9E model can stuck in ECO mode https://github.com/networkupstools/nut/issues/2719 */
    { 2, "ESS", eaton_input_ess_mode_report, NULL },
    { 0, NULL, NULL, NULL }
    };
  • info_lkp_t eaton_input_bypass_mode_on_info[] at

    nut/drivers/mge-hid.c

    Lines 1140 to 1145 in 06d1032

    /* Automatic Bypass mode on */
    static info_lkp_t eaton_input_bypass_mode_on_info[] = {
    { 0, "disabled", NULL, NULL },
    { 1, "on", eaton_input_bypass_check_range, NULL },
    { 0, NULL, NULL, NULL }
    };

...and probably older mappings too, or did I misunderstand something when reading the methods above? CC @arnaudquette-eaton - please help us out here (and help fix Eaton support as relevant) :)
They are moderately impacted though, as every line refers to same fun/nuf methods so hitting them via first line when acting for a second one does not have practical impact; skipping the explicit string<->number conversion (or doing it different in table and in actually called methods) might be more confusing. For example:

  • pegasus_yes_no_info[] at

    nut/drivers/mge-hid.c

    Lines 873 to 877 in 06d1032

    static info_lkp_t pegasus_yes_no_info[] = {
    { 0, "no", pegasus_yes_no_info_fun, pegasus_yes_no_info_nuf },
    { 1, "yes", pegasus_yes_no_info_fun, pegasus_yes_no_info_nuf },
    { 0, NULL, NULL, NULL }
    };
  • pegasus_threshold_info[] at

    nut/drivers/mge-hid.c

    Lines 823 to 828 in 06d1032

    static info_lkp_t pegasus_threshold_info[] = {
    { 10, "10", eaton_check_pegasus_fun, NULL },
    { 25, "25", eaton_check_pegasus_fun, NULL },
    { 60, "60", eaton_check_pegasus_fun, NULL },
    { 0, NULL, NULL, NULL }
    };

Some summary thoughts:

  • I did not check further, just enough to confirm there may be decades worth of confusion here
    • worth either a revision of existing mappings to use either single entries for each fun/nuf involved, or function-less static conversions,
    • or a careful redesign/rewrite of hu_find_valinfo()/hu_find_infoval() to consider the non-first entry methods - but this probably makes little sense, as a single facade method should be able to handle all argument values (and may dispatch to further methods for particular practical features where applicable).
    • MAAAYBE it makes sense to support raising e.g. an errno (or a driver-defined equivalent) when handling a fun()/nuf() when the method refuses to handle an argument value, so we would proceed with fixed table lookup?
    • It would anyhow be useful to know that the function disliked an argument, so we can return STAT_INSTCMD_FAILED, STAT_SET_INVALID, etc.
  • Similar concerns may impact snmp-ups and/or nutdrv_qx with their take on such mapping tables.
    • Makes sense to revise what they do as well, and end up with some consistent approach across the board.
  • Someone gotta take a look if any of this is clarified in the docs (they should be the first place to start... but might differ from actual code - something to fix in that case).
  • The short-term fix for this PR is to revise the ECO mapping tables, so if there are functions to call - they are in the first entry of a table, and so there are separate tables for separate functions or a common dispatcher function calls further methods based on the argument ("normal", "ECO", "ESS" for nuf() here) - and somehow visibly rejects or quietly ignores any unsupported argument values.

Finally note that these functions seem designed to convert the arguments from one type to another, not so much to perform a series of active operations on the device (as we want in this PR, to chain several changes of HW/FW state in practice). There may be several correct-ish solutions to wedge this desire into existing framework:

  • In instcmd(), after we get some value = hu_find_valinfo(hidups_item->hid2info, val); (or convert from the default number directly if there is no hid2info sub-mapping), we go on to HIDSetDataValue(udev, hidups_item->hiddata, value). So if the methods do something complex inside, keep in mind they should return a value that is reasonable, benign, and does not contradict the other activity.
  • Limit the mapping methods to actual data conversions and no interaction with the device, and for complex operations like this - dstate_addcmd("experimental.bypass.ecomode.start") perhaps during mge_claim() AND ensure the subdriver has a say in instcmd() processing from the main driver - but I see no precedent for such approach in neither drivers/*-hid.c, nor drivers/*-mib.c, nor drivers/nutdrv_qx_*.c -- so probably now is not a good time to start with that. Mapping tables are the vehicle we have somehow functional and well-tested here.

@masterwishx
Copy link
Copy Markdown
Contributor Author

For reference, definitions of mapping table elements (as of latest commit in this PR branch) are:

Yep i checked this but seems i forgot a little how its working :)

...and specifically it fails in hu_find_valinfo() at the last quoted line. That method looks into an info_lkp_t *hid2info (treated as a single element if (hid2info->fun != NULL), or a lookup array while info_lkp->nut_value != NULL otherwise... for apparently static lookups for) as seen at

Thanks will look into it

Thanks for making me dig into this - now I think this problem seems to impact your other tables with fun entries not at the first spot, e.g.

Strange those functions working fine from the tests that we had with @ZivertX confirmed by for bypass and ecomode ( for both upsrw and cmd (with NULL)) :

nut/drivers/mge-hid.c

Lines 1016 to 1022 in 06d1032

/* High Efficiency (aka ECO) mode, Energy Saver System (aka ESS) mode makes sense for UPS like (93PM G2, 9395P) */
static info_lkp_t eaton_input_eco_mode_on_off_info[] = {
{ 0, "normal", NULL, NULL },
{ 1, "ECO", eaton_input_eco_mode_check_range, NULL }, /* NOTE: "ECO" = tested on 9SX model and working fine, 9E model can stuck in ECO mode https://github.com/networkupstools/nut/issues/2719 */
{ 2, "ESS", eaton_input_ess_mode_report, NULL },
{ 0, NULL, NULL, NULL }
};

nut/drivers/mge-hid.c

Lines 1140 to 1145 in 06d1032

/* Automatic Bypass mode on */
static info_lkp_t eaton_input_bypass_mode_on_info[] = {
{ 0, "disabled", NULL, NULL },
{ 1, "on", eaton_input_bypass_check_range, NULL },
{ 0, NULL, NULL, NULL }
};

But will check again with your info :)

Finally note that these functions seem designed to convert the arguments from one type to another, not so much to perform a series of active operations on the device (as we want in this PR, to chain several changes of HW/FW state in practice). There may be several correct-ish solutions to wedge this desire into existing framework:

Wow i need more time to check it :)

@jimklimov
Copy link
Copy Markdown
Member

Disregard netbsd agent CI faults, the worker had an environmental issue.

if (!strcmp(bypass_switch_off_str, "disabled")) {
setvar("input.bypass.switch.off", "off");
} else {
upsdebugx(1, "Bypass switch off state is: %s , must be disabled before switching off", bypass_switch_off_str);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Might be good to prefix all these upsdebugx with %s: and __func__ so we can see more easily which functions get called and do what during the testing and also later when in production.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

upsdebugx(1, "%s: Bypass switch off state is: %s , must be disabled before switching off", __func__, bypass_switch_off_str); its ok ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes that's how I usually do it so it shows which function emits the message.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes that's how I usually do it so it shows which function emits the message.

Yep i also did it but for some of upsdebugx in functions but forgot from back then about it and how stuff was working :(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes that's how I usually do it so it shows which function emits the message.

Maybe you can check about current issue we have here if you have time ?

…__ for easy debug later

Signed-off-by: DaRK AnGeL <28630321+masterwishx@users.noreply.github.com>
@AppVeyorBot
Copy link
Copy Markdown

…alue [networkupstools#2956]

We want it evaluated on every quick-update loop, so that the
correct buzzwords are always set (if device serves the feature).
Also quick-update the bypass voltage and frequency, so we know
relevant clues (keep semi-static settings as they were though).

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
…hat value==1 [networkupstools#2956]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
…put if we remain in ECO/non-ECO mode [networkupstools#2956]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
…n ups_status_set() [networkupstools#2956]

Avoid extra work and occasional log messages that:

    str_add_unique_token: skip token 'vendor:default:ECO': was already set

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
@jimklimov
Copy link
Copy Markdown
Member

jimklimov commented Jul 17, 2025

Prepared some more commits based on previous post's findings, see uploaded above.

@masterwishx
Copy link
Copy Markdown
Contributor Author

Actually, far from every update. Only at cycles

Yep sorry I meaned the cycle

@masterwishx
Copy link
Copy Markdown
Contributor Author

Can you please look at more context around? Seems it failed a sanity check so refused to work (not sure if the failure was correct or not, did not investigate; but the safety logic seems to have worked):

I think it's when waiting one value but got other.. Will check again in next test?

Please let me know when it's done for test.

Another question all worked fine befor, so you think it worth all new changes?
Do you think was not so good logic befor?

…g for "value==1" [networkupstools#2956]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
@jimklimov
Copy link
Copy Markdown
Member

I think it's when waiting one value but got other.. Will check again in next test?
Please let me know when it's done for test.

Well, that latest iteration of fixes (quick poll, better/quieter logging) is all I planned to do for now, so can test with it as well.

Another question all worked fine befor, so you think it worth all new changes? Do you think was not so good logic befor?

You tell me, as the author :) From what I saw, in most of those small mapping tables, either the logic (in added methods) was not called at all, or not all mapping values supposed to be supported were in fact handled. If it worked well then, maybe the complex methods are not needed and simple mappings (number <=> string) would suffice?

For example, when handling "input.eco.switchable" -- in eaton_input_eco_mode_check_range(), if value==1, we test for various power-quality values being in range, and say the device can be switched into a certain ("ECO") mode or not. Can we just trust what the UPS says (0/1/2 meaning exactly "normal"/"ECO"/"ESS") and delete this method?

BTW we have a similarly written eaton_input_bypass_check_range() (just found a typo there I added recently, that it could not really handle "value==1" - should be fixed now too). It is referenced from eaton_input_bypass_mode_on_info[] for "input.bypass.switch.on" mapping, which now remains HU_FLAG_SEMI_STATIC. Shouldn't it also be frequently updated? The opposite(?) "input.bypass.switch.off" is a semi-static with fixed number-string mapping. Is that all correct?

@masterwishx
Copy link
Copy Markdown
Contributor Author

so can test with it as well.

If will have time today will check it if no then tomorrow.

You tell me, as the author :) From what I saw, in most of those small mapping tables, either the logic (in added methods) was not called at all, or not all mapping values supposed to be supported were in fact handled. If it worked well then, maybe the complex methods are not needed and simple mappings (number <=> string) would suffice?

For real test on my unit was tests of (switch to/from bypass/ecomode), but after that my unit stuck in ecomode was unable to test for real only by logs (they all avaliable in previous prs), only after that I added to check bypass range/ecomode range.
But @ZivertX tested with some logs so was hoping on his tests.

Can we just trust what the UPS says (0/1/2 meaning exactly "normal"/"ECO"/"ESS") and delete this method?

No, I added this method (check range) to be exactly as in documentation of 9E/9SX that ups when switched to ecomode (needs to check when in bypass if can be switched by thresholds).

Same for bypass.

input.bypass.switch.on" mapping, which now remains HU_FLAG_SEMI_STATIC. Shouldn't it also be frequently updated? The opposite(?) "input.bypass.switch.off" is a semi-static with fixed number-string mapping. Is that all correct?

input.bypass.switch.on=on
Is on when switched to bypass (by command or variable)

input.bypass.switch.off=off
Is off when inverter on (switched from bypass)

So if user switch bypass on/off by buttons HU_FLAG_SEMI_STATIC should be updated as I remember from tests or better to change it?
Also it changed when using cmd/variable...

I added HU_FLAG_SEMI_STATIC to all variable as it was for all other variables so was assuming this how should work (when tryed understand how things work)

@masterwishx
Copy link
Copy Markdown
Contributor Author

masterwishx commented Jul 17, 2025

Shouldn't it also be frequently updated? The opposite(?)

Yes I think will be better to be quick updated, maybe when input power/freq by range from the wall will be changed for example...

Then ups will change bypass mode.

HU_FLAG_SEMI_STATIC can't do that? (don't remember)

@AppVeyorBot
Copy link
Copy Markdown

@AppVeyorBot
Copy link
Copy Markdown

Signed-off-by: DaRK AnGeL <28630321+masterwishx@users.noreply.github.com>
@masterwishx
Copy link
Copy Markdown
Contributor Author

Tested : LGTM , waiting your approval:)

nut-18.7.25.log

@masterwishx
Copy link
Copy Markdown
Contributor Author

Just for info:
@jimklimov
As you know my 9E unit stuck in ecomode after 3 commands instead of 2:
Bypass on + ecomode + bypass off
(so now both input.bypass.switch.off=disabled
input.bypass.switch.on=disabled)
When one of them should have =1 (bypass on or inverter on)

So I think my 9E have some issues in firmware (cuted/partial from 9sx firmware about ecomode)
However 9E has all values needed for ecomode but missed physical buttons for ecomode on/off)

Also when asked time ago for Eaton support, they said only in snmp ecomode can work on 9E.

But they don't knew that I can add support for nut for 9E with usb :)

So hopefully some time will find how to solve it...

Maybe will check by ecomode range (if can be switched back to online when changed)

Maybe needs to be fixed in libusb like was for ups name etc...

@jimklimov
Copy link
Copy Markdown
Member

my 9E unit stuck in ecomode ...
So I think my 9E have some issues in firmware (cuted/partial from 9sx firmware about ecomode)
However 9E has all values needed for ecomode but missed physical buttons for ecomode on/off)
Also when asked time ago for Eaton support, they said only in snmp ecomode can work on 9E.

BTW, CCing @arnaudquette-eaton : can you please check if the issue is known/addressed internally?

Whether this was intended to be supported or not, having devices in the field that can in fact be somewhat bricked by accepting some command sequence is anyhow a bug to fix, right?

@jimklimov
Copy link
Copy Markdown
Member

@masterwishx : thanks for the new test and log :)

The method seems quieter now, confirming that it remains in ECO mode every 2 seconds:

Jul 18 09:52:08 Myserver usbhid-ups[906601]: [D2:906601] Path: UPS.PowerConverter.Input.[5].Switchable, Type: Feature, ReportID: 0x3f, Offset: 0, Size: 8, Value: 1
Jul 18 09:52:08 Myserver usbhid-ups[906601]: [D4:906601] eaton_input_eco_mode_check_range: Still in ECO mode due to input conditions being within the transfer limits.

...with no re-publication of buzz mode on the bus after the initial posting (with two tokens) back when the driver was first initialized:

...
Jul 18 09:51:48 Myserver rc.nut:    6.069999#011[D5:904992] hid_lookup_usage: UPS -> 00840004
Jul 18 09:51:48 Myserver rc.nut:    6.070000#011[D5:904992] hid_lookup_usage: PowerConverter -> 00840016
Jul 18 09:51:48 Myserver rc.nut:    6.070002#011[D5:904992] hid_lookup_usage: Input -> 0084001a
Jul 18 09:51:48 Myserver rc.nut:    6.070004#011[D5:904992] hid_lookup_usage: [5] -> not found in lookup table
Jul 18 09:51:48 Myserver rc.nut:    6.070004#011[D5:904992] string_to_path: hid_lookup_usage failed, checking if token [5] is a raw value
Jul 18 09:51:48 Myserver rc.nut:    6.070006#011[D5:904992] hid_lookup_usage: Switchable -> 0084006c
Jul 18 09:51:48 Myserver rc.nut:    6.070006#011[D4:904992] string_to_path: depth = 5
Jul 18 09:51:48 Myserver rc.nut:    6.070008#011[D3:904992] Report[buf]: (2 bytes) => 3f 01
Jul 18 09:51:48 Myserver rc.nut:    6.070008#011[D5:904992] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 09:51:48 Myserver rc.nut:    6.070009#011[D5:904992] Unit = 00000000, UnitExp = 0
Jul 18 09:51:48 Myserver rc.nut:    6.070010#011[D5:904992] Exponent = 0
Jul 18 09:51:48 Myserver rc.nut:    6.070010#011[D2:904992] Path: UPS.PowerConverter.Input.[5].Switchable, Type: Feature, ReportID: 0x3f, Offset: 0, Size: 8, Value: 1
Jul 18 09:51:48 Myserver rc.nut:    6.070018#011[D1:904992] eaton_input_eco_mode_check_range: Entering ECO mode due to input conditions being within the transfer limits.
Jul 18 09:51:48 Myserver rc.nut:    6.070020#011[D5:904992] send_to_all: SETINFO input.eco.switchable "ECO"
Jul 18 09:51:48 Myserver rc.nut:    6.070021#011[D5:904992] send_to_all: SETFLAGS input.eco.switchable RW STRING
Jul 18 09:51:48 Myserver rc.nut:    6.070022#011[D5:904992] send_to_all: SETAUX input.eco.switchable 8
Jul 18 09:51:48 Myserver rc.nut:    6.070026#011[D5:904992] send_to_all: ADDCMD load.off
Jul 18 09:51:48 Myserver rc.nut:    6.070028#011[D5:904992] send_to_all: ADDCMD load.on
Jul 18 09:51:48 Myserver rc.nut:    6.070032#011[D5:904992] send_to_all: ADDCMD shutdown.return
Jul 18 09:51:48 Myserver rc.nut:    6.070033#011[D5:904992] send_to_all: ADDCMD shutdown.stayoff
Jul 18 09:51:48 Myserver rc.nut:    6.070035#011[D5:904992] send_to_all: SETINFO driver.state "init.quiet"
Jul 18 09:51:48 Myserver rc.nut:    6.070036#011[D5:904992] send_to_all: SETINFO driver.version "2.8.3.1"
...
Jul 18 09:51:49 Myserver rc.nut:    6.901776#011[D5:904992] send_to_all: SETINFO experimental.ups.mode.buzzwords "vendor:mge-hid:ECO vendor:default:ECO"

The [D6:906601] minimize_formatting_string: in-escape: assuming a cosmetic formatting char: '.' is now less confusing (not an "unknown char") and quieter (D6 not D1) for string widths. Maybe I should get it even quieter a bit - D7+ levels are rarely used nor requested by docs :)

INSTCMD and SETVAR events (just log excerpts, no analysis); it may have been just 15 minutes, but quite busy ones :)

Jul 18 09:52:26 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling INSTCMD with 2 args
Jul 18 09:52:26 Myserver usbhid-ups[906601]: [D2:906601] entering main_instcmd(bypass.stop, (null)) for [Eaton9E2000i] on socket 5
Jul 18 09:52:26 Myserver usbhid-ups[906601]: [D2:906601] shared main_instcmd() does not handle command bypass.stop, proceeding to driver-specific handler
Jul 18 09:52:26 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::instcmd('bypass.stop', '(null)')
Jul 18 09:52:26 Myserver usbhid-ups[906601]: [D3:906601] instcmd: using Path 'UPS.PowerConverter.Input.[2].SwitchOffControl'
Jul 18 09:52:26 Myserver usbhid-ups[906601]: instcmd: attempting an operation [bypass.stop] [(null) (1.000000)] which may impact power state on [Eaton9E2000i]
Jul 18 09:52:26 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 09:52:26 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 09:52:26 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 09:52:26 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 4f 01
Jul 18 09:52:26 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 09:52:26 Myserver usbhid-ups[906601]: [D3:906601] instcmd: SUCCEED
Jul 18 09:53:29 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling INSTCMD with 2 args
Jul 18 09:53:29 Myserver usbhid-ups[906601]: [D2:906601] entering main_instcmd(bypass.start, (null)) for [Eaton9E2000i] on socket 5
Jul 18 09:53:29 Myserver usbhid-ups[906601]: [D2:906601] shared main_instcmd() does not handle command bypass.start, proceeding to driver-specific handler
Jul 18 09:53:29 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::instcmd('bypass.start', '(null)')
Jul 18 09:53:29 Myserver usbhid-ups[906601]: [D3:906601] instcmd: using Path 'UPS.PowerConverter.Input.[2].SwitchOnControl'
Jul 18 09:53:29 Myserver usbhid-ups[906601]: instcmd: attempting an operation [bypass.start] [(null) (1.000000)] which may impact power state on [Eaton9E2000i]
Jul 18 09:53:29 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 09:53:29 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 09:53:29 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 09:53:29 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 59 01
Jul 18 09:53:29 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 09:53:29 Myserver usbhid-ups[906601]: [D3:906601] instcmd: SUCCEED
Jul 18 09:53:43 Myserver upsd[906713]: Instant command: admin@127.0.0.1 did experimental.ecomode.stop on Eaton9E2000i (tracking ID: disabled)
Jul 18 09:53:43 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling INSTCMD with 2 args
Jul 18 09:53:43 Myserver usbhid-ups[906601]: [D2:906601] entering main_instcmd(experimental.ecomode.stop, (null)) for [Eaton9E2000i] on socket 5
Jul 18 09:53:43 Myserver usbhid-ups[906601]: [D2:906601] shared main_instcmd() does not handle command experimental.ecomode.stop, proceeding to driver-specific handler
Jul 18 09:53:43 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::instcmd('experimental.ecomode.stop', '(null)')
Jul 18 09:53:43 Myserver usbhid-ups[906601]: [D3:906601] instcmd: using Path 'UPS.PowerConverter.Input.[5].Switchable'
Jul 18 09:53:43 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 09:53:43 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 09:53:43 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 09:53:43 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 3f 00
Jul 18 09:53:43 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 09:53:43 Myserver usbhid-ups[906601]: [D3:906601] instcmd: SUCCEED
Jul 18 09:53:50 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling INSTCMD with 2 args
Jul 18 09:53:50 Myserver usbhid-ups[906601]: [D2:906601] entering main_instcmd(experimental.essmode.start, (null)) for [Eaton9E2000i] on socket 5
Jul 18 09:53:50 Myserver usbhid-ups[906601]: [D2:906601] shared main_instcmd() does not handle command experimental.essmode.start, proceeding to driver-specific handler
Jul 18 09:53:50 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::instcmd('experimental.essmode.start', '(null)')
Jul 18 09:53:50 Myserver usbhid-ups[906601]: [D3:906601] instcmd: using Path 'UPS.PowerConverter.Input.[5].Switchable'
Jul 18 09:53:50 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 09:53:50 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 09:53:50 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 09:53:50 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 3f 02
Jul 18 09:53:50 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 09:53:50 Myserver usbhid-ups[906601]: [D3:906601] instcmd: SUCCEED
Jul 18 09:54:16 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling INSTCMD with 2 args
Jul 18 09:54:16 Myserver usbhid-ups[906601]: [D2:906601] entering main_instcmd(experimental.ecomode.stop, (null)) for [Eaton9E2000i] on socket 5
Jul 18 09:54:16 Myserver usbhid-ups[906601]: [D2:906601] shared main_instcmd() does not handle command experimental.ecomode.stop, proceeding to driver-specific handler
Jul 18 09:54:16 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::instcmd('experimental.ecomode.stop', '(null)')
Jul 18 09:54:16 Myserver usbhid-ups[906601]: [D3:906601] instcmd: using Path 'UPS.PowerConverter.Input.[5].Switchable'
Jul 18 09:54:16 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 09:54:16 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 09:54:16 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 09:54:16 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 3f 00
Jul 18 09:54:16 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 09:54:16 Myserver usbhid-ups[906601]: [D3:906601] instcmd: SUCCEED
Jul 18 09:54:20 Myserver upsd[906713]: Instant command: admin@127.0.0.1 did experimental.ecomode.start on Eaton9E2000i (tracking ID: disabled)
Jul 18 09:54:20 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling INSTCMD with 2 args
Jul 18 09:54:20 Myserver usbhid-ups[906601]: [D2:906601] entering main_instcmd(experimental.ecomode.start, (null)) for [Eaton9E2000i] on socket 5
Jul 18 09:54:20 Myserver usbhid-ups[906601]: [D2:906601] shared main_instcmd() does not handle command experimental.ecomode.start, proceeding to driver-specific handler
Jul 18 09:54:20 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::instcmd('experimental.ecomode.start', '(null)')
Jul 18 09:54:20 Myserver usbhid-ups[906601]: [D3:906601] instcmd: using Path 'UPS.PowerConverter.Input.[5].Switchable'
Jul 18 09:54:20 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 09:54:20 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 09:54:20 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 09:54:20 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 3f 01
Jul 18 09:54:20 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 09:54:20 Myserver usbhid-ups[906601]: [D3:906601] instcmd: SUCCEED
Jul 18 09:57:10 Myserver upsd[906713]: Instant command: admin@127.0.0.1 did experimental.bypass.ecomode.stop on Eaton9E2000i (tracking ID: disabled)
Jul 18 09:57:10 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling INSTCMD with 2 args
Jul 18 09:57:10 Myserver usbhid-ups[906601]: [D2:906601] entering main_instcmd(experimental.bypass.ecomode.stop, (null)) for [Eaton9E2000i] on socket 5
Jul 18 09:57:10 Myserver usbhid-ups[906601]: [D2:906601] shared main_instcmd() does not handle command experimental.bypass.ecomode.stop, proceeding to driver-specific handler
Jul 18 09:57:10 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::instcmd('experimental.bypass.ecomode.stop', '(null)')
Jul 18 09:57:10 Myserver usbhid-ups[906601]: [D3:906601] instcmd: using Path 'UPS.PowerConverter.Input.[5].Switchable'
Jul 18 09:57:10 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::setvar('input.bypass.switch.off', 'off')
Jul 18 09:57:10 Myserver usbhid-ups[906601]: [D5:906601] hu_find_valinfo: found off (value: 1)
Jul 18 09:57:10 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 09:57:10 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 09:57:10 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 4f 01
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D5:906601] setvar: SUCCEED
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::setvar('input.eco.switchable', 'normal')
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D5:906601] hu_find_valinfo: found 0 (value: 'normal')
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 3f 00
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D5:906601] setvar: SUCCEED
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D1:906601] eaton_input_eco_mode_auto_on_off_nuf: ECO Mode was disabled after switching from Bypass Mode
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D5:906601] hu_find_valinfo: found 0 (value: '0')
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 3f 00
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 09:57:11 Myserver usbhid-ups[906601]: [D3:906601] instcmd: SUCCEED
Jul 18 09:58:05 Myserver upsd[906713]: Instant command: admin@127.0.0.1 did experimental.bypass.ecomode.start on Eaton9E2000i (tracking ID: disabled)
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling INSTCMD with 2 args
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D2:906601] entering main_instcmd(experimental.bypass.ecomode.start, (null)) for [Eaton9E2000i] on socket 5
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D2:906601] shared main_instcmd() does not handle command experimental.bypass.ecomode.start, proceeding to driver-specific handler
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::instcmd('experimental.bypass.ecomode.start', '(null)')
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D3:906601] instcmd: using Path 'UPS.PowerConverter.Input.[5].Switchable'
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D1:906601] eaton_input_bypass_check_range: Entering Bypass mode due to input conditions being within the transfer limits.
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D1:906601] eaton_input_eco_mode_auto_on_off_nuf: ECO switch state is: ECO , must be normal before switching to ECO
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D5:906601] hu_find_valinfo: found 0 (value: '1')
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 3f 00
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 09:58:05 Myserver usbhid-ups[906601]: [D3:906601] instcmd: SUCCEED
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D6:906601] send_to_all: write 29 bytes to socket 5 succeeded (ret=29): SETINFO driver.state "quiet"
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling SET with 5 args
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D3:906601] sock_arg: TRACKING = 2DDC5036-F665-4D29-BE4C-0374D091D263
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D2:906601] entering main_setvar(input.bypass.switch.on, on) for [Eaton9E2000i] on socket 5
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D2:906601] shared main_setvar() does not handle variable input.bypass.switch.on, proceeding to driver-specific handler
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::setvar('input.bypass.switch.on', 'on')
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D5:906601] hu_find_valinfo: found on (value: 1)
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 59 01
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D5:906601] setvar: SUCCEED
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D2:906601] send_to_one: sending TRACKING 2DDC5036-F665-4D29-BE4C-0374D091D263 0
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D5:906601] send_to_one: TRACKING 2DDC5036-F665-4D29-BE4C-0374D091D263 0
Jul 18 09:58:52 Myserver usbhid-ups[906601]: [D6:906601] send_to_one: write 48 bytes to socket 5 succeeded (ret=48): TRACKING 2DDC5036-F665-4D29-BE4C-0374D091D263 0
Jul 18 09:58:52 Myserver upsd[906713]: tracking ID: 2DDC5036-F665-4D29-BE4C-0374D091D263#011result: SUCCESS
Jul 18 09:58:53 Myserver usbhid-ups[906601]: [D5:906601] send_to_all: SETINFO driver.state "updateinfo"
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling SET with 5 args
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D3:906601] sock_arg: TRACKING = 98C489FD-821C-4132-9D93-4F6590B55E63
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D2:906601] entering main_setvar(input.bypass.switch.off, off) for [Eaton9E2000i] on socket 5
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D2:906601] shared main_setvar() does not handle variable input.bypass.switch.off, proceeding to driver-specific handler
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::setvar('input.bypass.switch.off', 'off')
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D5:906601] hu_find_valinfo: found off (value: 1)
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 4f 01
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D5:906601] setvar: SUCCEED
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D2:906601] send_to_one: sending TRACKING 98C489FD-821C-4132-9D93-4F6590B55E63 0
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D5:906601] send_to_one: TRACKING 98C489FD-821C-4132-9D93-4F6590B55E63 0
Jul 18 09:59:00 Myserver usbhid-ups[906601]: [D6:906601] send_to_one: write 48 bytes to socket 5 succeeded (ret=48): TRACKING 98C489FD-821C-4132-9D93-4F6590B55E63 0
Jul 18 09:59:00 Myserver upsd[906713]: tracking ID: 98C489FD-821C-4132-9D93-4F6590B55E63#011result: SUCCESS
Jul 18 10:01:57 Myserver upsd[906713]: Set variable: admin@127.0.0.1 set input.bypass.switch.on on Eaton9E2000i to on (tracking ID: 59DF2263-3F15-4601-8786-9C36E1900437)
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling SET with 5 args
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D3:906601] sock_arg: TRACKING = 59DF2263-3F15-4601-8786-9C36E1900437
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D2:906601] entering main_setvar(input.bypass.switch.on, on) for [Eaton9E2000i] on socket 5
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D2:906601] shared main_setvar() does not handle variable input.bypass.switch.on, proceeding to driver-specific handler
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::setvar('input.bypass.switch.on', 'on')
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D5:906601] hu_find_valinfo: found on (value: 1)
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 59 01
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D5:906601] setvar: SUCCEED
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D2:906601] send_to_one: sending TRACKING 59DF2263-3F15-4601-8786-9C36E1900437 0
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D5:906601] send_to_one: TRACKING 59DF2263-3F15-4601-8786-9C36E1900437 0
Jul 18 10:01:57 Myserver usbhid-ups[906601]: [D6:906601] send_to_one: write 48 bytes to socket 5 succeeded (ret=48): TRACKING 59DF2263-3F15-4601-8786-9C36E1900437 0
Jul 18 10:01:57 Myserver upsd[906713]: tracking ID: 59DF2263-3F15-4601-8786-9C36E1900437#011result: SUCCESS
Jul 18 10:02:47 Myserver upsd[906713]: Set variable: admin@127.0.0.1 set input.bypass.switch.off on Eaton9E2000i to off (tracking ID: 1C41F5E4-24B7-4110-8D1F-821741A49CA4)
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling SET with 5 args
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D3:906601] sock_arg: TRACKING = 1C41F5E4-24B7-4110-8D1F-821741A49CA4
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D2:906601] entering main_setvar(input.bypass.switch.off, off) for [Eaton9E2000i] on socket 5
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D2:906601] shared main_setvar() does not handle variable input.bypass.switch.off, proceeding to driver-specific handler
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::setvar('input.bypass.switch.off', 'off')
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D5:906601] hu_find_valinfo: found off (value: 1)
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 4f 01
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D5:906601] setvar: SUCCEED
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D2:906601] send_to_one: sending TRACKING 1C41F5E4-24B7-4110-8D1F-821741A49CA4 0
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D5:906601] send_to_one: TRACKING 1C41F5E4-24B7-4110-8D1F-821741A49CA4 0
Jul 18 10:02:47 Myserver usbhid-ups[906601]: [D6:906601] send_to_one: write 48 bytes to socket 5 succeeded (ret=48): TRACKING 1C41F5E4-24B7-4110-8D1F-821741A49CA4 0
Jul 18 10:02:47 Myserver upsd[906713]: tracking ID: 1C41F5E4-24B7-4110-8D1F-821741A49CA4#011result: SUCCESS
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling SET with 5 args
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D3:906601] sock_arg: TRACKING = F4F78A1F-D59B-4F21-82C6-9729871FA9DC
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D2:906601] entering main_setvar(input.eco.switchable, normal) for [Eaton9E2000i] on socket 5
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D2:906601] shared main_setvar() does not handle variable input.eco.switchable, proceeding to driver-specific handler
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::setvar('input.eco.switchable', 'normal')
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D5:906601] hu_find_valinfo: found 0 (value: 'normal')
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 3f 00
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D5:906601] setvar: SUCCEED
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D2:906601] send_to_one: sending TRACKING F4F78A1F-D59B-4F21-82C6-9729871FA9DC 0
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D5:906601] send_to_one: TRACKING F4F78A1F-D59B-4F21-82C6-9729871FA9DC 0
Jul 18 10:02:52 Myserver usbhid-ups[906601]: [D6:906601] send_to_one: write 48 bytes to socket 5 succeeded (ret=48): TRACKING F4F78A1F-D59B-4F21-82C6-9729871FA9DC 0
Jul 18 10:02:52 Myserver upsd[906713]: tracking ID: F4F78A1F-D59B-4F21-82C6-9729871FA9DC#011result: SUCCESS
Jul 18 10:04:11 Myserver upsd[906713]: Set variable: admin@127.0.0.1 set input.eco.switchable on Eaton9E2000i to ECO (tracking ID: AB88AFE5-7E9E-4BEA-8033-8F712A3B5572)
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D6:906601] sock_arg: Driver on /var/run/nut/usbhid-ups-Eaton9E2000i is now handling SET with 5 args
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D3:906601] sock_arg: TRACKING = AB88AFE5-7E9E-4BEA-8033-8F712A3B5572
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D2:906601] entering main_setvar(input.eco.switchable, ECO) for [Eaton9E2000i] on socket 5
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D2:906601] shared main_setvar() does not handle variable input.eco.switchable, proceeding to driver-specific handler
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D1:906601] Starting usbhid-ups.c::setvar('input.eco.switchable', 'ECO')
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D5:906601] hu_find_valinfo: found 1 (value: 'ECO')
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D5:906601] Unit = 00000000, UnitExp = 0
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D5:906601] Exponent = 0
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D5:906601] PhyMax = 0, PhyMin = 0, LogMax = 255, LogMin = 0
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D3:906601] Report[set]: (2 bytes) => 3f 01
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D4:906601] Set report succeeded
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D5:906601] setvar: SUCCEED
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D2:906601] send_to_one: sending TRACKING AB88AFE5-7E9E-4BEA-8033-8F712A3B5572 0
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D5:906601] send_to_one: TRACKING AB88AFE5-7E9E-4BEA-8033-8F712A3B5572 0
Jul 18 10:04:11 Myserver usbhid-ups[906601]: [D6:906601] send_to_one: write 48 bytes to socket 5 succeeded (ret=48): TRACKING AB88AFE5-7E9E-4BEA-8033-8F712A3B5572 0
Jul 18 10:04:11 Myserver upsd[906713]: tracking ID: AB88AFE5-7E9E-4BEA-8033-8F712A3B5572#011result: SUCCESS

@masterwishx
Copy link
Copy Markdown
Contributor Author

masterwishx commented Jul 18, 2025

Whether this was intended to be supported or not, having devices in the field that can in fact be somewhat bricked by accepting some command sequence is anyhow a bug to fix, right?

Forgot to mention that ups LCD physical display has ECO mode (number 8) also by documentation , so it mean to be supported?!

image

@masterwishx
Copy link
Copy Markdown
Contributor Author

20250718_123108

@masterwishx
Copy link
Copy Markdown
Contributor Author

INSTCMD and SETVAR events (just log excerpts, no analysis); it may have been just 15 minutes, but quite busy ones :)

It's looks OK I think, just tested with cmd/variables
one cmd/var after another.

If needs more time to log next time let me know...

@jimklimov
Copy link
Copy Markdown
Member

@masterwishx @ZivertX : the PR looks OK to me code-wise (and by reasonable not-noisy behavior); but you are judges if it is actually good functionally regarding ECO/bypass/ESS/normal reporting and enablement :)

@masterwishx
Copy link
Copy Markdown
Contributor Author

BTW, CCing @arnaudquette-eaton : can you please check if the issue is known/addressed internally?

Whether this was intended to be supported or not, having devices in the field that can in fact be somewhat bricked by accepting some command sequence is anyhow a bug to fix, right?

@arnaudquette-eaton as we know that you retired from your child(nut), your help in adding rest unknown variables and bypass/ecomode was invaluable.

If you will find time to answer at least once/twice in one year will be great to continue help with Eaton driver in situations where no one else can contribute and help with it. :)

@masterwishx
Copy link
Copy Markdown
Contributor Author

@masterwishx @ZivertX : the PR looks OK to me code-wise (and by reasonable not-noisy behavior); but you are judges if it is actually good functionally regarding ECO/bypass/ESS/normal reporting and enablement :)

To me also looks good:

  • every hu_find_valinfo =found...
  • every cmd/set var = OK/Success

Unfortunately @ZivertX seems don't have time now
to test, but if he will find time to test will be cool.

Also will try to ask in Unraid plugin forum someone to test who has 9sx.

(ESS = only two enterprise ups units has it, not sure they use NUT :))

Any way can be merged for now I think.

@jimklimov jimklimov merged commit eecb8d3 into networkupstools:master Jul 18, 2025
30 checks passed
@masterwishx masterwishx deleted the ECOmode-auto-addon2-todo branch July 18, 2025 16:57
@masterwishx
Copy link
Copy Markdown
Contributor Author

BTW, CCing @arnaudquette-eaton : can you please check if the issue is known/addressed internally?

Whether this was intended to be supported or not, having devices in the field that can in fact be somewhat bricked by accepting some command sequence is anyhow a bug to fix, right?

Not sure we will get the answer here but for the future info better that pr will be open until then or no matter if merged?

Have opened isuue just in case:

#2719

jimklimov added a commit to jimklimov/nut that referenced this pull request Jul 18, 2025
…tic" chars at level 7 [networkupstools#2956]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Eaton ECO/ESS/HE/ABM modes Non-trivial power supply management modes (ECO, ESS, HE, ABM etc.) enhancement need testing Code looks reasonable, but the feature would better be tested against hardware or OSes NUT protocols USB

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants