PostgreSQL's window functions make anything involving adjacent rows a lot simpler than it used to be. Untried but should be roughly right:
select
date_trunc('hour', newest_time) as average_time,
(oldest_temp + middle_temp + newest_temp) / 3 as average_temp
from (
select
date_trunc('hour', sample_time) as average_time,
lag(sample_time, 2) over w as oldest_time,
lag(sample_time, 1) over w as middle_time,
sample_time as newest_time,
lag(sample_temp, 2) over w as oldest_temp,
lag(sample_temp, 1) over w as middle_temp,
sample_temp as newest_temp
from
samples
window
w as (order by sample_time)
) as s
where
oldest_time = newest_time - '4 minutes'::interval and
middle_time = newest_time - '2 minutes'::interval and
extract(minute from newest_time) in (2, 3);
I've restricted this in the where
clause to exactly the scenario you've described - latest value at :02 or :03, prior 2 values 2 and 4 minutes before. Just in case you have some missing data which would otherwise give odd results like averaging over a much longer interval.