diff --git a/.github/workflows/branch_builds.yaml b/.github/workflows/branch_builds.yaml new file mode 100644 index 0000000..4f4a759 --- /dev/null +++ b/.github/workflows/branch_builds.yaml @@ -0,0 +1,41 @@ +name: Build an image for each non-main branch with tag : + +permissions: + contents: write + +on: + push: + branches: + - '**' # matches every branch + - '!main' # excludes master + +jobs: + build-and-release: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + name: Dockerhub login + uses: docker/login-action@v2 + with: + username: ${{ github.repository_owner }} + password: ${{ secrets.DOCKER_TOKEN }} + - + name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Inject slug/short variables + uses: rlespinasse/github-slug-action@v4 + - + name: Docker build & push + uses: docker/build-push-action@v4 + with: + context: ./ingester + push: true + platforms: linux/amd64,linux/arm64 + tags: ${{ github.repository }}-ingester:${{ env.GITHUB_REF_SLUG }} diff --git a/ingester/app.py b/ingester/app.py index f91a94b..d40145d 100644 --- a/ingester/app.py +++ b/ingester/app.py @@ -11,7 +11,8 @@ from typing import Any, Union import subprocess -from formatters import parse_date_as_timestamp, parse_float_with_try, AppleStandHourFormatter +from formatters import parse_date_as_timestamp, parse_float_with_try, AppleStandHourFormatter, SleepAnalysisFormatter + import gpxpy from gpxpy.gpx import GPXTrackPoint from influxdb import InfluxDBClient @@ -56,18 +57,20 @@ def format_record(record: dict[str, Any]) -> dict[str, Any]: if measurement == "AppleStandHour": return AppleStandHourFormatter(record) + if measurement == "SleepAnalysis": + return SleepAnalysisFormatter(record) date = parse_date_as_timestamp(record.get("startDate", 0)) value = parse_float_with_try(record.get("value", 1)) unit = record.get("unit", "unit") device = record.get("sourceName", "unknown") - return { + return [{ "measurement": measurement, "time": date, "fields": {"value": value}, "tags": {"unit": unit, "device": device}, - } + }] def format_workout(record: dict[str, Any]) -> dict[str, Any]: @@ -136,7 +139,11 @@ def process_health_data(client: InfluxDBClient) -> None: context = etree.iterparse(export_file,recover=True) for _, elem in context: if elem.tag == "Record": - records.append(format_record(elem)) + rec = format_record(elem) + if isinstance(rec,list): + records += rec + else: + records.append(format_record(elem)) elem.clear() elif elem.tag == "Workout": records.append(format_workout(elem)) @@ -180,4 +187,4 @@ def process_health_data(client: InfluxDBClient) -> None: process_workout_routes(client) process_health_data(client) - print("All done! You can now check grafana.") + print("All done! You can now check grafana.") \ No newline at end of file diff --git a/ingester/formatters.py b/ingester/formatters.py index c69fd15..d567d8b 100644 --- a/ingester/formatters.py +++ b/ingester/formatters.py @@ -1,4 +1,6 @@ from datetime import datetime as dt +from datetime import timedelta + from typing import Any, Union @@ -28,4 +30,50 @@ def AppleStandHourFormatter(record: dict) -> dict: "time": date, "fields": {"value": value}, "tags": {"unit": unit, "device": device}, - } \ No newline at end of file + } + + +sleep_states_lookup={ + "HKCategoryValueSleepAnalysisAsleepDeep":0, + "HKCategoryValueSleepAnalysisAsleepCore":1, + "HKCategoryValueSleepAnalysisAsleepREM":2, + #"HKCategoryValueSleepAnalysisAsleepUnspecified":3, + "HKCategoryValueSleepAnalysisInBed": 3, + "HKCategoryValueSleepAnalysisAwake":4, +} + +sleep_states_short_lookup={ + "HKCategoryValueSleepAnalysisAsleepDeep":"Deep", + "HKCategoryValueSleepAnalysisAsleepCore":"Core", + "HKCategoryValueSleepAnalysisAsleepREM":"REM", + #"HKCategoryValueSleepAnalysisAsleepUnspecified":"Asleep", + "HKCategoryValueSleepAnalysisInBed": "Asleep", + "HKCategoryValueSleepAnalysisAwake":"Awake", +} + +def SleepAnalysisFormatter(record: dict) -> dict: + start_date = dt.fromisoformat(record.get("startDate")) + start_date.replace(second=0) + end_date = dt.fromisoformat(record.get("endDate")) + device = record.get("sourceName", "unknown") + state = sleep_states_lookup.get(record.get("value"),5) + if "Apple Watch" in device: + print(start_date,end_date,device,state) + + minutes_in_bed = [] + while start_date <= end_date: + minutes_in_bed.append({ + 'measurement':"SleepAnalysisTimes-{}".format(device), + "time":int(start_date.timestamp()), + "fields": {"value":state}, + "tags": {} + }) + start_date += timedelta(minutes=1) + + minutes_in_bed.append({ + 'measurement':'SleepAnalysis', + "time":start_date, + "fields": {"start": int(dt.fromisoformat(record.get("startDate")).timestamp()),"stop":int(dt.fromisoformat(record.get("endDate")).timestamp())}, + "tags": {"unit": 'seconds', "device": device,'state':sleep_states_short_lookup.get(record.get("value"),"Unspecified")} + }) + return minutes_in_bed diff --git a/provisioning/dashboards/dashs/sleep-tracking.json b/provisioning/dashboards/dashs/sleep-tracking.json new file mode 100644 index 0000000..4013b2b --- /dev/null +++ b/provisioning/dashboards/dashs/sleep-tracking.json @@ -0,0 +1,1174 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Pull from an Apple watch sleep tracking data", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 5, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds", + "seriesBy": "last" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisGridShow": false, + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 0, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 3, + "pointSize": 10, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "mappings": [ + { + "options": { + "0": { + "color": "purple", + "index": 0, + "text": "Deep sleep" + }, + "1": { + "color": "semi-dark-blue", + "index": 1, + "text": "Core Sleep" + }, + "2": { + "color": "light-blue", + "index": 2, + "text": "REM Sleep" + }, + "3": { + "color": "super-light-blue", + "index": 3, + "text": "Asleep" + }, + "4": { + "color": "light-orange", + "index": 4, + "text": "Awake" + } + }, + "type": "value" + } + ], + "max": 4, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + }, + { + "color": "semi-dark-blue", + "value": 1 + }, + { + "color": "blue", + "value": 2 + }, + { + "color": "super-light-blue", + "value": 3 + }, + { + "color": "yellow", + "value": 4 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "interval": "10s", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "measurement": "/^$sleep_sources$/", + "orderByTime": "ASC", + "policy": "autogen", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [] + } + ], + "title": "Sleep analysis", + "type": "timeseries" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + } + ] + }, + "unit": "m" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 15, + "x": 0, + "y": 13 + }, + "id": 5, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "vertical", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.3", + "targets": [ + { + "alias": "REM Sleep", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE (\"value\"::field = 2) AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + }, + { + "alias": "Core Sleep", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "hide": false, + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE (\"value\"::field = 1) AND $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + }, + { + "alias": "Deep Sleep", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "hide": false, + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE (\"value\"::field = 0) AND $timeFilter", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + }, + { + "alias": "Asleep", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "hide": false, + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE (\"value\"::field = 3) AND $timeFilter", + "rawQuery": true, + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + }, + { + "alias": "Awake", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "hide": false, + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE (\"value\"::field = 4) AND $timeFilter", + "rawQuery": true, + "refId": "E", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + }, + { + "alias": "Total sleep time", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "hide": false, + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE $timeFilter", + "rawQuery": true, + "refId": "F", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + } + ], + "title": "Time in each sleep category ", + "type": "stat" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "yellow", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 2, + "x": 15, + "y": 13 + }, + "id": 10, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.3", + "targets": [ + { + "alias": "Awake", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE (\"value\"::field = 4) AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + }, + { + "alias": "Total", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "hide": false, + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + } + ], + "transformations": [ + { + "id": "joinByField", + "options": { + "byField": "Time", + "mode": "outer" + } + }, + { + "id": "calculateField", + "options": { + "alias": "Awake", + "binary": { + "left": "Awake", + "operator": "/", + "reducer": "sum", + "right": "Total" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": true + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-blue", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 17, + "y": 13 + }, + "id": 8, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.3", + "targets": [ + { + "alias": "Normal Sleep", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE (\"value\"::field = 3) AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + }, + { + "alias": "Total", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "hide": false, + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + } + ], + "transformations": [ + { + "id": "joinByField", + "options": { + "byField": "Time", + "mode": "outer" + } + }, + { + "id": "calculateField", + "options": { + "alias": "Normal Sleep", + "binary": { + "left": "Normal Sleep", + "operator": "/", + "reducer": "sum", + "right": "Total" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": true + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 13 + }, + "id": 6, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.3", + "targets": [ + { + "alias": "REM Sleep", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE (\"value\"::field = 2) AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + }, + { + "alias": "Total", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "hide": false, + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + } + ], + "transformations": [ + { + "id": "joinByField", + "options": { + "byField": "Time", + "mode": "outer" + } + }, + { + "id": "calculateField", + "options": { + "alias": "REM Sleep", + "binary": { + "left": "REM Sleep", + "operator": "/", + "reducer": "sum", + "right": "Total" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": true + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-blue", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 17, + "y": 17 + }, + "id": 9, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.3", + "targets": [ + { + "alias": "Core Sleep", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE (\"value\"::field = 1) AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + }, + { + "alias": "Total", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "hide": false, + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + } + ], + "transformations": [ + { + "id": "joinByField", + "options": { + "byField": "Time", + "mode": "outer" + } + }, + { + "id": "calculateField", + "options": { + "alias": "Core Sleep ", + "binary": { + "left": "Core Sleep", + "operator": "/", + "reducer": "sum", + "right": "Total" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": true + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-blue", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 21, + "y": 17 + }, + "id": 7, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.0.3", + "targets": [ + { + "alias": "Deep Sleep", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE (\"value\"::field = 1) AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + }, + { + "alias": "Total", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "hide": false, + "measurement": "SleepAnalysisTimes-Apple Watch", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT count(\"value\") FROM \"autogen\"./^$sleep_sources$/ WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "value::field", + "operator": "=", + "value": "2" + } + ] + } + ], + "transformations": [ + { + "id": "joinByField", + "options": { + "byField": "Time", + "mode": "outer" + } + }, + { + "id": "calculateField", + "options": { + "alias": "Deep Sleep", + "binary": { + "left": "Deep Sleep", + "operator": "/", + "reducer": "sum", + "right": "Total" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": true + } + } + ], + "type": "stat" + } + ], + "refresh": false, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "SleepAnalysisTimes-Apple Watch", + "value": "SleepAnalysisTimes-Apple Watch" + }, + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "definition": "show measurements WITH MEASUREMENT =~ /SleepAnalysisTimes.*/", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "sleep_sources", + "options": [], + "query": "show measurements WITH MEASUREMENT =~ /SleepAnalysisTimes.*/", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-7d", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Sleep tracking dashboard", + "uid": "a46f7443-1bc1-478d-8100-40c05aef654c", + "version": 9, + "weekStart": "" +} \ No newline at end of file diff --git a/provisioning/dashboards/dashs/specific-metrics.json b/provisioning/dashboards/dashs/specific-metrics.json index 4ba7d8d..65d10a4 100644 --- a/provisioning/dashboards/dashs/specific-metrics.json +++ b/provisioning/dashboards/dashs/specific-metrics.json @@ -99,7 +99,7 @@ }, "textMode": "value_and_name" }, - "pluginVersion": "9.3.13", + "pluginVersion": "9.5.3", "targets": [ { "alias": "Cycled distance this year ($tag_unit)", @@ -2479,10 +2479,545 @@ ], "title": "Heart rate through the day", "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 24, + "panels": [], + "title": "Sleep data", + "type": "row" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 61, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 3, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "mappings": [ + { + "options": { + "1": { + "index": 0, + "text": "In bed" + }, + "2": { + "index": 1, + "text": "Sleeping" + } + }, + "type": "value" + } + ], + "max": 2, + "min": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 10, + "x": 0, + "y": 48 + }, + "id": 25, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [ + { + "params": [ + "1m" + ], + "type": "time" + }, + { + "params": [ + "device::tag" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "SleepAnalysisTimes", + "orderByTime": "ASC", + "policy": "autogen", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "device::tag", + "operator": "=~", + "value": "/^$source$/" + } + ] + } + ], + "title": "Times in bed/sleeping", + "type": "timeseries" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + } + }, + "gridPos": { + "h": 13, + "w": 11, + "x": 10, + "y": 48 + }, + "id": 27, + "interval": "1d", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [ + { + "params": [ + "1d" + ], + "type": "time" + }, + { + "params": [ + "unit" + ], + "type": "tag" + }, + { + "params": [ + "device::tag" + ], + "type": "tag" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "SleepAnalysis", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "device::tag", + "operator": "=~", + "value": "/^$source$/" + } + ] + } + ], + "title": "Durations of time in bed", + "type": "timeseries" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + } + ] + }, + "unit": "h" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 3, + "x": 21, + "y": 48 + }, + "id": 26, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.3", + "targets": [ + { + "alias": "Sleep Goal", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [], + "measurement": "SleepDurationGoal", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT \"value\" FROM \"autogen\".\"SleepDurationGoal\" ", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [] + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-blue", + "value": null + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*bed.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 3, + "x": 21, + "y": 53 + }, + "id": 29, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.3", + "targets": [ + { + "alias": "Total time spent in bed ($tag_device)", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [ + { + "params": [ + "device::tag" + ], + "type": "tag" + } + ], + "hide": false, + "measurement": "SleepAnalysis", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT sum(\"value\") FROM \"autogen\".\"SleepAnalysis\" WHERE (\"state\"::tag = 'HKCategoryValueSleepAnalysisInBed') AND $timeFilter GROUP BY \"device\"::tag", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "state::tag", + "operator": "=", + "value": "HKCategoryValueSleepAnalysisInBed" + } + ] + }, + { + "alias": "Total time spent asleep ($tag_device)", + "datasource": { + "type": "influxdb", + "uid": "influx" + }, + "groupBy": [ + { + "params": [ + "device::tag" + ], + "type": "tag" + } + ], + "hide": false, + "measurement": "SleepAnalysis", + "orderByTime": "ASC", + "policy": "autogen", + "query": "SELECT sum(\"value\") FROM \"autogen\".\"SleepAnalysis\" WHERE (\"state\"::tag = 'HKCategoryValueSleepAnalysisInBed') AND $timeFilter GROUP BY \"device\"::tag", + "rawQuery": false, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "state::tag", + "operator": "=", + "value": "HKCategoryValueSleepAnalysisAsleepUnspecified" + } + ] + } + ], + "type": "stat" } ], "refresh": "30s", - "schemaVersion": 37, + "schemaVersion": 38, "style": "dark", "tags": [], "templating": { @@ -2517,7 +3052,7 @@ ] }, "time": { - "from": "now-2y", + "from": "now-90d", "to": "now" }, "timepicker": {},