# Support for Hydro-Québec (Tariff D / Flex D): not based on power, tiered consumption model

**URL:** <https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers/10801>\
**Category:** Développement\
**Created:** [September 4, 2026, 4:14pm UTC](https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers/10801 "2026-09-04T16:14:34Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![lmilcent](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/lmilcent/32/7023_2.png) [@lmilcent](https://community.gladysassistant.com/u/lmilcent)\
**Post date:** [September 4, 2026, 4:14pm UTC](https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers/10801/1 "2026-09-04T16:14:34Z")

</div>

Hi @pierre-gilles

I wanted to open a discussion space on [GitHub - GladysAssistant/energy-contracts: Gladys Assistant Energy Contracts as JSON · GitHub](https://github.com/GladysAssistant/energy-contracts), but I can only open issues.

## Context

I would like to add Hydro-Québec’s residential rates (Québec’s public electricity provider, Canada) to this repo, but the pricing structure does not fit the current model.

## How the Current Model Works

Looking at EDF (`contracts/edf/base`) and other French providers in the repo, the price is always organized around a **subscribed power (kVA)**:

- a key per power tier (3, 6, 9, 12, 15 kVA…)
- for each tier: a fixed subscription (annualized to monthly) + a constant variable price per kWh
- existing variants: `base`, `peak-off-peak` (peak/off-peak hours), `tempo` (blue/white/red day)

## Why Hydro-Québec’s Tariff D Does Not Fit This Model

Tariff D (basic residential) has **no notion of subscribed power**. Its structure is:

- a **fixed daily network access fee** , independent of power
- a **progressive price per kWh based on actual daily consumption** (not a choice of tier in advance):
  - up to 40 kWh/day: a first price
  - beyond 40 kWh/day: a second, higher price

Rate grid in effect since April 1, 2026 (official source: [grille-tarifaire.pdf](https://www.hydroquebec.com/data/documents-donnees/pdf/grille-tarifaire.pdf)):

| Component | Value |
| --- | --- |
| Network Access Fee | 0.46154 $ CAD / day |
| Energy, ≤ 40 kWh/day | 0.07065 $ CAD / kWh |
| Energy, \> 40 kWh/day | 0.11142 $ CAD / kWh |

There is also a dynamic pricing option, **Flex D** , with a reduced off-peak price in winter and a surcharged price during critical peak events announced 24 hours in advance (figures to be precisely verified on the official grid before implementation):

| Component | Value (to confirm) |
| --- | --- |
| Network Access Fee | same as Tariff D |
| Off-peak, winter period (Dec 1–March 31) | ≈ 0.04886 $ CAD / kWh |
| Critical Peak (occasional events) | ≈ 0.50 $ CAD / kWh |
| Rest of the year | Standard Tariff D |

Other structural differences:

- currency **CAD** , not yet used in the repo (only `eur` seems to be used in practice)
- no notion of subscribed power to be chosen by the customer

## What I Propose to Discuss

1. **How to encode a tariff without subscribed power?** A neutral key (`"none"` / `"standard"`) instead of the kVA tier, or an evolution of the schema to make this dimension optional?
2. **How to encode a tiered kWh rate** (price that changes based on the volume consumed in the period, not based on the time or day)? Nothing in the current repo seems to cover this case — the existing variants (`base`, `peak-off-peak`, `tempo`) are all independent of volume.
3. Would a new type of folder be relevant, for example, `tiered-consumption`, in addition to `base` / `peak-off-peak` / `tempo`?
4. Confirmation that the `cad` currency is supported/accepted by the `process.js` pipeline / the Gladys frontend that consumes this JSON.

I would appreciate feedback before investing time (well, tokens 😉) in the CSV + `convert.js`. Once the format is validated, I can propose a PR with:

- `contracts/hydro-quebec/base` (Tariff D)
- `contracts/hydro-quebec/flex` (Flex D)

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [September 25, 2026, 1:35pm UTC](https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers/10801/2 "2026-09-25T13:35:49Z")

</div>

Hello @lmilcent,

Thanks for this very complete topic, it’s perfect timing! 🙌

I’m currently overhauling the energy tracking in Gladys (I presented it here: [API : permettre aux intégrations externes de déclarer leurs propres types de contrat énergie - #3 par pierre-gilles](https://community.gladysassistant.com/t/api-permettre-aux-integrations-externes-de-declarer-leurs-propres-types-de-contrat-energie/10704/3?u=pierre-gilles)).

Contracts are no longer limited to Base / Off-Peak / Tempo: each contract is described by rules, and this covers exactly the points you raise.

**Tariff D: this will be possible directly**

- **No subscribed power** : this field becomes optional.
- **Consumption tiers** : « the first 40 kWh of the day at one price, the rest at another » is managed natively.
- **Daily access fees** : a fixed amount per day.
- **Canadian dollar** : each contract has its own currency (CAD, USD, EUR…).

Concretely, with the prices from your message, Tariff D is written like this:

```auto
{
  "tariff_version": 1,
  "components": [
    {
      "key": "energy",
      "kind": "consumption",
      "rules": [
        { "label": "First 40 kWh of the day", "when": { "tier": { "cumulative": "day", "from_kwh": 0, "to_kwh": 40 } }, "price": 0.07065 }
      ],
      "fallback": { "label": "Beyond 40 kWh", "price": 0.11142 }
    },
    { "key": "access", "kind": "fixed", "amount": 0.46154, "per": "day" }
  ]
}

```

You’ll be able to paste it into Gladys’ contract editor, and it can also be added to the community catalog so everyone can have it in one click.

**Flex D: the calculation is planned, the source of critical peaks is missing**

The calculation itself is covered: winter period from December 1st to March 31st, reduced price outside peak hours, high price during critical peak events. But since the events are announced the day before, something needs to retrieve them and transmit them to Gladys.

This will be the role of an **external integration** , which publishes the peak days in a « calendar » that the contract uses. Everything is planned in Gladys for this, but this integration still needs to be written.

**Two questions to make sure it matches your bill**

1. For the 40 kWh threshold, does Hydro-Québec calculate it **day by day** , or as « 40 kWh × number of days » over the entire billing period? This slightly changes the result on days where you exceed 40 kWh.
2. For Flex D, can you confirm **the time slots** of the peak events, and if the 40 kWh tiers also apply during the winter?

It’s not out yet, it’s being reviewed before a next version.

---

<div class="post-metadata">

**Author:** ![lmilcent](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/lmilcent/32/7023_2.png) [@lmilcent](https://community.gladysassistant.com/u/lmilcent)\
**Post date:** [September 26, 2026, 2:59am UTC](https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers/10801/3 "2026-09-26T02:59:07Z")

</div>

Cool to see that you’re revisiting the topic! 🎉

## 40 kWh Threshold (Tariff D)

Hydro-Québec calculates this **cumulatively over the entire billing period** , not day by day: the first tier = 40 kWh × number of days in the period, applied to the total consumption of the period.

Concrete example from my bill: 368 kWh over 63 days, threshold = 40 × 63 = 2,520 kWh → everything is billed at the first price (368 × 0.07065 $ = 26.00 $), regardless of whether an individual day exceeded 40 kWh.

In your JSON example, `"cumulative": "day"` probably doesn’t correspond to the actual method; it would rather be a cumulative total over the entire billing period (`"cumulative": "billing_period"` or equivalent), without daily resets.

## Flex D Based on the Official 2026 Grid (Article 2.72)

| Component | Price |
| --- | --- |
| Network Access Fee, per day | 46.154 ¢ |
| Winter, Off-Peak — up to 40 kWh/day | 4.886 ¢/kWh |
| Winter, Off-Peak — remaining energy | 9.103 ¢/kWh |
| Winter, During a Peak Event | 46.463 ¢/kWh (single price) |
| Summer (rest of the year) — up to 40 kWh/day | 7.065 ¢/kWh |
| Summer (rest of the year) — remaining energy | 11.142 ¢/kWh |

**The 40 kWh tier applies during the winter Flex D** , outside of an event: it’s only during a peak event that a single price replaces the tiers.

Peak events: between 6 a.m.-10 a.m. and 4 p.m.-8 p.m., **every day of the week** (including weekends), maximum 120 hours per winter, winter period from December 1 to March 31 inclusive. Rest of the year: Standard Tariff D.

# Hydro Quebec Integration

For the external integration that would publish peak days in a calendar, my current integration based on the hydroqc project could support it (I need to adapt the Gladys module). But this project requires account credentials.

Otherwise, I found that Hydro-Québec publishes an official open data portal ([https://donnees.hydroquebec.com](https://donnees.hydroquebec.com)) with a dataset `evenements-pointe` that lists all peak events (Winter Credit AND Flex D, filterable by offer: `CPC-D`, `TPC-DPC`, etc.), via a standard REST API (OpenDataSoft), **without account or authentication**. The project `Beat-YT/hydropeak-ha` (MIT) already relies on it for Home Assistant, without ever touching the customer’s credentials.

This would allow a much simpler and safer external integration: a single public feed shared for all users, instead of having to store each user’s Hydro-Québec credentials. Of course, this doesn’t change the fact that credentials are still necessary to retrieve consumption.

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [September 26, 2026, 8:32am UTC](https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers/10801/4 "2026-09-26T08:32:54Z")

</div>

Thanks @lmilcent, that’s exactly what I needed! 🙏

**Correction on the threshold** : my first JSON applied 40 kWh per day, which is wrong. Since Gladys splits by month, I apply the threshold « 40 kWh × days in the month » to the monthly total (1,240 / 1,200 / 1,120 kWh). On an example, this gives exactly the Hydro-Québec calculation, whereas the « per day » version overestimated by 14%.

Only limitation: your billing period lasts about 2 months. If a high-consumption month is followed by a low-consumption month in the same period, Gladys will count a bit too many kWh at the 2nd level. Leap year February (2028) is also offset by 40 kWh.

**Tariff D**

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

```

**Flex D**

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

```

For peaks, the « evenements-pointe » dataset from open data is perfect: a small external integration can read it and publish the peak slots in the `hq-critical-peaks` calendar, without any identifier. Since the slots come from the data, the rule doesn’t need the 6 a.m.–10 a.m. / 4 p.m.–8 p.m. ranges. `hydropeak-ha` is a good base for retrieval. If someone wants to take it on, I’m here to help!

Last question: do the kWh consumed during a peak count towards the 40 kWh × days threshold? For now, I count them.

---

<div class="post-metadata">

**Author:** ![lmilcent](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/lmilcent/32/7023_2.png) [@lmilcent](https://community.gladysassistant.com/u/lmilcent)\
**Post date:** [September 26, 2026, 11:13am UTC](https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers/10801/5 "2026-09-26T11:13:19Z")

</div>

Now that’s a good question! I had no idea, but Claude really helped me with all the documents I gave him 😄

For peak kWh: the official tariff grid (article 2.72) describes three distinct and mutually exclusive categories:

- «&nbsp;Up to 40 kWh of energy per day **outside peak events** &nbsp;»
- «&nbsp;Remaining energy consumed **outside peak events** &nbsp;»
- «&nbsp;Energy consumed **during** peak events&nbsp;»

The 40 kWh × days threshold is explicitly scoped to off-peak in the text. Nothing indicates that peak energy feeds this same total — these are two separate meters. Therefore, kWh consumed during a peak event should not count towards the off-peak tier threshold.

This also aligns with the program’s logic: otherwise, a customer who cannot reduce their consumption during a peak event would be penalized twice (peak price + loss of advantageous tier for the rest of the month), which goes against the goal of a dynamic tariff.

For implementation, this would mean: in the rule «&nbsp;Winter Tier 1 / Tier 2&nbsp;», the window `tier.cumulative: "month"` should only count kWh outside `calendar: critical-peak`, not the total monthly gross.

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [September 27, 2026, 12:56pm UTC](https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers/10801/6 "2026-09-27T12:56:22Z")

</div>

Hi Louis,

Thanks for article 2.72, you were completely right! I’ve updated the Gladys engine with two additions to the tiers:

- **`to_kwh_per_day`** : the threshold becomes « 40 kWh × number of days in the period ». It is calculated on the total, and leap year February is handled.
- **`counts_when`** : you choose which kWh feed the tier. kWh consumed during a peak no longer eat your off-peak tier.

I’ve checked a few cases, to the centime near the grid:

- January with irregular days (1 220 kWh) : **$86.19** ;
- Leap year February 2028 : **$98.11** ;
- Flex D in January with 20 peak hours : **$116.90** (without the correction, we were at $118.45).

**Tariff D**

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

```

**Flex D**

```auto
{
  "tariff_version": 1,
  "calendars": ["hq-critical-peaks"],
  "components": [
    { "key": "energy", "kind": "consumption",
      "rules": [
        { "label": "Peak", "when": { "calendar": { "hq-critical-peaks": "critical-peak" } }, "price": 0.46463 },
        { "label": "Winter Tier 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 Tier 2", "when": { "season": { "from": "12-01", "to": "03-31" } }, "price": 0.09103 },
        { "label": "Summer Tier 1", "when": { "tier": { "cumulative": "billing_period", "from_kwh_per_day": 0, "to_kwh_per_day": 40 } }, "price": 0.07065 }
      ],
      "fallback": { "label": "Summer Tier 2", "price": 0.11142 } },
    { "key": "access", "kind": "fixed", "amount": 0.46154, "per": "day" }
  ]
}

```

Remaining limitation: Gladys splits billing by month, while your Hydro-Québec periods are about 2 months. The gap only plays if a heavy month and a light month end up in the same period.

For peaks to be actually billed, there remains the integration that reads events on Hydro-Québec’s open data.

---

<div class="post-metadata">

**Author:** ![lmilcent](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/lmilcent/32/7023_2.png) [@lmilcent](https://community.gladysassistant.com/u/lmilcent)\
**Post date:** [September 27, 2026, 1:32pm UTC](https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers/10801/7 "2026-09-27T13:32:25Z")

</div>

Excellent! Everything seems correct to me, too bad for the small flaw, it’s unlikely (unless you leave your home) to have two very different months on consumption during the winter, given the insulation of buildings and the type of heating here 🤣

When it’s released, I’ll update my module to synchronize the Hydro-Québec peak scheduling.

---

<div class="post-metadata">

**Author:** ![lmilcent](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/lmilcent/32/7023_2.png) [@lmilcent](https://community.gladysassistant.com/u/lmilcent)\
**Post date:** [October 9, 2026, 9:08pm UTC](https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers/10801/8 "2026-10-09T21:08:52Z")

</div>

Hi @pierre-gilles

Thanks for the contract overhaul, I’ve read #3130 and the SDK sync. As planned, I’ll update the Hydro-Québec module to **populate the `hq-critical-peaks` calendar** : the Flex D peaks (`TPC-DPC`) read from open data, published in 30-minute slots, with the Tarif D and Flex D models we’ve validated together. All Flex D events published since December 2024 are on the dot (6 a.m.–9 a.m., 6 a.m.–10 a.m., 4 p.m.–8 p.m.), so alignment isn’t an issue.

However, I’m still stuck on **getting the cost actually calculated** :

1. **Hydro-Québec only provides consumption with about a day’s delay** (hourly data from the previous day). Yet the only path planned for integration, the cumulative index, is processed in real time: the entire index gap goes into the current half-hour, and a state older than the cursor is ignored.
2. **Daily consumption isn’t enough for Flex D** : a day is billed at its start (midnight), so it never falls into a peak slot. And an integration can’t link a consumption/cost pair (`energy_parent_id`) on its own.

Would you consider:

- **letting an integration publish a dated `thirty-minutes-consumption`** (`created_at` in the past), from which the core would derive the cost functionality as it does for an index, then bill it upon arrival?
- **a dated `requestEnergyRecalculation({ from })`?** The current retry only covers 48 hours, and only contracts that read a calendar from the integration, so not Tarif D alone.

On my end, I’d split each hour into two equal half-hours. Since peaks start on the hour, nothing would be misattributed.

---

<div class="post-metadata">

**Author:** ![cursor-bot](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/cursor-bot/32/22252_2.png) [@cursor-bot](https://community.gladysassistant.com/u/cursor-bot)\
**Post date:** [October 11, 2026, 11:10am UTC](https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers/10801/9 "2026-10-11T11:10:23Z")

</div>

Hi everyone!

This topic is now **in development**.

A PR has been opened to allow external integrations to publish a dated consumption (late data providers, such as Hydro-Québec):

> <https://github.com/GladysAssistant/Gladys/pull/3187>
>
> \### Description
> 
> Field feedback on the external energy contracts (Hydro-Québec T…arif D / Flex D, forum topic below): the supplier serves yesterday's readings only, and an integration can neither feed the live index pipeline with a day of late data (the 30-minutes job collapses the whole dump into the current half-hour and ignores what is older than its cursor) nor price a daily total against a critical-peak slot. This PR lets an external integration publish \*\*dated consumption\*\* instead of an index, the way the Enedis service already works internally, and lets the core recompute the costs from there.
> 
> \*\*Discovery: cost derived from a published consumption.\*\* A device publishing an \`energy-sensor\` / \`thirty-minutes-consumption\` (or \`daily-consumption\`) feature with no index now gets its \`\<external\_id\>\_cost\` feature derived by \`getDiscoveredDevices\` (new \`addConsumptionCostFeatures\` helper next to \`addEnergyFeatures\`), hanging off the consumption through \`energy\_parent\_id\`, with the consumption attached to the main electric meter when it has no parent. Same lifecycle as the index-derived features: DB-only cost re-injected on republication (by name or by parent link), \`structure\_changed\` when missing, dropped when the consumption disappears. A consumption named like the one derived from an index stays the index pipeline's.
> 
> \*\*Host API: \`POST /api/integration/v1/energy/consumption\`.\*\* Body \`{ device\_feature\_external\_id, intervals: \[{ starts\_at | date, kwh }\] }\`, ≤ 2,000 intervals per call. The feature must belong to the integration, be created by the user (\`404\` otherwise) and be a 30-minutes or daily consumption that is not derived from an index (\`400\`). Intervals must be aligned on a 30-minute slot (or a local midnight) of the Gladys timezone, elapsed, and at most 5 years old. The kWh are converted into the feature's unit and upserted by instant with the core convention (a 30-minutes state at the end of its interval, a daily state at the start of its day), so a republication or a corrected reading never duplicates and an unchanged value writes nothing. The response carries \`count\` and \`changed\_from\`.
> 
> \*\*Recalculation.\*\* When at least one value changed, the core queues a cost recalculation of the feature's root meter from the earliest changed state (\`energyContract.requestMeterRecalculation\`), bounded to one per meter per 10 minutes with the same merging as the calendar recalculation, never before the earliest \`valid\_from\` of the meter's contracts and not at all for a meter without a contract. The bounded scheduler is now shared between calendars and meters (\`recalculation.schedule.js\`). No generic dated "recalculate from" endpoint is added: the publication carries the date.
> 
> \*\*Specs\*\* updated in the same diff: \`contracts/host-api-endpoints.md\` (derivation and endpoint), \`capabilities/energy-contracts.md\` (recalculation, SDK \`publishConsumption\`, tests), \`energy-contracts.md\` §7.4 (new job row).
> 
> No front change: nothing new is declared in the manifest.
> 
> \### Related request
> 
> Forum: \`\`https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers\`\`/10801
> 
> \### Checklist
> 
> \- \[x\] If a forum topic or GitHub issue exists, the description links it (\`Forum: https://community.gladysassistant.com/t/...\` or \`Closes #...\`)
> \- \[x\] Tests pass: \`cd server && npm run coverage\` (Codecov requires 100% coverage on changed lines) and Cypress (\`npm run cypress:run\`) if the UI changed
> \- \[x\] Linter and prettier pass on both front and server (\`npm run eslint\`, \`npm run prettier\`)
> \- \[x\] No undocumented breaking change
> 
> 🤖 Generated with \[Claude Code\](https://claude.com/claude-code)
> 
> https://claude.ai/code/session\_01Myq9fAN1NzE5C6358wLgHS
> 
> \---
> \_Generated by \[Claude Code\](https://claude.ai/code/session\_01Myq9fAN1NzE5C6358wLgHS)\_

Feel free to follow the PR, test (optional, especially for small requests) and provide your feedback here if needed.

---

<div class="post-metadata">

**Author:** ![cursor-bot](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/cursor-bot/32/22252_2.png) [@cursor-bot](https://community.gladysassistant.com/u/cursor-bot)\
**Post date:** [October 12, 2026, 8:18am UTC](https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers/10801/10 "2026-10-12T08:18:53Z")

</div>

Hi everyone!

This topic is now **in development**.

A PR has been opened to prevent the main counter from attaching to itself (and breaking the cost calculation):

> <https://github.com/GladysAssistant/Gladys/pull/3191>
>
> \### Description
> 
> Follow-up to GladysAssistant/Gladys#3187, found while testing t…he dated consumption publication live in the UI. The test used a fake "Hydro-Québec" external integration: a WebSocket connection plus the host API, with a manifest declaring a Flex D template and the \`hq-critical-peaks\` calendar.
> 
> \*\*Bug.\*\* For a late-data supplier integration, the meter the contract is attached to \*is\* the supplier meter, so its consumption feature is exactly the feature \`getDefaultElectricMeterFeatureId\` returns. On every republication, \`addConsumptionCostFeatures\` set that feature's own id as its \`energy\_parent\_id\`. When the integration republishes a structure change, the user clicks "Update" in Discovery and the self-loop is saved to the database. After that:
> \- \`getRootElectricMeterDevice\` logs \`Circular reference detected\` and returns \`null\`;
> \- \`POST /energy/consumption\` still answers \`200\` with a \`changed\_from\`, but logs \`no valid root meter, costs not recomputed\`, so the integration gets no signal;
> \- the costs of that meter, and of every sub-meter under it, are no longer computed (the 30-minutes job skips them too);
> \- the "My devices" energy page shows the "circular or broken dependencies" banner.
> 
> Reproduced live, then verified fixed the same way: after "Update" the feature stays a root, and the next correction is recalculated right away (2.4 kWh × 0.46463 = 1.115112 on a critical-peak slot).
> 
> \*\*Fix.\*\* The fallback to the main meter skips the main meter's own feature, in \`addConsumptionCostFeatures\` and in \`addEnergyFeatures\`. The second one has the same guard for an index that is itself the main meter; that path already exists on \`master\`. The spec (\`contracts/host-api-endpoints.md\`) is updated in the same diff.
> 
> \*\*Tests.\*\* 3 new tests (\`addConsumptionCostFeatures\`, \`addEnergyFeatures\`, \`getDiscoveredDevices\` with the main meter republishing itself). They fail without the fix and pass with it. The energy-monitoring, external-integration, energy-contract, tasmota and zigbee2mqtt suites pass locally. The only local failure is \`integrationHost.controller.test.js › sub-container\`, which fails identically without this change: it depends on the sandbox, which has no Docker.
> 
> \*\*Also checked live, working as specified in #3187:\*\*
> \- the cost feature is derived at discovery for a 30-minute, a daily and an index-derived consumption;
> \- \`404\` before the device is created;
> \- every validation \`400\` (unaligned, current or future slot, older than 5 years, negative or string kWh, \`date\` on a 30-minute feature, a UTC midnight on a daily feature, a feature of another integration, an index-derived consumption);
> \- idempotent upsert (\`changed\_from: null\`), daily \`date\` stored in Wh;
> \- critical-peak slots priced at 0.46463, and the total matches the wizard preview;
> \- the bounded recalculation is deferred and merged from the earliest instant.
> 
> \### Related request
> 
> Forum: https://community.gladysassistant.com/t/10801
> 
> \### Checklist
> 
> \- \[x\] If a forum topic or GitHub issue exists, the description links it (\`Forum: https://community.gladysassistant.com/t/...\` or \`Closes #...\`)
> \- \[x\] Tests pass: \`cd server && npm run coverage\` (Codecov requires 100% coverage on changed lines) and Cypress (\`npm run cypress:run\`) if the UI changed
> \- \[x\] Linter and prettier pass on both front and server (\`npm run eslint\`, \`npm run prettier\`)
> \- \[x\] No undocumented breaking change
> 
> 🤖 Generated with \[Claude Code\](https://claude.com/claude-code)
> 
> https://claude.ai/code/session\_01VZapFvQvK9NPwuwT4MbZsh
> 
> \---
> \_Generated by \[Claude Code\](https://claude.ai/code/session\_01VZapFvQvK9NPwuwT4MbZsh)\_

Feel free to follow the PR, test (optional, especially for small requests) and give your feedback here if needed.

---

<div class="post-metadata">

**Author:** ![lmilcent](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/lmilcent/32/7023_2.png) [@lmilcent](https://community.gladysassistant.com/u/lmilcent)\
**Post date:** [October 13, 2026, 10:12am UTC](https://community.gladysassistant.com/t/support-pour-hydro-quebec-tarif-d-flex-d-non-base-sur-une-puissance-modele-de-consommation-par-tiers/10801/11 "2026-10-13T10:12:06Z")

</div>

Hi!

Thanks to the release of Gladys 5.2, the dated consumption now exactly matches the need, and the fact that the publication itself triggers the recalculation greatly simplifies the module.

**Version 0.2.0 of the Hydro-Québec integration is available** and relies on it (Gladys 5.2 minimum):

- **Consumption by half-hour** : Hydro-Québec’s hourly readings (from the previous day) are published with `publishEnergyConsumption`, each hour split in two. On first startup, the integration catches up on consumption since the 1st of the month, so that the tiers are counted in full.
- **Two contract models** in the assistant: **Hydro-Québec – Tariff D** and **Hydro-Québec – Flex D** , with the grids from April 1, 2026 that we had validated here (tiers « 40 kWh × days », kWh of peak excluded from the off-peak tier).
- **Calendar `hq-critical-peaks`** : Flex D peaks are read from Hydro-Québec’s open data and published in 30-minute slots. A canceled peak before its start becomes normal again.
- The scene triggers already present (announced peak, preheating, start and end of peak) remain to the minute and complement the native trigger « Electricity price change ».

**To activate it** : update the integration, click on « Update » in the Discovery tab, then create a contract in **Energy Tracking → Contracts** with the Hydro-Québec device as the meter. For the Winter Credit, choose Tariff D: the credit remains tracked by the device’s features.

⚠ **Change to note** : daily consumption is replaced by half-hourly consumption, and its history is deleted during the update.

**Call for testers** : none of this has yet run on a real account. If you are with Hydro-Québec, especially in Flex D or with the Winter Credit, your feedback interests me a lot: do the hourly data arrive correctly, and is the cost calculated by Gladys consistent with your bill?

Thanks again!
