Skip to content

Usermod INA219 Current, Voltage & Power Sensor #4237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 58 commits into
base: main
Choose a base branch
from
Open

Conversation

KrX3D
Copy link

@KrX3D KrX3D commented Oct 31, 2024

Hi,

i created a usermod for the ina219 Current, Voltage & Power Sensor:

INA219-Pin-Outs

I took a liking to the INA226 Usermod here:

https://github.com/Aircoookie/WLED/tree/0_15/usermods/INA226_v2

and took some parts and added my 3 cents to it.

I hope the readme states everything needed to get what can be done.

the only think i couldnt solved is to add the sensors data to the wled home assistant integration page (if thats even possible) so instead it is added just to mqtt. if there is a way to have the autodiscover to add it directly to the wled integrations page, i would be more than happy to change the usermod.

also i hope i added everything correctly in git, since its my first time working like this in git

Summary by CodeRabbit

  • New Features

    • Added support for INA2xx series current/voltage sensors, enabling real-time monitoring of voltage, current, power, and energy consumption.
    • Integrated MQTT publishing and Home Assistant discovery for seamless smart home integration.
    • User interface enhancements for configuring sensor parameters and monitoring energy usage.
  • Documentation

    • Added detailed documentation covering setup, configuration, usage, and integration of the INA2xx sensor module.

@DedeHai
Copy link
Collaborator

DedeHai commented Nov 1, 2024

since you keep adding commits, is this work in progress? if so, mark it as such or better yet: commit to this PR once you are finished.

@KrX3D
Copy link
Author

KrX3D commented Nov 1, 2024

since you keep adding commits, is this work in progress? if so, mark it as such or better yet: commit to this PR once you are finished.

Hi,

no its finsied. I just did some small formatting changes while waiting for a reply. But now im happy with it ;)

EDIT: im also using it for like 2 weeks now without any problems

@DedeHai
Copy link
Collaborator

DedeHai commented Nov 1, 2024

ok nice. did you test it working on different ESPs?

@KrX3D
Copy link
Author

KrX3D commented Nov 1, 2024

i tested it on an ESP32 S2 (lolin_s2_mini) and an C3 (esp32c3dev) where it is working.

like i said its already running for around 2 weeks

@KrX3D
Copy link
Author

KrX3D commented Nov 14, 2024

Hi,

i tested it now also with an ESp32 Wroom-32 (esp32dev) and it also worked.

did i forget something so it will be added to version 0,15?
im new to git with all this pull request stuff

@DedeHai
Copy link
Collaborator

DedeHai commented Nov 14, 2024

looks fine, needs more testing and review, there are a few usermods in pipeline so please be patient.

changed uint8_t to int8_t for _sdaPin and _sclPin --->  to be able to pick "unused" in pin selection which is -1,
Several optimizations for WLED_MQTT_CONNECTED and if Usermod is enabled/disabled
@netmindz netmindz changed the base branch from 0_15 to main December 16, 2024 13:29
@KrX3D KrX3D requested a review from DedeHai January 29, 2025 18:31
KrX3D added 3 commits January 30, 2025 18:34
- Moved configurable settings to the top of the file for better readability.
- Defined default values for each configuration option using #ifndef directives.
- Updated default I2C pins to WLED ESP32 defaults (SDA: 21, SCL: 22).
- Cleaned up variable initialization to use pre-defined constants for configuration.
@KrX3D KrX3D requested a review from DedeHai January 31, 2025 16:59
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
usermods/INA219_v2/INA219_v2.cpp (2)

44-46: Missing <cmath> include.

The code uses math functions like roundf, powf, and fabsf but doesn't include the necessary header.

 #include "wled.h"
 #include <INA219_WE.h>
+#include <cmath>          // roundf, powf, fabsf

142-154: ⚠️ Potential issue

Potential memory leak if initialization fails.

If _ina219->init() fails, the allocated object is not deleted, causing memory leaks.

 _ina219 = new INA219_WE(_i2cAddress);

 if (!_ina219) {
     DEBUG_PRINTLN(F("Failed to allocate memory for INA219 sensor!"));
     enabled = false;
     return false;
 }

 if (!_ina219->init()) {
     DEBUG_PRINTLN(F("INA219 initialization failed!"));
     enabled = false;
+    delete _ina219;
+    _ina219 = nullptr;
     return false;
 }
🧹 Nitpick comments (2)
usermods/INA219_v2/INA219_v2.cpp (2)

126-136: Consider adding a null check before accessing _ina219.

When updateINA219Settings() is called, you check for valid I2C pins but don't verify that _ina219 is properly allocated before dereference in the initialization or other functions.

 // Validate I2C pins; if invalid, disable usermod and log message
 if (i2c_scl < 0 || i2c_sda < 0) {
     enabled = false;
     DEBUG_PRINTLN(F("INA219 disabled: Invalid I2C pins. Check global I2C settings."));
     return false;
 }

400-404: Consider adding overflow protection for power calculation.

The energy calculation assumes the power value is valid. Consider adding a check for overflow or out-of-range values before updating energy consumption.

 // Update energy consumption
 if (lastPublishTime != 0) {
+    // Only update energy if power reading is valid and not in overflow state
+    if (!overflow && power >= 0) {
         updateEnergy(power, lastCheck - lastPublishTime);
+    }
 }
 lastPublishTime = lastCheck;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f4dd600 and a1aaba3.

📒 Files selected for processing (1)
  • usermods/INA219_v2/INA219_v2.cpp (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
usermods/INA219_v2/INA219_v2.cpp (1)
Learnt from: KrX3D
PR: wled/WLED#4237
File: usermods/INA219_v2/INA219_v2.cpp:265-276
Timestamp: 2025-04-18T22:27:58.634Z
Learning: When implementing MQTT message handling in WLED usermods, use `strstr(topic, "/specific/path")` instead of `strcmp_P(topic, PSTR("/specific/path"))` to properly match topics that include the device prefix. The full MQTT topic typically follows the pattern `<mqttDeviceTopic>/specific/path`.
🔇 Additional comments (11)
usermods/INA219_v2/INA219_v2.cpp (11)

101-107: Good use of powf with float arguments.

The function correctly uses powf with float arguments to avoid unnecessary type conversions, which saves flash memory on ESP devices.


162-201: Efficient UTF-8 character handling for MQTT client ID sanitization.

The function to sanitize MQTT client IDs handles UTF-8 encoded characters like umlauts and ß efficiently by checking for the UTF-8 lead byte and mapping them to ASCII equivalents.


206-238: Energy calculation implementation with time-based resets.

The energy calculation logic handles daily and monthly resets appropriately based on date/time changes. This approach ensures accurate energy tracking over time.


273-275: Fixed potential buffer overflow risk by passing buffer size.

By using the buffer size parameter in serializeJson(), the code mitigates the risk of buffer overflows when serializing JSON.


333-335: Fixed potential buffer overflow risk by passing buffer size.

The code correctly uses serializeJson(doc, buffer, sizeof(buffer)) to prevent potential buffer overflows when serializing JSON for Home Assistant discovery.


379-381: Good early-return pattern for optimization.

The loop function efficiently uses the early-return pattern to avoid unnecessary processing when conditions aren't met, which is a good optimization for microcontrollers.


479-480: Properly using strstr for MQTT topic matching.

The code correctly uses strstr to check if the topic contains the path rather than requiring an exact match, which is essential for MQTT topic handling with prefixes.


615-616: Correctly storing the check interval in seconds in the config.

The code divides the millisecond value by 1000 to store it as seconds in the config JSON, which is the expected format.


670-680: Correct handling of interval values with safe conversion.

The code properly validates the check interval value from the config and uses a safe conversion with static_cast<uint32_t> to avoid overflow issues.


702-704: Standard usermod ID implementation.

The getId() method returns the appropriate constant defined in WLED's constant definitions, which is necessary for proper usermod registration.


707-710: Proper usermod registration using the REGISTER_USERMOD macro.

The code correctly creates a static instance and registers it with the WLED framework using the standard registration macro.

@DedeHai
Copy link
Collaborator

DedeHai commented Apr 20, 2025

not sure what you mean, do you mean the INA226 usermod? i didnt test it since i dont have that module, but it worked with some i2c temp sensors

got the numbers mixed up, yes I mean INA226 which should work very much the same way, so would be good to support both using a #define since you already put in a lot of work and this UM is much more versatile than the old one.

@KrX3D
Copy link
Author

KrX3D commented Apr 21, 2025

got the numbers mixed up, yes I mean INA226 which should work very much the same way, so would be good to support both using a #define since you already put in a lot of work and this UM is much more versatile than the old one.

ok i will give it a try soon, but it will take some time, since i also want to buy an ina226 so i can try it out

EDIT:
since i would merge them and use a #define to pick which to use. any suggestions how to rename this usermod?

also the library.json looks like this now:

{
  "name": "INA219_v2",
  "dependencies": {
    "wollewald/INA219_WE":"~1.3.8"
  }
}

how can i splitt is so that only the correct lib will be used, like this? (cant test it currently)

with
-D INA_SENSOR=INA219
-D INA_SENSOR=INA226

library.json:

{
  "name": "INA_Sensors",
  "build": {
    "extraScript": "setup_ina_deps.py"
  }
}

setup_ina_deps.py:

import('env')

# Check for sensor type define in build flags
build_flags = env.get('BUILD_FLAGS', '')

# Default to INA219 if not specified
sensor_type = "INA219"

# Check if INA_SENSOR is defined in build flags
if "INA_SENSOR=INA226" in build_flags:
    sensor_type = "INA226"
elif "INA_SENSOR=INA219" in build_flags:
    sensor_type = "INA219"

# Add appropriate library dependency based on sensor type
if sensor_type == "INA219":
    env.Append(LIBDEPS=["wollewald/INA219_WE@~1.3.8"])
elif sensor_type == "INA226":
    env.Append(LIBDEPS=["wollewald/INA226_WE":"~1.2.9"])

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
usermods/INA219_v2/INA219_v2.cpp (1)

44-46: ⚠️ Potential issue

Missing <cmath> include for mathematical functions

The code uses mathematical functions (roundf, powf, fabsf) but doesn't include the <cmath> header explicitly. While it might compile due to indirect inclusions, this is fragile and platform-dependent.

 #include "wled.h"
 #include <INA219_WE.h>
+#include <cmath>
🧹 Nitpick comments (2)
usermods/INA219_v2/INA219_v2.cpp (2)

209-211: Consider handling edge cases in energy calculation

The updateEnergy function doesn't handle very small power values which might lead to rounding errors when calculating extremely low energy usage.

    void updateEnergy(float power, unsigned long durationMs) {
        float durationHours = durationMs / 3600000.0; // Milliseconds to hours
+       // Skip negligible power values to avoid accumulating rounding errors
+       if (power < 0.01) return;
        float energy_kWh = (power / 1000.0) * durationHours; // Watts to kilowatt-hours (kWh)

388-402: Missing error handling for sensor communication failures

The sensor reading code doesn't include error handling for potential I2C communication failures which might occur during operation, especially in environments with electrical noise.

Consider adding error detection and recovery:

        // Fetch sensor data
+       bool readSuccess = true;
+       
        shuntVoltage = truncateDecimals(_ina219->getShuntVoltage_mV());
        busVoltage = truncateDecimals(_ina219->getBusVoltage_V());
        
        float rawCurrent_mA = _ina219->getCurrent_mA();
+       // Simple error check - unrealistic values might indicate communication issues
+       if (rawCurrent_mA < -10000 || rawCurrent_mA > 10000) {
+           DEBUG_PRINTLN(F("INA219 unrealistic current reading detected"));
+           readSuccess = false;
+       }
        current_mA = truncateDecimals(rawCurrent_mA);
        current = truncateDecimals(rawCurrent_mA / 1000.0); // Convert from mA to A

        float rawPower_mW = _ina219->getBusPower();
+       // Skip energy calculation on suspicious readings
+       if (!readSuccess) {
+           DEBUG_PRINTLN(F("INA219 skipping energy calculation due to suspicious readings"));
+           return;
+       }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a0ec3ba and 6fec39b.

📒 Files selected for processing (1)
  • usermods/INA219_v2/INA219_v2.cpp (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
usermods/INA219_v2/INA219_v2.cpp (1)
Learnt from: KrX3D
PR: wled/WLED#4237
File: usermods/INA219_v2/INA219_v2.cpp:265-276
Timestamp: 2025-04-18T22:27:58.634Z
Learning: When implementing MQTT message handling in WLED usermods, use `strstr(topic, "/specific/path")` instead of `strcmp_P(topic, PSTR("/specific/path"))` to properly match topics that include the device prefix. The full MQTT topic typically follows the pattern `<mqttDeviceTopic>/specific/path`.
🔇 Additional comments (10)
usermods/INA219_v2/INA219_v2.cpp (10)

521-522: MQTT topic construction follows good practices

The MQTT subscription topic construction correctly uses the device's MQTT topic prefix, which will properly route incoming messages to this usermod.


481-485: Proper MQTT topic matching implementation

Good job using strstr() instead of strcmp_P() for topic matching. This correctly handles the device topic prefix in MQTT messages, ensuring proper functionality.


675-685: Well-implemented interval validation

The code properly validates the check interval and uses appropriate type conversions to prevent overflow. The use of static_cast<uint32_t> and 1000UL ensures correct handling of larger intervals.


277-278: Buffer overflow protection correctly implemented

Good job protecting against buffer overflow by passing the buffer size to serializeJson(). This ensures that the serialization won't write beyond the allocated buffer.


127-136: Good I2C pin validation

The code properly validates the I2C pins before proceeding with sensor initialization, preventing potential issues on platforms where I2C might not be available.


150-156: Proper memory cleanup during initialization failure

The initialization code properly handles failure cases by deleting the allocated sensor object and setting it to nullptr when initialization fails, preventing memory leaks.


224-228: Energy tracking with daily reset

The daily energy reset logic correctly handles both midnight resets and day changes, ensuring energy tracking is properly compartmentalized by day.


232-240: Energy tracking with monthly reset

The monthly energy reset logic correctly identifies month changes using a clever calculation (year*12 + month), ensuring proper monthly energy tracking.


458-472: Clean cleanup of Home Assistant entities

The code properly removes all Home Assistant entities when the discovery feature is disabled, which is an important cleanup step to avoid orphaned entities in Home Assistant.


142-149: 🛠️ Refactor suggestion

Memory allocation check improvement needed

The new operator allocation result is checked at line 144, but it's actually safer to check the result immediately after allocation to avoid any potential dereference of a null pointer.

-       _ina219 = new INA219_WE(_i2cAddress);
-
-       if (!_ina219) {
+       auto* tmp = new INA219_WE(_i2cAddress);
+       if (!tmp) {
            DEBUG_PRINTLN(F("Failed to allocate memory for INA219 sensor!"));
            enabled = false;
            return false;
        }
+       _ina219 = tmp;

Likely an incorrect or invalid review comment.

@DedeHai
Copy link
Collaborator

DedeHai commented Apr 22, 2025

good question. what happens if you add in both libraries in the dependencies? does that eat up flash even if only one of them is used?
you could name it "INA2xx_Sensor" and if you have all the functionality (and more) of the original, the original could be removed to avoid confusion? Or is the new one incompatible with existing setups (MQTT topics etc)? If so, would it be easy to add a "compatibility" define so it is compatible to setups using the old one? just a suggestion and a nice to have.

@KrX3D
Copy link
Author

KrX3D commented Apr 22, 2025

good question. what happens if you add in both libraries in the dependencies? does that eat up flash even if only one of them is used?

ok i tried it with:

{
  "name": "INA219_v2",
  "dependencies": {
    "wollewald/INA219_WE":"~1.3.8",
    "wollewald/INA226_WE":"~1.2.9"
  }
}

and before and after the ram and flash size didnt change from:

RAM:   [==        ]  16.1% (used 52640 bytes from 327680 bytes)
Flash: [=======   ]  69.9% (used 1099014 bytes from 1572864 bytes)

the bin file is also the same size 1074kb, so i will keep it that way

you could name it "INA2xx_Sensor" and if you have all the functionality (and more) of the original, the original could be removed to avoid confusion?

ok i will rename it that way. i think when i add the ina226 the current once can be removed, since i also started with that usermod to create this one.

Or is the new one incompatible with existing setups (MQTT topics etc)? If so, would it be easy to add a "compatibility" define so it is compatible to setups using the old one? just a suggestion and a nice to have.

hmm i need to look that up, but i think mostly the mqtt topics are the same. i think only the overflow changed since it wasnt working for me.
But when i fiished it i will compare it to the current mqtt topics

KrX3D added 3 commits April 22, 2025 17:47
…bility

- Fixed issue with energy values being overwritten on startup or reflash
- Restored energy values from MQTT are now added to current totals instead of replacing them
- Added additional configuration options for INA sensor behavior
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
usermods/INA219_v2/INA219_v2.cpp (1)

60-62: ⚠️ Potential issue

Missing <cmath> include

Functions like roundf, pow, and fabsf from <cmath> are used but the header is not included. The code may compile due to indirect inclusions, but this is fragile.

 #include "wled.h"
 #include <INA219_WE.h>
+#include <cmath>          // roundf, pow, fabsf
🧹 Nitpick comments (1)
usermods/INA219_v2/INA219_v2.cpp (1)

869-1021: Configuration handling could be simplified

The readFromConfig method is quite long (150+ lines) and follows a repetitive pattern. Consider refactoring to use a helper function for each setting type to reduce code duplication.

Example pattern that could be extracted into a helper:

template<typename T>
bool updateConfigValue(JsonObject& obj, const char* key, T& current, const char* logName) {
  T temp = current;
  if (getJsonValue(obj[key], temp)) {
    if (temp != current) {
      _logUsermodInaSensor("%s updated to: %d", logName, temp);
      current = temp;
    }
    return true;
  }
  return false;
}

This would reduce the repetitive pattern seen throughout the method.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 011de93 and ecf2401.

⛔ Files ignored due to path filters (3)
  • usermods/INA219_v2/img/homeassistant.png is excluded by !**/*.png
  • usermods/INA219_v2/img/info.png is excluded by !**/*.png
  • usermods/INA219_v2/img/usermod_settings.png is excluded by !**/*.png
📒 Files selected for processing (3)
  • usermods/INA219_v2/INA219_v2.cpp (1 hunks)
  • usermods/INA219_v2/library.json (1 hunks)
  • wled00/const.h (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wled00/const.h
🧰 Additional context used
🧠 Learnings (1)
usermods/INA219_v2/INA219_v2.cpp (1)
Learnt from: KrX3D
PR: wled/WLED#4237
File: usermods/INA219_v2/INA219_v2.cpp:265-276
Timestamp: 2025-04-18T22:27:58.634Z
Learning: When implementing MQTT message handling in WLED usermods, use `strstr(topic, "/specific/path")` instead of `strcmp_P(topic, PSTR("/specific/path"))` to properly match topics that include the device prefix. The full MQTT topic typically follows the pattern `<mqttDeviceTopic>/specific/path`.
🔇 Additional comments (12)
usermods/INA219_v2/library.json (1)

1-7: LGTM - Dependencies properly defined

The library manifest correctly defines dependencies on both INA219_WE and INA226_WE libraries with appropriate version constraints using the tilde notation (~), which allows patch-level updates but locks the minor version.

usermods/INA219_v2/INA219_v2.cpp (11)

1-58: Well-structured configuration section with appropriate defaults

The configuration section is well-organized with clear default values and descriptive comments for each parameter. The use of #ifndef/#define blocks allows for easy customization while providing sensible defaults.


123-130: Well-implemented decimal truncation function

The function correctly uses powf with float arguments as recommended in previous reviews, which helps avoid unnecessary type conversions and saves flash memory on ESP devices.


157-217: Memory management in sensor initialization is now safer

The function properly cleans up resources if initialization fails, preventing memory leaks. The function checks for required conditions (valid I2C pins) before attempting to initialize the sensor.


220-260: Thorough MQTT client ID sanitization

Good handling of character replacements, including UTF-8 accented characters. The function ensures MQTT client IDs meet specifications by replacing invalid characters with underscores.


265-314: Well-implemented energy calculation with data validation

The energy calculation includes several safeguards:

  1. Skips negligible power values to prevent cumulative rounding errors
  2. Rejects unrealistic energy values
  3. Properly handles daily and monthly resets
  4. Uses appropriate time conversion for energy calculation

The approach makes the energy calculation robust against outliers and calculation errors.


320-369: MQTT publishing correctly handles buffer size limits

The code now properly passes the buffer size to serializeJson() as recommended in previous reviews to prevent potential buffer overflows.


374-438: Home Assistant discovery implementation with proper buffer handling

The code correctly checks for potential buffer overflow in topic string construction, addressing earlier review feedback. The discovery configuration follows Home Assistant MQTT discovery standards.


440-457: Home Assistant sensor removal with proper buffer handling

Similar to the discovery implementation, this code now correctly checks for potential buffer overflow when constructing topic strings.


599-643: MQTT message handling correctly uses topic substring matching

The code now properly uses strstr() instead of strcmp_P() for checking MQTT topics as recommended in previous reviews, allowing it to correctly handle device-prefixed topics.


894-908: Improved handling of check_interval configuration

The code now correctly handles the conversion from seconds to milliseconds with proper type casting and validation, avoiding potential overflow issues.


1033-1034: Clear and proper usermod registration

The usermod is correctly registered with a static instance and the REGISTER_USERMOD macro, following the WLED convention.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
usermods/ina2xx_v2/ina2xx_v2.cpp (1)

123-130: truncateDecimals() rounds, re-computes powf() every call, and hurts performance

  1. The function name says truncate but the logic uses roundf, i.e. it
    rounds – that can be misleading when somebody expects a pure truncation.
  2. powf(10, _decimalFactor) is evaluated each sensor read, although
    _decimalFactor rarely changes.
    A cached factor (or a simple switch on 0-3) saves several floating-point
    operations per loop.
- float truncateDecimals(float val) {
-
-     float factor = powf(10.0f, _decimalFactor);
-     return roundf(val * factor) / factor;
- }
+ float roundDecimals(float val) {
+     static float factorLUT[4] = {1.f, 10.f, 100.f, 1000.f};
+     float factor = (_decimalFactor <= 3) ? factorLUT[_decimalFactor]
+                                          : powf(10.0f, _decimalFactor);
+     return roundf(val * factor) / factor;
+ }

Please also rename the caller(s) for clarity.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ecf2401 and 20c64eb.

⛔ Files ignored due to path filters (5)
  • usermods/ina2xx_v2/img/INA219-Pin-Outs.png is excluded by !**/*.png
  • usermods/ina2xx_v2/img/homeassistant.png is excluded by !**/*.png
  • usermods/ina2xx_v2/img/info.png is excluded by !**/*.png
  • usermods/ina2xx_v2/img/usermod_settings.png is excluded by !**/*.png
  • usermods/ina2xx_v2/img/usermod_settings_pins_selection.png is excluded by !**/*.png
📒 Files selected for processing (3)
  • usermods/ina2xx_v2/Readme.md (1 hunks)
  • usermods/ina2xx_v2/ina2xx_v2.cpp (1 hunks)
  • usermods/ina2xx_v2/library.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • usermods/ina2xx_v2/library.json
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
usermods/ina2xx_v2/Readme.md

44-44: Hard tabs
Column: 1

(MD010, no-hard-tabs)


46-46: Hard tabs
Column: 1

(MD010, no-hard-tabs)


48-48: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)


50-50: Hard tabs
Column: 1

(MD010, no-hard-tabs)


51-51: Hard tabs
Column: 1

(MD010, no-hard-tabs)


52-52: Hard tabs
Column: 1

(MD010, no-hard-tabs)


53-53: Hard tabs
Column: 1

(MD010, no-hard-tabs)


54-54: Hard tabs
Column: 1

(MD010, no-hard-tabs)


55-55: Hard tabs
Column: 1

(MD010, no-hard-tabs)


56-56: Hard tabs
Column: 1

(MD010, no-hard-tabs)


57-57: Hard tabs
Column: 1

(MD010, no-hard-tabs)


58-58: Hard tabs
Column: 1

(MD010, no-hard-tabs)


59-59: Hard tabs
Column: 1

(MD010, no-hard-tabs)


60-60: Hard tabs
Column: 1

(MD010, no-hard-tabs)


62-62: Hard tabs
Column: 1

(MD010, no-hard-tabs)


64-64: Hard tabs
Column: 1

(MD010, no-hard-tabs)


66-66: Hard tabs
Column: 1

(MD010, no-hard-tabs)


67-67: Hard tabs
Column: 1

(MD010, no-hard-tabs)


68-68: Hard tabs
Column: 1

(MD010, no-hard-tabs)


69-69: Hard tabs
Column: 1

(MD010, no-hard-tabs)


70-70: Hard tabs
Column: 1

(MD010, no-hard-tabs)


71-71: Hard tabs
Column: 1

(MD010, no-hard-tabs)


73-73: Hard tabs
Column: 1

(MD010, no-hard-tabs)


75-75: Hard tabs
Column: 1

(MD010, no-hard-tabs)


77-77: Hard tabs
Column: 1

(MD010, no-hard-tabs)


78-78: Hard tabs
Column: 1

(MD010, no-hard-tabs)


79-79: Hard tabs
Column: 1

(MD010, no-hard-tabs)


80-80: Hard tabs
Column: 1

(MD010, no-hard-tabs)


81-81: Hard tabs
Column: 1

(MD010, no-hard-tabs)


82-82: Hard tabs
Column: 1

(MD010, no-hard-tabs)


87-87: Code block style
Expected: indented; Actual: fenced

(MD046, code-block-style)


103-103: Hard tabs
Column: 1

(MD010, no-hard-tabs)


104-104: Hard tabs
Column: 1

(MD010, no-hard-tabs)


105-105: Hard tabs
Column: 1

(MD010, no-hard-tabs)


106-106: Hard tabs
Column: 1

(MD010, no-hard-tabs)


107-107: Hard tabs
Column: 1

(MD010, no-hard-tabs)


108-108: Hard tabs
Column: 1

(MD010, no-hard-tabs)


109-109: Hard tabs
Column: 1

(MD010, no-hard-tabs)


110-110: Hard tabs
Column: 1

(MD010, no-hard-tabs)


111-111: Hard tabs
Column: 1

(MD010, no-hard-tabs)


112-112: Hard tabs
Column: 1

(MD010, no-hard-tabs)

🔇 Additional comments (3)
usermods/ina2xx_v2/ina2xx_v2.cpp (2)

320-369: Possible MQTT payload truncation – 1 kB static buffer is not guaranteed to fit

serializeJson(jsonDoc, buffer, sizeof(buffer)) silently truncates when the
payload does not fit into 1024 bytes, leading to corrupted JSON and Home
Assistant discovery failures.

Please measure the exact size first or use serializeJson(doc, mqttClient);
with a dynamically sized String, e.g.

size_t len = measureJson(jsonDoc);
if (len >= sizeof(buffer)) {
  _logUsermodInaSensor("JSON size %u exceeds buffer", len);
}

or switch to StaticJsonDocument<512> + stream.


266-314: 🛠️ Refactor suggestion

Daily / monthly reset relies on hitting exactly 00:00 – can easily miss and drift

With a 5 s default sampling interval it is quite possible that the loop()
iteration never lands on minute = 0 (especially if the MCU is busy or Wi-Fi
blocks). When that happens the counters will never reset and start drifting.

Consider resetting solely on day / month change instead of the timestamp
edge:

- if ((hour(localTime) == 0 && minute(localTime) == 0 && dailyResetTime != currentDay) ||
-     (currentDay > dailyResetTime && dailyResetTime > 0)) {
+ if (currentDay != dailyResetTime) {
      …
 }

The same applies to the monthly logic below.

Likely an incorrect or invalid review comment.

usermods/ina2xx_v2/Readme.md (1)

86-91: Build instruction points to a non-existing identifier

custom_usermods = … INA219_v2
but the folder and the REGISTER_USERMOD macro register ina2xx_v2.
Copy-pasting these lines will therefore fail to compile.

- custom_usermods = ${env:d1_mini.custom_usermods} INA219_v2
+ custom_usermods = ${env:d1_mini.custom_usermods} ina2xx_v2
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

87-87: Code block style
Expected: indented; Actual: fenced

(MD046, code-block-style)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
usermods/ina2xx_v2/ina2xx_v2.cpp (1)

195-196: Implement INA226 sensor support

Currently, the code only instantiates INA219_WE objects despite the more generic INA2xx naming.

I see from the learnings that you plan to add INA226 support in a future update. When implementing it, consider using a compile-time switch approach as previously suggested:

-  _ina2xx = new INA219_WE(_i2cAddress);
+  #if defined(USE_INA226)
+    _ina2xx = new INA226_WE(_i2cAddress);
+  #else
+    _ina2xx = new INA219_WE(_i2cAddress);
+  #endif
🧹 Nitpick comments (4)
usermods/ina2xx_v2/ina2xx_v2.cpp (4)

149-155: Consider using named constants instead of magic numbers

The threshold value (0.01f) is hardcoded, which makes it harder to understand its significance and makes future adjustments more difficult.

-bool hasSignificantChange(float oldValue, float newValue, float threshold = 0.01f) {
+// Define at class level
+static constexpr float DEFAULT_CHANGE_THRESHOLD = 0.01f;
+
+bool hasSignificantChange(float oldValue, float newValue, float threshold = DEFAULT_CHANGE_THRESHOLD) {

287-296: Replace magic numbers with named constants

The code uses hardcoded thresholds (0.01 and 10.0) for filtering negligible power values and unrealistic energy spikes.

+// Define at class level
+static constexpr float MIN_POWER_THRESHOLD_W = 0.01f;  // Minimum power in watts to consider for energy calculation
+static constexpr float MAX_ENERGY_SPIKE_KWH = 10.0f;   // Maximum realistic energy spike in kWh

 // Skip negligible power values to avoid accumulating rounding errors
-if (power < 0.01) {
+if (power < MIN_POWER_THRESHOLD_W) {
   _logUsermodInaSensor("SKIPPED: Power too low (%.3f W) — skipping to avoid rounding errors.", power);
   return;
 }

 // Skip negative values or unrealistic spikes
-if (energy_kWh < 0 || energy_kWh > 10.0) { // 10 kWh in a few seconds is unrealistic
+if (energy_kWh < 0 || energy_kWh > MAX_ENERGY_SPIKE_KWH) { // Unrealistic energy spike
   _logUsermodInaSensor("SKIPPED: Energy value out of range (%.6f kWh)", energy_kWh);
   return;
 }

530-537: Handle millis() overflow in time calculations

When calculating time differences with millis(), overflow can occur after approximately 49.7 days of uptime, which could affect energy calculations.

 // Update energy consumption
 if (lastPublishTime != 0) {
   if (power >= 0) {
-    updateEnergy(power, lastCheck - lastPublishTime);
+    // Handle millis() overflow when calculating duration
+    unsigned long duration = (lastCheck >= lastPublishTime) 
+                           ? (lastCheck - lastPublishTime) 
+                           : (0xFFFFFFFF - lastPublishTime + lastCheck + 1);
+    updateEnergy(power, duration);
   } else {
     _logUsermodInaSensor("Skipping energy update due to negative power: %.3f W", power);
   }
 } else {
   _logUsermodInaSensor("First reading - establishing baseline for energy calculation");
 }
 lastPublishTime = lastCheck;

61-61: Consider preparing for future INA226 support

The code only includes the INA219_WE library but plans to support INA226 in the future.

 #include "wled.h"
 #include <INA219_WE.h>
+// Uncomment when adding INA226 support
+// #include <INA226_WE.h>
+
+// Uncomment and define when implementing INA226 support
+// #define USE_INA226
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 20c64eb and be4c08c.

📒 Files selected for processing (1)
  • usermods/ina2xx_v2/ina2xx_v2.cpp (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
usermods/ina2xx_v2/ina2xx_v2.cpp (1)
Learnt from: KrX3D
PR: wled/WLED#4237
File: usermods/ina2xx_v2/ina2xx_v2.cpp:178-185
Timestamp: 2025-05-06T20:31:05.167Z
Learning: KrX3D plans to add INA226 support to the INA2xx usermod in a future update. Currently, the code only instantiates INA219_WE objects despite the more generic naming.
🔇 Additional comments (4)
usermods/ina2xx_v2/ina2xx_v2.cpp (4)

173-234: Robust sensor initialization flow

The sensor initialization code is well-implemented with proper error handling and comprehensive logging. It validates I2C pins, ensures memory allocation is successful, and checks for successful sensor initialization.


282-331: Well-structured energy calculation logic

The energy calculation implementation is thorough with:

  • Proper conversion from power and duration to energy
  • Filtering of negligible or unrealistic values to avoid accumulating errors
  • Intelligent day/month boundary detection for counter resets
  • Detailed logging at each step

This creates a reliable foundation for accurate energy tracking over time.


391-455: Comprehensive Home Assistant integration

The Home Assistant MQTT discovery implementation is excellent, with:

  • Proper device and entity configuration
  • Unique IDs to prevent duplicates
  • Appropriate device classes and units
  • Well-structured value templates
  • Buffer overflow checks for topic generation

This will provide a seamless integration experience for Home Assistant users.


84-99: Well-organized configuration variables

The configuration variables are well-structured with clear naming and appropriate use of static casting for enum types. This creates a maintainable foundation for the module's configuration.

@DedeHai
Copy link
Collaborator

DedeHai commented Jun 5, 2025

what is the status?
I briefly checked the files, looks like the readme needs updating: UM is now called ina2xx_v2 and it should also mention it supports INA226 as well and how to select which one to compile.

@KrX3D
Copy link
Author

KrX3D commented Jun 5, 2025

Hi,
i received a ina226 and i already made changes but i couldnt totally test it so far since im on holiday. i think i get it done till monday and will update the files in git then

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
usermods/ina2xx_v2/Readme.md (2)

20-20: Remove hard tabs in markdown
Line 20 is triggering a markdownlint MD010 error (no-hard-tabs). Convert any hard tabs to spaces for consistent formatting.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

20-20: Hard tabs
Column: 144

(MD010, no-hard-tabs)


133-161: Fix numbering in Usage steps
Steps are numbered 1, 2, 3, 3. Please renumber to maintain a single ascending sequence (e.g., 1–4) to avoid confusion.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc6e33b and 6702151.

⛔ Files ignored due to path filters (2)
  • usermods/ina2xx_v2/img/usermod_settings_ina219.png is excluded by !**/*.png
  • usermods/ina2xx_v2/img/usermod_settings_ina226.png is excluded by !**/*.png
📒 Files selected for processing (1)
  • usermods/ina2xx_v2/Readme.md (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: willmmiles
PR: wled/WLED#4623
File: usermods/word-clock-matrix/word-clock-matrix.cpp:332-332
Timestamp: 2025-03-29T01:22:54.617Z
Learning: In the WLED project, hardcoded usermod IDs (like 500 in the WordClockMatrix's getId() method) are intentionally used as part of a strategy to avoid modifying core code. There are plans to remove numeric usermod IDs entirely in the future.
usermods/ina2xx_v2/Readme.md (1)
Learnt from: KrX3D
PR: wled/WLED#4237
File: usermods/ina2xx_v2/ina2xx_v2.cpp:178-185
Timestamp: 2025-05-06T20:31:05.208Z
Learning: KrX3D plans to add INA226 support to the INA2xx usermod in a future update. Currently, the code only instantiates INA219_WE objects despite the more generic naming.
🪛 markdownlint-cli2 (0.17.2)
usermods/ina2xx_v2/Readme.md

20-20: Hard tabs
Column: 144

(MD010, no-hard-tabs)

🔇 Additional comments (2)
usermods/ina2xx_v2/Readme.md (2)

1-4: Title and intro claim INA226 support before it’s implemented
The README states support for both INA219 and INA226, but the current code only instantiates INA219_WE objects (per retrieved learnings). Please confirm whether INA226 is fully supported in this release or adjust the documentation accordingly.


120-130: Verify custom_usermods identifier matches code
The example uses INA2XX_v2—please confirm that this matches the actual folder name, class name, and #define USERMOD_ID_INA2XX entry so that PlatformIO will pick it up correctly.

@KrX3D
Copy link
Author

KrX3D commented Jun 8, 2025

Hi @DedeHai

i updated the usermod to support the INA226.

I tested it in series with my Ina219 sensor which is running since months on a project and the values reported were nearly the same (0,002 difference)

I also updated the readme and some pictures

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
usermods/ina2xx_v2/Readme.md (2)

24-29: Update screenshots to show the combined INA2XX usermod interface

The screenshots still show separate INA219 and INA226 settings pages, but this is now a unified usermod with a sensor type selector.


181-181: Update instruction to reference the unified INA2XX usermod

The text should refer to "the INA2XX usermod" instead of separately mentioning INA219 or INA226.

🧹 Nitpick comments (2)
usermods/ina2xx_v2/ina2xx_v2.h (1)

80-92: Macro has implicit dependency on configComplete variable

The UPDATE_CONFIG macro requires configComplete to be in scope wherever it's used. Consider documenting this requirement or passing it as a parameter to make the dependency explicit.

-#define UPDATE_CONFIG(obj, key, var, fmt)                     \
+// Note: Requires 'configComplete' boolean variable in scope
+#define UPDATE_CONFIG(obj, key, var, fmt)                     \
usermods/ina2xx_v2/Readme.md (1)

3-3: Fix grammar: "sensor" should be "sensors"

Since you're referring to both INA219 and INA226, use the plural form.

-This Usermod integrates the INA219 **and** INA226 sensor with WLED to monitor energy consumption. It can read voltage, current, power, and calculate daily, monthly and total energy usage for either sensor.
+This Usermod integrates the INA219 **and** INA226 sensors with WLED to monitor energy consumption. It can read voltage, current, power, and calculate daily, monthly and total energy usage for either sensor.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~3-~3: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...od integrates the INA219 and INA226 sensor with WLED to monitor energy consumption...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6702151 and be0d1ca.

📒 Files selected for processing (4)
  • usermods/ina2xx_v2/Readme.md (1 hunks)
  • usermods/ina2xx_v2/ina2xx_v2.cpp (1 hunks)
  • usermods/ina2xx_v2/ina2xx_v2.h (1 hunks)
  • usermods/ina2xx_v2/library.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • usermods/ina2xx_v2/library.json
  • usermods/ina2xx_v2/ina2xx_v2.cpp
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: willmmiles
PR: wled/WLED#4623
File: usermods/word-clock-matrix/word-clock-matrix.cpp:332-332
Timestamp: 2025-03-29T01:22:54.617Z
Learning: In the WLED project, hardcoded usermod IDs (like 500 in the WordClockMatrix's getId() method) are intentionally used as part of a strategy to avoid modifying core code. There are plans to remove numeric usermod IDs entirely in the future.
usermods/ina2xx_v2/Readme.md (1)
Learnt from: KrX3D
PR: wled/WLED#4237
File: usermods/ina2xx_v2/ina2xx_v2.cpp:178-185
Timestamp: 2025-05-06T20:31:05.208Z
Learning: KrX3D plans to add INA226 support to the INA2xx usermod in a future update. Currently, the code only instantiates INA219_WE objects despite the more generic naming.
🧬 Code Graph Analysis (1)
usermods/ina2xx_v2/ina2xx_v2.h (1)
usermods/ina2xx_v2/ina2xx_v2.cpp (1)
  • UsermodINA2xx (434-440)
🪛 LanguageTool
usermods/ina2xx_v2/Readme.md

[uncategorized] ~3-~3: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...od integrates the INA219 and INA226 sensor with WLED to monitor energy consumption...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)

🪛 markdownlint-cli2 (0.17.2)
usermods/ina2xx_v2/Readme.md

20-20: Hard tabs
Column: 152

(MD010, no-hard-tabs)

🔇 Additional comments (4)
usermods/ina2xx_v2/ina2xx_v2.h (4)

1-5: LGTM!

Standard header structure with appropriate includes.


6-20: Well-designed sensor type selection mechanism

The compile-time sensor selection using type alias provides a clean abstraction. Good error handling for invalid sensor types.


93-159: Well-structured class member variables

Good organization with clear separation of configuration, state, and sensor-specific variables. The change detection mechanism using last sent values is a nice optimization.


178-179: Proper resource cleanup in destructor

The destructor correctly handles cleanup of the dynamically allocated sensor object as shown in the implementation.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
usermods/ina2xx_v2/Readme.md (2)

26-29: Screenshots not reflecting unified UI.
The Settings section still shows separate INA219 and INA226 pages, but this is a single INA2XX usermod with a sensor-type selector. Please update these images to display the combined UI.


181-181: Update final enable instruction.
The callout refers to enabling the "INA219" or "INA226" usermod, but the unified module should be referred to as "INA2XX" (with sensor-type selector).

🧹 Nitpick comments (3)
usermods/ina2xx_v2/Readme.md (3)

3-3: Grammar: Use plural for sensors.
Replace "sensor" with "sensors" to match the plural integration scope.

- This Usermod integrates the INA219 **and** INA226 sensor with WLED to monitor energy consumption.
+ This Usermod integrates the INA219 **and** INA226 sensors with WLED to monitor energy consumption.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~3-~3: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...od integrates the INA219 and INA226 sensor with WLED to monitor energy consumption...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)


20-22: Replace hard tabs with spaces.
Static analysis flagged a hard tab in the table header (line 20). Convert any hard tabs to spaces to comply with markdownlint MD010.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

20-20: Hard tabs
Column: 152

(MD010, no-hard-tabs)


34-38: Consolidate sensor type definition instructions.
The README duplicates the #define INA_SENSOR_TYPE snippet in two places. Consider merging into a single section and referring back to avoid redundancy.

Also applies to: 133-137

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be0d1ca and f440a46.

⛔ Files ignored due to path filters (1)
  • usermods/ina2xx_v2/img/INA226-Pin-Outs.png is excluded by !**/*.png
📒 Files selected for processing (1)
  • usermods/ina2xx_v2/Readme.md (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: willmmiles
PR: wled/WLED#4623
File: usermods/word-clock-matrix/word-clock-matrix.cpp:332-332
Timestamp: 2025-03-29T01:22:54.617Z
Learning: In the WLED project, hardcoded usermod IDs (like 500 in the WordClockMatrix's getId() method) are intentionally used as part of a strategy to avoid modifying core code. There are plans to remove numeric usermod IDs entirely in the future.
usermods/ina2xx_v2/Readme.md (1)
Learnt from: KrX3D
PR: wled/WLED#4237
File: usermods/ina2xx_v2/ina2xx_v2.cpp:178-185
Timestamp: 2025-05-06T20:31:05.208Z
Learning: KrX3D plans to add INA226 support to the INA2xx usermod in a future update. Currently, the code only instantiates INA219_WE objects despite the more generic naming.
🪛 LanguageTool
usermods/ina2xx_v2/Readme.md

[uncategorized] ~3-~3: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...od integrates the INA219 and INA226 sensor with WLED to monitor energy consumption...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)

🪛 markdownlint-cli2 (0.17.2)
usermods/ina2xx_v2/Readme.md

20-20: Hard tabs
Column: 152

(MD010, no-hard-tabs)

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

Successfully merging this pull request may close these issues.

2 participants