Monitor your natural gas comsumption (in France - Gazpar / GRDF)

This is a quick tutorial for my French compatriots on how you can monitor your natural gas consumption in openHAB - probably appropriate that you would want to do that given the, em, current situation in the world, as some would say, and the resulting price hike - if you have their new “smart” Gazpar meter installed (not that you have a choice anyway, it will happen). I’ve actually used this setup for almost a year.

The main assumption is that you already have your account at GRDF and can see the info on their website i.e. https://monespace.grdf.fr/. If not, follow their registration process and make sure you do.

I’m currently using GitHub - yukulehe/gazpar2mqtt: Python script to fetch GRDF's website data and publish data to a mqtt broker. to fetch the data, which is scraping the website, never a good sign, but it’s been pretty well maintained so far and you don’t have an alternative for now.

Of course you need a MQTT broker already installed, configured and running.

I run the script with this command in a cronjob:

0 8,12,16,20 * * * python3 /home/ys/gazpar2mqtt/app/gazpar2mqtt.py --grdf_username=******** --grdf_password=******** --mqtt_host=localhost --hass_discovery=True

A typical log is like this:

2022-04-13 22:45:46,655 INFO Database version 0.6.3
2022-04-13 22:45:46,656 INFO Please note that the the tool is still under development, various functions may disappear or be modified.
2022-04-13 22:45:46,656 INFO -----------------------------------------------------------
2022-04-13 22:45:46,657 INFO #                Program parameters                       #
2022-04-13 22:45:46,657 INFO -----------------------------------------------------------
2022-04-13 22:45:46,657 INFO GRDF config : username = ******@****.**, password = ******
2022-04-13 22:45:46,658 INFO MQTT broker config : host = localhost, port = 1883, clientId = gazpar2mqtt, qos = 1, topic = gazpar, retain = False, ssl
= False
2022-04-13 22:45:46,658 INFO Standlone mode : Enable = True
2022-04-13 22:45:46,659 INFO Home Assistant discovery : Enable = True, Topic prefix = homeassistant, Device name = gazpar
2022-04-13 22:45:46,659 INFO Thresold options : Warning percentage = 80
2022-04-13 22:45:46,660 INFO Database options : Force reinitialization = False
2022-04-13 22:45:46,661 INFO Debug mode : Enable = False
2022-04-13 22:45:46,661 INFO Check parameters...
2022-04-13 22:45:46,661 INFO Parameters are ok !
2022-04-13 22:45:46,662 INFO -----------------------------------------------------------
2022-04-13 22:45:46,663 INFO #        Connexion to SQLite database                     #
2022-04-13 22:45:46,663 INFO -----------------------------------------------------------
2022-04-13 22:45:46,663 INFO Check local database/cache
2022-04-13 22:45:46,665 INFO SQLite database connected !
2022-04-13 22:45:46,665 INFO Checking database version...
2022-04-13 22:45:46,667 INFO Database is already up to date : version 0.6.3.
2022-04-13 22:45:46,668 INFO Calculate database statistics..
2022-04-13 22:45:46,669 INFO 285 measures stored
2022-04-13 22:45:46,670 INFO First measure 2020-12-02
2022-04-13 22:45:46,670 INFO Last measure 2022-04-11
2022-04-13 22:45:46,671 INFO -----------------------------------------------------------
2022-04-13 22:45:46,671 INFO #              Connexion to Mqtt broker                   #
2022-04-13 22:45:46,671 INFO -----------------------------------------------------------
2022-04-13 22:45:46,672 INFO Connect to Mqtt broker...
2022-04-13 22:45:50,683 INFO Mqtt broker connected !
2022-04-13 22:45:50,683 INFO -----------------------------------------------------------
2022-04-13 22:45:50,684 INFO #            Get data from GRDF website                   #
2022-04-13 22:45:50,685 INFO -----------------------------------------------------------
2022-04-13 22:45:50,685 INFO Connexion to GRDF, try 1/14...
2022-04-13 22:45:52,141 INFO GRDF connected !
2022-04-13 22:45:52,142 INFO Retrieve account informations
2022-04-13 22:45:52,289 INFO Retrieve list of PCEs...
2022-04-13 22:45:52,483 INFO 1 PCE found !
2022-04-13 22:45:52,497 INFO Get measures of PCE xxxxx alias xxxxx
2022-04-13 22:45:52,498 INFO ---------------------------------
2022-04-13 22:45:52,499 INFO Range period : from 2019-04-13 (3 years ago) to 2022-04-13 (today) ...
2022-04-13 22:45:53,520 INFO Analysis of measures provided by GRDF...
2022-04-13 22:45:53,522 INFO 496 measures provided by Grdf
2022-04-13 22:45:53,523 INFO 285 measures are ok
2022-04-13 22:45:53,523 INFO Accuracy is 57 percent
2022-04-13 22:45:53,523 INFO Update of database with retrieved measures...
2022-04-13 22:45:53,573 INFO Database updated !
2022-04-13 22:45:53,574 INFO Last valid measure provided by GRDF :
2022-04-13 22:45:53,574 INFO Date = 2022-04-11
2022-04-13 22:45:53,575 INFO Start index = xxx, End index = xxx
2022-04-13 22:45:53,575 INFO Volume = x m3, Energy = xx kWh, Factor = 10.91
2022-04-13 22:45:53,575 WARNING Inconsistencies detected on the measure :
2022-04-13 22:45:53,576 WARNING Volume provided by Grdf (x m3) has been replaced by the volume between start index and end index (x m3)
2022-04-13 22:45:53,576 INFO Get PCE's thresolds from GRDF...
2022-04-13 22:45:54,215 INFO 22 thresolds found !
2022-04-13 22:45:54,216 INFO Update of database with retrieved thresolds...
2022-04-13 22:45:54,233 INFO Database updated !
2022-04-13 22:45:54,247 INFO -----------------------------------------------------------
2022-04-13 22:45:54,247 INFO #           Stand alone publication mode                  #
2022-04-13 22:45:54,247 INFO -----------------------------------------------------------
2022-04-13 22:45:54,248 INFO Publishing values of PCE xxxxx alias xxxxx...
2022-04-13 22:45:54,248 INFO ---------------------------------
2022-04-13 22:45:54,249 INFO You can retrieve published values subscribing topic gazpar/xxxxx/#
2022-04-13 22:45:54,252 INFO Publishing to Mqtt...
2022-04-13 22:46:01,494 INFO All measures published !
2022-04-13 22:46:01,495 INFO Publishing to Mqtt status values...
2022-04-13 22:46:01,898 INFO Status values published !
2022-04-13 22:46:01,898 INFO -----------------------------------------------------------
2022-04-13 22:46:01,899 INFO #           Home assistant publication mode               #
2022-04-13 22:46:01,899 INFO -----------------------------------------------------------
2022-04-13 22:46:01,900 INFO Publishing values of PCE xxxxx alias xxxxx...
2022-04-13 22:46:01,901 INFO ---------------------------------
2022-04-13 22:46:01,907 INFO Publishing devices...
2022-04-13 22:46:01,908 INFO You can retrieve published values subscribing topic homeassistant/+/gazpar_xxxxx/#
2022-04-13 22:46:16,186 INFO Devices published !
2022-04-13 22:46:16,187 INFO -----------------------------------------------------------
2022-04-13 22:46:16,188 INFO #               Disconnexion from MQTT                    #
2022-04-13 22:46:16,189 INFO -----------------------------------------------------------
2022-04-13 22:46:16,989 INFO Mqtt broker disconnected
2022-04-13 22:46:16,990 INFO -----------------------------------------------------------
2022-04-13 22:46:16,990 INFO #          Disconnexion from SQLite database              #
2022-04-13 22:46:16,991 INFO -----------------------------------------------------------
2022-04-13 22:46:16,992 INFO SQLite database disconnected
2022-04-13 22:46:16,993 INFO -----------------------------------------------------------
2022-04-13 22:46:16,994 INFO #                Next run                                 #
2022-04-13 22:46:16,994 INFO -----------------------------------------------------------
2022-04-13 22:46:16,994 INFO No schedule defined.
2022-04-13 22:46:16,995 INFO -----------------------------------------------------------
2022-04-13 22:46:16,996 INFO #                  End of program                         #
2022-04-13 22:46:16,996 INFO -----------------------------------------------------------
2022-04-13 22:46:16,996 INFO End of gazpar2mqtt. See u...

Note that I’ve used the Home Assistant discovery option (--hass_discovery=True) because then it will be normally detected by the MQTT binding and added without requiring to define the channels and such (there are a bunch of them) :

You can then add it to your model with the “Add Equipment to Model” button on that screen, be sure to keep the item names’ suffixes untouched (important for what comes next).

I have made this rather crude widget that you can add as the default standalone widget for the Gazpar meter equipment - all you have to define is the parent Equipment item whose name will act as a prefix, if you kept the default suggested item names for the Points:

uid: gazpar_summary
tags: []
props:
  parameters:
    - description: Gazpar Item Prefix
      label: item Prefix
      name: itemPrefix
      required: false
      type: TEXT
  parameterGroups: []
component: oh-list-card
config:
  accordionList: true
slots:
  default:
    - component: f7-list-item
      config:
        divider: true
        title: ="Dernière mesure (" + items[props.itemPrefix + 'consumptiondate'].state + ")"
    - component: f7-list-item
      config:
        after: =items[props.itemPrefix + "gas"].displayState
        title: Volume
    - component: f7-list-item
      config:
        after: =items[props.itemPrefix + "energy"].displayState
        title: Energie
    - component: f7-list-item
      config:
        after: =(items[props.itemPrefix + "energy"].state * items.Prix_Gaz.state).toFixed(2) + ' €'
        title: Prix
    - component: oh-list-item
      config:
        accordionItem: true
        title: Jours précédents
      slots:
        accordion:
          - component: oh-repeater
            config:
              for: i
              fragment: true
              rangeStart: 1
              rangeStop: 7
              sourceType: range
            slots:
              default:
                - component: oh-label-item
                  config:
                    item: =props.itemPrefix + "day" + loop.i + "gas"
                    title: =dayjs().subtract(loop.i, 'day').format('dddd DD MMM')
    - component: f7-list-item
      config:
        divider: true
        title: ="Cette semaine"
    - component: f7-list-item
      config:
        after: =items[props.itemPrefix + "rollingweekgas"].displayState + ' / ' + items[props.itemPrefix + "currentweekgas"].displayState
        title: Volume
    - component: f7-list-item
      config:
        after: =Math.round(items[props.itemPrefix + "currentweekgas"].state * items[props.itemPrefix + "conversionfactor"].state) + " kWh"
        title: Energie
    - component: f7-list-item
      config:
        after: =(items[props.itemPrefix + "currentweekgas"].state * items[props.itemPrefix + "conversionfactor"].state * items.Prix_Gaz.state).toFixed(2) + " €"
        title: Prix
    - component: f7-list-item
      config:
        after: =items[props.itemPrefix + "rollingweekoflastweekgas"].displayState + ' / ' + items[props.itemPrefix + "previousweekgas"].displayState
        title: Semaine dernière
    - component: f7-list-item
      config:
        after: =items[props.itemPrefix + "rollingweekoflastyear"].displayState + ' / ' + items[props.itemPrefix + "currentweekoflastyeargas"].displayState
        title: L'année dernière
    - component: f7-list-item
      config:
        divider: true
        title: ="Ce mois"
    - component: f7-list-item
      config:
        after: =items[props.itemPrefix + "rollingmonthgas"].displayState + ' / ' + items[props.itemPrefix + "currentmonthgas"].displayState
        title: Volume
    - component: f7-list-item
      config:
        after: =Math.round(items[props.itemPrefix + "currentmonthgas"].state * items[props.itemPrefix + "conversionfactor"].state) + " kWh"
        title: Energie
    - component: f7-list-item
      config:
        after: =(items[props.itemPrefix + "currentmonthgas"].state * items[props.itemPrefix + "conversionfactor"].state * items.Prix_Gaz.state).toFixed(2) + " €"
        title: Prix
    - component: f7-list-item
      config:
        after: =items[props.itemPrefix + "thresoldofcurrentmonth"].displayState
        title: Seuil
    - component: oh-list-item
      config:
        after: =items[props.itemPrefix + "thresoldofcurrentmonthpercentage"].displayState
        title: Pourcentage du seuil
      slots:
        title:
          - component: f7-icon
            config:
              color: red
              f7: exclamationmark
              visible: =items[props.itemPrefix + "thresoldofcurrentmonthpercentage"].state > 100
    - component: f7-list-item
      slots:
        default:
          - component: f7-progressbar
            config:
              color: '=(+items[props.itemPrefix + "thresoldofcurrentmonthpercentage"].state > 100) ? "red" : "blue"'
              progress: =+items[props.itemPrefix + "thresoldofcurrentmonthpercentage"].state
    - component: f7-list-item
      config:
        after: =items[props.itemPrefix + "rollingmonthoflastyeargas"].displayState + ' / ' + items[props.itemPrefix + "currentmonthoflastyeargas"].displayState
        title: L'année dernière
    - component: f7-list-item
      config:
        divider: true
        title: ="Mois précédent"
    - component: f7-list-item
      config:
        after: =items[props.itemPrefix + "rollingmonthoflastmonthgas"].displayState + ' / ' + items[props.itemPrefix + "previousmonthgas"].displayState
        title: Volume
    - component: f7-list-item
      config:
        after: =Math.round(items[props.itemPrefix + "previousmonthgas"].state * items[props.itemPrefix + "conversionfactor"].state) + " kWh"
        title: Energie
    - component: f7-list-item
      config:
        after: =(items[props.itemPrefix + "previousmonthgas"].state * items[props.itemPrefix + "conversionfactor"].state * items.Prix_Gaz.state).toFixed(2) + " €"
        title: Prix
    - component: f7-list-item
      config:
        after: =items[props.itemPrefix + "thresoldofpreviousmonth"].displayState
        title: Seuil
    - component: f7-list-item
      config:
        after: =items[props.itemPrefix + "thresoldofpreviousmonthpercentage"].displayState
        title: Pourcentage du seuil
      slots:
        title:
          - component: f7-icon
            config:
              color: red
              f7: exclamationmark
              visible: =items[props.itemPrefix + "thresoldofpreviousmonthpercentage"].state > 100
    - component: f7-list-item
      slots:
        default:
          - component: f7-progressbar
            config:
              color: '=(+items[props.itemPrefix + "thresoldofpreviousmonthpercentage"].state > 100) ? "red" : "blue"'
              progress: =+items[props.itemPrefix + "thresoldofpreviousmonthpercentage"].state
    - component: f7-list-item
      config:
        divider: true
        title: ="Cette année"
    - component: f7-list-item
      config:
        after: =items[props.itemPrefix + "rollingyeargas"].displayState + ' / ' + items[props.itemPrefix + "currentyeargas"].displayState
        title: Volume
    - component: f7-list-item
      config:
        after: =Math.round(items[props.itemPrefix + "currentyeargas"].state * items[props.itemPrefix + "conversionfactor"].state) + " kWh"
        title: Energie
    - component: f7-list-item
      config:
        after: =(items[props.itemPrefix + "currentyeargas"].state * items[props.itemPrefix + "conversionfactor"].state * items.Prix_Gaz.state).toFixed(2) + " €"
        title: Prix
    - component: f7-list-item
      config:
        divider: true
        title: ="L'année dernière"
    - component: f7-list-item
      config:
        after: =items[props.itemPrefix + "previousyeargas"].displayState
        title: Volume
    - component: f7-list-item
      config:
        after: =Math.round(items[props.itemPrefix + "previousyeargas"].state * items[props.itemPrefix + "conversionfactor"].state) + " KWh"
        title: Energie
    - component: f7-list-item
      config:
        after: =(items[props.itemPrefix + "previousyeargas"].state * items[props.itemPrefix + "conversionfactor"].state * items.Prix_Gaz.state).toFixed(2) + " €"
        title: Prix
    - component: oh-list-item
      config:
        action: group
        actionGroupPopupItem: gazparxyz
        listButton: true
        title: Détails

(you actually have to define and set an item called Prix_Gaz if you want the price info, it’s currently hardcoded, sorry.)

You can also add this widget to your Pages.

Hope this helps!
Yannick

2 Likes

Note the “thresholds” (seuils) are defined on their website:

3 Likes