Reconstruct increments within the same physical meter, register and continuous counting segment before allocating them to business days. A declining reading must not automatically become zero or an absolute difference, and endpoints around a multi-day gap cannot recover each day’s actual consumption. This design concerns internal operating and energy analysis. Billing metrology, statutory verification and electrical protection require separate controls.
Specify what the reading measures and when it is valid
Distinguish power from energy first. kW measures power; kWh measures energy. Energy follows from a valid integration of power over time. Differencing cumulative register readings and integrating instantaneous power are different methods: do not difference power samples as if they were counters, or sum cumulative readings as consumption. Also distinguish imported active energy, exported active energy and net energy. A declining bidirectional net value does not necessarily mean a reset.
OpenEnergyMonitor’s daily-energy documentation separately handles power inputs, energy inputs that retain their value through power loss, and cumulative inputs that reset on restart.[1] These are behaviors of the described devices and software, not a guarantee about arbitrary field meters. Read the exact model’s register definitions, scaling, units, reset and rollover behavior. Without that evidence, investigate a decline instead of guessing its mechanism.
Each raw record should retain measurement point, physical meter identity, register, event time, receipt time, raw reading, unit, scaling-configuration version, quality code, source sequence and acquisition batch. A measurement point is the location being measured; a meter is the installed device. Do not merge those identities during replacement. Event time orders measurements; receipt time explains late delivery and what the system knew then. Late receipt does not move consumption to a later day.
Add an epoch_id for a sequence sharing one accumulation baseline, with a new epoch after a verified reset or replacement. Record the new start time and baseline, the preceding terminal reading and maintenance evidence. This is a proposed data model, not an assumption that devices supply the field. Incomplete evidence can justify separating epochs while retaining an unknown boundary; it cannot justify inventing a zero baseline.
OpenTelemetry’s stable Temporality section distinguishes cumulative and delta semantics and uses a start timestamp to help interpret an unbroken sequence.[2] It is a useful contract reference, not an electricity-meter protocol. The same page’s Resets and Gaps section remains marked Development. Pin the actual acquisition version and field meanings rather than presenting telemetry conventions as demonstrated device guarantees.
Build a reproducible interval ledger from two days of readings
Suppose an enterprise measures imported cumulative energy at point P1 using meter M1, register R1, already expressed in kWh with a multiplier of one and timezone Asia/Shanghai. Epoch E1 contains: November 10 at 00:00, 1000; 06:00, 1030; 18:00, 1090; November 11 at 06:00, 1150; and 12:00, 1180. Initially the November 11 midnight reading is missing. All supplied readings have valid quality, with no unregistered reset or scaling change during E1.
A maintenance record establishes that at November 11, 12:00, the operator read E1’s terminal value 1180, reset the counter and read E2’s baseline zero. The sequence is known and the example assumes no unmetered gap at that transition. E2 reads 24 at 18:00 and 48 at November 12, 00:00. The two noon records belong to different epochs; arbitrary ordering must not turn 1180 and zero into ordinary neighbors in one sequence.
E1’s four intervals contribute 1030−1000=30, 1090−1030=60, 1150−1090=60 and 1180−1150=30, totaling 180 kWh. E2 contributes 24−0=24 and 48−24=24, totaling 48. The two-day consumption is therefore 228 kWh. Subtracting the global first reading from the last gives 48−1000=−952, which has no meaningful consumption interpretation.
For every interval retain left and right event timestamps, both raw-record identifiers, meter and epoch, increment, quality status and calculation version. One record spans November 10, 18:00 to November 11, 06:00, from 1090 to 1150: 60 kWh, confirmed for the whole interval but unresolved by day. The endpoints establish a twelve-hour total, not a constant five-kilowatt load or thirty kWh on each side of midnight.
Apply one boundary convention consistently: an increment belongs to the interval between adjacent observations, and daily reporting covers local midnight to the next midnight. Boundary representation must not double-count adjacent intervals. Without a trustworthy midnight reading or other evidence at that boundary, retain the cross-day interval instead of assigning all sixty kWh to November 11 when the next record arrived. Interval completeness and daily completeness require separate acceptance.
A missing midnight reading changes daily allocation without changing the total
If the business only needs the two-day total, the example supplies the continuity evidence for 228 kWh. Daily energy per unit of production needs the sixty-kWh cross-day amount allocated first. Wait for a genuine boundary reading or, where the business explicitly permits it, generate an estimated view. Do not give both equal evidential status. Production quantities must use the same day boundaries and revision cutoff.
Suppose an interim view allocates linearly. Each side of midnight covers six of the twelve hours, giving thirty kWh to each. November 10 is estimated at 30+60+30=120; November 11 at 30+30+24+24=108; the total remains 228. This expresses a uniform-load assumption, not an observed daily profile recovered from the counter.
A genuine November 11 midnight reading of 1130 subsequently arrives. Replace the original cross-day interval with 1130−1090=40 and 1150−1130=20. November 10 becomes 30+60+40=130; November 11 becomes 20+30+24+24=98. The total is still 228. Testing only the combined total misses the original ten-kWh error in each daily allocation.
OpenEnergyMonitor’s Join processing draws a straight line across gaps.[1] Prometheus increase adjusts counter decreases and extrapolates over the selected range.[3] Each behavior has a purpose, but a function result cannot establish that a real midnight observation has been recovered. Store actual interval energy, estimated daily energy, estimation method and unresolved span separately, retaining their status in both displays and exports.
The existing method for industrial sensor resampling and missing data explains why interpolation is not observation. The additional requirement here is conservation: estimated allocations must sum to the trustworthy spanning total while remaining explicitly distinct from daily truth. If days, shifts and hours are estimated separately, test their rollups for consistency instead of allowing three dashboards to create incompatible allocations.
Publish a new result version after backfill, retaining the former 120/108, revised 130/98, source records and revision time. Earlier analytical reports must still resolve the versions they used. Consumers decide whether conclusions require revision; the pipeline delivers the differences. Silently replacing history cannot establish that the actual daily values were known at the original decision time.
Reset, replacement and rollover need different evidence
A reset changes the counting baseline of the same device. The example’s 1180-to-zero transition is supported by maintenance evidence and readings on both sides. If only the post-reset 24 arrives and the pre-reset terminal value is missing, consumption between the last old reading and the reset is unknown. Even with a confirmed zero baseline, only the new twenty-four-kWh segment and the unresolved boundary can be reported. Clipping a negative difference to zero hides missing evidence; taking its absolute value fabricates consumption.
Replacement changes physical identity. Suppose M1 is removed at November 12, 00:00 with a terminal reading of 48. M2 is installed at the same point with an initial reading of 500 and reaches 518 at 06:00. With a complete, gap-free installation boundary, the new meter contributes eighteen kWh. The 500−48=452 difference between devices is not energy use. Any unmetered removal-and-installation period remains unknown; the two meters’ numbers cannot reconstruct it.
Rollover occurs when a counter with known finite capacity passes its limit and continues from the beginning. Suppose device documentation defines modulus M=10000 kWh, the capacity of one complete cycle. Within one otherwise continuous sequence, the counter reads 9980 and, three hours later, 25, without reset or replacement. A single-rollover candidate is 10000−9980+25=45. The modulus is not the last displayed value 9999; resolution and step size must match the device definition.
Forty-five does not always establish exactly one rollover. Over a long interval the increment could be 45 plus additional multiples of 10000. If this example has a trustworthy engineering upper bound of twenty kW, three hours permit at most sixty kWh: forty-five fits, while another full cycle does not. The bound is an explicit assumption, not a universal threshold. Without modulus, continuity or bounding evidence, keep rollover unresolved.
A positive difference alone does not establish continuity either. Between samples a device could reset and accumulate beyond its previous value, or its scaling could change. Check maintenance events, configuration history and acquisition completeness. If those records are absent, state the supported scope; fixing every observed negative difference does not prove that all counter anomalies have been resolved.
Two implementation paths preserve different evidence at different cost
The first path builds an auditable interval ledger in detailed storage. Resolve duplicate records under authorized source and revision rules, partition by physical meter, register and epoch, and connect adjacent trustworthy observations. PostgreSQL 18 lag returns the preceding row in a partition, defaults to NULL when none exists and does not automatically skip NULL values.[4] Do not default a first predecessor to zero or assume the database determines measurement validity.
An illustrative expression is lag(reading_kwh) OVER (PARTITION BY meter_id, register_id, epoch_id ORDER BY event_time, source_sequence). This SQL fragment explains grouping and ordering; it has not been executed against a database for this article. A source_sequence only resolves order when the source defines its meaning. Conflicting readings at the same instant require investigation, not an arbitrary sequence number that manufactures an apparent fact.
After identifying trustworthy adjacent readings, check units, scaling and continuity before ordinary differencing or an evidence-approved rollover correction. A daily query needs the necessary preceding and following anchors. Filtering to rows inside the day before applying lag can lose its first interval. Cross-day anchors do not authorize interpolation automatically: an interval lacking an actual day boundary remains unallocated or explicitly estimated.
The second path uses time-series counter functions for operational trends. It suits known data types, restart semantics, labels and sampling behavior, where the business accepts the function’s estimation boundary. Prometheus increase has documented extrapolation and decrease-handling semantics.[3] For daily accounting that must be explained interval by interval, retain original readings and segmentation evidence rather than only a final function value.
The Flux 0.7.1+ difference documentation defines adjacent-value and null behavior together with nonNegative and initialZero options. Default output generally has one fewer row; retaining the first row gives it a null difference.[5] Parameter choices alter results after a decline. A function called non-negative does not establish correct handling of replacement, rollover or faults. Pin version, grouping and ordering, then verify the counterexamples in this article.
The ledger adds storage, revision processing and version maintenance, but supports interval-by-interval explanation. Time-series functions are convenient for trends but require explicit acceptance of extrapolation, restarts and label changes. Both can coexist: an operational dashboard can use an approved trend definition while management reports reference an auditable version. Do not use an indistinguishable field name for outputs carrying different evidence.
Backfills and corrections affect neighboring intervals
When the midnight reading 1130 arrives, invalidate the original sixty-kWh interval from 1090 to 1150 and create forty- and twenty-kWh replacements. Appending only the new forty while retaining the original sixty double-counts energy. Give intervals identities derived from their endpoint records and rule version, and identify the revision that supersedes an old interval. Retrying the same revision batch should yield the same active interval set.
Correcting a middle reading also changes both adjacent intervals. Changing 1030 to 1032 turns the first increment from thirty to thirty-two and the next from sixty to fifty-eight. With unchanged outer endpoints, their total remains ninety. Updating only the current difference breaks conservation; checking only the total can miss changed shift allocations. Find predecessor and successor, then refresh affected day, shift and downstream metric versions.
Distinguish identical retransmission from genuine revision. The same stable source identifier and content can be received idempotently. The same identifier with another value requires the source’s revision protocol or quarantine, not blind last-arrival-wins behavior. Reconstruct event-time order before calculating out-of-order data; retain receipt time to explain when the evidence became available.
Do not apply today’s multiplier to the entire historical counter. Establish whether the register represents primary- or secondary-side energy, whether the device already applies scaling and whether a boundary reading exists at the change. Segment by configuration version. Otherwise scaling may be applied twice or may rescale a previous cumulative baseline. If the boundary is unknown, restrict cross-boundary differencing and preserve raw values.
Invalid quality codes require more than deleting rows. If the meter kept accumulating correctly during communication loss, trustworthy endpoints may still support the whole interval. If measurement itself failed, bridging the gap may have no valid interpretation. Decide from the fault type, retain its cause and approval evidence, and do not automatically classify an unknown fault as ordinary transmission delay.
Six counterexample groups test values, status and recovery
First test a missing midnight point. Supply 1090 and 1150: the twelve-hour sixty-kWh total should be supported, while daily allocation remains unknown or explicitly estimated as thirty/thirty. Backfill 1130: it must become forty/twenty, superseding the old interval without changing the two-day total. Inspect interval keys, estimation flags and versions. Repair duplicate-contribution logic if necessary, then backfill the same record twice to verify idempotency.
Second test resets with and without evidence. Use 1180, a reset baseline zero and 24; the new epoch should contribute twenty-four. Remove the old terminal reading: the boundary should become unknown and the complete total unavailable. Inspect maintenance records and endpoints, supply authorized evidence or restrict publication, and retest. Acceptance must demonstrate both successful handling of a known reset and refusal to invent missing evidence.
Third test replacement. At one point, use M1’s terminal 48, M2’s initial 500 and subsequent 518. The new interval should contribute only eighteen, never 452. Removing installation-boundary evidence should reveal the uncovered period. If the system differences across devices, repair physical identity and validity intervals, then upload both devices out of order and confirm event-based attribution.
Fourth test rollover. With modulus 10000, readings 9980 and 25, three hours and a twenty-kW upper bound, the candidate forty-five should pass under those conditions. Remove the modulus or extend the interval enough to allow multiple cycles: a unique increment should no longer be asserted. Check model documentation, the bound’s provenance and event evidence. Retest genuine rollover alongside an artificial negative jump so neither enters an unconditional correction formula.
Fifth test duplicates, conflicts and units. Repeating a source record must not add consumption. Conflicting 1030 and 1032 readings with the same identity and instant, but no revision evidence, should be quarantined. Changing a reading’s unit from kWh to Wh requires versioned conversion or blocking. Inspect raw records, conflicts and configuration versions; after repair, recalculate adjacent intervals rather than merely checking row counts.
Sixth test windows and nulls. The first valid reading must not implicitly start from zero; daily filtering must retain necessary predecessors; an invalid intermediate value must not become zero. Expected outputs identify a missing anchor or unknown measurement continuity. Inspect query boundaries and quality rules, provide correct anchors, and retest duration and increments. These are constructed acceptance cases, not claims of field-device or production-system tests.
Deliver daily values with coverage and maintenance responsibility
A transferable daily result includes measurement-point and meter scope, business timezone, boundaries, observed interval energy, estimated allocation, unknown spans, raw-record version and result revision. Approved uses may display a combined value, but its components must remain separately queryable. A critical missing boundary must not yield an unqualified total with no quality status.
Monitor unexplained decreases, identity conflicts, unit changes, excessive gaps, backfill backlog and failed revisions. Thresholds should follow device characteristics and business commitments, not a universal negative-value percentage. Operators need a path from an anomalous result to both source readings, maintenance events and scaling versions to decide between data correction, equipment investigation and restricted use.
For scale, ten thousand points sampled once per minute generate 14.4 million rows daily and about 432 million in thirty days, before retransmissions and revisions. This arithmetic is not a capacity benchmark. Organize storage by point and time, preserve source evidence and maintain an incremental revision queue. Validate indexes, retention and recomputation windows under the real workload; using a window function does not establish adequate throughput.
For rule upgrades, generate old and new interval and daily results from fixed inputs, comparing increments, unknown coverage and revision sets. Switch readers only after differences are explained. Roll back the complete old result-and-rule combination rather than changing code while retaining mixed outputs. Acquisition owners confirm raw evidence, data engineers confirm segmentation and conservation, and business owners determine which estimates may support which decisions.
References
- OpenEnergyMonitor: Daily kWh (online documentation; accessed 2026-11-13)
- OpenTelemetry: Metrics Data Model (1.62.0; Temporality Stable; accessed 2026-11-13)
- Prometheus: Query functions, increase (current documentation; accessed 2026-11-13)
- PostgreSQL 18: Window Functions (accessed 2026-11-13)
- Flux: difference() (Flux 0.7.1+; accessed 2026-11-13)
