Prepare aggregateWindow() for Meter-Reading … or for correct time display in the output.
Motivation get the right meter value in the right time zone.
There are several issues that’s why I make 3 steps for testing.
- step 1 prepare aggregate Windows (this Topic)
- step 2 use the correct functions for meter reading
- step 3 test time zone
I am a very enthusiastic user of flux.
And I’ve been busy with meter readings for a while.
What I ran into is very ‘basic’ and I see that this topic has been communicated several times in the past.
Because I couldn’t find a “White Paper” or document on this
I would like to explain my findings in detail.
Influxdb is made for storage of measurements without beginning and end. (streaming data).
Therefore, we want to intercept the values by extracting units of time for an operation. (sum, mean, spread, first, last, max, min)
Especially for meter reading is determining the value of the difference between two values.
The window
function or aggregateWindows() has been created for this purpose.
aggregateWindow(every: 1d,
fn: mean,
createEmpty: false)
Before you know it, it is automatically filled in by the UI and the results fly across the screen. but !!!
Let’s take a closer look at what results this produces.
First we generate predictable data.
Test script flux
For this we use the flux data generator which will give a predictable outcome.
Data description:
we take the first week of 2023
January 1 starts on Sunday
day of the year = 1
day of the month = 1
day of the week = 0
period exactly 1 week = 7 days = 10080 minutes
And for clarity ***no*** 'timezone'.
We can fill the values per minute with the following data.
-
fn: (n) => (1) all _vallue 's ’ = 1
-
fn: (n) => n/1440 "week_day [sun = 0 , mon = 1, … sat = 6) ]
-
fn: (n) => (n) erery minuut sum up with 1 unit [ 2023-01-01T00:00:00 = 0, … 2023-01-01T23:59:59 = 10080]
Flux test script
start_block.flux →
import "generate"
import "date"
start_proc = 2023-01-01T00:00:00Z
stop_proc = 2023-01-08T00:00:00Z
raw_data =
generate.from(
// 24 * 60 = 1440 minuten for 1 day window
// 7 * 24 * 60 =10080 minuten for 7 days window
count: 10080,
// comment out for 1 of the 3 funtions
// 3 different function's
//fn: (n) => n / 1440 ,
fn: (n) => (1),
//fn: (n) => (n),
start: start_proc,
stop: stop_proc
)
analyse_block.flux
// replace this with the experimnet's
// pass true first 20 records
output_data =
raw_data
|> range(start: start_proc, stop: stop_proc)
|> limit(n: 20)
output_block.flux
Continuous output with test
for date time calendar
functions.
output_data
|> range(start: start_proc, stop: stop_proc)
|> map(fn: (r) => ({r with week_day : date.weekDay(t: r._time)}))
|> map(fn: (r) => ({r with month : date.month(t: r._time)}))
|> map(fn: (r) => ({r with month_day : date.monthDay(t: r._time)}))
|> map(fn: (r) => ({r with year_day : date.yearDay(t: r._time)}))
|> keep(columns: ["_value", "week_day","month","month_day","year_day" "_time"])
|> yield(name: "output data")
first experiment
we fill the week with a 1 every minute and see what it produces with a standard aggregateWindow() function.
The expected outcome should be 7 days with 1440 minutes each.
output_data =
raw_data
|> range(start: start_proc, stop: stop_proc)
|> aggregateWindow(every: 1d,
fn: sum,
createEmpty: false)
_time | _value | week_day | month | mont_day | year_day |
---|---|---|---|---|---|
2023-01-02T00:00:00Z | 1440 | 1 | 1 | 2 | 2 |
2023-01-03T00:00:00Z | 1440 | 2 | 1 | 3 | 3 |
2023-01-04T00:00:00Z | 1440 | 3 | 1 | 4 | 4 |
2023-01-05T00:00:00Z | 1440 | 4 | 1 | 5 | 5 |
2023-01-06T00:00:00Z | 1440 | 5 | 1 | 6 | 6 |
2023-01-07T00:00:00Z | 1440 | 6 | 1 | 7 | 7 |
You would quickly overlook this but you miss the first day.
and the value of the first day is January 2.
The last day goes to next week.
How do we know that the values have moved a day???
we now fill the values with fn: (n) => n/1440
.
(by moving the comment in start_block.flux)
week_day [sun = 0 , mon = 1, ... ,sat = 6 ]
_time | _value | week_day | month | mont_day | year_day |
---|---|---|---|---|---|
2023-01-02T00:00:00Z | 0 | 1 | 1 | 2 | 2 |
2023-01-03T00:00:00Z | 1440 | 2 | 1 | 3 | 3 |
2023-01-04T00:00:00Z | 2880 | 3 | 1 | 4 | 4 |
2023-01-05T00:00:00Z | 4320 | 4 | 1 | 5 | 5 |
2023-01-06T00:00:00Z | 5760 | 5 | 1 | 6 | 6 |
2023-01-07T00:00:00Z | 7200 | 6 | 1 | 7 | 7 |
Sunday has only added values 0
that should be 0
This value is therefore at Monday.
Cause ??
This is because aggregateWindow moves time forward.
The function is made up of underlying functions.
|> aggregateWindow(every: 1d,
fn: sum,
createEmpty: false)
same as:
// ===============================================
|> window(every: 1d)
|> sum()
|> duplicate(as: "_time", column: "_stop")
|> window(every: inf, timeColumn: "_time")
// ===============================================
We can
duplicate(as: "_time", column: "_stop")
change into
duplicate(as: "_time", column: "_start")
this solved this problem.
Or use an additional option for aggregateWindows().
output_data =
raw_data
|> range(start: start_proc, stop: stop_proc)
|> aggregateWindow(every: 1d,
fn: sum,
timeSrc : "_start",
timeDst : "_time",
createEmpty: false)
last and correct result.
_time | _value | week_day | month | mont_day | year_day |
---|---|---|---|---|---|
2023-01-01T00:00:00Z | 0 | 0 | 1 | 1 | 1 |
2023-01-02T00:00:00Z | 1440 | 1 | 1 | 2 | 2 |
2023-01-03T00:00:00Z | 2880 | 2 | 1 | 3 | 3 |
2023-01-04T00:00:00Z | 4320 | 3 | 1 | 4 | 4 |
2023-01-05T00:00:00Z | 5760 | 4 | 1 | 5 | 5 |
2023-01-06T00:00:00Z | 7200 | 5 | 1 | 6 | 6 |
2023-01-07T00:00:00Z | 8640 | 6 | 1 | 7 | 7 |
This extra option gives the correct days and values in the right place. (This applies to the functions that are suitable for aggregate.)
Conclusion:
- AggregateWindows has option to take the
_start
time instead of_stop
to prevent time shift.
go to the next topic:
- step 2 use the correct functions for meter-reading.
Have fun with flux