added weather again
This commit is contained in:
parent
f7c30d71d2
commit
e2b0476aaa
@ -9,12 +9,12 @@ import {registerLocaleData} from '@angular/common';
|
|||||||
import localeDe from '@angular/common/locales/de';
|
import localeDe from '@angular/common/locales/de';
|
||||||
import localeDeExtra from '@angular/common/locales/extra/de';
|
import localeDeExtra from '@angular/common/locales/extra/de';
|
||||||
import {stompServiceFactory} from './common';
|
import {stompServiceFactory} from './common';
|
||||||
import {BarController, BarElement, Chart, Legend, LinearScale, TimeScale, Tooltip} from 'chart.js';
|
import {BarController, BarElement, Chart, Filler, Legend, LinearScale, LineController, LineElement, PointElement, TimeScale, Tooltip} from 'chart.js';
|
||||||
import 'chartjs-adapter-date-fns';
|
import 'chartjs-adapter-date-fns';
|
||||||
|
|
||||||
registerLocaleData(localeDe, 'de-DE', localeDeExtra);
|
registerLocaleData(localeDe, 'de-DE', localeDeExtra);
|
||||||
|
|
||||||
Chart.register(TimeScale, LinearScale, BarController, BarElement, Tooltip, Legend);
|
Chart.register(TimeScale, LinearScale, BarController, BarElement, Tooltip, Legend, LineController, PointElement, LineElement, Filler);
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
providers: [
|
providers: [
|
||||||
|
|||||||
@ -2,6 +2,15 @@
|
|||||||
|
|
||||||
<app-location-power [location]="location"></app-location-power>
|
<app-location-power [location]="location"></app-location-power>
|
||||||
|
|
||||||
|
<div class="Section3">
|
||||||
|
<div class="SectionHeading">
|
||||||
|
<div class="SectionHeadingText">
|
||||||
|
Wettervorhersage
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-weather-component [location]="location"></app-weather-component>
|
||||||
|
</div>
|
||||||
|
|
||||||
<app-location-energy [location]="location" [interval]="Interval.DAY" [offset]="offsetDay" unit="⌀W" [factor]="12 * 1000" [maxY]="850" [minY]="-850">
|
<app-location-energy [location]="location" [interval]="Interval.DAY" [offset]="offsetDay" unit="⌀W" [factor]="12 * 1000" [maxY]="850" [minY]="-850">
|
||||||
<div style="display: flex; width: 100%; gap: 0.25em;">
|
<div style="display: flex; width: 100%; gap: 0.25em;">
|
||||||
<div (click)="offsetDayAdd(+1)">←</div>
|
<div (click)="offsetDayAdd(+1)">←</div>
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import {SeriesType} from '../../series/SeriesType';
|
|||||||
import {DateService} from '../../date.service';
|
import {DateService} from '../../date.service';
|
||||||
import {LocationPower} from '../power/location-power';
|
import {LocationPower} from '../power/location-power';
|
||||||
import {ConfigService} from '../../config.service';
|
import {ConfigService} from '../../config.service';
|
||||||
|
import {WeatherComponent} from '../../weather/plot/weather-component';
|
||||||
|
|
||||||
export function paramNumberOrNull(params: Params, key: string): number | null {
|
export function paramNumberOrNull(params: Params, key: string): number | null {
|
||||||
const param = params[key];
|
const param = params[key];
|
||||||
@ -35,7 +36,8 @@ export function paramNumberOrNull(params: Params, key: string): number | null {
|
|||||||
Number,
|
Number,
|
||||||
SeriesSelect,
|
SeriesSelect,
|
||||||
LocationEnergy,
|
LocationEnergy,
|
||||||
LocationPower
|
LocationPower,
|
||||||
|
WeatherComponent
|
||||||
],
|
],
|
||||||
templateUrl: './location-detail.html',
|
templateUrl: './location-detail.html',
|
||||||
styleUrl: './location-detail.less',
|
styleUrl: './location-detail.less',
|
||||||
|
|||||||
@ -10,8 +10,10 @@ import {formatNumber} from '@angular/common';
|
|||||||
|
|
||||||
const COLOR_BACK_PURCHASE = "#ffb9b9";
|
const COLOR_BACK_PURCHASE = "#ffb9b9";
|
||||||
const COLOR_BACK_DELIVER = "#ff59ff";
|
const COLOR_BACK_DELIVER = "#ff59ff";
|
||||||
|
// noinspection JSUnusedLocalSymbols
|
||||||
const COLOR_BACK_PRODUCE = "#5cbcff";
|
const COLOR_BACK_PRODUCE = "#5cbcff";
|
||||||
const COLOR_BACK_SELF = "#60ff8c";
|
const COLOR_BACK_SELF = "#60ff8c";
|
||||||
|
// noinspection JSUnusedLocalSymbols
|
||||||
const COLOR_BACK_CONSUME = "#ffc07a";
|
const COLOR_BACK_CONSUME = "#ffc07a";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -71,7 +73,6 @@ export class EnergyCharts implements OnChanges {
|
|||||||
locale: de
|
locale: de
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
bounds: 'ticks',
|
|
||||||
},
|
},
|
||||||
y: {},
|
y: {},
|
||||||
},
|
},
|
||||||
|
|||||||
25
src/main/angular/src/app/weather/WeatherHour.ts
Normal file
25
src/main/angular/src/app/weather/WeatherHour.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import {validateDate, validateNumber} from '../common';
|
||||||
|
|
||||||
|
export class WeatherHour {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly date: Date,
|
||||||
|
readonly clouds: number,
|
||||||
|
readonly irradiation: number,
|
||||||
|
readonly precipitation: number,
|
||||||
|
readonly temperature: number,
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json: any): WeatherHour {
|
||||||
|
return new WeatherHour(
|
||||||
|
validateDate(json.date),
|
||||||
|
validateNumber(json.clouds),
|
||||||
|
validateNumber(json.irradiation),
|
||||||
|
validateNumber(json.precipitation),
|
||||||
|
validateNumber(json.temperature),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
<div #container class="container">
|
||||||
|
<canvas #chartCanvas></canvas>
|
||||||
|
</div>
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
238
src/main/angular/src/app/weather/plot/weather-component.ts
Normal file
238
src/main/angular/src/app/weather/plot/weather-component.ts
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
import {AfterViewInit, Component, ElementRef, Inject, Input, LOCALE_ID, ViewChild} from '@angular/core';
|
||||||
|
import {WeatherService} from '../weather-service';
|
||||||
|
import {WeatherHour} from '../WeatherHour';
|
||||||
|
import {Chart} from 'chart.js';
|
||||||
|
|
||||||
|
import {de} from 'date-fns/locale';
|
||||||
|
import {format} from 'date-fns';
|
||||||
|
import {Location} from '../../location/Location';
|
||||||
|
import {formatNumber} from '@angular/common';
|
||||||
|
|
||||||
|
export function toPoint(f: (hour: WeatherHour) => number): (hour: WeatherHour) => { x: number, y: number } {
|
||||||
|
return (hour: WeatherHour) => {
|
||||||
|
return {
|
||||||
|
x: hour.date.getTime(),
|
||||||
|
y: f(hour),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function temperatureColor(value: number | null | undefined) {
|
||||||
|
if (!value) {
|
||||||
|
return "black";
|
||||||
|
} else if (value < 0) {
|
||||||
|
return 'blue';
|
||||||
|
} else if (value < 20) {
|
||||||
|
return '#c1b100';
|
||||||
|
} else if (value < 30) {
|
||||||
|
return '#ff8100';
|
||||||
|
}
|
||||||
|
return TEMPERATURE_HIGH_COLOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEMPERATURE_HIGH_COLOR = '#FF0000';
|
||||||
|
const PRECIPITATION_COLOR = '#0000FF';
|
||||||
|
const CLOUDS_COLOR = '#cccccc';
|
||||||
|
const SUN_COLOR = '#ffc400';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-weather-component',
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './weather-component.html',
|
||||||
|
styleUrl: './weather-component.less'
|
||||||
|
})
|
||||||
|
export class WeatherComponent implements AfterViewInit {
|
||||||
|
|
||||||
|
@ViewChild('chartCanvas')
|
||||||
|
protected canvasRef!: ElementRef<HTMLCanvasElement>;
|
||||||
|
|
||||||
|
@ViewChild('container')
|
||||||
|
protected chartContainer!: ElementRef<HTMLDivElement>;
|
||||||
|
|
||||||
|
private chart!: Chart;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
location!: Location;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(LOCALE_ID) readonly locale: string,
|
||||||
|
readonly weatherService: WeatherService,
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
this.chart = new Chart(this.canvasRef.nativeElement, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
datasets: [],
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
animation: false,
|
||||||
|
interaction: {
|
||||||
|
mode: 'index',
|
||||||
|
intersect: false
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
mode: 'index',
|
||||||
|
intersect: false,
|
||||||
|
itemSort: (a, b) => b.datasetIndex - a.datasetIndex,
|
||||||
|
usePointStyle: true,
|
||||||
|
callbacks: {
|
||||||
|
title: function (items) {
|
||||||
|
const date = items[0].parsed.x as unknown as Date;
|
||||||
|
return format(date, 'EE dd.MM. HH:mm', {locale: de});
|
||||||
|
},
|
||||||
|
label: ((ctx: any) => {
|
||||||
|
const groups = /^(?<name>.+)\[(?<unit>.+)]$/.exec(ctx.dataset.label || '')?.groups;
|
||||||
|
if (groups) {
|
||||||
|
const value = ctx.parsed.y === null ? '-' : formatNumber(Math.abs(ctx.parsed.y), this.locale, '0.2-2');
|
||||||
|
return `${value} ${groups['unit']} ${groups['name']}`;
|
||||||
|
}
|
||||||
|
return ctx.dataset.label;
|
||||||
|
}) as any,
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: "Wetter",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
type: 'time',
|
||||||
|
time: {
|
||||||
|
unit: "day",
|
||||||
|
displayFormats: {
|
||||||
|
day: "EE dd.MM"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
adapters: {
|
||||||
|
date: {
|
||||||
|
locale: de,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
y_temperature: {
|
||||||
|
display: true,
|
||||||
|
position: "right",
|
||||||
|
title: {
|
||||||
|
display: false,
|
||||||
|
text: "Temperatur [°C]",
|
||||||
|
color: TEMPERATURE_HIGH_COLOR,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
color: context => temperatureColor(context.tick.value),
|
||||||
|
},
|
||||||
|
min: -10,
|
||||||
|
max: 35,
|
||||||
|
},
|
||||||
|
y_precipitation: {
|
||||||
|
display: false,
|
||||||
|
grid: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
display: false,
|
||||||
|
text: "Niederschlag [mm]",
|
||||||
|
color: PRECIPITATION_COLOR,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
color: PRECIPITATION_COLOR,
|
||||||
|
},
|
||||||
|
min: 0,
|
||||||
|
max: 15,
|
||||||
|
},
|
||||||
|
y_sun: {
|
||||||
|
display: false,
|
||||||
|
grid: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
position: "right",
|
||||||
|
title: {
|
||||||
|
display: false,
|
||||||
|
text: "Sonne [kWh/m²]",
|
||||||
|
color: SUN_COLOR,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
color: SUN_COLOR,
|
||||||
|
},
|
||||||
|
min: 0,
|
||||||
|
max: 1000,
|
||||||
|
},
|
||||||
|
y_clouds: {
|
||||||
|
display: false,
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: "Wolkenbedeckung [%]",
|
||||||
|
color: CLOUDS_COLOR,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
color: CLOUDS_COLOR,
|
||||||
|
},
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.weatherService.forLocation(this.location, hours => {
|
||||||
|
const now = Date.now();
|
||||||
|
const filtered = hours.filter(h => h.date.getTime() >= now);
|
||||||
|
this.chart.data.datasets.push({
|
||||||
|
label: "Niederschlag [mm]",
|
||||||
|
categoryPercentage: 1.0,
|
||||||
|
barPercentage: 1.0,
|
||||||
|
type: "bar",
|
||||||
|
yAxisID: "y_precipitation",
|
||||||
|
data: filtered.map(toPoint(h => h.precipitation)),
|
||||||
|
borderColor: PRECIPITATION_COLOR,
|
||||||
|
backgroundColor: PRECIPITATION_COLOR + '66',
|
||||||
|
borderWidth: 0,
|
||||||
|
pointStyle: "rect",
|
||||||
|
});
|
||||||
|
this.chart.data.datasets.push({
|
||||||
|
label: "Sonne [W/m²]",
|
||||||
|
type: "line",
|
||||||
|
fill: "origin",
|
||||||
|
yAxisID: "y_sun",
|
||||||
|
data: filtered.map(toPoint(h => h.irradiation)),
|
||||||
|
borderColor: SUN_COLOR,
|
||||||
|
backgroundColor: SUN_COLOR + '88',
|
||||||
|
borderWidth: 0,
|
||||||
|
pointRadius: 0,
|
||||||
|
});
|
||||||
|
this.chart.data.datasets.push({
|
||||||
|
label: "Temperatur [°C]",
|
||||||
|
type: "line",
|
||||||
|
yAxisID: "y_temperature",
|
||||||
|
data: filtered.map(toPoint(h => h.temperature)),
|
||||||
|
backgroundColor: TEMPERATURE_HIGH_COLOR + '66',
|
||||||
|
borderWidth: 0,
|
||||||
|
pointRadius: 1,
|
||||||
|
pointBackgroundColor: context => temperatureColor(context.parsed.y),
|
||||||
|
pointStyle: "point",
|
||||||
|
});
|
||||||
|
this.chart.data.datasets.push({
|
||||||
|
label: "Bewölkung [%]",
|
||||||
|
type: "line",
|
||||||
|
fill: "origin",
|
||||||
|
yAxisID: "y_clouds",
|
||||||
|
data: filtered.map(toPoint(h => h.clouds)),
|
||||||
|
borderColor: CLOUDS_COLOR,
|
||||||
|
backgroundColor: CLOUDS_COLOR + '88',
|
||||||
|
borderWidth: 0,
|
||||||
|
pointRadius: 0,
|
||||||
|
});
|
||||||
|
this.chart.update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
22
src/main/angular/src/app/weather/weather-service.ts
Normal file
22
src/main/angular/src/app/weather/weather-service.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {ApiService, CrudService, Next, WebsocketService} from '../common';
|
||||||
|
import {WeatherHour} from './WeatherHour';
|
||||||
|
import {Location} from '../location/Location';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class WeatherService extends CrudService<WeatherHour> {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
api: ApiService,
|
||||||
|
ws: WebsocketService,
|
||||||
|
) {
|
||||||
|
super(api, ws, ['Weather'], WeatherHour.fromJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
forLocation(location: Location, next: Next<WeatherHour[]>) {
|
||||||
|
this.getList(['forLocation', location.id], next);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -71,6 +71,7 @@ div {
|
|||||||
> .SectionHeading {
|
> .SectionHeading {
|
||||||
display: flex;
|
display: flex;
|
||||||
color: dimgray;
|
color: dimgray;
|
||||||
|
font-size: 80%;
|
||||||
margin-top: -1.25em;
|
margin-top: -1.25em;
|
||||||
|
|
||||||
> .SectionHeadingText {
|
> .SectionHeadingText {
|
||||||
|
|||||||
@ -11,10 +11,6 @@ public class WeatherConfig {
|
|||||||
|
|
||||||
private String urlPattern = "https://api.brightsky.dev/weather?date={date}&lat={latitude}&lon={longitude}&units=dwd";
|
private String urlPattern = "https://api.brightsky.dev/weather?date={date}&lat={latitude}&lon={longitude}&units=dwd";
|
||||||
|
|
||||||
private double latitude = 49.320789191091194;
|
|
||||||
|
|
||||||
private double longitude = 7.102111982262271;
|
|
||||||
|
|
||||||
private int pastDays = 9;
|
private int pastDays = 9;
|
||||||
|
|
||||||
private int futureDays = 9;
|
private int futureDays = 9;
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package de.ph87.data.weather;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@ -16,9 +17,9 @@ public class WeatherController {
|
|||||||
|
|
||||||
private final WeatherService weatherService;
|
private final WeatherService weatherService;
|
||||||
|
|
||||||
@GetMapping("all")
|
@GetMapping("forLocation/{id}")
|
||||||
public List<WeatherHour> all() {
|
public List<WeatherHour> forLocation(@PathVariable final long id) {
|
||||||
return weatherService.all();
|
return weatherService.forLocation(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,17 @@
|
|||||||
package de.ph87.data.weather;
|
package de.ph87.data.weather;
|
||||||
|
|
||||||
|
import de.ph87.data.location.LocationDto;
|
||||||
|
import de.ph87.data.location.LocationRepository;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -20,7 +24,9 @@ import java.time.ZoneId;
|
|||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ -28,43 +34,53 @@ import java.util.List;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class WeatherService {
|
public class WeatherService {
|
||||||
|
|
||||||
private List<WeatherHour> hours = new ArrayList<>();
|
private final LocationRepository locationRepository;
|
||||||
|
|
||||||
|
private final Map<Long, List<WeatherHour>> locationHours = new HashMap<>();
|
||||||
|
|
||||||
private final WeatherConfig weatherConfig;
|
private final WeatherConfig weatherConfig;
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<WeatherHour> all() {
|
public List<WeatherHour> forLocation(final long id) {
|
||||||
|
final List<WeatherHour> hours = this.locationHours.get(id);
|
||||||
|
if (hours == null) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
return new ArrayList<>(hours);
|
return new ArrayList<>(hours);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(cron = "0 0 * * * *")
|
@Scheduled(cron = "0 0 * * * *")
|
||||||
@EventListener(ApplicationStartedEvent.class)
|
@EventListener(ApplicationStartedEvent.class)
|
||||||
public void update() {
|
public void updateAll() {
|
||||||
|
locationRepository.findAllDto().forEach(this::update);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update(@NonNull final LocationDto location) {
|
||||||
try {
|
try {
|
||||||
final LocalDate today = LocalDate.now();
|
final LocalDate today = LocalDate.now();
|
||||||
final LocalDate first = today.minusDays(weatherConfig.getPastDays());
|
final LocalDate first = today.minusDays(weatherConfig.getPastDays());
|
||||||
final LocalDate end = today.plusDays(weatherConfig.getFutureDays());
|
final LocalDate end = today.plusDays(weatherConfig.getFutureDays());
|
||||||
final List<WeatherHour> hours = new ArrayList<>();
|
final List<WeatherHour> hours = new ArrayList<>();
|
||||||
log.debug("Updating Weather...");
|
log.debug("Updating Weather for Location: {}", location.name);
|
||||||
for (LocalDate day = first; !day.isAfter(end); day = day.plusDays(1)) {
|
for (LocalDate day = first; !day.isAfter(end); day = day.plusDays(1)) {
|
||||||
fetchDay(day).getWeather().stream().map(WeatherHour::new).forEach(hours::add);
|
fetchDay(location, day).getWeather().stream().map(WeatherHour::new).forEach(hours::add);
|
||||||
}
|
}
|
||||||
this.hours = hours;
|
this.locationHours.put(location.id, hours);
|
||||||
log.info("Weather update complete");
|
log.info("Weather update complete for Location: {}", location.name);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed fetching Weather data: {}", e.toString());
|
log.error("Failed fetching Weather data for Location: {}: {}", location.name, e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public BrightSkyDto fetchDay(@NonNull final LocalDate day) throws IOException {
|
public BrightSkyDto fetchDay(@NonNull final LocationDto location, @NonNull final LocalDate day) throws IOException {
|
||||||
final String url = weatherConfig
|
final String url = weatherConfig
|
||||||
.getUrlPattern()
|
.getUrlPattern()
|
||||||
.replace("{date}", ZonedDateTime.of(day, LocalTime.MIDNIGHT, ZoneId.systemDefault()).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME))
|
.replace("{date}", ZonedDateTime.of(day, LocalTime.MIDNIGHT, ZoneId.systemDefault()).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME))
|
||||||
.replace("{latitude}", weatherConfig.getLatitude() + "")
|
.replace("{latitude}", location.getLatitude() + "")
|
||||||
.replace("{longitude}", weatherConfig.getLongitude() + "");
|
.replace("{longitude}", location.getLongitude() + "");
|
||||||
final HttpURLConnection connection = (HttpURLConnection) URI.create(url).toURL().openConnection();
|
final HttpURLConnection connection = (HttpURLConnection) URI.create(url).toURL().openConnection();
|
||||||
final int responseCode = connection.getResponseCode();
|
final int responseCode = connection.getResponseCode();
|
||||||
final byte[] bytes = connection.getInputStream().readAllBytes();
|
final byte[] bytes = connection.getInputStream().readAllBytes();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user