Skip to content

Add optional EcoFlow CDC telemetry to usbhid-ups - #3569

Open
user01010111 wants to merge 7 commits into
networkupstools:masterfrom
user01010111:feature/ecoflow-cdc-telemetry
Open

Add optional EcoFlow CDC telemetry to usbhid-ups#3569
user01010111 wants to merge 7 commits into
networkupstools:masterfrom
user01010111:feature/ecoflow-cdc-telemetry

Conversation

@user01010111

Copy link
Copy Markdown

Summary

  • Add optional lifecycle hooks for HID subdrivers which need a companion transport.
  • Add a read-only EcoFlow CDC ACM companion selected with ecoflow_cdc_port.
  • Expose standard power, load, frequency, temperature, capacity and outlet readings through existing NUT names.
  • Keep EcoFlow-specific readings under experimental.ecoflow.*.
  • Document the configuration and add captured-frame protocol tests.

Rationale

The EcoFlow RIVER 3 Plus HID interface provides the data needed for UPS monitoring and shutdown, but it does not provide live power and temperature telemetry. The same USB device exposes richer read-only data through a CDC ACM interface.

This change keeps HID authoritative and enriches the same NUT device instead of creating a second partial UPS. CDC support is opt-in. A missing or failed CDC connection reconnects independently and never marks the HID data stale.

The protocol framing and field work builds on the public r3pcomms project and was independently verified against a RIVER 3 Plus.

Related to #2735.

Safety

  • Only the known telemetry request is implemented.
  • No device-control commands are present.
  • Response preamble, declared length, CRC and sequence number are validated.
  • Malformed segments are rejected.
  • CDC failures are rate-limited and isolated from HID state.
  • The feature does nothing unless ecoflow_cdc_port is configured.

Testing

  • make -j2 check: 7 passed, 0 failed.
  • Protocol test with a captured, serial-redacted response.
  • AddressSanitizer and UndefinedBehaviorSanitizer protocol test.
  • usbhid-ups build with serial support enabled.
  • usbhid-ups build with serial support disabled.
  • Live RIVER 3 Plus test: HID status, charge and runtime remained present while CDC added power, load, frequency, temperature, capacity and outlet data.
  • Live missing-port test: CDC reported reconnect.trying while HID remained responsive and continued reporting status, charge and runtime.

Contributor note

I used an AI coding assistant during implementation. I reviewed the resulting changes and validated them with the tests and hardware checks listed above.

The commit includes the required DCO sign-off.

Signed-off-by: user01010111 <lapses.50.booster@icloud.com>
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown

A ZIP file with standard source tarball and another tarball with pre-built docs for commit 73bbd12 is temporarily available: NUT-tarballs-PR-3569.zip.

@AppVeyorBot

Copy link
Copy Markdown

@AppVeyorBot

Copy link
Copy Markdown

Build nut 2.8.5.5051-master failed (commit 637bf29682 by @)

user01010111 added 2 commits August 13, 2026 18:06
Signed-off-by: user01010111 <lapses.50.booster@icloud.com>
Signed-off-by: user01010111 <lapses.50.booster@icloud.com>
@AppVeyorBot

Copy link
Copy Markdown

Signed-off-by: user01010111 <lapses.50.booster@icloud.com>
@AppVeyorBot

Copy link
Copy Markdown

@AppVeyorBot

Copy link
Copy Markdown

Build nut 2.8.5.5054-master completed (commit 6506ebb503 by @)

@AppVeyorBot

Copy link
Copy Markdown

Build nut 2.8.5.5054-master completed (commit 6506ebb503 by @)

@jimklimov jimklimov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Quite solid, thanks. Commented on a couple of stylistic nits, but neither is something that requires an immediate code change - more as hints for future contributions.

Comment thread tests/ecoflow_cdc_protocol_utest.c
Comment thread drivers/usbhid-ups.c
@jimklimov jimklimov added enhancement USB serial port EcoFlow Issues and PRs about EcoFlow River 3, Delta 3 UPS series AI For good or bad, machine tools are upon us. Humans are still the responsible ones. labels Aug 13, 2026
@jimklimov jimklimov added this to the 2.8.6 milestone Aug 13, 2026

@jimklimov jimklimov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ah, my earlier review missed an aspect that does need a change: bump driver versions (usbhid-ups.c itself, and the *-hid.c subdrivers, due to structure format change), at least if nothing else bumped them since v2.8.5 release.

I wonder also if ecoflow-cdc{,-protocol}.{c,h} might stand as a driver code base on its own merit, or is strictly meant to be part of usbhid-ups? Maybe introducing a structured naming for the new aux tweaks should be useful (e.g. we have ecoflow-hid for usbhid-ups, so AUX tweaks could be ecoflow-hid-aux-something - WDYT?)

@user01010111

Copy link
Copy Markdown
Author

Thanks for the review. I’ve updated the branch to bump usbhid-ups and all HID subdriver versions, rename the runtime companion to ecoflow-hid-aux-cdc, and use f_equal() for the exact floating-point test comparisons.

I retained ecoflow-cdc-protocol because it is the transport-independent parser, and kept the existing configuration and state names for compatibility. The updated code passes the Clang warning check, unit tests, serial and non-serial builds, and distribution checks locally.

Signed-off-by: user01010111 <lapses.50.booster@icloud.com>
@user01010111
user01010111 force-pushed the feature/ecoflow-cdc-telemetry branch from eb4e00f to 55bf78d Compare August 13, 2026 11:30
@user01010111
user01010111 marked this pull request as ready for review August 13, 2026 11:41
@AppVeyorBot

Copy link
Copy Markdown

Build nut 2.8.5.5057-master completed (commit d83200915e by @)

@AppVeyorBot

Copy link
Copy Markdown

Build nut 2.8.5.5058-master completed (commit adc52e30d2 by @)

@user01010111
user01010111 requested a review from jimklimov August 14, 2026 04:53
Signed-off-by: user01010111 <lapses.50.booster@icloud.com>
@AppVeyorBot

Copy link
Copy Markdown

Build nut 2.8.5.5060-master completed (commit 5971854a5d by @)

@jimklimov jimklimov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the update :)

jimklimov added a commit to jimklimov/nut that referenced this pull request Aug 14, 2026
jimklimov added a commit to jimklimov/nut that referenced this pull request Aug 14, 2026
@jimklimov

jimklimov commented Aug 16, 2026

Copy link
Copy Markdown
Member

Collected complaints from multi-platform CI:

  • On illumos (OmniOS and OpenIndiana):
ecoflow-cdc-protocol.c: In function 'parse_segment':
ecoflow-cdc-protocol.c:124:29: error: implicit declaration of function 'isfinite' [-Werror=implicit-function-declaration]
  124 |                         if (isfinite(value)) { \
      |                             ^~~~~~~~
ecoflow-cdc-protocol.c:130:9: note: in expansion of macro 'ECOFLOW_PARSE_FLOAT'
  130 |         ECOFLOW_PARSE_FLOAT(7, output_power, 0);
      |         ^~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
  • On FreeBSD (primarily gotta find where that comes from and do stuff differently; as fallback maybe check in configure.ac the usability of said _Generic presence in impacted OS headers and usability for the current build, and if it is present but not usable - define as an empty macro?):
ecoflow-cdc-protocol.c:130:2: error: '_Generic' is incompatible with C standards before C11 [-Werror,-Wpre-c11-compat]
  130 |         ECOFLOW_PARSE_FLOAT(7, output_power, 0);
      |         ^
ecoflow-cdc-protocol.c:124:8: note: expanded from macro 'ECOFLOW_PARSE_FLOAT'
  124 |                         if (isfinite(value)) { \
      |                             ^
/usr/include/math.h:94:21: note: expanded from macro 'isfinite'
   94 | #define isfinite(x) __fp_type_select(x, __isfinitef, __isfinite, __isfinitel)
      |                     ^
/usr/include/math.h:74:53: note: expanded from macro '__fp_type_select'
   74 | #define __fp_type_select(x, f, d, ld) __extension__ _Generic((x),       \
      |                                                     ^
ecoflow-cdc-protocol.c:131:2: error: '_Generic' is incompatible with C standards before C11 [-Werror,-Wpre-c11-compat]
  131 |         ECOFLOW_PARSE_FLOAT(8, input_power, 0);
      |         ^
ecoflow-cdc-protocol.c:124:8: note: expanded from macro 'ECOFLOW_PARSE_FLOAT'
  124 |                         if (isfinite(value)) { \
      |                             ^
/usr/include/math.h:94:21: note: expanded from macro 'isfinite'
   94 | #define isfinite(x) __fp_type_select(x, __isfinitef, __isfinite, __isfinitel)
      |                     ^
/usr/include/math.h:74:53: note: expanded from macro '__fp_type_select'
   74 | #define __fp_type_select(x, f, d, ld) __extension__ _Generic((x),       \
      |                                                     ^
ecoflow-cdc-protocol.c:132:2: error: '_Generic' is incompatible with C standards before C11 [-Werror,-Wpre-c11-compat]
  132 |         ECOFLOW_PARSE_FLOAT(9, ac_input_power, 0);
      |         ^
ecoflow-cdc-protocol.c:124:8: note: expanded from macro 'ECOFLOW_PARSE_FLOAT'
  124 |                         if (isfinite(value)) { \
      |                             ^
/usr/include/math.h:94:21: note: expanded from macro 'isfinite'
   94 | #define isfinite(x) __fp_type_select(x, __isfinitef, __isfinite, __isfinitel)
      |                     ^
/usr/include/math.h:74:53: note: expanded from macro '__fp_type_select'
   74 | #define __fp_type_select(x, f, d, ld) __extension__ _Generic((x),       \
      |                                                     ^
ecoflow-cdc-protocol.c:133:2: error: '_Generic' is incompatible with C standards before C11 [-Werror,-Wpre-c11-compat]
  133 |         ECOFLOW_PARSE_FLOAT(11, ac_input_voltage, 0);
      |         ^
ecoflow-cdc-protocol.c:124:8: note: expanded from macro 'ECOFLOW_PARSE_FLOAT'
  124 |                         if (isfinite(value)) { \
      |                             ^
/usr/include/math.h:94:21: note: expanded from macro 'isfinite'
   94 | #define isfinite(x) __fp_type_select(x, __isfinitef, __isfinite, __isfinitel)
      |                     ^
/usr/include/math.h:74:53: note: expanded from macro '__fp_type_select'
   74 | #define __fp_type_select(x, f, d, ld) __extension__ _Generic((x),       \
      |                                                     ^
ecoflow-cdc-protocol.c:134:2: error: '_Generic' is incompatible with C standards before C11 [-Werror,-Wpre-c11-compat]
  134 |         ECOFLOW_PARSE_FLOAT(12, solar_input_power, 0);
      |         ^
ecoflow-cdc-protocol.c:124:8: note: expanded from macro 'ECOFLOW_PARSE_FLOAT'
  124 |                         if (isfinite(value)) { \
      |                             ^
/usr/include/math.h:94:21: note: expanded from macro 'isfinite'
   94 | #define isfinite(x) __fp_type_select(x, __isfinitef, __isfinite, __isfinitel)
      |                     ^
/usr/include/math.h:74:53: note: expanded from macro '__fp_type_select'
   74 | #define __fp_type_select(x, f, d, ld) __extension__ _Generic((x),       \
      |                                                     ^
ecoflow-cdc-protocol.c:135:2: error: '_Generic' is incompatible with C standards before C11 [-Werror,-Wpre-c11-compat]
  135 |         ECOFLOW_PARSE_FLOAT(14, ac_output_power, 1);
      |         ^
ecoflow-cdc-protocol.c:124:8: note: expanded from macro 'ECOFLOW_PARSE_FLOAT'
  124 |                         if (isfinite(value)) { \
      |                             ^
/usr/include/math.h:94:21: note: expanded from macro 'isfinite'
   94 | #define isfinite(x) __fp_type_select(x, __isfinitef, __isfinite, __isfinitel)
      |                     ^
/usr/include/math.h:74:53: note: expanded from macro '__fp_type_select'
   74 | #define __fp_type_select(x, f, d, ld) __extension__ _Generic((x),       \
      |                                                     ^
ecoflow-cdc-protocol.c:136:2: error: '_Generic' is incompatible with C standards before C11 [-Werror,-Wpre-c11-compat]
  136 |         ECOFLOW_PARSE_FLOAT(16, dc_output_power, 1);
      |         ^
ecoflow-cdc-protocol.c:124:8: note: expanded from macro 'ECOFLOW_PARSE_FLOAT'
  124 |                         if (isfinite(value)) { \
      |                             ^
/usr/include/math.h:94:21: note: expanded from macro 'isfinite'
   94 | #define isfinite(x) __fp_type_select(x, __isfinitef, __isfinite, __isfinitel)
      |                     ^
/usr/include/math.h:74:53: note: expanded from macro '__fp_type_select'
   74 | #define __fp_type_select(x, f, d, ld) __extension__ _Generic((x),       \
      |                                                     ^
ecoflow-cdc-protocol.c:137:2: error: '_Generic' is incompatible with C standards before C11 [-Werror,-Wpre-c11-compat]
  137 |         ECOFLOW_PARSE_FLOAT(17, usb_a_output_power, 1);
      |         ^
ecoflow-cdc-protocol.c:124:8: note: expanded from macro 'ECOFLOW_PARSE_FLOAT'
  124 |                         if (isfinite(value)) { \
      |                             ^
/usr/include/math.h:94:21: note: expanded from macro 'isfinite'
   94 | #define isfinite(x) __fp_type_select(x, __isfinitef, __isfinite, __isfinitel)
      |                     ^
/usr/include/math.h:74:53: note: expanded from macro '__fp_type_select'
   74 | #define __fp_type_select(x, f, d, ld) __extension__ _Generic((x),       \
      |                                                     ^
ecoflow-cdc-protocol.c:138:2: error: '_Generic' is incompatible with C standards before C11 [-Werror,-Wpre-c11-compat]
  138 |         ECOFLOW_PARSE_FLOAT(18, usb_c_output_power, 1);
      |         ^
ecoflow-cdc-protocol.c:124:8: note: expanded from macro 'ECOFLOW_PARSE_FLOAT'
  124 |                         if (isfinite(value)) { \
      |                             ^
/usr/include/math.h:94:21: note: expanded from macro 'isfinite'
   94 | #define isfinite(x) __fp_type_select(x, __isfinitef, __isfinite, __isfinitel)
      |                     ^
/usr/include/math.h:74:53: note: expanded from macro '__fp_type_select'
   74 | #define __fp_type_select(x, f, d, ld) __extension__ _Generic((x),       \
      |                                                     ^
ecoflow-cdc-protocol.c:139:2: error: '_Generic' is incompatible with C standards before C11 [-Werror,-Wpre-c11-compat]
  139 |         ECOFLOW_PARSE_FLOAT(20, extra_battery_input_power, 0);
      |         ^
ecoflow-cdc-protocol.c:124:8: note: expanded from macro 'ECOFLOW_PARSE_FLOAT'
  124 |                         if (isfinite(value)) { \
      |                             ^
/usr/include/math.h:94:21: note: expanded from macro 'isfinite'
   94 | #define isfinite(x) __fp_type_select(x, __isfinitef, __isfinite, __isfinitel)
      |                     ^
/usr/include/math.h:74:53: note: expanded from macro '__fp_type_select'
   74 | #define __fp_type_select(x, f, d, ld) __extension__ _Generic((x),       \
      |                                                     ^
ecoflow-cdc-protocol.c:140:2: error: '_Generic' is incompatible with C standards before C11 [-Werror,-Wpre-c11-compat]
  140 |         ECOFLOW_PARSE_FLOAT(21, extra_battery_output_power, 1);
      |         ^
ecoflow-cdc-protocol.c:124:8: note: expanded from macro 'ECOFLOW_PARSE_FLOAT'
  124 |                         if (isfinite(value)) { \
      |                             ^
/usr/include/math.h:94:21: note: expanded from macro 'isfinite'
   94 | #define isfinite(x) __fp_type_select(x, __isfinitef, __isfinite, __isfinitel)
      |                     ^
/usr/include/math.h:74:53: note: expanded from macro '__fp_type_select'
   74 | #define __fp_type_select(x, f, d, ld) __extension__ _Generic((x),       \
      |                                                     ^
11 errors generated.
*** Error code 1 (continuing)
  • On Ubuntu Trusty (likely a problem with system headers - macros/inlines optimization, to be fixed by quiescing pragmas like we have elsewhere):
ecoflow-cdc-protocol.c:140:299: error: will never be executed [-Werror,-Wunreachable-code]
 case 21: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_extra_battery_output_power = 1; metrics->extra_battery_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                                                                                                                                                                                                          ^~~~~
ecoflow-cdc-protocol.c:140:119: error: will never be executed [-Werror,-Wunreachable-code]
 case 21: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_extra_battery_output_power = 1; metrics->extra_battery_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                      ^~~~~~~~~~~~~~
ecoflow-cdc-protocol.c:140:155: error: will never be executed [-Werror,-Wunreachable-code]
 case 21: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_extra_battery_output_power = 1; metrics->extra_battery_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                                                          ^~~~~~~~
ecoflow-cdc-protocol.c:139:283: error: will never be executed [-Werror,-Wunreachable-code]
 case 20: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_extra_battery_input_power = 1; metrics->extra_battery_input_power = (0) ? fabs(value) : value; } } break;
                                                                                                                                                                                                                                                                                          ^~~~
ecoflow-cdc-protocol.c:139:119: error: will never be executed [-Werror,-Wunreachable-code]
 case 20: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_extra_battery_input_power = 1; metrics->extra_battery_input_power = (0) ? fabs(value) : value; } } break;
                                                                                                                      ^~~~~~~~~~~~~~
ecoflow-cdc-protocol.c:139:155: error: will never be executed [-Werror,-Wunreachable-code]
 case 20: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_extra_battery_input_power = 1; metrics->extra_battery_input_power = (0) ? fabs(value) : value; } } break;
                                                                                                                                                          ^~~~~~~~
ecoflow-cdc-protocol.c:138:283: error: will never be executed [-Werror,-Wunreachable-code]
 case 18: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_usb_c_output_power = 1; metrics->usb_c_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                                                                                                                                                                                          ^~~~~
ecoflow-cdc-protocol.c:138:119: error: will never be executed [-Werror,-Wunreachable-code]
 case 18: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_usb_c_output_power = 1; metrics->usb_c_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                      ^~~~~~~~~~~~~~
ecoflow-cdc-protocol.c:138:155: error: will never be executed [-Werror,-Wunreachable-code]
 case 18: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_usb_c_output_power = 1; metrics->usb_c_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                                                          ^~~~~~~~
ecoflow-cdc-protocol.c:137:283: error: will never be executed [-Werror,-Wunreachable-code]
 case 17: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_usb_a_output_power = 1; metrics->usb_a_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                                                                                                                                                                                          ^~~~~
ecoflow-cdc-protocol.c:137:119: error: will never be executed [-Werror,-Wunreachable-code]
 case 17: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_usb_a_output_power = 1; metrics->usb_a_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                      ^~~~~~~~~~~~~~
ecoflow-cdc-protocol.c:137:155: error: will never be executed [-Werror,-Wunreachable-code]
 case 17: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_usb_a_output_power = 1; metrics->usb_a_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                                                          ^~~~~~~~
ecoflow-cdc-protocol.c:136:277: error: will never be executed [-Werror,-Wunreachable-code]
 case 16: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_dc_output_power = 1; metrics->dc_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                                                                                                                                                                                    ^~~~~
ecoflow-cdc-protocol.c:136:119: error: will never be executed [-Werror,-Wunreachable-code]
 case 16: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_dc_output_power = 1; metrics->dc_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                      ^~~~~~~~~~~~~~
ecoflow-cdc-protocol.c:136:155: error: will never be executed [-Werror,-Wunreachable-code]
 case 16: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_dc_output_power = 1; metrics->dc_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                                                          ^~~~~~~~
ecoflow-cdc-protocol.c:135:277: error: will never be executed [-Werror,-Wunreachable-code]
 case 14: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_ac_output_power = 1; metrics->ac_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                                                                                                                                                                                    ^~~~~
ecoflow-cdc-protocol.c:135:119: error: will never be executed [-Werror,-Wunreachable-code]
 case 14: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_ac_output_power = 1; metrics->ac_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                      ^~~~~~~~~~~~~~
ecoflow-cdc-protocol.c:135:155: error: will never be executed [-Werror,-Wunreachable-code]
 case 14: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_ac_output_power = 1; metrics->ac_output_power = (1) ? fabs(value) : value; } } break;
                                                                                                                                                          ^~~~~~~~
ecoflow-cdc-protocol.c:134:267: error: will never be executed [-Werror,-Wunreachable-code]
 case 12: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_solar_input_power = 1; metrics->solar_input_power = (0) ? fabs(value) : value; } } break;
                                                                                                                                                                                                                                                                          ^~~~
ecoflow-cdc-protocol.c:134:119: error: will never be executed [-Werror,-Wunreachable-code]
 case 12: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_solar_input_power = 1; metrics->solar_input_power = (0) ? fabs(value) : value; } } break;
                                                                                                                      ^~~~~~~~~~~~~~
ecoflow-cdc-protocol.c:134:155: error: will never be executed [-Werror,-Wunreachable-code]
 case 12: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_solar_input_power = 1; metrics->solar_input_power = (0) ? fabs(value) : value; } } break;
                                                                                                                                                          ^~~~~~~~
ecoflow-cdc-protocol.c:133:265: error: will never be executed [-Werror,-Wunreachable-code]
 case 11: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_ac_input_voltage = 1; metrics->ac_input_voltage = (0) ? fabs(value) : value; } } break;
                                                                                                                                                                                                                                                                        ^~~~
ecoflow-cdc-protocol.c:133:119: error: will never be executed [-Werror,-Wunreachable-code]
 case 11: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_ac_input_voltage = 1; metrics->ac_input_voltage = (0) ? fabs(value) : value; } } break;
                                                                                                                      ^~~~~~~~~~~~~~
ecoflow-cdc-protocol.c:133:155: error: will never be executed [-Werror,-Wunreachable-code]
 case 11: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_ac_input_voltage = 1; metrics->ac_input_voltage = (0) ? fabs(value) : value; } } break;
                                                                                                                                                          ^~~~~~~~
ecoflow-cdc-protocol.c:132:260: error: will never be executed [-Werror,-Wunreachable-code]
 case 9: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_ac_input_power = 1; metrics->ac_input_power = (0) ? fabs(value) : value; } } break;
                                                                                                                                                                                                                                                                   ^~~~
ecoflow-cdc-protocol.c:132:118: error: will never be executed [-Werror,-Wunreachable-code]
 case 9: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_ac_input_power = 1; metrics->ac_input_power = (0) ? fabs(value) : value; } } break;
                                                                                                                     ^~~~~~~~~~~~~~
ecoflow-cdc-protocol.c:132:154: error: will never be executed [-Werror,-Wunreachable-code]
 case 9: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_ac_input_power = 1; metrics->ac_input_power = (0) ? fabs(value) : value; } } break;
                                                                                                                                                         ^~~~~~~~
ecoflow-cdc-protocol.c:131:254: error: will never be executed [-Werror,-Wunreachable-code]
 case 8: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_input_power = 1; metrics->input_power = (0) ? fabs(value) : value; } } break;
                                                                                                                                                                                                                                                             ^~~~
ecoflow-cdc-protocol.c:131:118: error: will never be executed [-Werror,-Wunreachable-code]
 case 8: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_input_power = 1; metrics->input_power = (0) ? fabs(value) : value; } } break;
                                                                                                                     ^~~~~~~~~~~~~~
ecoflow-cdc-protocol.c:131:154: error: will never be executed [-Werror,-Wunreachable-code]
 case 8: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_input_power = 1; metrics->input_power = (0) ? fabs(value) : value; } } break;
                                                                                                                                                         ^~~~~~~~
ecoflow-cdc-protocol.c:130:256: error: will never be executed [-Werror,-Wunreachable-code]
 case 7: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_output_power = 1; metrics->output_power = (0) ? fabs(value) : value; } } break;
                                                                                                                                                                                                                                                               ^~~~
ecoflow-cdc-protocol.c:130:118: error: will never be executed [-Werror,-Wunreachable-code]
 case 7: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_output_power = 1; metrics->output_power = (0) ? fabs(value) : value; } } break;
                                                                                                                     ^~~~~~~~~~~~~~
ecoflow-cdc-protocol.c:130:154: error: will never be executed [-Werror,-Wunreachable-code]
 case 7: if (length == 4) { value = load_le_float(data); if ((sizeof (value) == sizeof (float) ? __finitef (value) : sizeof (value) == sizeof (double) ? __finite (value) : __finitel (value))) { metrics->has_output_power = 1; metrics->output_power = (0) ? fabs(value) : value; } } break;
                                                                                                                                                         ^~~~~~~~
33 errors generated.
make[2]: *** [ecoflow-cdc-protocol.o] Error 1
make[2]: Target `all' not remade because of errors.

@user01010111

Copy link
Copy Markdown
Author

Addressed the multi-platform compiler failures reported above.

The decoder now parses the IEEE-754 binary32 wire representation directly instead of using the platform’s native float representation and isfinite(). This removes the illumos implicit declaration, FreeBSD pre-C11 _Generic expansion, and Ubuntu Trusty unreachable-code failures.

I also replaced the constant absolute-value branch with separate signed and absolute loaders, and added regression coverage for signed finite values, NaN, and positive and negative infinity.

Local validation completed with strict GCC and Clang C99 builds, the relevant pre-C11 and unreachable-code warnings enabled, ASan/UBSan, USB and serial driver builds, and make distcheck.

Signed-off-by: user01010111 <lapses.50.booster@icloud.com>
@user01010111
user01010111 force-pushed the feature/ecoflow-cdc-telemetry branch from b71925f to 73bbd12 Compare August 16, 2026 16:06
@AppVeyorBot

Copy link
Copy Markdown

Build nut 2.8.5.5070-master completed (commit efe8bafd2f by @)

@AppVeyorBot

Copy link
Copy Markdown

Build nut 2.8.5.5071-master completed (commit 46512d29c8 by @)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI For good or bad, machine tools are upon us. Humans are still the responsible ones. EcoFlow Issues and PRs about EcoFlow River 3, Delta 3 UPS series enhancement serial port USB

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants