Assuming ts is supposed to be type timestamp:
SELECT date_trunc('hour', ts) AS hour, min(value) AS min_val
FROM cgl
GROUP BY 1;
date_trunc() truncates timestamps to the hour. Of course, you get no row for hours without any data from this. If you need a row for *every hour, generate a total set of hours with generate_series() first. Example:
If ts is in fact integer, it's probably supposed to be a UNIX epoch, and you need to convert it with to_timestamp() first:
SELECT date_trunc('hour', to_timestamp(ts)) AS hour, min(value) AS min_val
FROM cgl
GROUP BY 1;
Consider storing a proper timestamp to begin with.
Aside: "partition" would hint at window functions, which would be the wrong tool for this.