package de.ph87.data.weather; import com.fasterxml.jackson.databind.*; import lombok.*; import lombok.extern.slf4j.*; import org.springframework.boot.context.event.*; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.*; import org.springframework.stereotype.*; import java.io.*; import java.net.*; import java.nio.charset.*; import java.time.*; import java.time.format.*; import java.util.*; @Slf4j @Service @EnableScheduling @RequiredArgsConstructor public class WeatherService { private List days = new ArrayList<>(); private final WeatherConfig weatherConfig; private final ObjectMapper objectMapper; @NonNull public List all() { return new ArrayList<>(days); } @Scheduled(cron = "0 0 * * * *") @EventListener(ApplicationStartedEvent.class) public void update() { try { final LocalDate today = LocalDate.now(); final LocalDate first = today.minusDays(weatherConfig.getPastDays()); final LocalDate end = today.plusDays(weatherConfig.getFutureDays()); final List newDays = new ArrayList<>(); log.debug("Updating Weather..."); for (LocalDate day = first; !day.isAfter(end); day = day.plusDays(1)) { final WeatherDay weatherDay = new WeatherDay(fetchDay(day)); newDays.add(weatherDay); if (log.isDebugEnabled()) { log.debug(" {}:", weatherDay); for (WeatherDay.Hour hour : weatherDay.getHours()) { log.debug(" %s: %4s clouds, %9s, %4s".formatted(hour.date.toLocalTime(), hour.getClouds(), hour.getIrradiation(), hour.getPrecipitation())); } } } days = newDays; log.info("Weather update complete"); } catch (IOException e) { log.error(e.toString()); } } @NonNull public BrightSkyDto fetchDay(@NonNull final LocalDate day) throws IOException { final String url = weatherConfig.getUrlPattern() .replace("{date}", ZonedDateTime.of(day, LocalTime.MIDNIGHT, ZoneId.systemDefault()).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)) .replace("{latitude}", weatherConfig.getLatitude() + "") .replace("{longitude}", weatherConfig.getLongitude() + ""); final HttpURLConnection connection = (HttpURLConnection) URI.create(url).toURL().openConnection(); final int responseCode = connection.getResponseCode(); final byte[] bytes = connection.getInputStream().readAllBytes(); if (responseCode / 100 != 2) { throw new IOException("responseCode=%d, message: %s".formatted(responseCode, new String(bytes, StandardCharsets.UTF_8))); } return objectMapper.readValue(bytes, BrightSkyDto.class); } }