diff --git a/public/styles.css b/public/styles.css
index bd16263..3409307 100644
--- a/public/styles.css
+++ b/public/styles.css
@@ -80,7 +80,14 @@ html, body {
.a-hero { align-self: center; }
.a-label { font-size: 22px; color: var(--muted); font-weight: 500; display: flex; gap: 14px; align-items: baseline; }
.a-trend { font-size: 17px; font-weight: 400; }
-.a-temp { font-size: 200px; font-weight: 200; letter-spacing: -.045em; line-height: .95; margin: 4px 0 10px -8px; }
+.a-temprow { display: flex; align-items: center; gap: 28px; margin: 4px 0 10px 0; }
+.a-temp { font-size: 200px; font-weight: 200; letter-spacing: -.045em; line-height: .95; margin-left: -8px; }
+
+/* Temperatuurverloop van vandaag, in de ruimte rechts van het grote getal */
+.a-today { flex: 1; min-width: 0; }
+.a-today[hidden] { display: none; }
+.a-tcap { font-size: 15px; color: var(--muted); margin-bottom: 4px; }
+.a-tspark { display: block; width: 100%; height: 96px; overflow: visible; }
.a-hum { font-size: 17px; font-weight: 400; }
.a-hum:not(:empty)::before { content: "·"; margin-right: 14px; }
.a-range { width: 560px; }
diff --git a/public/sw.js b/public/sw.js
index d7f1f75..dc4c1f4 100644
--- a/public/sw.js
+++ b/public/sw.js
@@ -1,6 +1,6 @@
/* Service worker: app-shell cache-first, API network-first met timeout en fallback op de laatste response. */
-const VERSION = 'weerscherm-v9';
+const VERSION = 'weerscherm-v10';
const SHELL = [
'./',
'./index.html',
diff --git a/src/Config.php b/src/Config.php
index 5ceaccf..5fe563f 100644
--- a/src/Config.php
+++ b/src/Config.php
@@ -19,6 +19,7 @@ final class Config
'stations' => 300,
'measure' => 900,
'pressure' => 900,
+ 'temperature' => 900,
'forecast' => 3600,
'radar' => 240,
],
diff --git a/src/DashboardService.php b/src/DashboardService.php
index 6df5f62..b021b5b 100644
--- a/src/DashboardService.php
+++ b/src/DashboardService.php
@@ -10,6 +10,8 @@ namespace Weerscherm;
*/
final class DashboardService
{
+ private const PRESSURE_HOURS = 24;
+
private const ERR_NETATMO_AUTH = 'netatmo_auth';
private const ERR_NETATMO = 'netatmo_unavailable';
private const ERR_FORECAST = 'forecast_unavailable';
@@ -48,6 +50,7 @@ final class DashboardService
$rain = $this->rain($station, $now);
$pressure = $this->pressure($station, $now);
+ $outdoorHistory = $this->outdoorHistory($station, $now);
$forecast = $this->forecast($station, $tz);
return [
@@ -66,6 +69,7 @@ final class DashboardService
'max_at' => $this->iso($station['outdoor']['max_at'], $tz),
'humidity' => $station['outdoor']['humidity'],
],
+ 'outdoor_history' => $outdoorHistory,
'indoor' => $station['indoor'],
'rain' => $rain,
'pressure' => $pressure,
@@ -101,14 +105,37 @@ final class DashboardService
if ($station['device_id'] === null) {
return $base + ['history' => [], 'stale' => false];
}
- $begin = $now->getTimestamp() - PressureHistory::HOURS * 3600;
+ $begin = $now->getTimestamp() - self::PRESSURE_HOURS * 3600;
$measure = $this->fetch(
'pressure',
fn() => $this->source->pressureHistory($station['device_id'], $begin, $now->getTimestamp()),
self::ERR_NETATMO,
);
return $base + [
- 'history' => $measure['data'] === null ? [] : PressureHistory::map($measure['data'], $now->getTimezone()),
+ 'history' => $measure['data'] === null ? [] : MeasureSeries::map($measure['data'], $now->getTimezone(), 'hpa'),
+ 'stale' => $measure['stale'],
+ ];
+ }
+
+ /**
+ * Temperatuurverloop van vandaag: vanaf middernacht lokale tijd tot nu.
+ *
+ * @return array{points: list
, stale: bool}
+ */
+ private function outdoorHistory(array $station, \DateTimeImmutable $now): array
+ {
+ $moduleId = $station['outdoor_module_id'];
+ if ($station['device_id'] === null || $moduleId === null) {
+ return ['points' => [], 'stale' => false];
+ }
+ $begin = $now->setTime(0, 0, 0)->getTimestamp();
+ $measure = $this->fetch(
+ 'temperature',
+ fn() => $this->source->temperatureHistory($station['device_id'], $moduleId, $begin, $now->getTimestamp()),
+ self::ERR_NETATMO,
+ );
+ return [
+ 'points' => $measure['data'] === null ? [] : MeasureSeries::map($measure['data'], $now->getTimezone(), 'temp'),
'stale' => $measure['stale'],
];
}
diff --git a/src/FixtureSource.php b/src/FixtureSource.php
index 304aee7..9fa5bdf 100644
--- a/src/FixtureSource.php
+++ b/src/FixtureSource.php
@@ -61,12 +61,30 @@ final class FixtureSource implements WeatherSource
{
$body = [];
for ($ts = $begin - ($begin % 1800); $ts <= $end; $ts += 1800) {
- $i = ($end - $ts) / 1800;
+ // Hele halfuren sinds het einde; intdiv houdt $i een int, zodat de modulo hieronder geen
+ // deprecation geeft (en de waarschuwing niet vóór de JSON in de response belandt).
+ $i = intdiv($end - $ts, 1800);
$body[(string) $ts] = [round(1012 + 3 * sin($i / 8) + ($i % 5) * 0.1, 1)];
}
return $body;
}
+ public function temperatureHistory(string $deviceId, string $moduleId, int $begin, int $end): array
+ {
+ // Dagcurve tussen de min en max uit stationsData(): koudst rond 06:00, warmst rond 15:00.
+ $body = [];
+ for ($ts = $begin - ($begin % 1800); $ts <= $end; $ts += 1800) {
+ if ($ts < $begin) {
+ continue;
+ }
+ $at = (new \DateTimeImmutable('@' . $ts))->setTimezone($this->now->getTimezone());
+ $hour = (int) $at->format('G') + (int) $at->format('i') / 60;
+ $t = 9.2 + (19.8 - 9.2) * (0.5 + 0.5 * sin((($hour - 10) / 24) * 2 * M_PI));
+ $body[(string) $ts] = [round($t, 1)];
+ }
+ return $body;
+ }
+
public function forecast(float $lat, float $lon, string $timezone): array
{
$tmin = [11.0, 10.1, 11.3, 12.0, 9.4, 8.1];
diff --git a/src/LiveSource.php b/src/LiveSource.php
index 5c23249..9699f1d 100644
--- a/src/LiveSource.php
+++ b/src/LiveSource.php
@@ -39,6 +39,11 @@ final class LiveSource implements WeatherSource
return $this->netatmo->getPressureHistory($deviceId, $begin, $end);
}
+ public function temperatureHistory(string $deviceId, string $moduleId, int $begin, int $end): array
+ {
+ return $this->netatmo->getTemperatureHistory($deviceId, $moduleId, $begin, $end);
+ }
+
public function forecast(float $lat, float $lon, string $timezone): array
{
return $this->openMeteo->forecast($lat, $lon, $timezone);
diff --git a/src/MeasureSeries.php b/src/MeasureSeries.php
new file mode 100644
index 0000000..0845d3d
--- /dev/null
+++ b/src/MeasureSeries.php
@@ -0,0 +1,38 @@
+ $body
+ * @return list elk punt heeft "at" en het veld $valueKey
+ */
+ public static function map(array $body, \DateTimeZone $tz, string $valueKey): array
+ {
+ $points = [];
+ foreach ($body as $timestamp => $values) {
+ if (!is_numeric($timestamp) || !is_array($values) || !isset($values[0]) || !is_numeric($values[0])) {
+ continue;
+ }
+ $points[(int) $timestamp] = (float) $values[0];
+ }
+ ksort($points);
+
+ $out = [];
+ foreach ($points as $ts => $value) {
+ $out[] = [
+ 'at' => (new \DateTimeImmutable('@' . $ts))->setTimezone($tz)->format(\DATE_ATOM),
+ $valueKey => $value,
+ ];
+ }
+ return $out;
+ }
+}
diff --git a/src/NetatmoClient.php b/src/NetatmoClient.php
index ae4b0db..74b0993 100644
--- a/src/NetatmoClient.php
+++ b/src/NetatmoClient.php
@@ -60,17 +60,33 @@ final class NetatmoClient
/** @return array timestamp => [hPa], per 30 minuten, van het basisstation */
public function getPressureHistory(string $deviceId, int $begin, int $end): array
{
- $json = $this->apiGet('getmeasure', [
- 'device_id' => $deviceId,
+ return $this->measureSeries('Pressure', ['device_id' => $deviceId], $begin, $end);
+ }
+
+ /** @return array timestamp => [°C], per 30 minuten, van de opgegeven module */
+ public function getTemperatureHistory(string $deviceId, string $moduleId, int $begin, int $end): array
+ {
+ return $this->measureSeries('Temperature', ['device_id' => $deviceId, 'module_id' => $moduleId], $begin, $end);
+ }
+
+ /**
+ * Eén meetreeks per 30 minuten ophalen. $target bevat device_id en eventueel module_id.
+ *
+ * @param array $target
+ * @return array
+ */
+ private function measureSeries(string $type, array $target, int $begin, int $end): array
+ {
+ $json = $this->apiGet('getmeasure', $target + [
'scale' => '30min',
- 'type' => 'Pressure',
+ 'type' => $type,
'date_begin' => $begin,
'date_end' => $end,
'optimize' => 'false',
'real_time' => 'false',
]);
if (!is_array($json['body'] ?? null)) {
- throw new UpstreamException('getmeasure (Pressure): geen body in antwoord');
+ throw new UpstreamException("getmeasure ($type): geen body in antwoord");
}
return $json['body'];
}
diff --git a/src/PressureHistory.php b/src/PressureHistory.php
deleted file mode 100644
index ec4d622..0000000
--- a/src/PressureHistory.php
+++ /dev/null
@@ -1,33 +0,0 @@
- $body
- * @return list
- */
- public static function map(array $body, \DateTimeZone $tz): array
- {
- $points = [];
- foreach ($body as $timestamp => $values) {
- if (!is_numeric($timestamp) || !is_array($values) || !isset($values[0]) || !is_numeric($values[0])) {
- continue;
- }
- $points[(int) $timestamp] = (float) $values[0];
- }
- ksort($points);
-
- $out = [];
- foreach ($points as $ts => $hpa) {
- $out[] = ['at' => (new \DateTimeImmutable('@' . $ts))->setTimezone($tz)->format(\DATE_ATOM), 'hpa' => $hpa];
- }
- return $out;
- }
-}
diff --git a/src/StationMapper.php b/src/StationMapper.php
index d66f40a..4ea27ef 100644
--- a/src/StationMapper.php
+++ b/src/StationMapper.php
@@ -20,7 +20,7 @@ final class StationMapper
* outdoor: array{temp: ?float, trend: ?string, min: ?float, min_at: ?int, max: ?float, max_at: ?int, humidity: ?float},
* indoor: list,
* pressure: array{current: ?float, trend: ?string},
- * rain_module_id: ?string, sum_rain_24: ?float}
+ * outdoor_module_id: ?string, rain_module_id: ?string, sum_rain_24: ?float}
*/
public static function map(array $body, ?string $deviceId, array $indoorModules): array
{
@@ -29,7 +29,7 @@ final class StationMapper
return [
'timezone' => null, 'lat' => null, 'lon' => null, 'device_id' => null, 'measured_at' => null,
'outdoor' => self::EMPTY_OUTDOOR, 'indoor' => [], 'pressure' => self::EMPTY_PRESSURE,
- 'rain_module_id' => null, 'sum_rain_24' => null,
+ 'outdoor_module_id' => null, 'rain_module_id' => null, 'sum_rain_24' => null,
];
}
@@ -50,6 +50,7 @@ final class StationMapper
'current' => self::floatOrNull(self::dashboard($device)['Pressure'] ?? null),
'trend' => self::stringOrNull(self::dashboard($device)['pressure_trend'] ?? null),
],
+ 'outdoor_module_id' => $outdoor === null ? null : self::stringOrNull($outdoor['_id'] ?? null),
'rain_module_id' => $rain === null ? null : self::stringOrNull($rain['_id'] ?? null),
'sum_rain_24' => self::floatOrNull(self::dashboard($rain)['sum_rain_24'] ?? null),
];
diff --git a/src/WeatherSource.php b/src/WeatherSource.php
index 33b35cd..22c8590 100644
--- a/src/WeatherSource.php
+++ b/src/WeatherSource.php
@@ -16,6 +16,9 @@ interface WeatherSource
/** @return array de "body" van Netatmo getmeasure (timestamp => [hPa]) voor het basisstation */
public function pressureHistory(string $deviceId, int $begin, int $end): array;
+ /** @return array de "body" van Netatmo getmeasure (timestamp => [°C]) voor de buitenmodule */
+ public function temperatureHistory(string $deviceId, string $moduleId, int $begin, int $end): array;
+
/** @return array{daily: array, hourly: array} de "daily"- en "hourly"-blokken van Open-Meteo */
public function forecast(float $lat, float $lon, string $timezone): array;
}
diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php
index c0a44b3..bb35a33 100644
--- a/tests/ConfigTest.php
+++ b/tests/ConfigTest.php
@@ -28,7 +28,7 @@ final class ConfigTest extends TestCase
self::assertSame('Europe/Berlin', $config->get('timezone'));
self::assertSame('fixture', $config->get('data_source'));
- self::assertSame(['stations' => 300, 'measure' => 900, 'pressure' => 900, 'forecast' => 3600, 'radar' => 240], $config->get('cache_ttl'));
+ self::assertSame(['stations' => 300, 'measure' => 900, 'pressure' => 900, 'temperature' => 900, 'forecast' => 3600, 'radar' => 240], $config->get('cache_ttl'));
self::assertSame([], $config->get('indoor_modules'));
self::assertNull($config->get('netatmo_device_id'));
}
@@ -39,7 +39,7 @@ final class ConfigTest extends TestCase
$config = Config::load($this->file);
self::assertSame('Europe/Amsterdam', $config->get('timezone'));
- self::assertSame(['stations' => 60, 'measure' => 900, 'pressure' => 900, 'forecast' => 3600, 'radar' => 240], $config->get('cache_ttl'));
+ self::assertSame(['stations' => 60, 'measure' => 900, 'pressure' => 900, 'temperature' => 900, 'forecast' => 3600, 'radar' => 240], $config->get('cache_ttl'));
}
public function testUnknownKeyReturnsGivenDefault(): void
diff --git a/tests/DashboardServiceTest.php b/tests/DashboardServiceTest.php
index a562ab3..88f4c16 100644
--- a/tests/DashboardServiceTest.php
+++ b/tests/DashboardServiceTest.php
@@ -32,7 +32,7 @@ final class DashboardServiceTest extends TestCase
return new DashboardService(
$this->source,
new Cache($this->dir),
- ['stations' => 300, 'measure' => 900, 'pressure' => 900, 'forecast' => 3600],
+ ['stations' => 300, 'measure' => 900, 'pressure' => 900, 'temperature' => 900, 'forecast' => 3600],
'Europe/Amsterdam',
$lat,
$lon,
@@ -46,7 +46,7 @@ final class DashboardServiceTest extends TestCase
{
$p = $this->service()->build();
- self::assertSame(['generated_at', 'timezone', 'station', 'outdoor', 'indoor', 'rain', 'pressure', 'forecast', 'forecast_stale', 'errors'], array_keys($p));
+ self::assertSame(['generated_at', 'timezone', 'station', 'outdoor', 'outdoor_history', 'indoor', 'rain', 'pressure', 'forecast', 'forecast_stale', 'errors'], array_keys($p));
self::assertSame('2026-09-11T14:32:05+02:00', $p['generated_at']);
self::assertSame('Europe/Berlin', $p['timezone']);
self::assertSame(['measured_at' => '2026-09-11T14:30:12+02:00', 'stale' => false], $p['station']);
@@ -83,6 +83,32 @@ final class DashboardServiceTest extends TestCase
self::assertSame((new \DateTimeImmutable('2026-09-11 12:32:05 UTC'))->getTimestamp(), $end);
}
+ public function testOutdoorHistoryCoversTodayFromLocalMidnight(): void
+ {
+ $p = $this->service()->build();
+
+ [$deviceId, $moduleId, $begin, $end] = $this->source->lastArgs['temperature'];
+ self::assertSame('70:ee:50:00:00:01', $deviceId);
+ self::assertSame('02:00:00:00:00:01', $moduleId, 'de buitenmodule, niet het basisstation');
+ self::assertSame((new \DateTimeImmutable('2026-09-11 00:00', new \DateTimeZone('Europe/Berlin')))->getTimestamp(), $begin);
+ self::assertSame((new \DateTimeImmutable('2026-09-11 12:32:05 UTC'))->getTimestamp(), $end);
+
+ self::assertNotEmpty($p['outdoor_history']['points']);
+ self::assertSame(['at', 'temp'], array_keys($p['outdoor_history']['points'][0]));
+ self::assertFalse($p['outdoor_history']['stale']);
+ }
+
+ public function testOutdoorHistoryFailureLeavesTheRestIntact(): void
+ {
+ $this->source->responses['temperature'] = new UpstreamException('500');
+
+ $p = $this->service()->build();
+
+ self::assertSame(['points' => [], 'stale' => true], $p['outdoor_history']);
+ self::assertSame(16.4, $p['outdoor']['temp'], 'de actuele waarden komen uit stationsdata en blijven staan');
+ self::assertSame(['netatmo_unavailable'], $p['errors']);
+ }
+
public function testPressureHistoryIsRequestedForLast24Hours(): void
{
$this->service()->build();
@@ -130,6 +156,8 @@ final class DashboardServiceTest extends TestCase
self::assertNull($p['rain']['today']);
self::assertSame(0, $this->source->calls['measure'], 'zonder regenmeter-id geen getmeasure-call');
self::assertSame(0, $this->source->calls['pressure'], 'zonder device-id geen luchtdruk-call');
+ self::assertSame(0, $this->source->calls['temperature'], 'zonder buitenmodule geen temperatuur-call');
+ self::assertSame(['points' => [], 'stale' => false], $p['outdoor_history']);
self::assertSame(['current' => null, 'trend' => null, 'history' => [], 'stale' => false], $p['pressure']);
self::assertSame('Europe/Amsterdam', $p['timezone'], 'fallback-tijdzone uit config');
self::assertSame(['netatmo_unavailable', 'forecast_unavailable'], $p['errors']);
@@ -203,7 +231,7 @@ final class DashboardServiceTest extends TestCase
$this->service()->build();
$this->service('2026-09-11 12:36:05 UTC')->build();
- self::assertSame(['stations' => 1, 'measure' => 1, 'pressure' => 1, 'forecast' => 1], $this->source->calls);
+ self::assertSame(['stations' => 1, 'measure' => 1, 'pressure' => 1, 'temperature' => 1, 'forecast' => 1], $this->source->calls);
$this->service('2026-09-11 12:38:05 UTC')->build();
self::assertSame(2, $this->source->calls['stations'], 'stations na 5 min opnieuw');
diff --git a/tests/FakeSource.php b/tests/FakeSource.php
index 6a78ed3..7da26da 100644
--- a/tests/FakeSource.php
+++ b/tests/FakeSource.php
@@ -13,7 +13,7 @@ final class FakeSource implements WeatherSource
public array $responses = [];
/** @var array */
- public array $calls = ['stations' => 0, 'measure' => 0, 'pressure' => 0, 'forecast' => 0];
+ public array $calls = ['stations' => 0, 'measure' => 0, 'pressure' => 0, 'temperature' => 0, 'forecast' => 0];
/** @var array */
public array $lastArgs = [];
@@ -25,6 +25,7 @@ final class FakeSource implements WeatherSource
'stations' => json_decode((string) file_get_contents(__DIR__ . '/fixtures/getstationsdata.json'), true)['body'],
'measure' => json_decode((string) file_get_contents(__DIR__ . '/fixtures/getmeasure.json'), true)['body'],
'pressure' => json_decode((string) file_get_contents(__DIR__ . '/fixtures/getmeasure-pressure.json'), true)['body'],
+ 'temperature' => json_decode((string) file_get_contents(__DIR__ . '/fixtures/getmeasure-temperature.json'), true)['body'],
'forecast' => array_intersect_key(
json_decode((string) file_get_contents(__DIR__ . '/fixtures/forecast.json'), true),
['daily' => null, 'hourly' => null],
@@ -48,6 +49,11 @@ final class FakeSource implements WeatherSource
return $this->answer('pressure', func_get_args());
}
+ public function temperatureHistory(string $deviceId, string $moduleId, int $begin, int $end): array
+ {
+ return $this->answer('temperature', func_get_args());
+ }
+
public function forecast(float $lat, float $lon, string $timezone): array
{
return $this->answer('forecast', func_get_args());
diff --git a/tests/PressureHistoryTest.php b/tests/MeasureSeriesTest.php
similarity index 52%
rename from tests/PressureHistoryTest.php
rename to tests/MeasureSeriesTest.php
index 031dfa6..d48c824 100644
--- a/tests/PressureHistoryTest.php
+++ b/tests/MeasureSeriesTest.php
@@ -5,16 +5,16 @@ declare(strict_types=1);
namespace Weerscherm\Tests;
use PHPUnit\Framework\TestCase;
-use Weerscherm\PressureHistory;
+use Weerscherm\MeasureSeries;
-final class PressureHistoryTest extends TestCase
+final class MeasureSeriesTest extends TestCase
{
public function testMapsAndSortsPoints(): void
{
$body = json_decode((string) file_get_contents(__DIR__ . '/fixtures/getmeasure-pressure.json'), true)['body'];
$shuffled = array_reverse($body, true);
- $points = PressureHistory::map($shuffled, new \DateTimeZone('Europe/Berlin'));
+ $points = MeasureSeries::map($shuffled, new \DateTimeZone('Europe/Berlin'), 'hpa');
self::assertCount(49, $points);
self::assertSame('2026-09-10T14:30:00+02:00', $points[0]['at']);
@@ -25,8 +25,19 @@ final class PressureHistoryTest extends TestCase
public function testSkipsGarbage(): void
{
- $points = PressureHistory::map(['abc' => [1000.0], '1789129800' => ['x'], '1789133400' => [1013.5]], new \DateTimeZone('UTC'));
+ $points = MeasureSeries::map(['abc' => [1000.0], '1789129800' => ['x'], '1789133400' => [1013.5]], new \DateTimeZone('UTC'), 'hpa');
self::assertSame([['at' => '2026-09-11T13:30:00+00:00', 'hpa' => 1013.5]], $points);
}
+
+ public function testTheValueFieldIsNamedPerMeasurement(): void
+ {
+ $body = ['1789129800' => [16.4], '1789131600' => [16.9]];
+
+ $temps = MeasureSeries::map($body, new \DateTimeZone('Europe/Berlin'), 'temp');
+
+ self::assertSame(['at', 'temp'], array_keys($temps[0]));
+ self::assertSame(16.4, $temps[0]['temp']);
+ self::assertSame(16.9, $temps[1]['temp']);
+ }
}
diff --git a/tests/fixtures/getmeasure-temperature.json b/tests/fixtures/getmeasure-temperature.json
new file mode 100644
index 0000000..3fe9996
--- /dev/null
+++ b/tests/fixtures/getmeasure-temperature.json
@@ -0,0 +1,95 @@
+{
+ "body": {
+ "1789077600": [
+ 11.9
+ ],
+ "1789079400": [
+ 11.9
+ ],
+ "1789081200": [
+ 10.8
+ ],
+ "1789083000": [
+ 10.8
+ ],
+ "1789084800": [
+ 9.9
+ ],
+ "1789086600": [
+ 9.9
+ ],
+ "1789088400": [
+ 9.4
+ ],
+ "1789090200": [
+ 9.4
+ ],
+ "1789092000": [
+ 9.2
+ ],
+ "1789093800": [
+ 9.2
+ ],
+ "1789095600": [
+ 9.4
+ ],
+ "1789097400": [
+ 9.4
+ ],
+ "1789099200": [
+ 9.9
+ ],
+ "1789101000": [
+ 9.9
+ ],
+ "1789102800": [
+ 10.8
+ ],
+ "1789104600": [
+ 10.8
+ ],
+ "1789106400": [
+ 11.9
+ ],
+ "1789108200": [
+ 11.9
+ ],
+ "1789110000": [
+ 13.1
+ ],
+ "1789111800": [
+ 13.1
+ ],
+ "1789113600": [
+ 14.5
+ ],
+ "1789115400": [
+ 14.5
+ ],
+ "1789117200": [
+ 15.9
+ ],
+ "1789119000": [
+ 15.9
+ ],
+ "1789120800": [
+ 17.2
+ ],
+ "1789122600": [
+ 17.2
+ ],
+ "1789124400": [
+ 18.2
+ ],
+ "1789126200": [
+ 18.2
+ ],
+ "1789128000": [
+ 19.1
+ ],
+ "1789129800": [
+ 19.1
+ ]
+ },
+ "status": "ok"
+}