Skip to content

Commit

Permalink
merge from develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom Goetz committed Jul 24, 2022
2 parents d2a5dc6 + df680da commit ba61f40
Show file tree
Hide file tree
Showing 19 changed files with 369 additions and 31 deletions.
2 changes: 1 addition & 1 deletion Fit
Submodule Fit updated from e5a5ec to 85de3d
5 changes: 3 additions & 2 deletions Jupyter/checkup.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@
],
"metadata": {
"interpreter": {
"hash": "d4f50e87ad7f9cd136d9d3dcf547b8236ee2585f92d0ab7c53dfb80e44e3fae9"
"hash": "bfd9857ee3bb42c16b52c1ffe04453343fea53c05fc5f9f2d5ac6a881cdaa36c"
},
"kernelspec": {
"display_name": "Python 3.9.5 64-bit ('.venv')",
"display_name": "Python 3.9.10 ('.venv': venv)",
"language": "python",
"name": "python3"
},
"language_info": {
Expand Down
214 changes: 214 additions & 0 deletions Jupyter/daily_trends.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "b8aada92",
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.dates as dates\n",
"import math\n",
"\n",
"import numpy as np\n",
"import datetime\n",
"from IPython.display import display, Markdown\n",
"import snakemd\n",
"import pandas as pd\n",
"\n",
"from garmindb import ConfigManager, Graph\n",
"from garmindb.garmindb import GarminSummaryDb, DaysSummary, MonitoringDb, MonitoringHeartRate, Sleep, GarminDb\n",
"from garmindb.summarydb import DaysSummary, WeeksSummary, MonthsSummary, SummaryDb\n",
"\n",
"from jupyter_funcs import format_number"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2d38e0f7-2ee5-40df-9373-b6485798d541",
"metadata": {},
"outputs": [],
"source": [
"def minsFromTime(t):\n",
" return float(t.hour * 3600 + t.minute * 60 + t.second) / 60.0"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7353aa53-92a0-44d9-b476-e050295c4748",
"metadata": {},
"outputs": [],
"source": [
"# start date\n",
"start_ts = datetime.datetime.combine(datetime.date(year=2022, month=5, day=1), datetime.datetime.min.time())\n",
"# end date (today)\n",
"end_ts = datetime.datetime.combine(datetime.date.today(), datetime.datetime.max.time())\n",
"\n",
"db_params = ConfigManager.get_db_params()\n",
"garmin_db = GarminDb(db_params)\n",
"sum_db = SummaryDb(db_params, False)\n",
"data = DaysSummary.get_for_period(sum_db, start_ts, end_ts, DaysSummary)\n",
"sleep = Sleep.get_for_period(garmin_db, start_ts, end_ts)\n",
"\n",
"time = [entry.day for entry in data]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e41203c2-d435-4045-9c84-3559b4d3b367",
"metadata": {},
"outputs": [],
"source": [
"stress_avg = [entry.stress_avg for entry in data]\n",
"bb_max = [entry.bb_max for entry in data]\n",
"bb_min = [entry.bb_min for entry in data]\n",
"rem_sleep_max = [minsFromTime(entry.rem_sleep_avg) for entry in data]\n",
"sleep_avg = [minsFromTime(entry.sleep_avg) / 60 for entry in data]\n",
"deep_sleep = [minsFromTime(sleep_event.deep_sleep) for sleep_event in sleep]\n",
"dm_df = pd.DataFrame([time, stress_avg, bb_max, bb_min, rem_sleep_max,deep_sleep, sleep_avg]).T\n",
"dm_df.columns = [\"Date\", \"stress_avg\", \"bb_max\", \"bb_min\", \"rem_sleep_max\", \"deep_sleep\", \"sleep_avg\"]\n",
"# remove the last record 'cause it's noisy sometimes\n",
"dm_df.drop(dm_df.tail(1).index,inplace=True) \n",
"dm_df\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ed0fe315",
"metadata": {},
"outputs": [],
"source": [
"\n",
"\n",
"columns = { \"stress_avg\" : \n",
" {\n",
" \"label\": \"Stress average\",\n",
" \"trend_marker\": \"--\",\n",
" \"color\": \"red\"\n",
"\n",
" }, \n",
" \"bb_max\": \n",
" {\n",
" \"label\": \"Body battery max\",\n",
" \"trend_marker\": \"--\",\n",
" \"color\": \"orange\"\n",
" },\n",
" \n",
" \"sleep_avg\": \n",
" {\n",
" \"label\": \"Sleep time (hrs)\",\n",
" \"trend_marker\": \"-.\",\n",
" \"color\": \"blue\"\n",
" },\n",
" \"rem_sleep_max\": \n",
" {\n",
" \"label\": \"Rem Sleep time (mins)\",\n",
" \"trend_marker\": \"-\",\n",
" \"color\": \"purple\"\n",
" },\n",
" \n",
" \"deep_sleep\": \n",
" {\n",
" \"label\": \"Deep sleep (mins)\",\n",
" \"trend_marker\": \"-\",\n",
" \"color\": \"green\"\n",
" }\n",
" }\n",
"\n",
"# these are the data columns to plot\n",
"show_cols = {\"deep_sleep\", \"stress_avg\", \"bb_max\"}\n",
"\n",
"fig, host = plt.subplots(figsize=(22,16))\n",
"\n",
"plots = []\n",
"fit_summary = []\n",
"step = 0\n",
"\n",
"for col in show_cols:\n",
" label=columns[col][\"label\"]\n",
" \n",
" ax2 = host.twinx()\n",
" ax2.set_ylabel(label)\n",
" ax2.tick_params(axis='y', labelcolor=columns[col][\"color\"])\n",
"\n",
" # data\n",
" plot, = ax2.plot(dm_df.Date, dm_df[col], 'o', ms=3.0, color=columns[col][\"color\"], label=label)\n",
" plots.append(plot)\n",
" \n",
" # trend\n",
" fitlabel = 'Fit {}'.format(label)\n",
" x_dates = dates.date2num(dm_df.Date)\n",
" trend = np.polyfit(x_dates, dm_df[col].astype(float) , 1)\n",
" fit = np.poly1d(trend)\n",
" x_fit = np.linspace(x_dates.min(), x_dates.max())\n",
" fit, = ax2.plot(dates.num2date(x_fit), fit(x_fit), linestyle=columns[col][\"trend_marker\"], color=columns[col][\"color\"],label=fitlabel)\n",
" plots.append(fit)\n",
" \n",
" ax2.spines['right'].set_position(('outward', step))\n",
" \n",
" step = step + 60\n",
"\n",
" fit_data = fit.get_ydata()\n",
" \n",
" fit_summary.append({\"\": fitlabel, \"min\": math.floor(fit_data.min()), \"max\":math.floor(fit_data.max())})\n",
" \n",
" \n",
" \n",
" \n",
"host.legend(handles=plots, loc='best')\n",
"\n",
"col_label = \"\"\n",
"for col in show_cols:\n",
" if len(col_label):\n",
" col_label += \", \"\n",
" col_label += f\"{col}\"\n",
"\n",
"title = f\"{col_label} from {start_ts.date()} to {end_ts.date()}\"\n",
"\n",
"plt.title(label=title, fontsize=25)\n",
"\n",
"plt.show()\n",
"pd.DataFrame(fit_summary)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cab36f4b",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"interpreter": {
"hash": "bfd9857ee3bb42c16b52c1ffe04453343fea53c05fc5f9f2d5ac6a881cdaa36c"
},
"kernelspec": {
"display_name": "Python 3.9.10 ('.venv': venv)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
5 changes: 3 additions & 2 deletions Jupyter/monitoring.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,11 @@
],
"metadata": {
"interpreter": {
"hash": "d4f50e87ad7f9cd136d9d3dcf547b8236ee2585f92d0ab7c53dfb80e44e3fae9"
"hash": "bfd9857ee3bb42c16b52c1ffe04453343fea53c05fc5f9f2d5ac6a881cdaa36c"
},
"kernelspec": {
"display_name": "Python 3.9.5 64-bit ('.venv')",
"display_name": "Python 3.9.10 ('.venv': venv)",
"language": "python",
"name": "python3"
},
"language_info": {
Expand Down
3 changes: 2 additions & 1 deletion Jupyter/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
snakemd
snakemd
pandas
2 changes: 1 addition & 1 deletion Plugins
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

[![Screen shot of an activity display](https://raw.githubusercontent.com/tcgoetz/GarminDB/master/Screenshots/Screen_Shot_activity_sm.jpg)](https://github.com/tcgoetz/GarminDB/wiki/Screenshots)

---

[![Screen shot of daily trend ](Screenshots/Screen_Shot_daily_trend.png)](https://github.com/tcgoetz/GarminDB/wiki/Screenshots)


# GarminDB

Expand Down
Binary file added Screenshots/Screen_Shot_daily_trend.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion garmindb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from .statistics import Statistics
from .tcx import Tcx
from .monitoring_fit_file_processor import MonitoringFitFileProcessor
from .sleep_fit_file_processor import SleepFitFileProcessor
from .export_activities import ActivityExporter
from .open_with_basecamp import OpenWithBaseCamp
from .open_with_google_earth import OpenWithGoogleEarth
Expand All @@ -34,7 +35,7 @@
from .plugin_manager import PluginManager
from .version import format_version, log_version, python_version_check

from .import_monitoring import GarminMonitoringFitData, GarminSummaryData, GarminProfile, GarminWeightData, GarminSleepData, GarminRhrData, GarminSettingsFitData, GarminHydrationData
from .import_monitoring import GarminMonitoringFitData, GarminSleepFitData, GarminSummaryData, GarminProfile, GarminWeightData, GarminSleepData, GarminRhrData, GarminSettingsFitData, GarminHydrationData
from .activities_fit_data import GarminActivitiesFitData
from .garmin_tcx_data import GarminTcxData
from .garmin_json_data import GarminJsonSummaryData, GarminJsonDetailsData
10 changes: 5 additions & 5 deletions garmindb/fit_file_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
class FitFileProcessor():
"""Class that takes a parsed FIT file object and imports it into a database."""

def __init__(self, db_params, plugin_manager, debug=0):
def __init__(self, db_params, plugin_manager=None, debug=0):
"""
Return a new FitFileProcessor instance.
Expand Down Expand Up @@ -204,15 +204,15 @@ def _write_attributes(self, timestamp, message_fields, attribute_names):
for attribute_name in attribute_names:
self._write_attribute(timestamp, message_fields, attribute_name)

def _write_measurement_ssytem_attributes(self, timestamp, message_fields):
def _write_measurement_sytem_attributes(self, timestamp, message_fields):
for attribute_name in ['dist_setting', 'speed_setting', 'height_setting', 'temperature_setting']:
self._write_attribute(timestamp, message_fields, attribute_name, 'measurement_system')

def _write_device_settings_entry(self, fit_file, message_fields):
root_logger.debug("device settings message: %r", message_fields)
timestamp = fit_file.time_created_local
self._write_attributes(timestamp, message_fields, ['active_time_zone', 'date_mode'])
self._write_measurement_ssytem_attributes(timestamp, message_fields)
self._write_measurement_sytem_attributes(timestamp, message_fields)
self._write_attribute(timestamp, message_fields, 'active_time_zone', 'time_zone')
self._write_attribute(timestamp, message_fields, 'date_mode', 'date_format')

Expand All @@ -223,11 +223,11 @@ def _write_user_profile_entry(self, fit_file, message_fields):
root_logger.debug("user profile message: %r", message_fields)
timestamp = fit_file.time_created_local
attribute_names = [
'gender', 'height', 'weight', 'language', 'dist_setting', 'weight_setting', 'position_setting', 'elev_setting', 'sleep_time', 'wake_time',
'gender', 'height', 'weight', 'age', 'year_of_birth', 'language', 'dist_setting', 'weight_setting', 'position_setting', 'elev_setting', 'sleep_time', 'wake_time',
'speed_setting'
]
self._write_attributes(timestamp, message_fields, attribute_names)
self._write_measurement_ssytem_attributes(timestamp, message_fields)
self._write_measurement_sytem_attributes(timestamp, message_fields)

def _write_activity_entry(self, fit_file, message_fields):
root_logger.debug("activity message: %r", message_fields)
Expand Down
29 changes: 28 additions & 1 deletion garmindb/garmindb/garmin_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ class Sleep(GarminDb.Base, idbutils.DbObject):
__tablename__ = 'sleep'

db = GarminDb
table_version = 1
table_version = 2

day = Column(Date, primary_key=True)
start = Column(DateTime)
Expand All @@ -235,6 +235,9 @@ class Sleep(GarminDb.Base, idbutils.DbObject):
light_sleep = Column(Time, nullable=False, default=datetime.time.min)
rem_sleep = Column(Time, nullable=False, default=datetime.time.min)
awake = Column(Time, nullable=False, default=datetime.time.min)
avg_spo2 = Column(Float)
avg_rr = Column(Float)
avg_stress = Column(Float)

@classmethod
def get_stats(cls, session, start_ts, end_ts):
Expand Down Expand Up @@ -270,6 +273,30 @@ def get_wake_time(cls, db, day_date):
if len(values) > 0:
return values[0][0]

@classmethod
def get_level_time(cls, session, day_date, sleep_level):
"""Return the time in a given sleep level for a given date."""
day_start_ts = datetime.datetime.combine(day_date, datetime.time.min)
day_stop_ts = datetime.datetime.combine(day_date, datetime.time.max)
result = cls._s_query(session, cls._time_from_secs(func.sum(cls._secs_from_time(cls.duration))), None, day_start_ts, day_stop_ts,
cls._secs_from_time(cls.duration)).filter(cls.event == sleep_level).scalar()
return datetime.datetime.strptime(result, '%H:%M:%S').time() if result is not None else datetime.time.min

@classmethod
def get_day_stats(cls, session, day_date):
"""Return a dictionary of aggregate statistics for the given time period."""
deep_sleep = cls.get_level_time(cls, session, day_date, 'deep_sleep')
light_sleep = cls.get_level_time(cls, session, day_date, 'light_sleep')
rem_sleep = cls.get_level_time(cls, session, day_date, 'rem_sleep')
awake = cls.get_level_time(cls, session, day_date, 'awake')
return {
'total_sleep': deep_sleep + light_sleep + rem_sleep,
'deep_sleep': deep_sleep,
'light_sleep': light_sleep,
'rem_sleep': rem_sleep,
'awake': awake
}


class RestingHeartRate(GarminDb.Base, idbutils.DbObject):
"""Class representing a daily resting heart rate reading."""
Expand Down
Loading

0 comments on commit ba61f40

Please sign in to comment.