Εισαγωγή
Ο ύπνος και ο πύθωνας. Δύο από τα αγαπημένα μου πράγματα, όταν συνδυάζονται με το Βιβλιοθήκη Python Fitbit, Matplotlibκαι Πάντα, μπορεί να δημιουργήσει ενημερωτικά σχέδια για τις συνήθειες ύπνου σας! Αυτή η ανάρτηση διερευνά πώς μπορούμε να βγάλουμε ημερομηνία από το Fitbit API, δημιουργήστε ένα Pandas Dataframe και, στη συνέχεια, σχεδιάστε τα αποτελέσματα.

Σε αυτό το σεμινάριο, έχω χρησιμοποιήσει Πύθων 3.7 για πρόσβαση σε δεδομένα, το Βιβλιοθήκη Fitbit Python (με ορισμένες προσαρμογές για την έκδοση 1.2 του Fitbit API), Πάντα για τη διαχείριση των δεδομένων και Matplotlib για να δημιουργήσετε κάποιες απεικονίσεις.
Λειτουργικότητα Fitbit Direct Export
Σημειώστε ότι μπορείτε επίσης να ζητήσετε δεδομένα ως ενιαία ένδειξη απευθείας από το Ιστοσελίδα Fitbit. Συνδεθείτε, μεταβείτε στις ρυθμίσεις, εξαγωγή δεδομένων και «αίτημα εξαγωγής». (δείτε την οδηγία εδώ) Σημειώστε ότι ενδέχεται να χρειαστούν μερικές ώρες για την εξαγωγή των δεδομένων σας, εάν υπάρχουν πολλά, μπορεί να προσθέσω μερικά σενάρια για την ανάλυση δεδομένων σε αυτήν τη μορφή, αν μπορώ.

Πρόσβαση στο Fitbit API και στο OAuth
ο Fitbit API είναι ένα καλά τεκμηριωμένο RESTful API όπου όλα σου κίνηση, ύπνος, ΠΑΛΜΟΣ ΚΑΡΔΙΑΣ, και υλοτομία τροφίμων Τα δεδομένα (εάν παρακολουθούνται από μια συσκευή Fitbit) είναι προσβάσιμα μέσω προγραμματισμού. Για να αποκτήσετε πρόσβαση σε δεδομένα, θα χρειαστεί να δημιουργήσετε μια «εφαρμογή» με έναν εγγεγραμμένο λογαριασμό χρήστη προγραμματιστή Fitbit. Οι εφαρμογές θα έχουν πρόσβαση στα προσωπικά σας δεδομένα Fitbit μέσω του API. Η εξουσιοδότηση εφαρμογής ακολουθεί αυτό που ονομάζεται προδιαγραφή „OAuth2.0“.
Υπάρχουν διαφορετικά τελικά σημεία API για κάθε τύπο δεδομένων και όλες οι απαντήσεις επανέρχονται Μορφές JSON που μπορεί εύκολα να μετατραπεί ξανά σε Λεξικά Python και Pandas Dataframes για επεξεργασία.
Παράδειγμα απάντησης JSON:
{ "logId" : 27198605014, "dateOfSleep" : "2020-05-16", "startTime" : "2020-05-16T03:01:00.000", "endTime" : "2020-05-16T11:10:30.000", "duration" : 29340000, "minutesToFallAsleep" : 0, "minutesAsleep" : 437, "minutesAwake" : 52, "minutesAfterWakeup" : 0, "timeInBed" : 489, "efficiency" : 97, "type" : "stages", "infoCode" : 0, "levels" : { "summary" : { "deep" : { "count" : 4, "minutes" : 73, "thirtyDayAvgMinutes" : 77 }, "wake" : { "count" : 40, "minutes" : 52, "thirtyDayAvgMinutes" : 57 }, "light" : { "count" : 41, "minutes" : 264, "thirtyDayAvgMinutes" : 254 }, "rem" : { "count" : 10, "minutes" : 100, "thirtyDayAvgMinutes" : 103 } } }
Αστάρι Oauth2
Για να κάνουμε τη ζωή μας εύκολη, θα χρησιμοποιήσουμε το υπάρχον και το εξαιρετικό Βιβλιοθήκη Fitbit Python για να χειριστείτε μερικά από τα επανειλημμένα για τον έλεγχο ταυτότητας της εφαρμογής, αλλά αξίζει να κατανοήσετε τα βασικά. Το OAuth2 είναι μια μέθοδος χορήγησης πρόσβασης σε εφαρμογές ή χρήστες σε συγκεκριμένα δεδομένα ή πόρους και ουσιαστικά η ροή είναι:
- Η εφαρμογή σας οδηγεί τον τελικό χρήστη (μέσω ενός προγράμματος περιήγησης) στη σελίδα εξουσιοδότησης Fitbit χρησιμοποιώντας ένα αναγνωριστικό πελάτη εφαρμογής και ένα μυστικό κλειδί.
- Ο χρήστης συνδέεται και «παραχωρεί πρόσβαση» σε διαφορετικά «πεδία» (περιγραφές επιπέδων πρόσβασης δεδομένων).
- Δημιουργείται ένας «κωδικός εξουσιοδότησης» ο οποίος επιστρέφεται στην εφαρμογή σας ανακατευθύνοντας το πρόγραμμα περιήγησης σε μια «url επανάκλησης» (προς το παρόν, θα φιλοξενείται στον υπολογιστή σας).
- Η εφαρμογή δημιουργεί ένα «κουπόνι πρόσβασης» και «κουπόνι ανανέωσης» με βάση τον κωδικό εξουσιοδότησης.
- Το „κουπόνι πρόσβασης“ χρησιμοποιείται σε περαιτέρω αιτήματα API για τη λήψη δεδομένων.
- Με την πάροδο του χρόνου, το διακριτικό πρόσβασης θα λήξει (8 ώρες) και το διακριτικό ανανέωσης μπορεί να χρησιμοποιηθεί για τη δημιουργία ενός νέου διακριτικού πρόσβασης και ανανέωσης.
Βλέπω εδώ για συγκεκριμένες υλοποιήσεις Fitbit του OAuth2.

Δημιουργήστε μια προσωπική εφαρμογή Fitbit
Ξεκινήστε δημιουργώντας μια νέα εφαρμογή στο dev.fitbit.com.
Δημιουργήστε έναν λογαριασμό στο dev.fitbit.com και δημιουργήστε μια νέα «εφαρμογή». Θα δημιουργήσετε απλώς μια «προσωπική» εφαρμογή για χρήση μόνο με τον δικό σας λογαριασμό, επομένως οι λεπτομέρειες για τον ιστότοπο, τους όρους παροχής υπηρεσιών και την πολιτική απορρήτου δεν έχουν ιδιαίτερη σημασία.
Το βασικό στοιχείο για να φτάσετε εδώ είναι να ορίσετε τη „URL επιστροφής κλήσης“ σε „http://127.0.0.1:8080/“. Αυτή η διεύθυνση URL θα χρησιμοποιηθεί ως μέρος της εξουσιοδότησης OAuth2 που περιγράφεται παραπάνω στο βήμα 3. Η ρύθμιση της εφαρμογής μου μοιάζει με αυτό:

Όταν δημιουργηθεί η εφαρμογή, θα μπορείτε να κατεβάσετε το „αναγνωριστικό πελάτη“ και το „μυστικό πελάτη“ της εφαρμογής. Αυτά είναι τα βασικά διαπιστευτήρια για την αίτησή σας και χρησιμοποιούνται κατά τη διαδικασία OAuth2 – αποθηκεύστε τα κάπου για το επόμενο βήμα.
Πραγματοποιήστε έλεγχο ταυτότητας και αποκτήστε ένα διακριτικό API
Υπάρχει ένα χρήσιμο αρχείο στη βιβλιοθήκη Fitbit Python που ονομάζεται „collect_keys_oauth2.py” (διατίθεται το πρωτότυπο εδώ). Αυτό το αρχείο υλοποιεί έναν μικρό τοπικό διακομιστή ιστού που μπορείτε να χρησιμοποιήσετε για έλεγχο ταυτότητας με το Fitbit API για να ζητήσετε ένα διακριτικό πρόσβασης και ανανέωσης.
Υπάρχουν μερικά απλά βήματα για να εκτελέσετε αυτήν την εφαρμογή τοπικά στον υπολογιστή σας:
- Αντιγράψτε τα περιεχόμενα του collect_keys_oauth2.py σε ένα τοπικό αρχείο με το ίδιο όνομα.
- Εγκαταστήστε το κεράσι (
pip install cherrypy
) και Fitbit (pip install fitbit
) βιβλιοθήκες στο περιβάλλον Python σας. (Ιδανικά, ρυθμίστε ένα τοπικό εικονικό περιβάλλον για το έργο σας) Cherrypy είναι ένα ελαφρύ λογισμικό διακομιστή ιστού που βοηθά με τη διεύθυνση URL ανακατεύθυνσης από το Fitbit κατά τη ροή OAuth2. - Ενεργοποιήστε το εικονικό σας περιβάλλον, αλλάξτε τον κατάλογο στον οποίο έχετε δημιουργήσει το δικό σας
gather_keys_oauth2.py
αρχείο και εκτελέστε το αρχείο, προσδιορίζοντας το αναγνωριστικό πελάτη της εφαρμογής σας και το μυστικό κλειδί στην εντολή, π.χ.python gather_keys_oauth2.py CLIENT_ID CLIENT_SECRET
για μένα, αυτό ήταν παρόμοιο με (όχι πραγματικούς κωδικούς εδώ):python gather_keys_oauth2.py 22ARNQ f3ad3eedfabccbd33a3149f3b
- Το σενάριο θα ανοίξει ένα παράθυρο του προγράμματος περιήγησης που παρουσιάζει μια σελίδα σύνδεσης στο Fitbit, όπου μπορείτε να δώσετε άδεια στην εφαρμογή σας να έχει πρόσβαση στα δεδομένα σας.
- Όταν πιστοποιηθεί επιτυχώς, το
gather_keys_oauth2.py
Το σενάριο θα εκτυπώσει το διακριτικό πρόσβασης και θα ανανεώσει το διακριτικό στο παράθυρο της κονσόλας.



Κατεβάστε τα δεδομένα ύπνου σας
Η βιβλιοθήκη Fitbit python, από προεπιλογή, έχει ρυθμιστεί να χρησιμοποιεί την έκδοση 1 του Fitbit API, ενώ υπάρχουν δεδομένα καλύτερης ποιότητας διαθέσιμα από το V1.2 API. Θα χρησιμοποιήσουμε τη βιβλιοθήκη Fitbit για τη διαχείριση των αιτημάτων δεδομένων, αλλά θα καθορίσουμε με μη αυτόματο τρόπο τις διευθύνσεις URL API V1.2, ώστε να έχουμε τα καλύτερα δεδομένα.
Για τη συγκεκριμένη ανάρτηση, μας ενδιαφέρει δεδομένα ύπνουκαι οι διευθύνσεις URL πόρων που είναι χρήσιμες είναι:
- Διαθέσιμα δεδομένα ανά ημέρα σε:
https://api.fitbit.com/1.2/user/[user-id]/sleep/date/[date].json
- Διαθέσιμα δεδομένα εύρους ημερομηνιών σε (μέγιστο 100 ημέρες):
https://api.fitbit.com/1.2/user/[user-id]/sleep/date/[startDate]/[endDate].json
Η απάντηση από το API, κατά τον έλεγχο ταυτότητας, περιλαμβάνει περιλήψεις του ύπνου σας για κάθε ημερομηνία:
- Μια ανάλυση της βραδιάς σας, σε δύο μορφές:
- „Στάδια“: Πρόκειται για πιο λεπτομερή ανάλυση του ύπνου σας στις πιο πρόσφατες συσκευές. Τα δεδομένα περιλαμβάνουν τον συνολικό αριθμό συμβάντων και τα συνολικά λεπτά βαθιάς, φωτός, REM και εγρήγορσης για τη νύχτα
- „Κλασικό“: Μια πιο βασική ανάλυση του ύπνου σας σε στιγμές ύπνου, ξύπνιου και ανήσυχου.
- Συνοπτικά στατιστικά σχετικά με τα συνολικά λεπτά της εγρήγορσης, τα συνολικά λεπτά ύπνου, τον χρόνο στο κρεβάτι, τα λεπτά για να κοιμηθώ (βρήκα αυτό το τελευταίο ελαφρώς αναξιόπιστο).
Τα δεδομένα χωρίζονται σε δύο ενότητες στην απόκριση JSON, „δεδομένα“ που περιλαμβάνει τυχόν στάδια ύπνου ή περιόδους αφύπνισης μεγαλύτερες από τρία λεπτά και ένα „σύντομα δεδομένα“ που περιλαμβάνει σύντομες περιόδους αφύπνισης διάρκειας μικρότερης των 3 λεπτών.
Εδώ, θέλω να κατεβάσω δεδομένα για περισσότερες από 100 ημέρες και επομένως πρέπει να δημιουργήσουμε όλες τις περιόδους 100 ημερών μεταξύ των τελικών στόχων ημερομηνιών μας. Έχω χρησιμοποιήσει το Βιβλιοθήκη διαχείρισης ημερομηνίας/ώρας με βέλος για να γίνει αυτό πιο εύκολο.
import fitbit import pandas as pd import matplotlib.pyplot as plt import matplotlib.dates as mdates import arrow. # Arrow is a really useful date time helper library client = fitbit.Fitbit( '<paste application client ID>', '<paste application secret key>', access_token='<paste access_token here>', refresh_token='<paste refresh token here>' ) start_date = arrow.get("2018-09-01") end_date = arrow.get("2020-11-01") # Create a series of 100-day date-range tuples between start_date and end_date date_ranges = [] start_range = start_date while start_range < end_date: if start_range.shift(days=100) < end_date: date_ranges.append((start_range, start_range.shift(days=100))) start_range = start_range.shift(days=101) else: date_ranges.append((start_range, end_date)) start_range = end_date # Print the result to the console date_ranges

Τώρα απλώς επαναλαμβάνουμε τα διαφορετικά εύρη ημερομηνιών και ζητάμε τα δεδομένα για κάθε ένα από το Fitbit:
all_data = [] for date_range in date_ranges: print(f"Requesting data for {date_range[0]} to {date_range[1]}.") url = f"{client.API_ENDPOINT}/1.2/user/-/sleep/date/{date_range[0].year}-{date_range[0].month:02}-{date_range[0].day:02}/{date_range[1].year}-{date_range[1].month:02}-{date_range[1].day:02}.json" range_data = client.make_request(url) all_data.append(range_data) print(f"Success!")
Μετατροπή δεδομένων σε Pandas DataFrame
Το τελευταίο βήμα είναι να συνδυάσετε όλα τα δεδομένα μαζί σε ένα διαχειρίσιμο και εύκολα οπτικοποιήσιμο Pandas DataFrame.
sleep_summaries = [] # Iterate through all data and create a list of dictionaries of results: for data in all_data: for sleep in data["sleep"]: # For simplicity, ignoring "naps" and going for only "stage" data if sleep["isMainSleep"] and sleep["type"] == "stages": sleep_summaries.append(dict( date=pd.to_datetime(sleep["dateOfSleep"]).date(), duration_hours=sleep["duration"]/1000/60/60, total_sleep_minutes=sleep["minutesAsleep"], total_time_in_bed=sleep["timeInBed"], start_time=sleep["startTime"], deep_minutes=sleep["levels"]["summary"].get("deep").get("minutes"), light_minutes=sleep["levels"]["summary"].get("light").get("minutes"), rem_minutes=sleep["levels"]["summary"].get("rem").get("minutes"), wake_minutes=sleep["levels"]["summary"].get("wake").get("minutes"), )) # Convert new dictionary format to DataFrame sleep_data = pd.DataFrame(sleep_summaries) # Sort by date and view first rows sleep_data.sort_values("date", inplace=True) sleep_data.reset_index(drop=True, inplace=True) sleep_data.head()

Μπορούμε να προσθέσουμε μερικές χρήσιμες στήλες για να βοηθήσουμε στην οπτικοποίηση τώρα:
# It's useful for grouping to get the "date" from every timestamp sleep_data["date"] = pd.to_datetime(sleep_data["date"]) # Also add a boolean column for weekend detection sleep_data["is_weekend"] = sleep_data["date"].dt.weekday > 4
Οραματιστείτε με Pandas και Matplotlib!
Επιτέλους για τη διασκέδαση! Για αυτήν την ανάρτηση, χρησιμοποίησα την ενσωματωμένη ενσωμάτωση μεταξύ Matplotlib και Pandas για να δημιουργήσω μερικά συνοπτικά γραφικά των δεδομένων ύπνου μου:
Κατανομές ύπνου
Ένα ιστόγραμμα δύο επιπέδων του χρόνου ύπνου έναντι του συνολικού χρόνου στο κρεβάτι είναι μια ωραία απεικόνιση της «αποτελεσματικότητας του κρεβατιού» που επιτυγχάνετε!
# Sleep distribution (sleep_data["total_sleep_minutes"]/60).plot( kind="hist", bins=50, alpha=0.8, figsize=(12,8) ) (sleep_data["total_time_in_bed"]/60).plot( kind="hist", bins=50, alpha=0.8 ) plt.legend() # add some nice axis labels: ax = plt.gca() ax.set_xticks(range(2,12)) plt.grid("minor", linestyle=":") plt.xlabel("Hours") plt.ylabel("Frequency") plt.title("Sleeping Hours")

Αποτελεσματικότητα ύπνου
Μαζί με το ιστόγραμμα, μια γραφική παράσταση διασποράς είναι μια αποτελεσματική μέθοδος σύγκρισης της συνολικής διάρκειας κρεβατιού με τη συνολική διάρκεια ύπνου και η προσθήκη μιας τέλειας γραμμής γραμμικής προσαρμογής δείχνει πόσο μακριά είναι η «100% αποδοτικότητα» του ύπνου μου. Δεν ταίριαξα μια γραμμή στα δεδομένα, αλλά το γράφημα υποδηλώνει μια τομή Χ περίπου 50 λεπτών που χάνεται κάθε βράδυ σε στιγμές «ξύπνισης στο κρεβάτι» (!), σε συμφωνία με το παραπάνω ιστόγραμμα.
# Plot a scatter plot directly from Pandas sleep_data.plot( x="total_time_in_bed", y="total_sleep_minutes", kind="scatter", figsize=(10,10) ) # Add a perfect 1:1 line for comparison ax = plt.gca() ax.set_aspect("equal") x = np.linspace(*ax.get_xlim()) ax.plot(x,x, linestyle="--") plt.grid(linestyle=":")

Πρότυπα ύπνου με την πάροδο του χρόνου
Δείξτε ένα μακροπρόθεσμο μοτίβο ύπνου σε διάρκεια ενός ή δύο ετών για να δείτε τις γενικές τάσεις. Έμεινα έκπληκτος όταν είδα πόσο σταθερός ήταν ο ύπνος όλα αυτά τα χρόνια, με τον περίεργο πολύ μεγάλο ή πολύ σύντομο ύπνο που, μετά από έρευνα, θα μπορούσα να αποδώσω σε ιδιαίτερα πρώιμες πτήσεις ή ξεκούραστες διακοπές!
# Sleep makeup - calculate data to plot plot_data = sleep_data.\ sort_values("date").\ set_index("date")\ [["deep_minutes", "light_minutes", "rem_minutes", "wake_minutes"]] # Matplotlib doesn't natively support stacked bars, so some messing here: df = plot_data fig, ax = plt.subplots(figsize=(30,7), constrained_layout=True) bottom = 0 for c in df.columns: ax.bar(df.index, df[c], bottom=bottom, width=1, label=c) bottom+=df[c] # Set a date axis for the x-axis allows nicer tickmarks. ax.xaxis.set_major_locator(mdates.MonthLocator()) ax.xaxis.set_major_formatter(mdates.DateFormatter('%d-%m-%Y')) ax.legend() plt.xlabel("Date") plt.ylabel("Minutes") # Show a subset of data for clarity on the website: plt.xlim(pd.to_datetime("2018-10-01"), pd.to_datetime("2020-10-01"))

Πήγαινε Παραπέρα
Μπορείτε επίσης να χρησιμοποιήσετε την παραπάνω μέθοδο για να ανακτήσετε και να αναλύσετε δεδομένα φαγητού, δραστηριότητας και καρδιακού ρυθμού, τα οποία όλα θα αποτελούσαν φανταστικό θέμα για περαιτέρω πλοκές και εξερεύνηση.
Εάν κολλήσετε, υπάρχουν περαιτέρω αναρτήσεις ιστολογίου και πόροι σχετικά με το θέμα που αξίζει να αναφερθείτε: