diff --git a/resources/migrations/20260419020000-add-elprice-tariff-total.down.sql b/resources/migrations/20260419020000-add-elprice-tariff-total.down.sql new file mode 100644 index 0000000..e7bb21f --- /dev/null +++ b/resources/migrations/20260419020000-add-elprice-tariff-total.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE elprice DROP COLUMN total_dkk; +--;; +ALTER TABLE elprice DROP COLUMN tariff_dkk; diff --git a/resources/migrations/20260419020000-add-elprice-tariff-total.up.sql b/resources/migrations/20260419020000-add-elprice-tariff-total.up.sql new file mode 100644 index 0000000..196f2c3 --- /dev/null +++ b/resources/migrations/20260419020000-add-elprice-tariff-total.up.sql @@ -0,0 +1,21 @@ +ALTER TABLE elprice ADD COLUMN tariff_dkk NUMERIC(10,2); +--;; +ALTER TABLE elprice ADD COLUMN total_dkk NUMERIC(10,2); +--;; +UPDATE elprice + SET tariff_dkk = CASE + WHEN EXTRACT(MONTH FROM time_dk) BETWEEN 4 AND 9 THEN + CASE + WHEN EXTRACT(HOUR FROM time_dk) < 6 THEN 109.80 + WHEN EXTRACT(HOUR FROM time_dk) >= 17 AND EXTRACT(HOUR FROM time_dk) < 21 THEN 428.30 + ELSE 164.70 + END + ELSE + CASE + WHEN EXTRACT(HOUR FROM time_dk) < 6 THEN 109.80 + WHEN EXTRACT(HOUR FROM time_dk) >= 17 AND EXTRACT(HOUR FROM time_dk) < 21 THEN 988.40 + ELSE 329.50 + END + END; +--;; +UPDATE elprice SET total_dkk = price_dkk + tariff_dkk WHERE tariff_dkk IS NOT NULL; diff --git a/resources/queries.sql b/resources/queries.sql index 2637335..c87f38f 100644 --- a/resources/queries.sql +++ b/resources/queries.sql @@ -67,14 +67,16 @@ VALUES (:time-start, :hour, :kwh) ON CONFLICT (time_start, hour) DO NOTHING; -- :name insert-elprice! :! :n --- :doc Insert an hourly el-price row; keep first value on conflict -INSERT INTO elprice (time_dk, price_area, price_dkk) -VALUES (:time-dk, :price-area, :price-dkk) -ON CONFLICT (time_dk, price_area) DO NOTHING; +-- :doc Upsert an hourly el-price row; refresh tariff/total on conflict +INSERT INTO elprice (time_dk, price_area, price_dkk, tariff_dkk, total_dkk) +VALUES (:time-dk, :price-area, :price-dkk, :tariff-dkk, :total-dkk) +ON CONFLICT (time_dk, price_area) DO UPDATE SET + tariff_dkk = EXCLUDED.tariff_dkk, + total_dkk = EXCLUDED.total_dkk; -- :name get-elprice-for-date :? :* -- :doc Hourly prices for a DK local date, both areas -SELECT time_dk, price_area, price_dkk +SELECT time_dk, price_area, price_dkk, tariff_dkk, total_dkk FROM elprice WHERE time_dk::date = :date ORDER BY time_dk, price_area; diff --git a/src/clj/pmagnus/elprice/web/controllers/elprice.clj b/src/clj/pmagnus/elprice/web/controllers/elprice.clj index 28d99ba..a250147 100644 --- a/src/clj/pmagnus/elprice/web/controllers/elprice.clj +++ b/src/clj/pmagnus/elprice/web/controllers/elprice.clj @@ -1,7 +1,8 @@ (ns pmagnus.elprice.web.controllers.elprice (:require [clojure.data.json :as json] - [clojure.tools.logging :as log]) + [clojure.tools.logging :as log] + [pmagnus.elprice.web.controllers.tariffs :as tariffs]) (:import (java.net URI @@ -14,6 +15,7 @@ Timestamp) (java.time LocalDate + LocalDateTime ZoneId) (java.time.format DateTimeFormatter))) @@ -68,14 +70,25 @@ (:records (fetch-json url)))) +(defn- tariff-dkk-mwh + "N1 time-of-use tariff converted from øre/kWh to DKK/MWh (×10)." + [^LocalDateTime dt] + (* 10.0 (tariffs/tariff-for-hour (.getMonthValue dt) (.getHour dt)))) + + (defn- save-records! [query-fn records] (doseq [rec records] (when-let [dkk (dkk-price (:DayAheadPriceDKK rec) (:DayAheadPriceEUR rec))] - (query-fn :insert-elprice! - {:time-dk (parse-timestamp (:TimeDK rec)) - :price-area (:PriceArea rec) - :price-dkk dkk})))) + (let [ts (parse-timestamp (:TimeDK rec)) + tariff (tariff-dkk-mwh (.toLocalDateTime ^Timestamp ts)) + total (+ (double dkk) tariff)] + (query-fn :insert-elprice! + {:time-dk ts + :price-area (:PriceArea rec) + :price-dkk dkk + :tariff-dkk tariff + :total-dkk total}))))) (defn get-or-fetch! diff --git a/src/clj/pmagnus/elprice/web/routes/api.clj b/src/clj/pmagnus/elprice/web/routes/api.clj index 8d0e308..93d8315 100644 --- a/src/clj/pmagnus/elprice/web/routes/api.clj +++ b/src/clj/pmagnus/elprice/web/routes/api.clj @@ -49,7 +49,9 @@ {:date date :prices (mapv (fn [r] {:time_dk (str (:time_dk r)) :price_area (:price_area r) - :price_dkk (:price_dkk r)}) + :price_dkk (:price_dkk r) + :tariff_dkk (:tariff_dkk r) + :total_dkk (:total_dkk r)}) rows)})) (catch DateTimeParseException _ (http-response/bad-request {:error "date must be YYYY-MM-DD"}))))