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.
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.