1+ <?php namespace de \thekid \dialog \import ;
2+
3+ use de \thekid \dialog \OpenMeteo ;
4+ use lang \FormatException ;
5+ use util \{Date , Dates , TimeZone , TimeInterval };
6+ use webservices \rest \Endpoint ;
7+
8+ /** Aggregates weather for entries using OpenMeteo */
9+ class LookupWeather extends Task {
10+ private $ weather = new OpenMeteo ('https://open-meteo.com/v1 ' );
11+
12+ public function __construct (private array<string, mixed > $ entry , private array <mixed> $ images ) { }
13+
14+ public function execute (Endpoint $ api ) {
15+ $ weather = [];
16+ $ min = $ max = null ;
17+ foreach ($ this ->entry ['locations ' ] as $ location ) {
18+ $ tz = new TimeZone ($ location ['timezone ' ]);
19+
20+ // Infer date range from first and last images
21+ $ dates = [];
22+ foreach ($ this ->images as $ image ) {
23+ $ dates []= new Date (strtr ($ image ['meta ' ]['dateTime ' ], ['+00:00 ' => '' ]), $ tz );
24+ }
25+ usort ($ dates , fn ($ a , $ b ) => $ b ->compareTo ($ a ));
26+ $ first = current ($ dates );
27+ $ last = end ($ dates );
28+
29+ // Filter hourly weather for the duration of the images
30+ $ result = $ this ->weather ->lookup ($ location ['lat ' ], $ location ['lon ' ], $ first , $ last , $ tz );
31+ $ start = array_search (Dates::truncate ($ first , TimeInterval::$ HOURS )->toString ('Y-m-d\TH:i ' ), $ result ['hourly ' ]['time ' ]);
32+ $ end = array_search (Dates::truncate ($ last , TimeInterval::$ HOURS )->toString ('Y-m-d\TH:i ' ), $ result ['hourly ' ]['time ' ]);
33+
34+ // Determine most common weather codes and temperature range
35+ $ codes = array_count_values (array_slice ($ result ['hourly ' ]['weather_code ' ], $ start , 1 + ($ end - $ start )));
36+ $ temp = array_slice ($ result ['hourly ' ]['apparent_temperature ' ], $ start , 1 + ($ end - $ start ));
37+ $ min = null === $ min ? min ($ temp ) : min ($ min , min ($ temp ));
38+ $ max = null === $ max ? max ($ temp ) : max ($ max , max ($ temp ));
39+
40+ arsort ($ codes );
41+ foreach ($ codes as $ code => $ count ) {
42+ $ weather [$ code ]??= 0 ;
43+ $ weather [$ code ]+= $ count ;
44+ }
45+
46+ yield $ location ['name ' ] => sprintf ('#%02d @ %.1f-%.1f °C ' , key ($ codes ), min ($ temp ), max ($ temp ));
47+ }
48+
49+ arsort ($ weather );
50+ return [
51+ 'code ' => sprintf ('%02d ' , key ($ weather )),
52+ 'min ' => $ min ,
53+ 'max ' => $ max ,
54+ ];
55+ }
56+
57+ public function description (): string { return 'Looking up weather ' ; }
58+ }
0 commit comments