Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:

# pytest:
# name: Pytests
# runs-on: ubuntu-22.04
# runs-on: ubuntu-latest
# steps:
# - name: Checkout Code
# uses: actions/checkout@v4
Expand All @@ -50,8 +50,7 @@ jobs:

# - name: Install Dependencies
# run: |
# if [ -e setup.py ]; then python3 -m pip install .; fi
# if [ -e requirements.txt ]; then python3 -m pip install -r requirements.txt; fi
# python3 -m pip install .
# python3 -m pip install pytest pytest-cov

# - name: Build coverage file
Expand Down
39 changes: 20 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
Access your Fitbit data directly from your terminal 💻. View 💤 sleep logs, ❤️ heart rate, 🏋️‍♂️ activity levels, 🩸 SpO2, and more, all presented in a simple, easy-to-read table format!

<p align="center">
<img alt="Fitbit logo", width="250" src="https://raw.githubusercontent.com/veerendra2/fitbit-cli/refs/heads/main/assets/Fitbit_Logo_White_RGB.jpg">
<img alt="Fitbit logo", width="350" src="https://raw.githubusercontent.com/veerendra2/fitbit-cli/refs/heads/main/assets/Fitbit_Logo_White_RGB.jpg">
</p>

[![asciicast](https://asciinema.org/a/696114.svg)](https://asciinema.org/a/696114)
Expand All @@ -18,14 +18,16 @@ Access your Fitbit data directly from your terminal 💻. View 💤 sleep logs,

> Only `GET` APIs are supported!

| API | Status |
| ----------------------------------------------------------------------------------------------------------------------- | ------ |
| [User](https://dev.fitbit.com/build/reference/web-api/user/) | ✅ |
| [Sleep](https://dev.fitbit.com/build/reference/web-api/sleep/) | ✅ |
| [SpO2](https://dev.fitbit.com/build/reference/web-api/spo2/) | ✅ |
| [Heart Rate Time Series](https://dev.fitbit.com/build/reference/web-api/heartrate-timeseries/) | ✅ |
| [Active Zone Minutes (AZM) Time Series](https://dev.fitbit.com/build/reference/web-api/active-zone-minutes-timeseries/) | ✅ |
| [Activity](https://dev.fitbit.com/build/reference/web-api/activity/) | ✅ |
| API | Status |
| ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| [Get Profile](https://dev.fitbit.com/build/reference/web-api/user/get-profile/) | ✅ |
| [Get Devices](https://dev.fitbit.com/build/reference/web-api/devices/get-devices/) | ✅ |
| [Get Sleep Log by Date Range](https://dev.fitbit.com/build/reference/web-api/sleep/get-sleep-log-by-date-range/) | ✅ |
| [Get SpO2 Summary by Interval](https://dev.fitbit.com/build/reference/web-api/spo2/get-spo2-summary-by-interval/) | ✅ |
| [Get Heart Rate Time Series by Date Range](https://dev.fitbit.com/build/reference/web-api/heartrate-timeseries/get-heartrate-timeseries-by-date-range/) | ✅ |
| [Get AZM Time Series by Interval](https://dev.fitbit.com/build/reference/web-api/active-zone-minutes-timeseries/get-azm-timeseries-by-interval/) | ✅ |
| [Get Breathing Rate Summary by Interval](https://dev.fitbit.com/build/reference/web-api/breathing-rate/get-br-summary-by-interval/) | ✅ |
| [Get Daily Activity Summary](https://dev.fitbit.com/build/reference/web-api/activity/get-daily-activity-summary/) | ⏳ |

## Usage Guide

Expand All @@ -38,9 +40,8 @@ python -m pip install fitbit-cli
2. See Help

```bash
fitbit-cli -h
usage: fitbit-cli [-h] [-i] [-s [DATE[,DATE]|RELATIVE]] [-o [DATE[,DATE]|RELATIVE]] [-e [DATE[,DATE]|RELATIVE]] [-a [DATE[,DATE]|RELATIVE]]
[-b [DATE[,DATE]|RELATIVE]] [-u] [-v]
$ fitbit-cli -h
usage: fitbit-cli [-h] [-i] [-s [DATE[,DATE]|RELATIVE]] [-o [DATE[,DATE]|RELATIVE]] [-e [DATE[,DATE]|RELATIVE]] [-a [DATE[,DATE]|RELATIVE]] [-b [DATE[,DATE]|RELATIVE]] [-u] [-d] [-v]

Fitbit CLI -- Access your Fitbit data at your terminal.

Expand All @@ -55,17 +56,17 @@ APIs:
If not provided, defaults to today's date.

-s, --sleep [DATE[,DATE]|RELATIVE]
Show sleep data
Show Sleep Log by Date Range.
-o, --spo2 [DATE[,DATE]|RELATIVE]
Show SpO2 data
Show SpO2 Summary by Interval.
-e, --heart [DATE[,DATE]|RELATIVE]
Show Heart Rate Time Series data
Show Heart Rate Time Series by Date Range.
-a, --active-zone [DATE[,DATE]|RELATIVE]
Show Active Zone Minutes (AZM) Time Series data
Show AZM Time Series by Interval.
-b, --breathing-rate [DATE[,DATE]|RELATIVE]
Show Breathing Rate Summary data
-u, --show-user-profile
Show user profile data
Show Breathing Rate Summary by Interval.
-u, --user-profile Show Profile.
-d, --devices Show Devices.
```

3. Register Fitbit App
Expand Down
2 changes: 1 addition & 1 deletion fitbit_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
fitbit_cli Module
"""

__version__ = "1.3.1"
__version__ = "1.4.0"
20 changes: 13 additions & 7 deletions fitbit_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def parse_arguments():
nargs="?",
const=(datetime.today().date(), None),
metavar="DATE[,DATE]|RELATIVE",
help="Show sleep data",
help="Show Sleep Log by Date Range.",
)
group.add_argument(
"-o",
Expand All @@ -94,7 +94,7 @@ def parse_arguments():
nargs="?",
const=(datetime.today().date(), None),
metavar="DATE[,DATE]|RELATIVE",
help="Show SpO2 data",
help="Show SpO2 Summary by Interval.",
)
group.add_argument(
"-e",
Expand All @@ -103,7 +103,7 @@ def parse_arguments():
nargs="?",
const=(datetime.today().date(), None),
metavar="DATE[,DATE]|RELATIVE",
help="Show Heart Rate Time Series data",
help="Show Heart Rate Time Series by Date Range.",
)
group.add_argument(
"-a",
Expand All @@ -112,7 +112,7 @@ def parse_arguments():
nargs="?",
const=(datetime.today().date(), None),
metavar="DATE[,DATE]|RELATIVE",
help="Show Active Zone Minutes (AZM) Time Series data",
help="Show AZM Time Series by Interval.",
)
group.add_argument(
"-b",
Expand All @@ -121,13 +121,19 @@ def parse_arguments():
nargs="?",
const=(datetime.today().date(), None),
metavar="DATE[,DATE]|RELATIVE",
help="Show Breathing Rate Summary data",
help="Show Breathing Rate Summary by Interval.",
)
group.add_argument(
"-u",
"--show-user-profile",
"--user-profile",
action="store_true",
help="Show user profile data",
help="Show Profile.",
)
group.add_argument(
"-d",
"--devices",
action="store_true",
help="Show Devices.",
)

parser.add_argument(
Expand Down
14 changes: 14 additions & 0 deletions fitbit_cli/fitbit_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ def get_user_profile(self):
response = self.make_request("GET", url)
return response.json()

def get_devices(self):
"""Get Devices"""

url = "https://api.fitbit.com/1/user/-/devices.json"
response = self.make_request("GET", url)
return response.json()

def get_sleep_log(self, start_date, end_date=None):
"""Get Sleep Logs by Date Range and Date"""

Expand Down Expand Up @@ -142,3 +149,10 @@ def get_breathing_rate_intraday(self, start_date, end_date=None):
url = f"https://api.fitbit.com/1/user/-/br/date/{date_range}/all.json"
response = self.make_request("GET", url)
return response.json()

def get_daily_activity_summary(self, start_date):
"""Get Daily Activity Summary"""

url = f"https://api.fitbit.com/1/user/-/activities/date/{start_date}.json"
response = self.make_request("GET", url)
return response.json()
29 changes: 29 additions & 0 deletions fitbit_cli/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,32 @@ def display_breathing_rate(breathing_rate_data):
)

CONSOLE.print(table)


def display_devices(devices):
"""Devices list formatter"""

def format_mac(mac):
if mac == "N/A" or len(mac) % 2:
return mac
return ":".join(mac[i : i + 2] for i in range(0, len(mac), 2))

table = Table(title="Devices List :link:", show_header=True)

table.add_column("Battery Level :battery:")
table.add_column("Device Model :watch:")
table.add_column("Device Type :iphone:")
table.add_column("Last Sync Time :clock3:")
table.add_column("MAC Address :label:")

for device in devices:
mac_address = format_mac(str(device.get("mac", "N/A")))
table.add_row(
str(device.get("batteryLevel", "N/A")),
str(device.get("deviceVersion", "N/A")),
str(device.get("type", "N/A")),
str(device.get("lastSyncTime", "N/A")),
mac_address,
)

CONSOLE.print(table)
4 changes: 3 additions & 1 deletion fitbit_cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ def main():
)

with fmt.CONSOLE.status("[bold green]Fetching data...") as _:
if args.show_user_profile:
if args.user_profile:
fmt.display_user_profile(fitbit.get_user_profile())
if args.devices:
fmt.display_devices(fitbit.get_devices())
if args.sleep:
fmt.display_sleep(fitbit.get_sleep_log(*args.sleep))
if args.spo2:
Expand Down
2 changes: 0 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@
"Operating System :: MacOS",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.9",
Expand Down
Empty file removed tests/.gitkeep
Empty file.