From d756c988107488013bb266df721a1672d7021dc7 Mon Sep 17 00:00:00 2001 From: Per Magnus Petersen Date: Sat, 14 Feb 2026 18:09:36 +0100 Subject: [PATCH] Add date-parameterized sync with production and consumption tables - Accept ?date= param on POST /eloverblik/sync (defaults to today) - Populate production table from D06 meter (571313113163368491) - Populate consumption table from D07 meter (571313113163368507) - ON CONFLICT DO NOTHING to skip existing data Co-Authored-By: Claude Opus 4.6 --- resources/queries.sql | 12 ++++++ .../elprice/web/controllers/eloverblik.clj | 37 +++++++++++++++---- src/clj/pmagnus/elprice/web/routes/ui.clj | 6 ++- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/resources/queries.sql b/resources/queries.sql index 7cc30a4..6090995 100644 --- a/resources/queries.sql +++ b/resources/queries.sql @@ -47,3 +47,15 @@ INSERT INTO charges (metering_point_id, charge_type, name, description, owner, VALUES (:metering-point-id, :charge-type, :name, :description, :owner, :valid-from-date, :valid-to-date, :period-type, :price, :quantity, :position) ON CONFLICT (metering_point_id, charge_type, name, owner, valid_from_date, position) DO NOTHING; + +-- :name insert-production! :! :n +-- :doc Insert a production record, skip if already exists +INSERT INTO production (time_start, hour, kwh) +VALUES (:time-start, :hour, :kwh) +ON CONFLICT (time_start, hour) DO NOTHING; + +-- :name insert-consumption! :! :n +-- :doc Insert a consumption record, skip if already exists +INSERT INTO consumption (time_start, hour, kwh) +VALUES (:time-start, :hour, :kwh) +ON CONFLICT (time_start, hour) DO NOTHING; diff --git a/src/clj/pmagnus/elprice/web/controllers/eloverblik.clj b/src/clj/pmagnus/elprice/web/controllers/eloverblik.clj index 7315743..77e3725 100644 --- a/src/clj/pmagnus/elprice/web/controllers/eloverblik.clj +++ b/src/clj/pmagnus/elprice/web/controllers/eloverblik.clj @@ -145,10 +145,30 @@ results metering-point-ids))) -(defn- save-time-series! [query-fn readings] +(def ^:private production-mp-id "571313113163368491") +(def ^:private consumption-mp-id "571313113163368507") + +(defn- utc-start-for-date + "Compute the UTC start of a Danish date (midnight DK -> UTC)." + [^LocalDate date] + (-> date + (.atStartOfDay dk-zone) + (.toInstant) + (Timestamp/from))) + +(defn- save-time-series! [query-fn readings from] (doseq [r readings] (query-fn :insert-meter-reading! r)) - (log/info "Saved" (count readings) "meter readings")) + (let [time-start (utc-start-for-date from)] + (doseq [r (filter #(= production-mp-id (:metering-point-id %)) readings)] + (let [hour (.getHour (.toLocalDateTime ^Timestamp (:time-dk r)))] + (query-fn :insert-production! + {:time-start time-start :hour hour :kwh (:quantity-kwh r)}))) + (doseq [r (filter #(= consumption-mp-id (:metering-point-id %)) readings)] + (let [hour (.getHour (.toLocalDateTime ^Timestamp (:time-dk r)))] + (query-fn :insert-consumption! + {:time-start time-start :hour hour :kwh (:quantity-kwh r)})))) + (log/info "Saved" (count readings) "meter readings + production/consumption")) ;; --- Charges --- @@ -223,9 +243,10 @@ ;; --- Orchestrator --- (defn fetch-and-save-all! - "Fetch all Eloverblik data and save to database." - [query-fn] - (log/info "Starting Eloverblik fetch") + "Fetch all Eloverblik data and save to database. + date is a LocalDate for which to fetch time series (one day)." + [query-fn ^LocalDate date] + (log/info "Starting Eloverblik fetch for" (.format date date-fmt)) (let [refresh-token (read-refresh-token) access-token (get-access-token refresh-token)] (if-not access-token @@ -239,14 +260,14 @@ (:childMeteringPoints mp))))) (distinct) (vec)) - from (LocalDate/of 2026 2 1) - to (LocalDate/of 2026 2 2)] + from date + to (.plusDays date 1)] (log/info "Found" (count all-ids) "metering points:" all-ids) (save-metering-points! query-fn mps) ;; Time series (let [ts-resp (fetch-time-series access-token all-ids from to) readings (parse-time-series ts-resp all-ids)] - (save-time-series! query-fn readings)) + (save-time-series! query-fn readings from)) ;; Charges (let [ch-resp (fetch-charges access-token all-ids)] (save-charges! query-fn ch-resp)) diff --git a/src/clj/pmagnus/elprice/web/routes/ui.clj b/src/clj/pmagnus/elprice/web/routes/ui.clj index 6ed4a4a..9210c4e 100644 --- a/src/clj/pmagnus/elprice/web/routes/ui.clj +++ b/src/clj/pmagnus/elprice/web/routes/ui.clj @@ -176,7 +176,11 @@ (price-content :today (prices/get-today-prices query-fn) (has-tomorrow? query-fn)))) (defn sync-eloverblik [query-fn request] - (let [result (eloverblik/fetch-and-save-all! query-fn)] + (let [date-str (get-in request [:params :date]) + date (if date-str + (java.time.LocalDate/parse date-str) + (java.time.LocalDate/now dk-zone)) + result (eloverblik/fetch-and-save-all! query-fn date)] (fragment (if (:error result) [:p {:class "text-red-600 font-medium"} (:error result)]