This problem could be easier to solve with Quick Sight if functions such as lead(), lag() and windowXXX() functions would support PRE_FILTER and PRE_AGG aggregation level (feature request alert
)
So my first suggestion would be to see if you could get this populated into your dataset (example via a window function from the underlying database).
Nevertheless, failing this, luckily this problem can still be solved totally within Quick Sight.
The idea is to sum the differences in time between each 2 readings. Each reading’s timestamp is first converted to a difference in seconds from the first reading’s time. Then this number is is assigned a + or - sign (determined by the uptime_metric_multiplier field). And finally all these are added together to give you the total_uptime. There is some additional logic to cater for cases where the last reading needs to be ignored (see comment at the bottom).
You need to add the following calculated fields:
run_status_int
ifelse(run_status = 'On', 1, 0)
rank_asc
denseRank([timestamp ASC], [model, model_serial_number], PRE_AGG)
rank_desc
denseRank([timestamp DESC], [model, model_serial_number], PRE_AGG)
first_value
minOver(ifelse({rank_asc} = 1, run_status_int, null), [model,model_serial_number], PRE_AGG)
first_timestamp
minOver(timestamp, [model,model_serial_number], PRE_AGG)
diff_first_timestamp
dateDiff({first_timestamp}, {timestamp}, 'SS')
uptime_metric_multiplier
ifelse(
{rank_desc} = 1 AND run_status_int = 1 , 0, /* Ignore last On metric */
{first_value} = 1,
ifelse(
{rank_asc} % 2 = 0, 1, /* Even metrics are Off */
{rank_asc} % 2 = 1, -1, /* Odd metrics are On */
null
),
{first_value} = 0,
ifelse(
{rank_asc} % 2 = 0, -1, /* Even metrics are On */
{rank_asc} % 2 = 1, 1, /* Odd metrics are Off */
null
),
null
)
total_uptime
sumOver({diff_first_timestamp} * {uptime_metric_multiplier}, [model, {model_serial_number}], PRE_AGG)
This will give you the total uptime. I will leave the definition of downtime for you to figure out
(it should not be difficult given the above). Also, worth noting here that if a sensor’s last value was On, then currently that last value is ignored since we cannot know the duration for which it remained on.