Google Fit Support

Is there any way to change the measurement units from metric to imperial for us ‘freedom unit’ impaired folks? I’m sure it could be done with templates, but it seems like the sensor should use the HA unit_system setting.

1 Like

I’m getting the following error:

2020-04-18 19:26:52 ERROR (MainThread) [homeassistant.components.sensor] google_fit: Error on device update!
Traceback (most recent call last):
  File "C:\Python38\lib\site-packages\homeassistant\helpers\entity_platform.py", line 312, in _async_add_entity
    await entity.async_device_update(warning=False)
  File "C:\Python38\lib\site-packages\homeassistant\helpers\entity.py", line 476, in async_device_update
    await self.hass.async_add_executor_job(self.update)
  File "C:\Python38\lib\concurrent\futures\thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "C:\Python38\lib\site-packages\homeassistant\util\__init__.py", line 240, in wrapper
    result = method(*args, **kwargs)
  File "C:\Python38\lib\site-packages\homeassistant\util\__init__.py", line 240, in wrapper
    result = method(*args, **kwargs)
  File "C:\Users\stefa\AppData\Roaming\.homeassistant\custom_components\google_fit\sensor.py", line 396, in update
    height_datasources = self._get_datasources('com.google.height')
  File "C:\Users\stefa\AppData\Roaming\.homeassistant\custom_components\google_fit\sensor.py", line 303, in _get_datasources
    datasources_request = self._client.users().dataSources().list(
AttributeError: 'NoneType' object has no attribute 'users'

I tried to remove the pycache and restart, but the error is still the same…

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, no errors in the log. Eyerything works fine.

“Freedom Unit” template sensor templates if still needed:

- platform: template
  sensors:
    sensor_weight:
      friendly_name: "weight"
      unit_of_measurement: 'lbs'
      value_template: "{{ (states('sensor.sensor_weight') | float * 2.20462262185) | round }}"
      icon_template: mdi:weight-pound
- platform: template
  sensors:
    sensor_distance:
      friendly_name: "distance"
      unit_of_measurement: 'mi'
      value_template: "{{ (states('sensor.sensor_distance') | float / 1.609) | round(2) }}"
      icon_template: mdi:map-marker-distance  
2 Likes

This works great, I’m digging it a lot! Hopefully this post helps anyone facing syncing issues… I use Fitbit and ended up needing to utilize a third party app to push my data over to Google Fit called FitToFit. Worked wonders syncing everything nice and easy, although I’m sure google will eventually make the sync more streamlined if they ever close on the Fitbit acquisition… FittoFit worked as an interim solution for me.

Disclaimer: I’m a total novice at this but if I can do it anyone can, hopefully the config can keep inspiring others as you have inspired me!

cards:
      - type: picture-elements
        title: Google Fit
        elements:
          - type: image
            image: /local/g_f.png
            style:
              width: 70%
              top: 50%
              left: 50%
              filter: blur(3px) brightness(80%)
          - type: state-label
            entity: sensor. s_calories
            style:
              top: 40%
              left: 50%
              font-size: 14px
              filter: brightness(140%)
          - type: state-icon
            entity: sensor. s_calories
            style:
              top: 20%
              left: 47%
              '--iron-icon-height': 70px
              '--iron-icon-width': 70px
              '--paper-item-icon-color': white
          - type: state-label
            entity: sensor. s_weight
            style:
              top: 80%
              left: 50%
              font-size: 14px
              filter: brightness(140%)
          - type: state-icon
            entity: sensor. s_weight
            style:
              top: 60%
              left: 47%
              '--iron-icon-height': 70px
              '--iron-icon-width': 70px
              '--paper-item-icon-color': white
          - type: state-label
            entity: sensor. s_sleep
            style:
              top: 80%
              left: 83%
              font-size: 14px
              filter: brightness(140%)
          - type: state-icon
            entity: sensor. s_sleep
            style:
              top: 60%
              left: 80%
              '--iron-icon-height': 70px
              '--iron-icon-width': 70px
              '--paper-item-icon-color': white
          - type: state-label
            entity: sensor. s_heart_rate
            style:
              top: 80%
              left: 18%
              font-size: 14px
              filter: brightness(140%)
          - type: state-icon
            entity: sensor. s_heart_rate
            style:
              top: 60%
              left: 15%
              '--iron-icon-height': 70px
              '--iron-icon-width': 70px
              '--paper-item-icon-color': white
          - type: state-label
            entity: sensor. s_steps
            style:
              top: 40%
              left: 18%
              font-size: 14px
              filter: brightness(140%)
          - type: state-icon
            entity: sensor. s_steps
            style:
              top: 20%
              left: 15%
              '--iron-icon-height': 70px
              '--iron-icon-width': 70px
              '--paper-item-icon-color': white
          - type: state-label
            entity: sensor. s_move_time
            style:
              top: 40%
              left: 83%
              font-size: 14px
              filter: brightness(140%)
          - type: state-icon
            entity: sensor.s_move_time
            style:
              top: 20%
              left: 80%
              '--iron-icon-height': 70px
              '--iron-icon-width': 70px
              '--paper-item-icon-color': white
        image: /local/gradient_background_1440x900_24bit.png
      - type: vertical-stack
        cards:
          - type: horizontal-stack
            cards:
              - type: sensor
                entity: sensor. s_move_time
                graph: line
                name: Move Time
              - entities:
                  - entity: sensor. s_steps
                    name: Steps
                hours_to_show: 168
                line_color:
                  - yellow
                icon: 'mdi:walk'
                refresh_interval: 0
                type: 'custom:mini-graph-card'
          - type: horizontal-stack
            cards:
              - entities:
                  - entity: sensor. s_heart_rate
                    name: Heart Rate
                hours_to_show: 24
                line_color:
                  - green
                icon: 'mdi:heart'
                refresh_interval: 0
                type: 'custom:mini-graph-card'
              - entities:
                  - entity: sensor. s_calories
                    name: Calories
                hours_to_show: 24
                line_color:
                  - red
                icon: 'mdi:food'
                refresh_interval: 0
                type: 'custom:mini-graph-card'
          - type: horizontal-stack
            cards:
              - entities:
                  - entity: sensor. s_move_time
                    name: Move Time
                hours_to_show: 24
                line_color:
                  - orange
                icon: 'mdi:clock-outline'
                refresh_interval: 0
                type: 'custom:mini-graph-card'
              - type: sensor
                entity: sensor.s_sleep
                name: Sleep
    icon: 'mdi:google-fit'
    path: google-fit
    title: Google Fit
6 Likes

Where can i find the repo for this custom component?

I used this: https://github.com/vmanuel/hacs-google-fit

Everything worked fine with google fit ( https://github.com/vmanuel/hacs-google-fit ) until updating to 0.109.0. Now i get a lot of errors in the log. However, the sensor still works.

2020-04-30 19:04:56 ERROR (MainThread) 
[homeassistant.components.websocket_api.http.connection.2770256720] Error handling message: Unknown error
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/decorators.py", line 20, in _handle_async_response
    await func(hass, connection, msg)
  File "/usr/src/homeassistant/homeassistant/components/frontend/__init__.py", line 550, in websocket_get_translations
    msg.get("config_flow"),
  File "/usr/src/homeassistant/homeassistant/helpers/translation.py", line 329, in async_get_translations
    resources = flatten(resource_func(results[0], components, category))
  File "/usr/src/homeassistant/homeassistant/helpers/translation.py", line 127, in merge_resources
    new_value = translation_strings[component].get(category)
KeyError: 'sensor.google_fit'
2020-04-30 19:04:58 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection.2770202000] Error handling message: Unknown error
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/decorators.py", line 20, in _handle_async_response
    await func(hass, connection, msg)
  File "/usr/src/homeassistant/homeassistant/components/frontend/__init__.py", line 550, in websocket_get_translations
    msg.get("config_flow"),
  File "/usr/src/homeassistant/homeassistant/helpers/translation.py", line 329, in async_get_translations
    resources = flatten(resource_func(results[0], components, category))
  File "/usr/src/homeassistant/homeassistant/helpers/translation.py", line 127, in merge_resources
    new_value = translation_strings[component].get(category)
KeyError: 'sensor.google_fit'
2020-04-30 19:04:59 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection.2796357232] Error handling message: Unknown error
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/decorators.py", line 20, in _handle_async_response
    await func(hass, connection, msg)
  File "/usr/src/homeassistant/homeassistant/components/frontend/__init__.py", line 550, in websocket_get_translations
    msg.get("config_flow"),
  File "/usr/src/homeassistant/homeassistant/helpers/translation.py", line 329, in async_get_translations
    resources = flatten(resource_func(results[0], components, category))
  File "/usr/src/homeassistant/homeassistant/helpers/translation.py", line 127, in merge_resources
    new_value = translation_strings[component].get(category)
KeyError: 'sensor.google_fit'

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?