logo elektroda
logo elektroda
X
logo elektroda

OpenBeken BL0937 Mod: Improved accuracy/resolution for low power readings and energy monitoring

listenobk 450 2
ADVERTISEMENT
  • Helpful post
    #1 21772024
    listenobk
    Level 5  
    I created a new mod (fork) with different approach at resolution and stable readings for power / energy monitoring with BL0937:
    https://github.com/listen-obk/OpenBK7231T_App_BLtest

    This approach will work only with frequency output power monitoring chips like BL0937 and HLW8012.
    My intention: I wanted to measure low loads like the consumptions of the plug (a second example). I have no control loop where regular quick updates are required, instead I prefer accurate and stable power / energy readings. This fork has been mentioned at
    https://www.elektroda.com/rtvforum/topic4114715.html#21745185] already, where a different solution is presented.

    My solution:
    According to the datasheet one pulse of BL0937 represents slightly below 0.5mWh which means the minimum resolution for power at sample frequency of one second is about 1.7W. But I don't need updates every second rather than higher resolution, therefore first I added a condition "minimum pulse count before update", means for low power applications it takes several seconds until there are enough pulses to calculate power. Also I changed the base: pulse counts are never reset. Like this no pulses will be missed, if not considered in current cycle the will be in the next. Then I realized that for more power I still have the same problem of to many updates and unsteady readings even with stable load, so I added another option of minimum and maximum cycle time. To control that, there are two new commands:

    BL0937_MinPulsesVCP <minPulses_V> <minPulses_C> <minPulses_P>
    BL0937_IntervalCPMinMax <minInterval> <maxInterval>


    After playing with it, I guess the most useful will be the second command.
    BL0937_IntervalCPMinMax <minInterval> controls the minimum update cycle in seconds. If set e.g. to 10, all energy pulses within 10 seconds are summarized and power is calculated from that. That means sort of hardware based power averaging (at least as long all pulses are caught by the interrupt routine). No dependency on sample frequency, short power peaks even below 1 sec duration will be covered from energy perspective but you will not see those high peaks as a power reading.

    Second requirement for an update is BL0937_MinPulsesVCP ... <minPulses_P>: if minInterval reached but not enough pulses minPulses_P, we wait until we see this pulse count limit. Another example: at 0.25W there is one pulse every 7 sec. for accuracy I want to have minimum 2 pulses - means the resulting interval will be 14 sec according to datasheet formula. If load raises, the interval will dynamically decrease (lower limit minInterval).

    For lower loads, BL0937_IntervalCPMinMax <maxInterval> will kick in: if minPulses_P not reached within this time, an update will be forced.

    Again, my focus is on power/energy monitoring, therefore <minPulses_V> <minPulses_C> will not trigger updates, they only control switching between V and C measurements. V measurement usually will take only one second but C may take longer. It does an average for both over the cycle (cycle time defined by power). Don't expect high accuracy, it's more informational character (impact on power factor calculation).

    Especially at long intervals it may be interesting to recognize power change more quickly (switch heater on/off). To achieve this, I added another command
    BL0937_ForceOnPwrROC <rateofchange_W/s> <rateofchange_W/cycle>
    <rateofchange_W/s> intended for power jumps (like on/off of a heater) and steady load. It compares power of current with last second. If the positive or negative difference is above the limit, readings are updated three times (following seconds). The first update will be the average power since the last regular update (<minInterval>), the second will have the real new power but sometimes volt/current are not yet updated properly.

    <rateofchange_W/cycle> intended for pulse (PWM) load (2 point controller like heater with thermostat). compares the average power of the current cycle with the power of the last cycle and triggers one update and triggers three updates like above.

    The intention is to set long intervals e.g. power average over 900sec but recognize on/off events with better time resolution. This will improve accuracy of external energy monitoring.


    I use MQTT (with FHEM) for history and control, and I missed to see current values. Tasmota responses with current values on change and if no arguments are given. I implemented the same for the new commands and for BL shared commands VCPPublishIntervals, VCPPublishThreshold and VCPPrecision. The behaviour must be enabled by another command EnabeMQTTOnCommand 1. This could be default but I wanted to be as compatible as possible.

    Compatibility is the reason for another command: BL0937_ScalefactorMultiply <factorV> <factorC> <factorP>
    Raw values of V and P for scaling and calibration are expected as int in drv_pwrCal.c but for better resolution (P below 1.7W) fractions of 1 are required. Therefore I multiply the raw value (frequency, V by 10, P by 1000) before scaling and apply a lower scale factor (move digit compared to the main branch).
    That means if the firmware changes from main branch, the internal scale factors must be changed. To keep calibration, usually it should be BL0937_ScalefactorMultiply 0.1 1 0.001.
    Another option could be BL0937_ScalefactorMultiply 0 0 0. As kind of new feature this will reset the calibration and use the new default values. After that new calibration might be good.
    No action required if the device initially is flashed with this mod or calibration was not executed before.
    Note: before flashing back to main branch firmware, BL0937_ScalefactorMultiply 10 1 1000 should be executed, otherwise recalibration will be required.

    On the device page the command will show currently used and the default values and recommend multipliers (10^x) to keep the calibration. Scientific notation should help to see differences.
    example log entry:
    Info:CMD:ts 5639 BL0937_ScalefactorMultiply: not enough arguments to change. Current (default) values V 1.248886E-01 (1.581335E-02) C 1.072063E-02 (1.287009E-02) P 1.280320E+00 (1.707145E-03), recommended factors 0.100000 1.000000 0.001000

    If the command is sent via MQTT, the response will contain the new scale factors (or current values if command sent without argument).
    Info:MQTT:Publishing val 1.248886E-01 1.072063E-02 1.280320E+00 to ecr66000CFF9367/ScalefactorsVCP retain=0

    Finally I wondered about accuracy of time because it is used for frequency calculation. For this I added the command SendTimestamps. With value 1 it will send NTP and internal timestamps (diff) via MQTT every hour. Ideally the difference should not change over time. This is just for interest because frequency in fact is included in overall calibration (scale factor). Default is disabled, enable it by command SendTimestamps 1.

    While this is a test version, there are several logs on debug and extra debug level to validate the calculation (command responses, ticks, pulses, frequency,...).

    By now I could only test on recent Tuya Plugs with ECR6600 and BL0937 which is using 2ms ticks. Would be great to see if it works (frequency calculation) on other platforms as well.
    Keep in mind that exiting settings VCPPublishIntervals and VCPPublishThreshold are additional conditions and may delay or prevent updates. This variant could be something like a replacement for VCPPublishIntervals.

    Feel free to try. Any comment on the solution and names are welcome. I had no issue with OTA from and to the main branches/versions above 200 (when I started). Only ScaleFactor must be considered, otherwise EnergyStats may have peaks or gaps while there are wrong power readings. Except security limits of history, there is no change on that code. I sync the fork from time to time to be up to date with main functionality.

    Hint: while this is a custom firmware, on github go to Actions and then click on the (last) successful workflow run, download from section Artifacts.
  • ADVERTISEMENT
  • #2 21772642
    p.kaczmarek2
    Moderator Smart Home
    Very interesting idea and it looks very promising. So with those scaling factor, could we integrate it in main without losing calibration?

    Also, have you tried to validate the measurements? Take a resistive load of known resistance, so for example, 0.25 W power is used, and check the reading? Then move to 1 W or 0.1 W ,etc?
    Helpful post? Buy me a coffee.
  • Helpful post
    #3 21772969
    listenobk
    Level 5  
    Sorry, long response - short answers italic.
    p.kaczmarek2 wrote:
    Very interesting idea and it looks very promising. So with those scaling factor, could we integrate it in main without losing calibration?

    Yes. It automatically adopts the multiplication of the user defined scale factor (by calibration).
    I implemented this after a comment from @divadiow on github.
    Some notes: with log10() function it recognizes the position of the decimal point and sets the multiplier based on the range (pow 10). I did not test close to limits (like 0.999 vs. 9.99 or 1.0101 vs. 0.10101) with this C++ code on the platform. I don't know if such values exist in real world.

    Another open question is about data types. I don't know if on any platform int has something different from 32bit. For ticks (timer) it will take 100 days (on ECR6600 platform) to see the overflow. Similar is for float, I don't know if this works the same on any platform, in best case just accuracy is impacted.

    I'm not experienced with multi-module code nor with github. Therfore, review of code (global vs. local variables, formatting, names,...) might be a good idea.
    For energy statistic save, I changed user_main.c to acces the restart indicator, not sure if this can be done in main branch or if there is a better indicator.
    I don't know what you think e.g. about the philosophy to respond with current values if a command was given with no arguments. This could be a general flag instead of separate command but I guess not every developer will like to change the code. Nor I don't know impact on all the use cases. For now I tried to keep impact on other modules as low as possible. Nevertheless I would be happy if some of the ideas would be integrated to the main branch (by any contributor, I don't care to be an author).

    p.kaczmarek2 wrote:
    Also, have you tried to validate the measurements? Take a resistive load of known resistance, so for example, 0.25 W power is used, and check the reading? Then move to 1 W or 0.1 W ,etc?

    No validation with resistive load but I checked for plausibility with different devices. I own 4 of those plugs and with one I measured the other ones. If I switch the relays on, the values are plausible (3 plugs increase 3 times compared to if performed with ony one). Additional consumption for one relay is between 0.3 and 0.5W). From a 3 EUR plug I do not expect absolute accuracy in that range. For 0.1W you have one pulse every 17.5 seconds according to the datasheet while the calibration shows >25% deviation from the datasheet values. I have no clue about the reason. Formual in datasheet includes Vref with 1.218V - if I remove that, everything is fine. Either fake chips or datasheet version does not match the chips in the plugs.
    One appliance for me is state detection of washing machine and dish washer. The difference between "waiting within program" and "finished, standby" sometimes is <0.15W. Absolute value (accuracy) is not very important in this case. The next step is to test my appliance. Currently I'm using tasmota but here the resolution does not allow to detect this in a stable way. There are always some changes over time. Unfortunately I have no spare plug with BL0937 to change from tasmota to OBK just for testing.

    I didn't validate with low resistive load because of two reasons:
    1. I don't have a setup to perform it at mains level yet (stick appropiate resistors into the plug), means I tried to prevent the risk so far.
    2. I don't think it is necessary because frequency for all three measurments is linear. For such low power I don't have equipment to verify.

    What I did: I calibrated with 2000W electrical heater (in reality 1850W) and PZEM004-T to adjust cos phi (to 1.000). The problem here is that I'm on grid and therefore the voltage is quite instable (floating between 228 and 239V). While the resistor is more or less constant (some temperature dependency) the real active power changes every second in a range of up to 25W. I trust in maths here - for 2W that means inaccuracy of 0.025W. Then I verified with Dell laptop switching power supply and resistive loads at 70W and 40W. Like that I get a constant active power but power factor is below 1 (depends on the wattage class of the supply). Deviation was about 0.5W (compared to PZEM004-T which has 1% error). There is always a delay between the measurements and reading. I set up some functionality in my HA (FHEM) - read PZEM004-T and write V, I and P to the OBK plug device via the set commands within one second but there are still deviations on the next read.
    As a final result, I think the values are plausible.
    Nevertheless I'm curious about functionality and accuracy with other device types.
ADVERTISEMENT