Add a module to retrieve electricity use from Linky

Hi,

I’m using the above setup to retrieve value of my linky at specific hour (halfhourly_xx_yy_consumption).
I would like to see my electricity consumption overtime, so I would like to plot it on a graph where each half hour the current consumption is plot. I searched about that but I was not able to find documentation about. Can one of you help me ?

Edit: I’ll give more information about what i’m trying to do.

The linky components give the consumption during the last 30min, so there is 48 points on the graph. The graph could either be a bar graph or it might link every dot with a line. If you have information about both bar and line graph, it will be great :slight_smile:

Can someone explain how to add this sensor?
Thanks.

Ehlo, I haven’t seen there was an official component and I just used the custom one until I took on me to make a component more properly coded. I made something that seems to work in my case and I aim to redo the custom card form a better data display (lots of charts).

Here is the configuration needed:

sensor:
  - platform: linky
    username: !secret linky_username
    password: !secret linky_password
    peak_hours:
     - ["07:00","14:00"]
     - ["17:00","02:00"]
    peak_hours_cost: 0.1761
    offpeak_hours_cost: 0.1291

It makes a sensor like this:

I may provide the code if people want it and even go to the troubles of making a PR but only if there’s enough demand. Might even make the card official if they accept it.

BTW: The monthly evolution is corrected only by actually making another request (since current month isn’t finished) so I made it to compare to the same month last year.

3 Likes

I like the way the sensor is structured. Can you share your work.
I think we should push for a PR as the current official component is very (too?) simple.

1 Like

I just openned a PR here.

I’ll try to make a card that goes with it. The best thing would be to make it actually work in general and have an energy cosumption card. The problem is that other people actually got a continious sensor for power cosumption and can rely on history while the Linky API makes it impossible to get the consumption in real time (due to limitations on Linky itself).
I’ll try to see if there’s a workaround for this.

1 Like

For now I ported the old custom component to my version of the sensor.

//import 'https://unpkg.com/@google-web-components/google-chart/google-chart.js?module';

class LinkyCard extends HTMLElement {
  set hass(hass) {
    if (!this.content) {
      const card = document.createElement('ha-card');
      const link = document.createElement('link');
      link.type = 'text/css';
      link.rel = 'stylesheet';
      link.href = '/local/custom_ui/linky-card.css?v=31';
      card.appendChild(link);
      this.content = document.createElement('div');
      this.content.className = 'card';
      card.appendChild(this.content);
      this.appendChild(card);
    }
    
    const entityId = this.config.entity;
    const state = hass.states[entityId];
    const stateStr = state ? state.state : 'unavailable';
    const attributes = state.attributes;
    
    this.content.innerHTML = `
      <div class="hp-hc-block">
        <google-chart
          type='pie'
          options='{"title": "${this.config.title}", "pieHole": 0.6}'
          cols='[{"label":"Heures", "type":"string"}, {"label":"Consomation", "type":"number"}]'
          rows='[["Pleines", ${Number.parseFloat(attributes.peak_hours).toFixed(1)}],["Creuse", ${Number.parseFloat(attributes.offpeak_hours).toFixed(1)}]]'>
        </google-chart>
        <span class="conso-hc">${Number.parseFloat(attributes.offpeak_hours).toFixed(1)}</span><span class="conso-unit-hc"> ${attributes.unit_of_measurement} <span class="more-unit">(en HC)</span></span><br />
        <span class="conso-hp">${Number.parseFloat(attributes.peak_hours).toFixed(1)}</span><span class="conso-unit-hp"> ${attributes.unit_of_measurement} <span class="more-unit">(en HP)</span></span>
      </div>
      <div class="cout-block">
        <span class="cout" title="Coût journalier">${Number.parseFloat(attributes.daily_cost).toFixed(2)}</span><span class="cout-unit"> €</span><!--FIXME: From yaml config or glabal setting--!>
      </div>
      <div class="clear"></div>
      <span>
        <ul class="variations-linky right">
            <li><span class="ha-icon"><ha-icon icon="mdi:flash"></ha-icon></span>${Math.round(attributes.peak_offpeak_percent)}<span class="unit"> % HP</span></li>
        </ul>
        <ul class="variations-linky">
            <li><span class="ha-icon"><ha-icon icon="mdi:arrow-right" style="transform: rotate(${(attributes.monthly_evolution < 0) ? '45' : ((attributes.monthly_evolution == 0) ? "0" : "-45")}deg)"></ha-icon></span>${Math.round(attributes.monthly_evolution)}<span class="unit"> %</span><span class="previous-month">par rapport à ${new Date((new Date().getTime()) - 365*60*60*24*1000).toLocaleDateString('fr-FR', {month: "long", year: "numeric"})}</span></li>
        </ul>
      </span>
      <div class="week-history clear">
          ${Object.keys(attributes.daily.slice(2, 7)).map((day, index) => `
          <div class="day">
              <span class="dayname">${new Date((new Date().getTime()) - day*60*60*24*1000).toLocaleDateString('fr-FR', {weekday: "long"}).split(' ')[0]}</span>
              <br><span class="cons-val">${Number.parseFloat(attributes.daily[day]).toFixed(1)} ${attributes.unit_of_measurement}</span>
          </div>`).join('')}
      </div>`;
  }

  setConfig(config) {
    if (!config.entity) {
      throw new Error('You need to define an entity');
    }
    this.config = config;
  }

  // @TODO: This requires more intelligent logic
  getCardSize() {
    return 3;
  }
}

customElements.define('linky-card', LinkyCard);

This is still a work in progress but it works for me.
Include it like this:

type: 'custom:linky-card'
entity: sensor.linky

Here’s the result so far:

Tell me if you use it or if you have any issue with it :smile:

2 Likes

I’m testing the linky component by @grea09

In found an error due to a division by zero:

          self._attributes["monthly_evolution"] = (
			1 - ((self._lk.monthly[0][CONSUMPTION]) /
				(self._lk.compare_month))) * 100

I’ve modified the code to bypass the error. It’s seems OK but I didn’t complete the custom card integration to do a complete check:

       if self._lk.compare_month == 0:
      self._attributes["monthly_evolution"] = 0
    else: 
      self._attributes["monthly_evolution"] = (
			1 - ((self._lk.monthly[0][CONSUMPTION]) /
				(self._lk.compare_month))) * 100
1 Like

About the “not continuous” sensor type. @grea09 perhaps we can create a fake one with a one day delay.
Imagine we are Tuesday 00:00. You take the value of Monday half hour by alf hour. This way it create a pseudo continuous sensor with step of half hour.

Do you think it cover what you have in mind ?

1 Like

I had this in mind and I almost coded it but I see a couple of problems with this:

  • Imagine wanting to make an automation on cosumption. This will trigger one day after the fact.
  • It might not be obvious to the user that there is a one day offset in history.
  • It becomes impossible to correlate the consumption with other measurements.

I think it might be better to simply hack the recorder into storing the value yesterday in the database.

Thanks ! I’m updating my PR with that.

Will this be in the next home assistant version realease ?

Depends on the owners of HA. Usually they are quite demanding on the code and especially on improvements. I think it will need 2-3 releases as usual.

Feedback on your implementation of the custom card.
Currently Enedis website is down and the custom component raise an error during HA reboot. The Linky custom card is at the top of a view and all other cards on the same view are not displayed. I don’t know if its due to the card or Home Assistant front end.

1 Like

Do you need help for making the PR progress ?

1 Like

I fixed that a bit ago: here’s the new card.

//import 'https://unpkg.com/@google-web-components/google-chart/google-chart.js?module';

class LinkyCard extends HTMLElement {
  set hass(hass) {
    const entityId = this.config.entity;
    const state = hass.states[entityId];
    const stateStr = state ? state.state : 'unavailable';
    const attributes = state.attributes;
    
    if (!this.content) {
      const card = document.createElement('ha-card');
      const link = document.createElement('link');
      link.type = 'text/css';
      link.rel = 'stylesheet';
      link.href = '/local/custom_ui/linky-card.css?v=31';
      card.appendChild(link);
      this.content = document.createElement('div');
      this.content.className = 'card';
      card.appendChild(this.content);
      if (stateStr == 'unavailable') {
          this.content.innerHTML = `
            <div id="states">
            <div class="name">
              <ha-icon id="icon" icon="mdi:flash" data-state="unavailable" data-domain="connection" style="color: var(--state-icon-unavailable-color)"></ha-icon>
              <span style="margin-right:2em">Linky : Site Enedis.fr inaccessible</span>
            </div>
            </div>`
      }
      this.appendChild(card);
    }
    

    if (stateStr != 'unavailable') {
      this.content.innerHTML = `
        <div class="hp-hc-block">
          <google-chart
            type='pie'
            options='{"title": "${this.config.title}", "pieHole": 0.6}'
            cols='[{"label":"Heures", "type":"string"}, {"label":"Consomation", "type":"number"}]'
            rows='[["Pleines", ${Number.parseFloat(attributes.peak_hours).toFixed(1)}],["Creuse", ${Number.parseFloat(attributes.offpeak_hours).toFixed(1)}]]'>
          </google-chart>
          <span class="conso-hc">${Number.parseFloat(attributes.offpeak_hours).toFixed(1)}</span><span class="conso-unit-hc"> ${attributes.unit_of_measurement} <span class="more-unit">(en HC)</span></span><br />
          <span class="conso-hp">${Number.parseFloat(attributes.peak_hours).toFixed(1)}</span><span class="conso-unit-hp"> ${attributes.unit_of_measurement} <span class="more-unit">(en HP)</span></span>
        </div>
        <div class="cout-block">
          <span class="cout" title="Coût journalier">${Number.parseFloat(attributes.daily_cost).toFixed(2)}</span><span class="cout-unit"> €</span><!--FIXME: From yaml config or glabal setting--!>
        </div>
        <div class="clear"></div>
        <span>
          <ul class="variations-linky right">
              <li><span class="ha-icon"><ha-icon icon="mdi:flash"></ha-icon></span>${Math.round(attributes.peak_offpeak_percent)}<span class="unit"> % HP</span></li>
          </ul>
          <ul class="variations-linky">
              <li><span class="ha-icon"><ha-icon icon="mdi:arrow-right" style="transform: rotate(${(attributes.monthly_evolution < 0) ? '45' : ((attributes.monthly_evolution == 0) ? "0" : "-45")}deg)"></ha-icon></span>${Math.round(attributes.monthly_evolution)}<span class="unit"> %</span><span class="previous-month">par rapport à ${new Date((new Date().getTime()) - 365*60*60*24*1000).toLocaleDateString('fr-FR', {month: "long", year: "numeric"})}</span></li>
          </ul>
        </span>
        <div class="week-history clear">
            ${Object.keys(attributes.daily.slice(2, 7).reverse()).map((day, index) => `
            <div class="day">
                <span class="dayname">${new Date(new Date().setDate(new Date().getDate()-(6-Number.parseInt(day)))).toLocaleDateString('fr-FR', {weekday: "long"}).split(' ')[0]}</span>
                <br><span class="cons-val">${Number.parseFloat(attributes.daily.slice(2, 7).reverse()[day]).toFixed(1)} ${attributes.unit_of_measurement}</span>
            </div>`).join('')}
        </div>`;
    }
  }

  setConfig(config) {
    if (!config.entity) {
      throw new Error('You need to define an entity');
    }
    this.config = config;
  }

  // @TODO: This requires more intelligent logic
  getCardSize() {
    return 3;
  }
}

customElements.define('linky-card', LinkyCard);
1 Like

Nice. Problem solved.

I just updated the PR to something a bit better formated. If you happen to know what is left to do please tell me, I would appreciate.

Thanks in advance.

You should read comments from older PR about the Linky sensor:
https://github.com/home-assistant/home-assistant/pull/16468
https://github.com/home-assistant/home-assistant/pull/13939

Your code needs to be updated to (new) HA standards.

1 Like

Do you have difficulties to fetch data with this custom component while you can log in the Enedis web UI and access all the data ?
I’ve this problem since few days.
There is an issue related to that raised on Github with the python module done by Pirionfr

I have no problems here. I’m using the latest version.

Also Enedis.fr is very often broken for some reason.