Added Google Fit backend
This commit is contained in:
parent
55c0896b31
commit
87d63d7cb3
4 changed files with 139 additions and 6 deletions
88
platypush/backend/google/fit.py
Normal file
88
platypush/backend/google/fit.py
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
import time
|
||||||
|
|
||||||
|
from platypush.backend import Backend
|
||||||
|
from platypush.context import get_plugin
|
||||||
|
from platypush.message.event.google.fit import GoogleFitEvent
|
||||||
|
|
||||||
|
|
||||||
|
class GoogleFitBackend(Backend):
|
||||||
|
"""
|
||||||
|
This backend will listen for new Google Fit events (e.g. new weight/height
|
||||||
|
measurements, new fitness activities etc.) on the specified data streams and
|
||||||
|
fire an event upon new data.
|
||||||
|
|
||||||
|
Triggers:
|
||||||
|
|
||||||
|
* :class:`platypush.message.event.google.fit.GoogleFitEvent` when a new
|
||||||
|
data point is received on one of the registered streams.
|
||||||
|
|
||||||
|
Requires:
|
||||||
|
|
||||||
|
* The **google.fit** plugin
|
||||||
|
(:class:`platypush.plugins.google.fit.GoogleFitPlugin`) enabled.
|
||||||
|
* The **db** plugin (:class:`platypush.plugins.db`) configured
|
||||||
|
"""
|
||||||
|
|
||||||
|
_default_poll_seconds = 60
|
||||||
|
_default_user_id = 'me'
|
||||||
|
_last_timestamp_varname = '_GOOGLE_FIT_LAST_TIMESTAMP'
|
||||||
|
|
||||||
|
def __init__(self, data_sources, user_id=_default_user_id,
|
||||||
|
poll_seconds=_default_poll_seconds, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
:param data_sources: Google Fit data source IDs to monitor. You can
|
||||||
|
get a list of the available data sources through the
|
||||||
|
:method:`platypush.plugins.google.fit.get_data_sources` action
|
||||||
|
:type data_sources: list[str]
|
||||||
|
|
||||||
|
:param user_id: Google user ID to track (default: 'me')
|
||||||
|
:type user_id: str
|
||||||
|
|
||||||
|
:param poll_seconds: How often the backend will query the data sources
|
||||||
|
for new data points (default: 60 seconds)
|
||||||
|
:type poll_seconds: float
|
||||||
|
"""
|
||||||
|
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.data_sources = data_sources
|
||||||
|
self.user_id = user_id
|
||||||
|
self.poll_seconds = poll_seconds
|
||||||
|
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
super().run()
|
||||||
|
self.logger.info('Started Google Fit backend on data sources {}'.format(
|
||||||
|
self.data_sources))
|
||||||
|
|
||||||
|
while not self.should_stop():
|
||||||
|
last_timestamp = float(get_plugin('variable').
|
||||||
|
get(self._last_timestamp_varname).output.
|
||||||
|
get(self._last_timestamp_varname)) or 0
|
||||||
|
|
||||||
|
for data_source in self.data_sources:
|
||||||
|
new_last_timestamp = last_timestamp
|
||||||
|
|
||||||
|
for dp in get_plugin('google.fit').get_data(
|
||||||
|
user_id=self.user_id, data_source_id=data_source).output:
|
||||||
|
dp_time = dp.get('startTime', 0)
|
||||||
|
if dp_time > last_timestamp:
|
||||||
|
self.bus.post(GoogleFitEvent(
|
||||||
|
user_id=self.user_id, data_source_id=data_source,
|
||||||
|
data_type=dp.get('dataTypeName'),
|
||||||
|
start_time=dp.get('startTime'),
|
||||||
|
end_time=dp.get('endTime'),
|
||||||
|
modified_time=dp.get('modifiedTime'),
|
||||||
|
values=dp.get('values')))
|
||||||
|
|
||||||
|
if dp_time > new_last_timestamp:
|
||||||
|
new_last_timestamp = dp_time
|
||||||
|
|
||||||
|
last_timestamp = new_last_timestamp
|
||||||
|
|
||||||
|
get_plugin('variable').set(**{
|
||||||
|
self._last_timestamp_varname: last_timestamp})
|
||||||
|
time.sleep(self.poll_seconds)
|
||||||
|
|
||||||
|
|
||||||
|
# vim:sw=4:ts=4:et:
|
0
platypush/message/event/google/__init__.py
Normal file
0
platypush/message/event/google/__init__.py
Normal file
14
platypush/message/event/google/fit.py
Normal file
14
platypush/message/event/google/fit.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
from platypush.message.event import Event
|
||||||
|
|
||||||
|
|
||||||
|
class GoogleFitEvent(Event):
|
||||||
|
"""
|
||||||
|
Event triggered upon new Google Fit data points
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, data_source_id, values, *args, **kwargs):
|
||||||
|
super().__init__(*args, data_source_id=data_source_id, values=values,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
# vim:sw=4:ts=4:et:
|
|
@ -1,5 +1,3 @@
|
||||||
from apiclient import discovery
|
|
||||||
|
|
||||||
from platypush.plugins import action
|
from platypush.plugins import action
|
||||||
from platypush.plugins.google import GooglePlugin
|
from platypush.plugins.google import GooglePlugin
|
||||||
|
|
||||||
|
@ -38,7 +36,7 @@ class GoogleFitPlugin(GooglePlugin):
|
||||||
return sources['dataSource']
|
return sources['dataSource']
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def get_data(self, data_source_id, user_id=None):
|
def get_data(self, data_source_id, user_id=None, limit=None):
|
||||||
"""
|
"""
|
||||||
Get raw data for the specified data_source_id
|
Get raw data for the specified data_source_id
|
||||||
|
|
||||||
|
@ -47,9 +45,42 @@ class GoogleFitPlugin(GooglePlugin):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
service = self.get_service(service='fitness', version='v1')
|
service = self.get_service(service='fitness', version='v1')
|
||||||
return service.users().dataSources().dataPointChanges() \
|
kwargs = {
|
||||||
.list(dataSourceId=data_source_id, userId=user_id or self.user_id) \
|
'dataSourceId': data_source_id,
|
||||||
.execute().get('insertedDataPoint', [])
|
'userId': user_id or self.user_id,
|
||||||
|
}
|
||||||
|
|
||||||
|
if limit:
|
||||||
|
kwargs['limit'] = limit
|
||||||
|
data_points = []
|
||||||
|
|
||||||
|
for data_point in service.users().dataSources().dataPointChanges(). \
|
||||||
|
list(**kwargs).execute().get('insertedDataPoint', []):
|
||||||
|
data_point['startTime'] = float(data_point.pop('startTimeNanos'))/1e9
|
||||||
|
data_point['endTime'] = float(data_point.pop('endTimeNanos'))/1e9
|
||||||
|
data_point['modifiedTime'] = float(data_point.pop('modifiedTimeMillis'))/1e6
|
||||||
|
values = []
|
||||||
|
|
||||||
|
for value in data_point.pop('value'):
|
||||||
|
if value.get('intVal') is not None:
|
||||||
|
value = value['intVal']
|
||||||
|
elif value.get('fpVal') is not None:
|
||||||
|
value = value['fpVal']
|
||||||
|
elif value.get('stringVal') is not None:
|
||||||
|
value = value['stringVal']
|
||||||
|
elif value.get('mapVal'):
|
||||||
|
value = {
|
||||||
|
v['key']: v['value'].get(
|
||||||
|
'intVal', v['value'].get(
|
||||||
|
'fpVal', v['value'].get('stringVal')))
|
||||||
|
for v in value['mapVal'] }
|
||||||
|
|
||||||
|
values.append(value)
|
||||||
|
|
||||||
|
data_point['values'] = values
|
||||||
|
data_points.append(data_point)
|
||||||
|
|
||||||
|
return data_points
|
||||||
|
|
||||||
|
|
||||||
# vim:sw=4:ts=4:et:
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
Loading…
Reference in a new issue