I am trying to calculate my energy cost with datapoints published to my influxdb. I need to utilize windowPeriod in order to go back far enough in time. I am currently taking a sum of my energy usage and trying to do arithmetic on it, which if I use hard coded times is no problem. But that doesn't scale at all.
from(bucket: "energydata")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["device_name"] == "Home-14")
|> filter(fn: (r) => r["detailed"] == "False")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> sum(column: "_value")
|> map(fn: (r) => ({r with _value: r._value * 0.13806 / (float(v: int(v: v.windowPeriod)) / 1000000000.0 * 60.0 ) }))
I believe it is when trying to convert the windowPeriod into something useful that it breaks. As I change my period of review my results are all over the place.
I was able to figure it out, in case anyone wants to know:
from(bucket: "energydata")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["device_name"] == "Home")
|> filter(fn: (r) => r["detailed"] == "False")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> sum(column: "_value")
|> map(fn: (r) => ({r with _value: r._value * (float(v: int(v: v.windowPeriod)) / (16000000000.0 * 60.0 * 60.0 * 60.0) ) * 0.13806 }))
Where 0.13806 is your cost per kWh. This converts windowPeriod into hours, and gets you kilowatt hours which you can use to make calculations.
The v.windowPeriod is a dynamic variable being set by the UI to make graphs looks better, I don't think it's the right thing to use for calculating costs.
And are you sure that you want to take the mean average of your values in windowed intervals before calculating the sum? I'm not sure what your actual data looks like, but this feels like it might be the wrong approach.
Related
we are using the influxDB for statistics and dashboards. We love it! Blazing fast and easy to integrate. However we are stuck when we launch new features.
We have the following FLUX query. A massive database with all "model_events" based on the businessUUID. However if the business doesn't have a car.created it returns no results instead of a range with 0's. If it has one car.created even without the range it will return a 0 range. Is there a possibility to always get the range even if the _measurement doesn't have a value?
from(bucket: "_events")
|> range(start: 2022-09-01, stop: 2022-09-11)
|> filter(fn: (r) => r["_measurement"] == "car.created")
|> filter(fn: (r) => r["business_uuid"] == "055ade92-ecd9-47b1-bf85-c1381d0afd22")
|> aggregateWindow(every: 1d, fn: count, createEmpty: true)
|> yield(name: "amount")
BTW.... a bit new to InfluxDB...
Maybe you could create a dummy table and union() it like:
import "experimental/array"
rows = [{_time: now(), _field: "someField", _value: 0}]
dummy = array.from(rows: rows)
data = from(bucket: "_events")
|> range(start: 2022-09-01, stop: 2022-09-11)
|> filter(fn: (r) => r["_measurement"] == "car.created")
|> filter(fn: (r) => r["business_uuid"] == "055ade92-ecd9-47b1-bf85-c1381d0afd22")
|> aggregateWindow(every: 1d, fn: count, createEmpty: true)
|> yield(name: "amount")
union(tables: [dummy, data])
Trying to write my fist TICKscript to work out when two sensor values cross: if the outside temperature has changed from lower to higher than the inside temperature then I need to close the windows (and conversely).
Using the query builder in InfluxDB I'm getting this for the meadian of the temperature values inside the house over the last 15 minutes:
from(bucket: "zigbee")
|> range(start: -15m, stop: now())
|> filter(fn: (r) => r["room"] == "Kitchen" or r["room"] == "DiningRoom" or r["room"] == "Bed3" or r["room"] == "Bed1")
|> filter(fn: (r) => r["_field"] == "temperature")
|> group(columns: ["_measurement"])
|> aggregateWindow(every: 15m, fn: mean, createEmpty: false)
|> yield(name:"inside")
The syntax |> appears to undocumented -- can you provide a reference?
Replacing |> with | breaks it.
It seems that group and aggregateWindow do not commute?
Presumably because aggregateWindow is forced to choose a single representative _time value for each window?
I think the plan is to
assign this to a stream,
copy and edit to creata a second stream shifted by 15 minutes,
create a second pair of streams for the outside temperature.
join all four streams and caluclate a value indicating whether the inside and outside temperatures have crossed over.
Unless you have a better idea?
(Right now it's looking easier to import the data into SQL.)
Check InfluxDB Flux language documentation for |>:
InfluxDB Pipe-forward operator
According to your flux syntax query:
from(bucket: "zigbee")
|> range(start: -15m, stop: now())
|> filter(fn: (r) => r["room"] == "Kitchen" or r["room"] == "DiningRoom" or r["room"] == "Bed3" or r["room"] == "Bed1")
|> filter(fn: (r) => r["_field"] == "temperature")
|> group(columns: ["_measurement"])
|> aggregateWindow(every: 15m, fn: mean, createEmpty: false)
|> yield(name:"inside")
You are taking data from bucket "zigbee"
Data from source are passed to range filter function with pipe-forward |> operator
Results from range filter data are passed to next filter function with another pipe-forward operator
Etc.
So all data flows as a result from one function to another.
You can group by but in your case columns are "room" key values if I understand your intentions correctly, so try:
|> group(columns: ["room"])
There is a difference between key values and measurement names - you should check InfluxDB documentation for understatnding data structure.
Flux data model documentation
I'ts not TICKscript, it's something do to with InfluxDB that might be called flux.
mean = from(bucket: "zigbee")
|> range(start: -5d, stop: now())
|> filter(fn: (r) => r["room"] == "Outside")
|> filter(fn: (r) => r["_measurement"] == "temperature")
|> aggregateWindow(every: 30m, fn: mean, createEmpty: false)
shift = mean
|> timeShift(duration: -3h)
j = join(tables: {mean: mean, shift: shift}, on: ["_time"])
|> map(fn: (r) => ({ r with diff: float(v: r._value_mean) - float( v: r._value_shift) }))
// yield contains 1 table with the required columns, but the UI doesn't understand it.
// The UI requires 1 table for each series.
j |> map(fn: (r) => ({_time: r._time, _value: r._value_mean})) |> yield(name: "mean")
j |> map(fn: (r) => ({_time: r._time, _value: r._value_shift})) |> yield(name: "shift")
j |> map(fn: (r) => ({_time: r._time, _value: r.diff})) |> yield(name: "diff")
The |> in TickScript "Declares a chaining method call which creates an instance of a new node and chains it to the node above it." as said in the official documentation
from(bucket: "bucket")
|> range(start: 2022-01-01T00:00:00Z, stop: 2022-12-31T00:00:00Z)
Few more steps needed here:
Narrow down to the measurement you are interested in
Narrow down to the field (i.e. "column") that is going to be summed
Create an aggregateWindow function to track the recurring results
You could try following via Flux:
from(bucket: "bucket")
|> range(start: 2022-01-01T00:00:00Z, stop: 2022-12-31T00:00:00Z)
|> filter(fn: (r) => r._measurement == "MeasurementName")
|> filter(fn: (r) => r._field == "FiledKey")
|> aggregateWindow(every : 3mo, fn : sum)
|> yield(name: "SomeResultSetName")
See more details here.
I'm migrating my InfluxDB1.8 version to InfluxDB2.0
I'm using a influxDB2.0 database and use grafana to display results.
What I insert as data are the results of my P1 meter, altough the results are total values, I would like to calculate and display the daily results.
What is being inserting is the current (gas usage) value. By calculating the difference of the begin and end of the day, I have my daily usage result.
I did find out a way to do this for 1 day. With the Spread function. But I don't get it working for a longer timeframe then 1 day.
But now to display this on a daily usage on a longer timeframe. I didn't find the right option to get this working
Week results
Anyone an idea?
Query for 1 day:
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "Gas-usage")
|> filter(fn: (r) => r["_field"] == "value")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> spread(column: "_value")```
I did some checks on the 1.8 one and what works there is:
SELECT spread("value")
FROM "Gas-usage"
WHERE $timeFilter
GROUP BY time(1d) fill(null) tz('Europe/Berlin')
what is the equivalant of this query in influxdb 2.0 ?
Try change your aggregate window, like this:
|> aggregateWindow(every: 1d, fn: mean)
use the spread function inside your aggreagateWindow function.
should be like this:
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "Gas-usage")
|> filter(fn: (r) => r["_field"] == "value")
|> aggregateWindow(every: 1d, fn: spread, createEmpty: false)
from(bucket: "${bucket}")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "system")
|> filter(fn: (r) => r.host == "${host}")
|> filter(fn: (r) => r["_field"] == "uptime")
|> aggregateWindow(every: 1d, fn: spread, createEmpty: false)
result of my grafana
Using the new Flux langauge, how best to calculate uptime? My current Flux query looks a bit like this:
from(bucket: "my-bucket")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "process_start_time_seconds")
|> filter(fn: (r) => r["_field"] == "gauge")
|> map(fn: (r) => ({
r with
_value: (int(v: now()) / 1000000000) - int(v: r._value)
})
)
|> aggregateWindow(every: v.windowPeriod, fn: last, createEmpty: false)
This works but seems to be incredibly complex for such a small thing, in Prometheus it's basically one line:
(time() - process_start_time_seconds{job="my-job"})
Is there a way I can improve the Flux query?
I don't think you can simplify it a lot, but here are some ideas:
Store the converted current time in a variable
Don't use aggregateWindow() when you only want to fetch a single value over time
Move the map() as far out as you can for better performance
Use prettier syntax
It could then look like this (just a sketch, not tested for syntax):
currentSeconds = (int(v: now()) / 1000000000)
from(bucket: "my-bucket")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r._measurement == "process_start_time_seconds")
|> filter(fn: (r) => r._field == "gauge")
|> last()
|> map(fn: (r) => ({
r with _value: currentSeconds - int(v: r._value)
})
)