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 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 18:09:36 +01:00
co-authored by Claude Opus 4.6
parent ca473c62bb
commit d756c98810
3 changed files with 46 additions and 9 deletions
+12
View File
@@ -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;
@@ -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))
+5 -1
View File
@@ -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)]