Automatische DWD Abfrage
Crontab hinzugefügt und automatische DWD Abfrage jeden Monat eingerichtet.
This commit is contained in:
3
.crontab
Normal file
3
.crontab
Normal file
@@ -0,0 +1,3 @@
|
||||
# Jeden Monat müssen wir die neuen Klimafaktoren vom DWD abholen, der Cronjob läuft immer am 28. für die höchste Wahrscheinlichkeit
|
||||
# dass die Daten schon da sind, falls der DWD mal später dran ist...
|
||||
0 12 28 * * bun ./src/cronjobs/update-dwd-klimafaktoren.ts
|
||||
4
build.sh
4
build.sh
@@ -52,3 +52,7 @@ docker run -d --name $APP_NAME --link $DB_CONTAINER_NAME \
|
||||
-e DB_PORT=${DB_PORT} \
|
||||
--env-file ~/apps/${APP_NAME}/.env \
|
||||
$APP_NAME;
|
||||
|
||||
# Crontab Updaten
|
||||
cd ~/$APP_NAME
|
||||
crontab .crontab
|
||||
@@ -9,24 +9,14 @@ services:
|
||||
environment:
|
||||
PORT: 3000
|
||||
NODE_ENV: "development"
|
||||
ports:
|
||||
- 3000:3000
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./:/online-energieausweis
|
||||
- ./node_modules/@ibcornelsen/ui:/online-energieausweis/node_modules/@ibcornelsen/ui
|
||||
- ./node_modules/@ibcornelsen/database:/online-energieausweis/node_modules/@ibcornelsen/database
|
||||
- ./persistent:/persistent
|
||||
networks:
|
||||
- postgres
|
||||
database:
|
||||
network_mode: host
|
||||
build: ../database
|
||||
env_file:
|
||||
- ../database/.env
|
||||
ports:
|
||||
- "5432:5432"
|
||||
networks:
|
||||
- postgres
|
||||
|
||||
networks:
|
||||
postgres:
|
||||
driver: bridge
|
||||
@@ -28,6 +28,7 @@
|
||||
"astro-i18next": "1.0.0-beta.21",
|
||||
"bun": "^1.0.2",
|
||||
"cookiejs": "^2.1.2",
|
||||
"csvtojson": "^2.0.10",
|
||||
"esbuild": "^0.18.17",
|
||||
"express": "^4.18.2",
|
||||
"flag-icons": "^6.9.2",
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
import DaemmungImage from "./DaemmungImage.svelte";
|
||||
import FensterImage from "./FensterImage.svelte";
|
||||
import Label from "../Label.svelte";
|
||||
import { Verbrauchsausweis } from "src/lib/Ausweis/Verbrauchsausweis";
|
||||
import { GebaeudeStammdaten, VerbrauchsausweisWohnen } from "@ibcornelsen/database";
|
||||
|
||||
export let gebaeude: GebaeudeStammdaten;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import HelpLabel from "../HelpLabel.svelte";
|
||||
import moment, { Moment } from "moment";
|
||||
import moment from "moment";
|
||||
import Label from "../Label.svelte";
|
||||
import fuelList from "./fuelList";
|
||||
import { auditVerbrauchAbweichung } from "../Verbrauchsausweis/audits/VerbrauchAbweichung";
|
||||
|
||||
73
src/cronjobs/update-dwd-klimafaktoren.ts
Normal file
73
src/cronjobs/update-dwd-klimafaktoren.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { prisma } from "@ibcornelsen/database";
|
||||
import moment from "moment";
|
||||
import csv from "csvtojson"
|
||||
|
||||
// Als erstes schauen wir, welches das letzte Jahr ist, für das wir einen Verbrauchsausweis haben.
|
||||
// Das machen wir, indem wir die Ausweise nach Jahr und Monat sortieren und dann den letzten Eintrag nehmen.
|
||||
const newestDate = await prisma.klimafaktoren.findFirst({
|
||||
orderBy: [
|
||||
{
|
||||
year: "desc",
|
||||
},
|
||||
{
|
||||
month: "desc",
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
if (!newestDate) {
|
||||
console.error("No last year found!")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Jetzt müssen wir abfragen, welche neuen Dateien es beim Deutschen Wetterdienst gibt.
|
||||
// https://opendata.dwd.de/climate_environment/CDC/derived_germany/techn/monthly/climate_correction_factor/recent/
|
||||
// Weil die Antwort in HTML ist und wir keinen Bock haben das alles zu parsen, versuchen wir einfach die neueste Datei abzufragen.
|
||||
// Das format des DWD ist wie folgt: KF_20221101_20231031.csv
|
||||
// Der Monat bei moment und in der Datenbank ist nullbasiert, also 0 = Januar, 11 = Dezember.
|
||||
const currentDate = moment().set("month", newestDate.month).set("year", newestDate.year).set("date", 1);
|
||||
|
||||
|
||||
const lastYearString = currentDate.clone().add(1, "month").startOf("month").format("YYYYMMDD");
|
||||
const nextYearString = currentDate.clone().add(1, "year").endOf("month").format("YYYYMMDD");
|
||||
|
||||
const filename = `KF_${lastYearString}_${nextYearString}.csv`
|
||||
|
||||
const url = "https://opendata.dwd.de/climate_environment/CDC/derived_germany/techn/monthly/climate_correction_factor/recent/"
|
||||
|
||||
const response = await fetch(`${url}${filename}`)
|
||||
|
||||
if (response.status !== 200) {
|
||||
console.error(`Could not fetch ${url}${filename}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const parser = csv({
|
||||
noheader: false,
|
||||
output: "json",
|
||||
delimiter: ";",
|
||||
})
|
||||
|
||||
const data: {
|
||||
DatAnf: string,
|
||||
DatEnd: string,
|
||||
PLZ: string,
|
||||
KF: string
|
||||
}[] = await parser.fromString(await response.text())
|
||||
|
||||
const year = currentDate.clone().add(1, "month").year();
|
||||
const month = currentDate.clone().add(1, "month").month();
|
||||
|
||||
const result = await prisma.klimafaktoren.createMany({
|
||||
data: data.map((row) => {
|
||||
return {
|
||||
year,
|
||||
month,
|
||||
klimafaktor: parseFloat(row.KF),
|
||||
plz: row.PLZ,
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
console.log(`Updated ${result.count} rows!`)
|
||||
@@ -1,36 +1,29 @@
|
||||
import moment, { Moment } from "moment";
|
||||
import { prisma } from "@ibcornelsen/database";
|
||||
|
||||
export async function getClimateFactor(dates: Moment[], zip: string): Promise<({ zip: string } & Record<string, number>) | null> {
|
||||
const formattedDates = dates.map(date => {
|
||||
let d = moment(date).format("MM_YYYY");
|
||||
return `d_${d}`
|
||||
});
|
||||
import { Klimafaktoren, prisma } from "@ibcornelsen/database";
|
||||
|
||||
export async function getClimateFactor(
|
||||
dates: Moment[],
|
||||
plz: string
|
||||
): Promise<Klimafaktoren[] | null> {
|
||||
if (dates.length == 0) {
|
||||
return null;
|
||||
}
|
||||
if (zip.length !== 5 && zip.length !== 4) {
|
||||
|
||||
if (plz.length !== 5 && plz.length !== 4) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let result: ({ zip: string } & Record<string, number>) | null = null;
|
||||
try {
|
||||
result = await prisma.klimafaktoren.findUnique({
|
||||
select: {
|
||||
zip: true,
|
||||
...formattedDates.reduce((acc, cur) => {
|
||||
acc[cur] = true;
|
||||
return acc;
|
||||
}, {} as Record<string, boolean>)
|
||||
},
|
||||
let result = await prisma.klimafaktoren.findMany({
|
||||
where: {
|
||||
zip
|
||||
}
|
||||
}) as ({ zip: string } & Record<string, number>) | null;
|
||||
} catch(e) {
|
||||
return null;
|
||||
}
|
||||
plz: plz,
|
||||
month: dates[0].month(),
|
||||
OR: dates.map((date) => {
|
||||
return {
|
||||
year: date.year(),
|
||||
};
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
return null;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import moment from "moment";
|
||||
import { ActionFailedError, InvalidDataError, MissingPropertyError, error, success } from "src/lib/APIResponse";
|
||||
import { ActionFailedError, MissingPropertyError, error, success } from "src/lib/APIResponse";
|
||||
import { getClimateFactor } from "src/lib/Klimafaktoren/getClimateFactor";
|
||||
|
||||
export const get: APIRoute = async function({ url }) {
|
||||
@@ -45,11 +45,19 @@ export const get: APIRoute = async function({ url }) {
|
||||
currentDate.add(1, accuracy);
|
||||
}
|
||||
|
||||
const climateFactors = await getClimateFactor(intervals, zip);
|
||||
const klimafaktoren = await getClimateFactor(intervals, zip);
|
||||
|
||||
if (!climateFactors) {
|
||||
if (!klimafaktoren) {
|
||||
return ActionFailedError();
|
||||
}
|
||||
|
||||
return success(climateFactors);
|
||||
if (klimafaktoren.length !== intervals.length) {
|
||||
return error(["Not all dates could be found."]);
|
||||
}
|
||||
|
||||
return success(klimafaktoren.map(klimafaktor => ({
|
||||
month: klimafaktor.month,
|
||||
year: klimafaktor.year,
|
||||
klimafaktor: klimafaktor.klimafaktor,
|
||||
})));
|
||||
}
|
||||
Reference in New Issue
Block a user