diff --git a/projects/common/src/fm/models/WeatherData.ts b/projects/common/src/fm/models/WeatherData.ts new file mode 100644 index 0000000..b450d4b --- /dev/null +++ b/projects/common/src/fm/models/WeatherData.ts @@ -0,0 +1,10 @@ +export interface WeatherData { + time: Date; + minTemp: number; + maxTemp: number; + relativeHumidity: number; + rain: number; + wspd?: number; + wdir_cardinal?: string; + wdir?: number; +} diff --git a/projects/common/src/fm/services/weather.service.ts b/projects/common/src/fm/services/weather.service.ts index 109ac10..da30509 100644 --- a/projects/common/src/fm/services/weather.service.ts +++ b/projects/common/src/fm/services/weather.service.ts @@ -3,21 +3,86 @@ import {HttpClient} from '@angular/common/http'; import {AppConfig} from '../shared/app.config'; import {Observable} from 'rxjs'; import {WeatherCurrentObservation} from '../models/weatherCurrentObservation'; +import {DatePipe} from '@angular/common'; +import {IItem} from '@farmmaps/common'; +import {WeatherData} from '../models/WeatherData'; +import {GeoJSON} from 'ol/format'; +import {map, switchMap} from 'rxjs/operators'; +import {getCenter} from 'ol/extent'; @Injectable({ providedIn: 'root', }) export class WeatherService { - private apiUrl = '/api/v1/weather/currentobservation'; + private apiCurrentObservationUrl = 'currentobservation'; + private apiObservation = 'observation'; + private apiForecast = 'forecast'; - constructor(public httpClient: HttpClient, public appConfig: AppConfig) { + private format: GeoJSON; + + constructor(public httpClient: HttpClient, public appConfig: AppConfig, private datePipe: DatePipe) { + this.format = new GeoJSON(); } public GetCurrentObservation(centroid: number[]): Observable { const endpoint = this.appConfig.getConfig('weatherApiEndPoint'); const apiKey = this.appConfig.getConfig('weatherApiKey'); - const observationUrl = `${endpoint}${this.apiUrl}/?c=${centroid[0]},${centroid[1]}&key=${apiKey}`; + const observationUrl = `${endpoint}${this.apiCurrentObservationUrl}/?c=${centroid[0]},${centroid[1]}&key=${apiKey}`; return this.httpClient.get(observationUrl); } + + public getWeatherRangeForItem(item: IItem, daysBefore = 10, daysAfter = 10): Observable { + const geometry = this.format.readGeometry(item.geometry); + const centroid = getCenter(geometry.getExtent()); + + const currentDate = new Date(Date.now()); + const sd = new Date(Date.now()); + const ed = new Date(Date.now()); + sd.setDate((currentDate.getDate() - daysBefore)); + ed.setDate((currentDate.getDate() + daysAfter)); + + return this.getWeatherRange(centroid, this.datePipe.transform(sd, 'yyyy-MM-ddThh:mm:ss'), + this.datePipe.transform(ed, 'yyyy-MM-ddThh:mm:ss')); + } + + public getWeatherRange(centroid: number[], startDate: string, endDate: string): Observable { + const endpoint = this.appConfig.getConfig('weatherApiEndPoint'); + const apiKey = this.appConfig.getConfig('weatherApiKey'); + + // weather does not support UTC format, also remove Z + const sd = encodeURIComponent(this.removeUTCZ(startDate)); + const ed = encodeURIComponent(this.removeUTCZ(endDate)); + + const historical = `${endpoint}${this.apiObservation}/?c=${centroid[0]},${centroid[1]}&sd=${sd}&ed=${ed}&interval=daily&key=${apiKey}`; + const forecast = `${endpoint}${this.apiForecast}/?c=${centroid[0]},${centroid[1]}&interval=daily&key=${apiKey}`; + + return this.httpClient.get(historical).pipe( + map(h => h.map(this.createWeatherDataFromHistorical)), + switchMap(h => { + return this.httpClient.get(forecast) + .pipe( + map(f => [...h, ...f.filter(fd => fd.date <= endDate) + .map(this.createWeatherDataFromForecast)])); + }) + ); + } + + private createWeatherDataFromHistorical(hd): WeatherData { + return {time: hd.date, minTemp: hd.minimumTemperature, + maxTemp: hd.maximumTemperature, relativeHumidity: hd.relativeHumidity, rain: hd.precipitation}; + } + + private createWeatherDataFromForecast(fd): WeatherData { + return {time: fd.date, minTemp: fd.minimumTemperature, + maxTemp: fd.maximumTemperature, relativeHumidity: fd.relativeHumidity, rain: fd.rain}; + } + + private removeUTCZ(dateFormat: string): string { + if (dateFormat[dateFormat.length - 1] === 'Z') { + return dateFormat.substring(0, dateFormat.length - 1); + } + + return dateFormat; + } }