Unterstützung für Hydro-Québec (Tarif D / Flex D): nicht leistungsbasiert, verbrauchsabhängiges Modell in drei Stufen

Hallo @pierre-gilles

Ich wollte einen Diskussionsraum auf GitHub - GladysAssistant/energy-contracts: Gladys Assistant Energy Contracts as JSON · GitHub eröffnen, aber ich kann nur Issues öffnen.

Kontext

Ich möchte die Tarife für Privathaushalte von Hydro-Québec (öffentlicher Stromanbieter in Québec, Kanada) zu diesem Repo hinzufügen, aber die Tarifstruktur passt nicht in das aktuelle Modell.

Wie funktioniert das aktuelle Modell

Wenn man sich EDF (contracts/edf/base) und die anderen französischen Anbieter im Repo anschaut, ist der Preis immer um eine abonnierte Leistung (kVA) organisiert:

  • ein Schlüssel pro Leistungsstufe (3, 6, 9, 12, 15 kVA…)
  • für jede Stufe: ein fester Abonnementpreis (jährlich auf monatlich umgerechnet) + ein konstanter variabler Preis pro kWh
  • bestehende Varianten: base, peak-off-peak (Hoch- und Niedertarifzeiten), tempo (blauer/weißer/roter Tag)

Warum passt der Tarif D von Hydro-Québec nicht in dieses Modell

Der Tarif D (Grundtarif für Privathaushalte) hat keine Vorstellung von abonnierter Leistung. Seine Struktur ist:

  • eine feste Netzzugriffsgebühr pro Tag, unabhängig von der Leistung
  • ein progressiver Preis pro kWh je nach tatsächlichem Verbrauch des Tages (keine Vorauswahl einer Stufe):
    • bis zu 40 kWh/Tag: ein erster Preis
    • über 40 kWh/Tag: ein zweiter, höherer Preis

Gültiger Tarif seit dem 1. April 2026 (offizielle Quelle: grille-tarifaire.pdf):

Komponente Wert
Netzzugriffsgebühr 0,46154 $ CAD / Tag
Energie, ≤ 40 kWh/Tag 0,07065 $ CAD / kWh
Energie, > 40 kWh/Tag 0,11142 $ CAD / kWh

Es gibt auch eine Option für dynamische Tarifierung, Flex D, mit einem reduzierten Außerspitzentarif im Winter und einem erhöhten Preis während kritischer Spitzenereignisse, die 24 Stunden im Voraus angekündigt werden (Zahlen müssen genau auf der offiziellen Tabelle überprüft werden, bevor die Implementierung erfolgt):

Komponente Wert (zu bestätigen)
Netzzugriffsgebühr identisch mit Tarif D
Außerhalb der Spitze, Winterperiode (1. Dezember–31. März) ≈ 0,04886 $ CAD / kWh
Spitze (punktuelle Ereignisse) ≈ 0,50 $ CAD / kWh
Rest des Jahres Standard-Tarif D

Weitere strukturelle Unterschiede:

  • Währung CAD, noch nicht im Repo verwendet (nur eur scheint praktisch verwendet zu werden)
  • keine Vorstellung von abonnierter Leistung, die der Kunde wählen kann

Was ich zur Diskussion vorschlage

  1. Wie kann ein Tarif ohne abonnierte Leistung codiert werden? Ein neutraler Schlüssel ("none" / "standard") anstelle der kVA-Stufe oder eine Entwicklung des Schemas, um diese Dimension optional zu machen?
  2. Wie kann ein gestaffelter kWh-Tarif codiert werden (Preis, der sich je nach verbrauchtem Volumen in der Periode ändert, nicht je nach Stunde oder Tag)? Nichts im aktuellen Repo scheint diesen Fall abzudecken — die bestehenden Varianten (base, peak-off-peak, tempo) sind alle unabhängig vom Volumen.
  3. Wäre ein neuer Ordner-Typ sinnvoll, z. B. tiered-consumption, zusätzlich zu base / peak-off-peak / tempo?
  4. Bestätigung, dass die Währung cad vom process.js-Pipeline / dem Gladys-Frontend, das dieses JSON verbraucht, unterstützt/akzeptiert wird.

Ich bin offen für Rückmeldungen, bevor ich Zeit (naja, Tokens :wink:) in die CSV + convert.js investiere. Sobald das Format validiert ist, kann ich einen PR mit:

  • contracts/hydro-quebec/base (Tarif D)
  • contracts/hydro-quebec/flex (Flex D)
    vorschlagen.

Hallo @lmilcent,

Vielen Dank für dieses sehr umfassende Thema, es kommt genau richtig! :raising_hands:

Ich bin gerade dabei, die Energieverfolgung in Gladys grundlegend zu überarbeiten (ich habe es hier vorgestellt: API : permettre aux intégrations externes de déclarer leurs propres types de contrat énergie - #3 par pierre-gilles ).

Die Verträge sind nicht mehr auf Basis / Niedertarif / Tempo beschränkt: Jeder Vertrag wird durch Regeln beschrieben, und das deckt genau die Punkte ab, die du ansprichst.

Tarif D: Das wird direkt möglich sein

  • Keine abonnierte Leistung: Dieses Feld wird optional.
  • Verbrauchsschwellen: « Die ersten 40 kWh des Tages zu einem Preis, der Rest zu einem anderen » wird nativ verwaltet.
  • Tägliche Zugangskosten: Ein fester Betrag pro Tag.
  • Kanadischer Dollar: Jeder Vertrag hat seine eigene Währung (CAD, USD, EUR…).

Konkreter gesagt, mit den Preisen deiner Nachricht sieht der Tarif D so aus:

{
  "tariff_version": 1,
  "components": [
    {
      "key": "energy",
      "kind": "consumption",
      "rules": [
        { "label": "40 ersten kWh des Tages", "when": { "tier": { "cumulative": "day", "from_kwh": 0, "to_kwh": 40 } }, "price": 0.07065 }
      ],
      "fallback": { "label": "Über 40 kWh", "price": 0.11142 }
    },
    { "key": "acces", "kind": "fixed", "amount": 0.46154, "per": "day" }
  ]
}

Du kannst es in den Vertrags-Editor von Gladys einfügen, und es kann auch dem Gemeinschaftskatalog hinzugefügt werden, damit jeder es mit einem Klick hat.

Flex D: Die Berechnung ist vorgesehen, die Quelle der kritischen Spitzen fehlt

Die Berechnung selbst ist abgedeckt: Winterperiode vom 1. Dezember bis 31. März, reduzierter Preis außerhalb der Spitzenzeiten, hoher Preis während der kritischen Spitzenereignisse. Aber da die Ereignisse am Vortag angekündigt werden, muss etwas sie abrufen und an Gladys übermitteln.

Das wird die Aufgabe einer externen Integration sein, die die Spitzen-Tage in einem « Kalender » veröffentlicht, den der Vertrag verwendet. Alles ist in Gladys dafür vorgesehen, aber diese Integration muss noch geschrieben werden.

Zwei Fragen, um sicherzustellen, dass es zu deiner Rechnung passt

  1. Bei der 40-kWh-Schwelle: Berechnet Hydro-Québec diese von Tag zu Tag, oder wie « 40 kWh × Anzahl der Tage » über den gesamten Abrechnungszeitraum? Das ändert das Ergebnis leicht an den Tagen, an denen du 40 kWh überschreitest.
  2. Bei Flex D: Kannst du mir die Zeitfenster der Spitzenereignisse bestätigen und ob die 40-kWh-Schwellen auch im Winter gelten?

Das ist noch nicht veröffentlicht, es wird vor einer nächsten Version überprüft.

Cool zu sehen, dass du dich wieder mit dem Thema beschäftigst! :tada:

Schwelle von 40 kWh (Tarif D)

Hydro-Québec berechnet dies kumulativ über den gesamten Abrechnungszeitraum, nicht täglich: Die erste Stufe = 40 kWh × Anzahl der Tage des Zeitraums, angewendet auf den Gesamtverbrauch des Zeitraums.

Konkrete Beispiel aus meiner Rechnung: 368 kWh über 63 Tage, Schwelle = 40 × 63 = 2.520 kWh → alles wird zum ersten Preis berechnet (368 × 0,07065 $ = 26,00 $), unabhängig davon, ob ein einzelner Tag 40 kWh überschritten hat.

In deinem JSON-Beispiel entspricht "cumulative": "day" wahrscheinlich nicht der tatsächlichen Methode, es wäre eher eine Kumulierung über den gesamten Abrechnungszeitraum ("cumulative": "billing_period" oder ähnlich), ohne tägliche Rücksetzung.

Flex D basierend auf dem offiziellen Raster 2026 (Artikel 2.72)

Komponente Preis
Netzzugriffsgebühren, pro Tag 46,154 ¢
Winter, Außerhalb der Spitzenzeiten — bis zu 40 kWh/Tag 4,886 ¢/kWh
Winter, Außerhalb der Spitzenzeiten — Rest der Energie 9,103 ¢/kWh
Winter, während eines Spitzenereignisses 46,463 ¢/kWh (Einheitspreis)
Sommer (Rest des Jahres) — bis zu 40 kWh/Tag 7,065 ¢/kWh
Sommer (Rest des Jahres) — Rest der Energie 11,142 ¢/kWh

Die 40-kWh-Schwelle gilt im Winter Flex D, außerhalb von Ereignissen: Nur während eines Spitzenereignisses ersetzt ein Einheitspreis die Stufen.

Spitzenereignisse: zwischen 6:00-10:00 und 16:00-20:00 Uhr, an allen Wochentagen (inklusive Wochenenden), maximal 120 Stunden pro Winter, Winterperiode vom 1. Dezember bis 31. März inklusive. Rest des Jahres: Standard-Tarif D.

Integration Hydro Quebec

Für die externe Integration, die die Spitzenlasttage in einem Kalender veröffentlichen würde, könnte meine aktuelle Integration, basierend auf dem Projekt hydroqc, dies unterstützen (ich muss das Gladys-Modul anpassen). Dieses Projekt erfordert jedoch die Anmeldedaten des Kontos.

Andernfalls habe ich festgestellt, dass Hydro-Québec ein offizielles Open-Data-Portal (https://donnees.hydroquebec.com) veröffentlicht, mit einem Datensatz evenements-pointe, der alle Spitzenereignisse auflistet (Winterkredit UND Flex D, filterbar nach Angebot: CPC-D, TPC-DPC, usw.), über eine Standard-REST-API (OpenDataSoft), ohne Konto oder Authentifizierung. Das Projekt Beat-YT/hydropeak-ha (MIT) stützt sich bereits darauf für Home Assistant, ohne jemals die Kundendaten zu berühren.

Dies würde eine externe Integration viel einfacher und sicherer ermöglichen: ein einziger öffentlicher Feed, der für alle Benutzer geteilt wird, anstatt die Hydro-Québec-Anmeldedaten jedes Einzelnen speichern zu müssen. Gut, das ändert nichts daran, dass die Anmeldedaten weiterhin erforderlich sind, um den Verbrauch abzurufen.

Danke @lmilcent, genau das habe ich gebraucht! :folded_hands:

Korrektur der Schwelle: Mein erstes JSON wendete die 40 kWh täglich an, was falsch ist. Da Gladys monatlich aufteilt, wende ich die Schwelle „40 kWh × Tage des Monats“ auf den Monatsverbrauch an (1.240 / 1.200 / 1.120 kWh). An einem Beispiel ergibt sich genau die Berechnung von Hydro-Québec, während die „tägliche“ Version um 14 % überschätzt hat.

Einziger Nachteil: Deine Abrechnungsperiode dauert etwa 2 Monate. Wenn ein verbrauchsintensiver Monat auf einen sparsamen Monat in derselben Periode folgt, zählt Gladys im 2. Schritt etwas zu viele kWh. Der Schaltfebruar (2028) ist auch um 40 kWh verschoben.

Tarif D

{
  "tariff_version": 1,
  "components": [
    { "key": "energy", "kind": "consumption",
      "rules": [
        { "label": "Stufe 1", "when": { "months": [1,3,5,7,8,10,12], "tier": { "cumulative": "month", "from_kwh": 0, "to_kwh": 1240 } }, "price": 0.07065 },
        { "label": "Stufe 1", "when": { "months": [4,6,9,11], "tier": { "cumulative": "month", "from_kwh": 0, "to_kwh": 1200 } }, "price": 0.07065 },
        { "label": "Stufe 1", "when": { "months": [2], "tier": { "cumulative": "month", "from_kwh": 0, "to_kwh": 1120 } }, "price": 0.07065 }
      ],
      "fallback": { "label": "Stufe 2", "price": 0.11142 } },
    { "key": "acces", "kind": "fixed", "amount": 0.46154, "per": "day" }
  ]
}

Flex D

{
  "tariff_version": 1,
  "calendars": ["hq-critical-peaks"],
  "components": [
    { "key": "energy", "kind": "consumption",
      "rules": [
        { "label": "Spitze", "when": { "months": [12,1,2,3], "calendar": { "hq-critical-peaks": "critical-peak" } }, "price": 0.46463 },
        { "label": "Winter Stufe 1", "when": { "months": [12,1,3], "tier": { "cumulative": "month", "from_kwh": 0, "to_kwh": 1240 } }, "price": 0.04886 },
        { "label": "Winter Stufe 1", "when": { "months": [2], "tier": { "cumulative": "month", "from_kwh": 0, "to_kwh": 1120 } }, "price": 0.04886 },
        { "label": "Winter Stufe 2", "when": { "months": [12,1,2,3] }, "price": 0.09103 },
        { "label": "Sommer Stufe 1", "when": { "months": [5,7,8,10], "tier": { "cumulative": "month", "from_kwh": 0, "to_kwh": 1240 } }, "price": 0.07065 },
        { "label": "Sommer Stufe 1", "when": { "months": [4,6,9,11], "tier": { "cumulative": "month", "from_kwh": 0, "to_kwh": 1200 } }, "price": 0.07065 }
      ],
      "fallback": { "label": "Sommer Stufe 2", "price": 0.11142 } },
    { "key": "acces", "kind": "fixed", "amount": 0.46154, "per": "day" }
  ]
}

Für die Spitzenzeiten ist der Datensatz „evenements-pointe“ der Open Data perfekt: Eine kleine externe Integration kann ihn lesen und die Spitzenzeiten im Kalender hq-critical-peaks veröffentlichen, ohne dass eine Anmeldung erforderlich ist. Da die Zeitfenster aus den Daten stammen, benötigt die Regel nicht die Bereiche 6:00–10:00 / 16:00–20:00. hydropeak-ha ist eine gute Basis für die Abfrage. Wenn jemand damit beginnen möchte, bin ich da, um zu helfen!

Letzte Frage: Werden die während einer Spitze verbrauchten kWh in die 40 kWh × Tage-Schwelle eingerechnet? Derzeit werden sie eingerechnet.

Das ist eine gute Frage! Ich hatte keine Ahnung, aber Claude hat mir mit allen Dokumenten, die ich ihm gegeben habe, sehr geholfen :grinning_face_with_smiling_eyes:

Für die kWh während der Spitzenlast: Die offizielle Tariftabelle (Artikel 2.72) beschreibt drei verschiedene und sich gegenseitig ausschließende Kategorien:

  • « Bis zu 40 kWh Energie pro Tag außerhalb der Spitzenlastereignisse »
  • « Rest der verbrauchten Energie außerhalb der Spitzenlastereignisse »
  • « Energie, die während der Spitzenlastereignisse verbraucht wird »

Die 40 kWh × Tage-Grenze ist explizit auf die Zeit außerhalb der Spitzenlast im Text begrenzt. Nichts deutet darauf hin, dass die Spitzenlastenergie in diese Summe einfließt — es handelt sich um zwei separate Zähler. Daher sollten die während eines Spitzenlastevents verbrauchten kWh nicht in die Grenze der Außer-Spitzenlast-Stufe einfließen.

Das entspricht auch der Logik des Programms: Andernfalls würde ein Kunde, der seinen Verbrauch während eines Ereignisses nicht reduzieren kann, doppelt bestraft werden (Spitzenlastpreis + Verlust des vorteilhaften Stufentarifs für den Rest des Monats), was dem Ziel eines dynamischen Tarifs widerspricht.

Für die Implementierung würde das bedeuten: In der Regel « Winterstufe 1 / Stufe 2 » sollte das Fenster tier.cumulative: "month" nur die kWh außerhalb von calendar: critical-peak berücksichtigen, nicht die gesamte monatliche Bruttosumme.

Hallo Louis,

Vielen Dank für den Artikel 2.72, du hattest vollkommen recht! Ich habe den Gladys-Motor mit zwei Ergänzungen zu den Stufen weiterentwickelt:

  • to_kwh_per_day : Die Schwelle wird zu „40 kWh × Anzahl der Tage des Zeitraums“. Sie wird auf dem Gesamtwert berechnet, und Februar mit Schaltjahr wird berücksichtigt.
  • counts_when : Man wählt aus, welche kWh die Stufe speisen. Die während einer Spitze verbrauchten kWh verbrauchen deine Außer-Spitze-Stufe nicht mehr.

Ich habe einige Fälle überprüft, bis auf den Cent genau im Vergleich zum Tarif:

  • Januar mit unregelmäßigen Tagen (1 220 kWh) : 86,19 $ ;
  • Februar 2028 mit Schaltjahr : 98,11 $ ;
  • Flex D im Januar mit 20 Stunden Spitze : 116,90 $ (ohne die Korrektur waren es 118,45 $).

Tarif D

{
  "tariff_version": 1,
  "components": [
    { "key": "energy", "kind": "consumption",
      "rules": [
        { "label": "Stufe 1", "when": { "tier": { "cumulative": "billing_period", "from_kwh_per_day": 0, "to_kwh_per_day": 40 } }, "price": 0.07065 }
      ],
      "fallback": { "label": "Stufe 2", "price": 0.11142 } },
    { "key": "acces", "kind": "fixed", "amount": 0.46154, "per": "day" }
  ]
}

Flex D

{
  "tariff_version": 1,
  "calendars": ["hq-critical-peaks"],
  "components": [
    { "key": "energy", "kind": "consumption",
      "rules": [
        { "label": "Spitze", "when": { "calendar": { "hq-critical-peaks": "critical-peak" } }, "price": 0.46463 },
        { "label": "Winter Stufe 1", "when": { "season": { "from": "12-01", "to": "03-31" }, "tier": { "cumulative": "billing_period", "from_kwh_per_day": 0, "to_kwh_per_day": 40, "counts_when": { "not_calendar": { "hq-critical-peaks": "critical-peak" } } } }, "price": 0.04886 },
        { "label": "Winter Stufe 2", "when": { "season": { "from": "12-01", "to": "03-31" } }, "price": 0.09103 },
        { "label": "Sommer Stufe 1", "when": { "tier": { "cumulative": "billing_period", "from_kwh_per_day": 0, "to_kwh_per_day": 40 } }, "price": 0.07065 }
      ],
      "fallback": { "label": "Sommer Stufe 2", "price": 0.11142 } },
    { "key": "acces", "kind": "fixed", "amount": 0.46154, "per": "day" }
  ]
}

Die einzige verbleibende Einschränkung: Gladys unterteilt die Abrechnung monatlich, während deine Hydro-Québec-Zeiträume etwa 2 Monate umfassen. Der Unterschied wirkt sich nur aus, wenn ein verbrauchsintensiver Monat und ein leichter Monat in denselben Zeitraum fallen.

Damit die Spitzen tatsächlich berechnet werden, bleibt die Integration, die die Ereignisse aus den offenen Daten von Hydro-Québec liest.

Ausgezeichnet! Alles scheint korrekt zu sein, schade um das kleine Loch, es ist unwahrscheinlich (außer man verlässt seine Wohnung), dass man im Winter zwei sehr unterschiedliche Monate beim Verbrauch hat, angesichts der Isolierung der Gebäude und der Art der Heizung hier :rofl:

Wenn es veröffentlicht wird, werde ich mein Modul aktualisieren, um den Hydro-Québec-Spitzenlastplan zu synchronisieren.