I’m working with a dataset where an IoT device sends a wh
(watt-hour) value at discrete timestamps, identified by an operationId
. I want to visualize this data by plotting the sum of average power per operation, broken down by hour.
Here is the raw data:
timestamp | operationId | wh |
---|---|---|
2025-04-01T14:10:59.000000Z | 1001 | 0 |
2025-04-01T14:20:01.000000Z | 1002 | 0 |
2025-04-01T15:06:29.000000Z | 1003 | 0 |
2025-04-01T18:18:05.000000Z | 1001 | 200 |
2025-04-01T20:06:36.000000Z | 1003 | 200 |
2025-04-01T22:20:10.000000Z | 1002 | 300 |
Compute mean power per operation
I’m using lag()
with a window function to get the previous wh
and timestamp, and compute the average power:
SELECT
timestamp AS end_time,
cast(prev_ts AS timestamp) AS start_time,
operationId,
(wh - prev_wh) / ((cast(timestamp AS DOUBLE) - prev_ts) / 3600000000.0) AS mean_power_w
FROM (
SELECT
timestamp,
wh,
operationId,
lag(wh) OVER (PARTITION BY operationId ORDER BY timestamp) AS prev_wh,
lag(cast(timestamp AS DOUBLE)) OVER (PARTITION BY operationId ORDER BY timestamp) AS prev_ts
FROM meter
)
WHERE prev_ts IS NOT NULL
ORDER BY timestamp;
This gives me:
end_time | start_time | mean_power_w | operationId |
---|---|---|---|
2025-04-01T18:18:05.000000Z | 2025-04-01T14:10:59.000000Z | 48.563334682314 | 1001 |
2025-04-01T20:06:36.000000Z | 2025-04-01T15:06:29.000000Z | 39.984450491475 | 1003 |
2025-04-01T22:20:10.000000Z | 2025-04-01T14:20:01.000000Z | 37.488284910965 | 1002 |
Expand the value across hours
Now I’d like to expand each row to hourly buckets between start_time
and end_time
, filling each hour with the cumulative energy based on the mean power.
For our example:
ts | operationId | energy |
---|---|---|
2025-04-01T14:00:00.000Z | 1001 | 39.67354647241263 |
2025-04-01T14:00:00.000Z | 1002 | 24.981776528168066 |
2025-04-01T15:00:00.000Z | 1001 | 48.563334682314 |
2025-04-01T15:00:00.000Z | 1003 | 35.66390848003506 |
2025-04-01T15:00:00.000Z | 1002 | 37.488284910965 |
2025-04-01T16:00:00.000Z | 1001 | 48.563334682314 |
2025-04-01T16:00:00.000Z | 1003 | 39.984450491475 |
2025-04-01T16:00:00.000Z | 1002 | 37.488284910965 |
2025-04-01T17:00:00.000Z | 1001 | 48.563334682314 |
2025-04-01T17:00:00.000Z | 1003 | 39.984450491475 |
2025-04-01T17:00:00.000Z | 1002 | 37.488284910965 |
2025-04-01T18:00:00.000Z | 1001 | 48.563334682314 |
2025-04-01T18:00:00.000Z | 1003 | 39.984450491475 |
2025-04-01T18:00:00.000Z | 1002 | 37.488284910965 |
2025-04-01T19:00:00.000Z | 1003 | 39.984450491475 |
2025-04-01T19:00:00.000Z | 1002 | 37.488284910965 |
2025-04-01T20:00:00.000Z | 1003 | 39.984450491475 |
2025-04-01T20:00:00.000Z | 1002 | 37.488284910965 |
2025-04-01T21:00:00.000Z | 1002 | 37.488284910965 |
2025-04-01T22:00:00.000Z | 1002 | 37.48828491096 |
How can I expand the results between start_time
and end_time
per hour and fill each hour with the correct mean_power_w
(converted to wh
for that period)?
Is there a way to achieve this using SAMPLE BY
, joins, or maybe generate_series-like logic in QuestDB?