Google Fit Support

If you used HACs to deploy as a custom rep, I had some weird behavior getting to work initially… Instead, I uninstalled it from HACs and just copied the files over to custom_components, like so:
image

Created a google_fit.yaml under the sensor folder(if you have a split up config):
image
image

No errors, just updated to 0.109.2

2 Likes

Awesome, works perfectly! Any chance Heart Points could be added?

Ok, I am having a go at adding Heart Points by modifying the sensor.py file…

This is what I have so far…

Add (under # Google Fit API URL.)…

HEARTMINUTES = 'heart points'

Then (under add_devices)…

        GoogleFitHeartMinutesSensor(client, name),

Lastly (inserted somewhere in the list of class sensors)…

class GoogleFitHeartMinutesSensor(GoogleFitSensor):
    DATA_SOURCE = "derived:	com.google.heart_minutes:" \
        "com.google.android.gms:merge_heart_minutes"

    @property
    def _name_suffix(self):
        """Returns the name suffix of the sensor."""
        return HEARTMINUTES
    @property
    def unit_of_measurement(self):
        """Returns the unit of measurement."""
        return HEARTMINUTES

    @property
    def icon(self):
        """Return the icon."""
        return 'mdi:heart'

    @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_UPDATES)
    def update(self):
        """Extracts the relevant data points for from the Fitness API."""

        values = []
        for point in self._get_dataset(self.DATA_SOURCE)["point"]:
            if int(point["startTimeNanos"]) > _today_dataset_start():
                values.append(point['value'][0]['fpVal'])

        self._last_updated = time.time()
        self._state = sum(values)
        _LOGGER.debug("Heart Points %s", self._state)
        self._attributes = {}

The above seems to be working (after a lot of messing around - trial and error style - the worst style!).

Can you please share images from your config?
Thanks.

I have done as ctowers recommended to install.

I had already done the 1st step when I set up my calender.

In order to generate your client_id and client_secret, see the prerequisites for Google Calender component: https://www.home-assistant.io/components/calendar.google/#prerequisites

I then enabled the Fitness API

To make sensor work you have to enable Fintness API in your project. In oder to enable Fitness API open Google cloud console: https://console.cloud.google.com/apis/library/fitness.googleapis.com and enable API.

I presume I use the same client_id and client_secret as I have with my calender?

I then continued to configure my /config/configuration.yaml

      
sensor:

  - platform: google_fit
    name: Mark
    client_id: redacted
    client_secret: redacted

After restarting HA I did the following

After restarting HomeAssistant, you should se a notification such as:

In order to authorize Home-Assistant to view your Google Fit data you must visit: https://www.google.com/device and enter code: XXXX-XXXX

After following this step and restarting Home Asssistant, I get the following errors in my log.

Log Details (ERROR)
Logger: homeassistant.components.sensor
Source: custom_components/google_fit/sensor.py:253
Integration: Sensor (documentation, issues)
First occurred: 14:21:35 (1 occurrences)
Last logged: 14:21:35

Error while setting up google_fit platform for sensor
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 186, in _async_setup_platform
    await asyncio.gather(*pending)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 295, in async_add_entities
    await asyncio.gather(*tasks)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 446, in _async_add_entity
    entity.async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 297, in async_write_ha_state
    self._async_write_ha_state()  # type: ignore
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 324, in _async_write_ha_state
    attr.update(self.device_state_attributes or {})
  File "/config/custom_components/google_fit/sensor.py", line 253, in device_state_attributes
    return self._attributes
AttributeError: 'GoogleFitWeightSensor' object has no attribute '_attributes'

What am i missing?

FYI: in case someone was using it. I am hiding (as private) my version of the Google Fit custom component

I think no one was using it as there were solutions built on top of mine (and others) with more sensors attributes. However, if you were using it, the Gist is still available.

This is a small protest against not having a YAML (or equivalent non-UI configuration) support mode for integrations (reference).

1 Like

Hi all,

Not sure if somethings changed but for steps and anything with a “during the day” setting there is a “bucketByTime”: { “durationMillis”: 86400000 } as well as the start, finish time. I think is why my steps go down and up, and then when I relax at the end of the day I finally get something close to my steps. I’ve tried but my python is not good - how do I add this in?

Here’s where it goes :slight_smile:

{
  "aggregateBy": [{
    "dataTypeName": "com.google.step_count.delta",
    "dataSourceId": "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps"
  }],
  "bucketByTime": { "durationMillis": 86400000 },
  "startTimeMillis": 1438705622000,
  "endTimeMillis": 1439310422000
}

I use to get information regarding deep and light sleep…now its never shown anymore… Any ideas?

This is a good idea. I think I’ll make my config and blog go dark in protest too

1 Like

Any updates on making this official?

Ok, care to share how you did that?

Xiaomi Scale 2


Google Fit:

Smart Band (Denver bhf 240) connect with google fit
https://g.co/kgs/Z9kHbc

Lovelace:
cards:

  • entities:

    • entity: sensor.alex
      name: Gewicht
    • entity: person.alexander
      name: ’ ’
      show_state: false
    • entity: sensor.alex_bmi
      icon: ‘mdi:human’
      name: BMI
      no_card: true
      show_header_toggle: false
      style: |

    ha-card {

    margin: 1rem 0.5rem;

    -webkit-box-shadow: 0px 3px 6px 3px rgba(0,0,0,0.48);

    -moz-box-shadow: 0px 3px 6px 3px rgba(0,0,0,0.48);

    box-shadow: 0px 3px 6px 3px rgba(0,0,0,0.48);

    }
    type: glance

  • elements:

    • color_stops:
      ‘1’: ‘#09C7E8
      ‘10000’: ‘#0BDF0E
      entity: sensor.google_fit_distance
      fill: ‘#1250
      font_style:
      font-color: white
      font-size: 1em
      text-shadow: 0.4px 0.4px black
      gradient: true
      max: 10
      min: 0
      name: Distanz
      show_card: false
      stroke_color: green
      stroke_width: 10
      style:
      height: 85px
      left: 75%
      top: 10%
      transform: none
      width: 85px
      type: ‘custom:circle-sensor-card’
      units: km
    • color_stops:
      ‘1’: ‘#09C7E8
      ‘10000’: ‘#0BDF0E
      entity: sensor.google_fit_steps
      fill: ‘#1250
      font_style:
      font-color: white
      font-size: 1em
      text-shadow: 2px 2px black
      gradient: true
      max: 10000
      min: 0
      name: Schritte
      show_card: false
      stroke_color: green
      stroke_width: 10
      style:
      height: 85px
      left: 5%
      top: 10%
      transform: none
      width: 85px
      type: ‘custom:circle-sensor-card’
      units: ’ ’
    • entity: sensor.google_fit_calories
      fill: ‘#1250
      font_style:
      font-color: white
      font-size: 1em
      text-shadow: 2px 2px black
      gradient: true
      max: 1000
      min: 0
      name: Kalorien
      show_card: false
      stroke_color: red
      stroke_width: 5
      style:
      height: 85px
      left: 5%
      top: 45%
      transform: none
      width: 85px
      type: ‘custom:circle-sensor-card’
      units: kcal
    • color_stops:
      ‘1’: ‘#09C7E8
      ‘30’: ‘#0BDF0E
      entity: sensor.google_fit_move_time
      fill: ‘#1250
      font_style:
      font-color: white
      font-size: 1em
      text-shadow: 2px 2px black
      gradient: true
      max: 30
      min: 0
      name: Aktivität
      show_card: false
      stroke_color: red
      stroke_width: 5
      style:
      height: 82px
      left: 75%
      top: 45%
      transform: none
      width: 90px
      type: ‘custom:circle-sensor-card’
      units: min
    • entity: sensor.google_fit_heart_rate
      style:
      color: white
      left: 42%
      top: 65%
      transform: none
      type: state-label
      image: /local/images/googlefitmaterialup.png
      no_card: true
      style: |

    ha-card {

    margin: 0rem 0rem;

    -webkit-box-shadow: 0px 3px 6px 3px rgba(0,0,0,0.48);

    -moz-box-shadow: 0px 3px 6px 3px rgba(0,0,0,0.48);

    box-shadow: 0px 3px 6px 3px rgba(0,0,0,0.48);

    }
    type: picture-elements

  • entities:

    • sensor.google_fit_heart_rate
      font_size: 100
      icon: ‘mdi:heart-pulse’
      line_color: red
      line_width: 2
      name: Puls
      no_card: true
      style: |

    ha-card {

    margin: 1rem 0.5rem;

    -webkit-box-shadow: 0px 3px 6px 3px rgba(0,0,0,0.48);

    -moz-box-shadow: 0px 3px 6px 3px rgba(0,0,0,0.48);

    box-shadow: 0px 3px 6px 3px rgba(0,0,0,0.48);

    }
    type: ‘custom:mini-graph-card’
    unit: BPM
    type: vertical-stack

2 Likes

Hi, would you be able to share this formatted?

cards:
  - entities:
      - entity: sensor.alex
        name: Gewicht
      - entity: person.alexander
        name: ' '
        show_state: false
      - entity: sensor.alex_bmi
        icon: 'mdi:human'
        name: BMI
    no_card: true
    show_header_toggle: false
    type: glance
  - elements:
      - color_stops:
          '1': '#09C7E8'
          '10000': '#0BDF0E'
        entity: sensor.google_fit_distance
        fill: '#1250'
        font_style:
          font-color: white
          font-size: 1em
          text-shadow: 0.4px 0.4px black
        gradient: true
        max: 10
        min: 0
        name: Distanz
        show_card: false
        stroke_color: green
        stroke_width: 10
        style:
          height: 85px
          left: 75%
          top: 10%
          transform: none
          width: 85px
        type: 'custom:circle-sensor-card'
        units: km
      - color_stops:
          '1': '#09C7E8'
          '10000': '#0BDF0E'
        entity: sensor.google_fit_steps
        fill: '#1250'
        font_style:
          font-color: white
          font-size: 1em
          text-shadow: 2px 2px black
        gradient: true
        max: 10000
        min: 0
        name: Schritte
        show_card: false
        stroke_color: green
        stroke_width: 10
        style:
          height: 85px
          left: 5%
          top: 10%
          transform: none
          width: 85px
        type: 'custom:circle-sensor-card'
        units: ' '
      - entity: sensor.google_fit_calories
        fill: '#1250'
        font_style:
          font-color: white
          font-size: 1em
          text-shadow: 2px 2px black
        gradient: true
        max: 1000
        min: 0
        name: Kalorien
        show_card: false
        stroke_color: red
        stroke_width: 5
        style:
          height: 85px
          left: 5%
          top: 45%
          transform: none
          width: 85px
        type: 'custom:circle-sensor-card'
        units: kcal
      - color_stops:
          '1': '#09C7E8'
          '30': '#0BDF0E'
        entity: sensor.google_fit_move_time
        fill: '#1250'
        font_style:
          font-color: white
          font-size: 1em
          text-shadow: 2px 2px black
        gradient: true
        max: 30
        min: 0
        name: Aktivität
        show_card: false
        stroke_color: red
        stroke_width: 5
        style:
          height: 82px
          left: 75%
          top: 45%
          transform: none
          width: 90px
        type: 'custom:circle-sensor-card'
        units: min
      - entity: sensor.google_fit_heart_rate
        style:
          color: white
          left: 42%
          top: 65%
          transform: none
        type: state-label
    image: /local/images/googlefitmaterialup.png
    no_card: true
    type: picture-elements
  - entities:
      - sensor.google_fit_heart_rate
    font_size: 100
    icon: 'mdi:heart-pulse'
    line_color: red
    line_width: 2
    name: Puls
    no_card: true
    type: 'custom:mini-graph-card'
    unit: BPM
type: vertical-stack

2 Likes

I haven’t been able to figure out how to use any of these custom components with multiple Google accounts. The hemantkamalakar mod says it supports this, but maybe I misunderstand what this means. I would like to be able to include data from several immediate family members, but have not found a way to format things such that HA creates functioning sensors for more than one user.

1 Like

Ok, so I am probably doing something obviously wrong but I can’t get the Google Fit sensor added.

Here’s steps to reproduce:

  1. Running Home Assistant Core 0.118.5 on a raspberry pi 3
  2. I have downloaded and installed hemants files from here: https://github.com/hemantkamalakar/google_fit_hass
  3. Downloaded ‘custom_components’ has been placed inside the config folder
  4. Added configuration to configurations.yaml:
sensor:  
  - platform: google_fit
    name: Carsten
    client_id: -myid-
    client_secret: -mysecret-
    scan_interval: 300
  1. When trying to verify the config file before restarting I get the following error:

Platform error sensor.google_fit - Integration ‘google_fit’ not found.

Does anyone know what I am doing wrong?

Edit: Most recent version of these files require the sensor to be called google_fit_hass and not just google_fit :slight_smile: It was even in the readme (though not the documentation)

Edit2: I waited the 6 hours after adding the sensor but nothing shows up in HA, any suggestions?

Could someone add support for reading bloodpressure?

Were you able to get multiple users? I’m trying to do the same. I’ve added another email as a test user and created a seperate Oauth credentials, but I’m not able to get the notification to add the device code

Managed to create multiple users in a lazy way: made another OAuth stuff and created another integration named Fit2- copied existing folder to another one and changed the integration names to e.g. GFit2 and created another binding in configuration.yaml with second user credentials.
Dirty but works OK :slight_smile:
Best, JR

2 Likes