Skip to content
This repository has been archived by the owner on Oct 31, 2023. It is now read-only.

Commit

Permalink
Merge pull request #8 from tomshaffner/master
Browse files Browse the repository at this point in the history
Renaming weight sensor and adding lbs version
  • Loading branch information
vmanuel authored May 5, 2021
2 parents 080f653 + e4a07f5 commit 7cc07c7
Showing 1 changed file with 171 additions and 16 deletions.
187 changes: 171 additions & 16 deletions custom_components/google_fit/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
CONF_CLIENT_SECRET = 'client_secret'
DEFAULT_NAME = 'Google Fit'
ICON = 'mdi:heart-pulse'
MIN_TIME_BETWEEN_SCANS = timedelta(minutes=10)
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=10)
MIN_TIME_BETWEEN_SCANS = timedelta(minutes=8)
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=8)
SENSOR_NAME = '{} {}'


Expand All @@ -51,13 +51,16 @@
# Google Fit API URL.
API_VERSION = 'v1'
API_USER_ID = 'me'
WEIGHT = 'weight'
WEIGHT_LBS = 'weight (lbs)'
WEIGHT_KG = 'weight (kg)'
HEIGHT = 'height'
DISTANCE = 'distance'
DISTANCE_KM = 'distance (km)'
DISTANCE_MI = 'distance (mi)'
STEPS = 'steps'
MOVE_TIME = 'move time'
CALORIES = 'calories'
SLEEP = 'sleep'
MEDITATION = 'meditation'
HEARTRATE = 'heart rate'
TOKEN_FILE = ''

Expand All @@ -69,13 +72,16 @@
'https://www.googleapis.com/auth/fitness.activity.read',
'https://www.googleapis.com/auth/fitness.location.read']


def _today_dataset_start():
today = datetime.today().date()
return int(time.mktime(today.timetuple()) * 1000000000)


def _today_dataset_end():
now = datetime.today()
return int(time.mktime(now.timetuple()) * 1000000000)
return int(time.mktime(now.timetuple()) * 1000000000 + 1)


def _get_client(token_file):
"""Get the Google Fit service with the storage file token.
Expand All @@ -99,6 +105,7 @@ def _get_client(token_file):
'fitness', API_VERSION, http=http, cache_discovery=False)
return service


def setup(hass, config):
"""Set up the Google Fit platform."""
name = config.get(const.CONF_NAME)
Expand Down Expand Up @@ -179,14 +186,17 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
token_file = hass.config.path(TOKEN_FILE)
client = _get_client(token_file)

add_devices([GoogleFitWeightSensor(client, name),
add_devices([GoogleFitWeightLbsSensor(client,name),
GoogleFitWeightKGSensor(client, name),
GoogleFitHeartRateSensor(client, name),
GoogleFitHeightSensor(client, name),
GoogleFitStepsSensor(client, name),
GoogleFitSleepSensor(client, name),
GoogleFitMeditationSensor(client, name),
GoogleFitMoveTimeSensor(client, name),
GoogleFitCaloriesSensor(client, name),
GoogleFitDistanceSensor(client, name)], True)
GoogleFitDistanceKmSensor(client, name),
GoogleFitDistanceMiSensor(client, name)], True)


class GoogleFitSensor(entity.Entity):
Expand Down Expand Up @@ -300,7 +310,8 @@ def _get_dataset_from_last_update(self, source):
get(userId=API_USER_ID, dataSourceId=source, datasetId=dataset). \
execute()

class GoogleFitWeightSensor(GoogleFitSensor):

class GoogleFitWeightKGSensor(GoogleFitSensor):
@property
def unit_of_measurement(self):
"""Returns the unit of measurement."""
Expand All @@ -314,7 +325,7 @@ def icon(self):
@property
def _name_suffix(self):
"""Returns the name suffix of the sensor."""
return WEIGHT
return WEIGHT_KG

@util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_UPDATES)
def update(self):
Expand Down Expand Up @@ -361,6 +372,67 @@ def update(self):
self._attributes = {}


class GoogleFitWeightLbsSensor(GoogleFitSensor):
@property
def unit_of_measurement(self):
"""Returns the unit of measurement."""
return const.MASS_POUNDS

@property
def icon(self):
"""Return the icon."""
return 'mdi:weight-pound'

@property
def _name_suffix(self):
"""Returns the name suffix of the sensor."""
return WEIGHT_LBS

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

weight_datasources = self._get_datasources('com.google.weight')

weight_datapoints = {}
for datasource in weight_datasources:
datasource_id = datasource.get('dataStreamId')
weight_request = self._client.users().dataSources().\
dataPointChanges().list(
userId=API_USER_ID,
dataSourceId=datasource_id,
)
weight_data = weight_request.execute()
weight_inserted_datapoints = weight_data.get('insertedDataPoint')

for datapoint in weight_inserted_datapoints:
point_value = datapoint.get('value')
if not point_value:
continue
weight = point_value[0].get('fpVal')
if not weight:
continue
weight = round(weight * 2.20462262185, 2) # Convert to pounds while rounding
last_update_milis = int(datapoint.get('modifiedTimeMillis', 0))
if not last_update_milis:
continue
weight_datapoints[last_update_milis] = weight

if weight_datapoints:
time_updates = list(weight_datapoints.keys())
time_updates.sort(reverse=True)

last_time_update = time_updates[0]
last_weight = weight_datapoints[last_time_update]

self._last_updated = round(last_time_update / 1000)
self._state = last_weight
_LOGGER.debug("Last weight %s", last_weight)
self._attributes = {}


class GoogleFitHeightSensor(GoogleFitSensor):
@property
def unit_of_measurement(self):
Expand Down Expand Up @@ -462,8 +534,6 @@ def update(self):
self._attributes = {}




class GoogleFitStepsSensor(GoogleFitSensor):
DATA_SOURCE = "derived:com.google.step_count.delta:" \
"com.google.android.gms:estimated_steps"
Expand Down Expand Up @@ -565,14 +635,14 @@ def update(self):
self._attributes = {}


class GoogleFitDistanceSensor(GoogleFitSensor):
class GoogleFitDistanceKmSensor(GoogleFitSensor):
DATA_SOURCE = "derived:com.google.distance.delta:" \
"com.google.android.gms:merge_distance_delta"

@property
def _name_suffix(self):
"""Returns the name suffix of the sensor."""
return DISTANCE
return DISTANCE_KM

@property
def unit_of_measurement(self):
Expand All @@ -597,8 +667,40 @@ def update(self):
_LOGGER.debug("Distance %s", self._state)
self._attributes = {}

class GoogleFitSleepSensor(GoogleFitSensor):

class GoogleFitDistanceMiSensor(GoogleFitSensor):
DATA_SOURCE = "derived:com.google.distance.delta:" \
"com.google.android.gms:merge_distance_delta"

@property
def _name_suffix(self):
"""Returns the name suffix of the sensor."""
return DISTANCE_MI

@property
def unit_of_measurement(self):
"""Returns the unit of measurement."""
return const.LENGTH_MILES

@property
def icon(self):
"""Return the icon."""
return 'mdi:map-marker-distance'

@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 = round(sum(values) / 1000 * 0.62137119, 2)
_LOGGER.debug("Distance %s", self._state)
self._attributes = {}


class GoogleFitSleepSensor(GoogleFitSensor):
@property
def _name_suffix(self):
"""Returns the name suffix of the sensor."""
Expand Down Expand Up @@ -657,4 +759,57 @@ def update(self):
else:
self._state = ""
self._attributes = {}
self._last_updated = time.time()
self._last_updated = time.time()


class GoogleFitMeditationSensor(GoogleFitSensor):
@property
def _name_suffix(self):
"""Returns the name suffix of the sensor."""
return MEDITATION

@property
def unit_of_measurement(self):
"""Returns the unit of measurement."""
return 'min'

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

@util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_UPDATES)
def update(self):
"""Extracts the relevant data points for from the Fitness API."""
yesterday = datetime.now().replace(hour=17,minute=0,second=0,microsecond=0)
yesterday = yesterday - timedelta(days=1)
starttime = yesterday.isoformat("T") + "Z"
today = datetime.now().replace(hour=11,minute=0,second=0,microsecond=0)
endtime = today.isoformat("T") + "Z"
_LOGGER.debug("Starttime %s, Endtime %s", starttime, endtime)
meditation_dataset = self._client.users().sessions().list(userId='me',fields='session',startTime=starttime,endTime=endtime).execute()
starts = []
ends = []
meditation = []
_LOGGER.debug("Meditation dataset %s", meditation_dataset)
for point in meditation_dataset["session"]:
if int(point["activityType"]) == 45 : # https://developers.google.com/fit/rest/v1/reference/activity-types
starts.append(int(point["startTimeMillis"]))
ends.append(int(point["endTimeMillis"]))
meditation_start = datetime.fromtimestamp(int(point["startTimeMillis"]) / 1000)
meditation_end = datetime.fromtimestamp(int(point["endTimeMillis"]) / 1000)
_LOGGER.debug("Meditation dataset Total %s", (meditation_end - meditation_start))
meditation.append(meditation_end - meditation_start)

if len(starts) != 0 or len(ends) != 0:
start_time = datetime.fromtimestamp(round(min(starts) / 1000))
end_time = datetime.fromtimestamp(round(max(ends) / 1000))
total_meditation = sum(meditation,timedelta())
state_dict = dict({'first_start_time': str(start_time), 'last_end_time': str(end_time), 'total_meditation': str(total_meditation)})
self._state = total_meditation.total_seconds() // 60
self._attributes = state_dict
self._last_updated = time.time()
else:
self._state = ""
self._attributes = {}
self._last_updated = time.time()

0 comments on commit 7cc07c7

Please sign in to comment.