feat: pretty print steps as table or csv

Add pretty_print module with a few functions for making things nicer.

Then use those to either print a CSV or a nicer version of steps to the
CLI
This commit is contained in:
Wesley Ellis 2024-10-20 21:54:44 -04:00
parent f8dc91fd4e
commit eb875b001a
8 changed files with 685 additions and 200 deletions

View File

@ -10,6 +10,11 @@ I got another 's' packet while asking for battery level
bytearray(b's\x0c+\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xab')
This one showed up when asking for steps for a day
bytearray(b's\x0cd\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4')
---
Set-time always includes

View File

@ -2,7 +2,10 @@
A python client for connecting to the Colmi R02 Smart ring
"""
import csv
import dataclasses
from datetime import datetime, timezone
from io import StringIO
from pathlib import Path
import logging
import time
@ -12,6 +15,7 @@ from bleak import BleakScanner
from colmi_r02_client.client import Client
from colmi_r02_client.hr import HeartRateLog
from colmi_r02_client import steps, pretty_print
logging.basicConfig(level=logging.WARNING, format="%(name)s: %(message)s")
@ -156,13 +160,26 @@ async def get_real_time_heart_rate(client: Client) -> None:
required=False,
help="The date you want steps for",
)
async def get_steps(client: Client, when: datetime | None = None) -> None:
@click.option("--as-csv", is_flag=True, help="Print as CSV", default=False)
async def get_steps(client: Client, when: datetime | None = None, as_csv: bool = False) -> None:
"""Get step data"""
if when is None:
when = datetime.now(tz=timezone.utc)
result = await client.get_steps(when)
click.echo(result)
if isinstance(result, steps.NoData):
click.echo("No results for day")
return
if not as_csv:
click.echo(pretty_print.print_dataclasses(result))
else:
out = StringIO()
writer = csv.DictWriter(out, fieldnames=[f.name for f in dataclasses.fields(steps.SportDetail)])
writer.writeheader()
for r in result:
writer.writerow(dataclasses.asdict(r))
click.echo(out.getvalue())
DEVICE_NAME_PREFIXES = [

View File

@ -0,0 +1,37 @@
"""
Utility class for printing lists of lists, lists of dicts and lists of dataclasses
"""
from typing import Any
import dataclasses
def print_lists(rows: list[list[Any]], header: bool = False) -> str:
widths = [0] * len(rows[0])
for row in rows:
for i, col in enumerate(row):
widths[i] = max(len(str(col)), widths[i])
result = []
for row in rows:
pretty_row = []
for i, col in enumerate(row):
x = str(col).rjust(widths[i])
pretty_row.append(x)
result.append(" | ".join(pretty_row))
if header:
sep = "-" * len(result[0])
result.insert(1, sep)
return "\n".join(result)
def print_dicts(rows: list[dict]) -> str:
lists = [list(rows[0].keys())]
lists.extend(list(x.values()) for x in rows)
return print_lists(lists, header=True)
def print_dataclasses(dcs: list[Any]) -> str:
dicted = [dataclasses.asdict(d) for d in dcs]
return print_dicts(dicted)

View File

@ -42,6 +42,7 @@
<li><a href="colmi_r02_client/hr.html">hr</a></li>
<li><a href="colmi_r02_client/hr_settings.html">hr_settings</a></li>
<li><a href="colmi_r02_client/packet.html">packet</a></li>
<li><a href="colmi_r02_client/pretty_print.html">pretty_print</a></li>
<li><a href="colmi_r02_client/real_time_hr.html">real_time_hr</a></li>
<li><a href="colmi_r02_client/set_time.html">set_time</a></li>
<li><a href="colmi_r02_client/steps.html">steps</a></li>

View File

@ -63,213 +63,230 @@
</span><span id="L-2"><a href="#L-2"><span class="linenos"> 2</span></a><span class="sd">A python client for connecting to the Colmi R02 Smart ring</span>
</span><span id="L-3"><a href="#L-3"><span class="linenos"> 3</span></a><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-4"><a href="#L-4"><span class="linenos"> 4</span></a>
</span><span id="L-5"><a href="#L-5"><span class="linenos"> 5</span></a><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timezone</span>
</span><span id="L-6"><a href="#L-6"><span class="linenos"> 6</span></a><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
</span><span id="L-7"><a href="#L-7"><span class="linenos"> 7</span></a><span class="kn">import</span> <span class="nn">logging</span>
</span><span id="L-8"><a href="#L-8"><span class="linenos"> 8</span></a><span class="kn">import</span> <span class="nn">time</span>
</span><span id="L-9"><a href="#L-9"><span class="linenos"> 9</span></a>
</span><span id="L-10"><a href="#L-10"><span class="linenos"> 10</span></a><span class="kn">import</span> <span class="nn">asyncclick</span> <span class="k">as</span> <span class="nn">click</span>
</span><span id="L-11"><a href="#L-11"><span class="linenos"> 11</span></a><span class="kn">from</span> <span class="nn">bleak</span> <span class="kn">import</span> <span class="n">BleakScanner</span>
</span><span id="L-5"><a href="#L-5"><span class="linenos"> 5</span></a><span class="kn">import</span> <span class="nn">csv</span>
</span><span id="L-6"><a href="#L-6"><span class="linenos"> 6</span></a><span class="kn">import</span> <span class="nn">dataclasses</span>
</span><span id="L-7"><a href="#L-7"><span class="linenos"> 7</span></a><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timezone</span>
</span><span id="L-8"><a href="#L-8"><span class="linenos"> 8</span></a><span class="kn">from</span> <span class="nn">io</span> <span class="kn">import</span> <span class="n">StringIO</span>
</span><span id="L-9"><a href="#L-9"><span class="linenos"> 9</span></a><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
</span><span id="L-10"><a href="#L-10"><span class="linenos"> 10</span></a><span class="kn">import</span> <span class="nn">logging</span>
</span><span id="L-11"><a href="#L-11"><span class="linenos"> 11</span></a><span class="kn">import</span> <span class="nn">time</span>
</span><span id="L-12"><a href="#L-12"><span class="linenos"> 12</span></a>
</span><span id="L-13"><a href="#L-13"><span class="linenos"> 13</span></a><span class="kn">from</span> <span class="nn">colmi_r02_client.client</span> <span class="kn">import</span> <span class="n">Client</span>
</span><span id="L-14"><a href="#L-14"><span class="linenos"> 14</span></a><span class="kn">from</span> <span class="nn">colmi_r02_client.hr</span> <span class="kn">import</span> <span class="n">HeartRateLog</span>
</span><span id="L-13"><a href="#L-13"><span class="linenos"> 13</span></a><span class="kn">import</span> <span class="nn">asyncclick</span> <span class="k">as</span> <span class="nn">click</span>
</span><span id="L-14"><a href="#L-14"><span class="linenos"> 14</span></a><span class="kn">from</span> <span class="nn">bleak</span> <span class="kn">import</span> <span class="n">BleakScanner</span>
</span><span id="L-15"><a href="#L-15"><span class="linenos"> 15</span></a>
</span><span id="L-16"><a href="#L-16"><span class="linenos"> 16</span></a><span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">WARNING</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="s2">&quot;</span><span class="si">%(name)s</span><span class="s2">: </span><span class="si">%(message)s</span><span class="s2">&quot;</span><span class="p">)</span>
</span><span id="L-17"><a href="#L-17"><span class="linenos"> 17</span></a>
</span><span id="L-18"><a href="#L-18"><span class="linenos"> 18</span></a><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
</span><span id="L-16"><a href="#L-16"><span class="linenos"> 16</span></a><span class="kn">from</span> <span class="nn">colmi_r02_client.client</span> <span class="kn">import</span> <span class="n">Client</span>
</span><span id="L-17"><a href="#L-17"><span class="linenos"> 17</span></a><span class="kn">from</span> <span class="nn">colmi_r02_client.hr</span> <span class="kn">import</span> <span class="n">HeartRateLog</span>
</span><span id="L-18"><a href="#L-18"><span class="linenos"> 18</span></a><span class="kn">from</span> <span class="nn">colmi_r02_client</span> <span class="kn">import</span> <span class="n">steps</span><span class="p">,</span> <span class="n">pretty_print</span>
</span><span id="L-19"><a href="#L-19"><span class="linenos"> 19</span></a>
</span><span id="L-20"><a href="#L-20"><span class="linenos"> 20</span></a>
</span><span id="L-21"><a href="#L-21"><span class="linenos"> 21</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">group</span><span class="p">()</span>
</span><span id="L-22"><a href="#L-22"><span class="linenos"> 22</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s2">&quot;--debug/--no-debug&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span><span id="L-23"><a href="#L-23"><span class="linenos"> 23</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span>
</span><span id="L-24"><a href="#L-24"><span class="linenos"> 24</span></a> <span class="s2">&quot;--record/--no-record&quot;</span><span class="p">,</span>
</span><span id="L-25"><a href="#L-25"><span class="linenos"> 25</span></a> <span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span><span id="L-26"><a href="#L-26"><span class="linenos"> 26</span></a> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;Write all received packets to a file&quot;</span><span class="p">,</span>
</span><span id="L-27"><a href="#L-27"><span class="linenos"> 27</span></a><span class="p">)</span>
</span><span id="L-28"><a href="#L-28"><span class="linenos"> 28</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s2">&quot;--address&quot;</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;Bluetooth address&quot;</span><span class="p">)</span>
</span><span id="L-29"><a href="#L-29"><span class="linenos"> 29</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s2">&quot;--name&quot;</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;Bluetooth name of the device, slower but will work on macOS&quot;</span><span class="p">)</span>
</span><span id="L-30"><a href="#L-30"><span class="linenos"> 30</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_context</span>
</span><span id="L-31"><a href="#L-31"><span class="linenos"> 31</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">cli_client</span><span class="p">(</span><span class="n">context</span><span class="p">:</span> <span class="n">click</span><span class="o">.</span><span class="n">Context</span><span class="p">,</span> <span class="n">debug</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span> <span class="n">record</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span> <span class="n">address</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-32"><a href="#L-32"><span class="linenos"> 32</span></a> <span class="k">if</span> <span class="p">(</span><span class="n">address</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">name</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">address</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">name</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">):</span>
</span><span id="L-33"><a href="#L-33"><span class="linenos"> 33</span></a> <span class="n">context</span><span class="o">.</span><span class="n">fail</span><span class="p">(</span><span class="s2">&quot;You must pass either the address option(preferred) or the name option, but not both&quot;</span><span class="p">)</span>
</span><span id="L-34"><a href="#L-34"><span class="linenos"> 34</span></a>
</span><span id="L-35"><a href="#L-35"><span class="linenos"> 35</span></a> <span class="k">if</span> <span class="n">debug</span><span class="p">:</span>
</span><span id="L-36"><a href="#L-36"><span class="linenos"> 36</span></a> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
</span><span id="L-37"><a href="#L-37"><span class="linenos"> 37</span></a> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s2">&quot;bleak&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">)</span>
</span><span id="L-20"><a href="#L-20"><span class="linenos"> 20</span></a><span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">WARNING</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="s2">&quot;</span><span class="si">%(name)s</span><span class="s2">: </span><span class="si">%(message)s</span><span class="s2">&quot;</span><span class="p">)</span>
</span><span id="L-21"><a href="#L-21"><span class="linenos"> 21</span></a>
</span><span id="L-22"><a href="#L-22"><span class="linenos"> 22</span></a><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
</span><span id="L-23"><a href="#L-23"><span class="linenos"> 23</span></a>
</span><span id="L-24"><a href="#L-24"><span class="linenos"> 24</span></a>
</span><span id="L-25"><a href="#L-25"><span class="linenos"> 25</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">group</span><span class="p">()</span>
</span><span id="L-26"><a href="#L-26"><span class="linenos"> 26</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s2">&quot;--debug/--no-debug&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span><span id="L-27"><a href="#L-27"><span class="linenos"> 27</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span>
</span><span id="L-28"><a href="#L-28"><span class="linenos"> 28</span></a> <span class="s2">&quot;--record/--no-record&quot;</span><span class="p">,</span>
</span><span id="L-29"><a href="#L-29"><span class="linenos"> 29</span></a> <span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span><span id="L-30"><a href="#L-30"><span class="linenos"> 30</span></a> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;Write all received packets to a file&quot;</span><span class="p">,</span>
</span><span id="L-31"><a href="#L-31"><span class="linenos"> 31</span></a><span class="p">)</span>
</span><span id="L-32"><a href="#L-32"><span class="linenos"> 32</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s2">&quot;--address&quot;</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;Bluetooth address&quot;</span><span class="p">)</span>
</span><span id="L-33"><a href="#L-33"><span class="linenos"> 33</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s2">&quot;--name&quot;</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;Bluetooth name of the device, slower but will work on macOS&quot;</span><span class="p">)</span>
</span><span id="L-34"><a href="#L-34"><span class="linenos"> 34</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_context</span>
</span><span id="L-35"><a href="#L-35"><span class="linenos"> 35</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">cli_client</span><span class="p">(</span><span class="n">context</span><span class="p">:</span> <span class="n">click</span><span class="o">.</span><span class="n">Context</span><span class="p">,</span> <span class="n">debug</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span> <span class="n">record</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span> <span class="n">address</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-36"><a href="#L-36"><span class="linenos"> 36</span></a> <span class="k">if</span> <span class="p">(</span><span class="n">address</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">name</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">address</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">name</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">):</span>
</span><span id="L-37"><a href="#L-37"><span class="linenos"> 37</span></a> <span class="n">context</span><span class="o">.</span><span class="n">fail</span><span class="p">(</span><span class="s2">&quot;You must pass either the address option(preferred) or the name option, but not both&quot;</span><span class="p">)</span>
</span><span id="L-38"><a href="#L-38"><span class="linenos"> 38</span></a>
</span><span id="L-39"><a href="#L-39"><span class="linenos"> 39</span></a> <span class="n">record_to</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="L-40"><a href="#L-40"><span class="linenos"> 40</span></a> <span class="k">if</span> <span class="n">record</span><span class="p">:</span>
</span><span id="L-41"><a href="#L-41"><span class="linenos"> 41</span></a> <span class="n">now</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())</span>
</span><span id="L-42"><a href="#L-42"><span class="linenos"> 42</span></a> <span class="n">captures</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s2">&quot;captures&quot;</span><span class="p">)</span>
</span><span id="L-43"><a href="#L-43"><span class="linenos"> 43</span></a> <span class="n">captures</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span><span id="L-44"><a href="#L-44"><span class="linenos"> 44</span></a> <span class="n">record_to</span> <span class="o">=</span> <span class="n">captures</span> <span class="o">/</span> <span class="n">Path</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;colmi_response_capture_</span><span class="si">{</span><span class="n">now</span><span class="si">}</span><span class="s2">.bin&quot;</span><span class="p">)</span>
</span><span id="L-45"><a href="#L-45"><span class="linenos"> 45</span></a> <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Recording responses to </span><span class="si">{</span><span class="n">record_to</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</span><span id="L-46"><a href="#L-46"><span class="linenos"> 46</span></a>
</span><span id="L-47"><a href="#L-47"><span class="linenos"> 47</span></a> <span class="k">if</span> <span class="n">name</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-48"><a href="#L-48"><span class="linenos"> 48</span></a> <span class="n">devices</span> <span class="o">=</span> <span class="k">await</span> <span class="n">BleakScanner</span><span class="o">.</span><span class="n">discover</span><span class="p">()</span>
</span><span id="L-49"><a href="#L-49"><span class="linenos"> 49</span></a> <span class="n">found</span> <span class="o">=</span> <span class="nb">next</span><span class="p">((</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">devices</span> <span class="k">if</span> <span class="n">x</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="n">name</span><span class="p">),</span> <span class="kc">None</span><span class="p">)</span>
</span><span id="L-50"><a href="#L-50"><span class="linenos"> 50</span></a> <span class="k">if</span> <span class="n">found</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-51"><a href="#L-51"><span class="linenos"> 51</span></a> <span class="n">context</span><span class="o">.</span><span class="n">fail</span><span class="p">(</span><span class="s2">&quot;No device found with given name&quot;</span><span class="p">)</span>
</span><span id="L-52"><a href="#L-52"><span class="linenos"> 52</span></a> <span class="n">address</span> <span class="o">=</span> <span class="n">found</span><span class="o">.</span><span class="n">address</span>
</span><span id="L-53"><a href="#L-53"><span class="linenos"> 53</span></a>
</span><span id="L-54"><a href="#L-54"><span class="linenos"> 54</span></a> <span class="k">assert</span> <span class="n">address</span>
</span><span id="L-55"><a href="#L-55"><span class="linenos"> 55</span></a>
</span><span id="L-56"><a href="#L-56"><span class="linenos"> 56</span></a> <span class="n">client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="n">address</span><span class="p">,</span> <span class="n">record_to</span><span class="o">=</span><span class="n">record_to</span><span class="p">)</span>
</span><span id="L-39"><a href="#L-39"><span class="linenos"> 39</span></a> <span class="k">if</span> <span class="n">debug</span><span class="p">:</span>
</span><span id="L-40"><a href="#L-40"><span class="linenos"> 40</span></a> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
</span><span id="L-41"><a href="#L-41"><span class="linenos"> 41</span></a> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s2">&quot;bleak&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">)</span>
</span><span id="L-42"><a href="#L-42"><span class="linenos"> 42</span></a>
</span><span id="L-43"><a href="#L-43"><span class="linenos"> 43</span></a> <span class="n">record_to</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="L-44"><a href="#L-44"><span class="linenos"> 44</span></a> <span class="k">if</span> <span class="n">record</span><span class="p">:</span>
</span><span id="L-45"><a href="#L-45"><span class="linenos"> 45</span></a> <span class="n">now</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())</span>
</span><span id="L-46"><a href="#L-46"><span class="linenos"> 46</span></a> <span class="n">captures</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s2">&quot;captures&quot;</span><span class="p">)</span>
</span><span id="L-47"><a href="#L-47"><span class="linenos"> 47</span></a> <span class="n">captures</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span><span id="L-48"><a href="#L-48"><span class="linenos"> 48</span></a> <span class="n">record_to</span> <span class="o">=</span> <span class="n">captures</span> <span class="o">/</span> <span class="n">Path</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;colmi_response_capture_</span><span class="si">{</span><span class="n">now</span><span class="si">}</span><span class="s2">.bin&quot;</span><span class="p">)</span>
</span><span id="L-49"><a href="#L-49"><span class="linenos"> 49</span></a> <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Recording responses to </span><span class="si">{</span><span class="n">record_to</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</span><span id="L-50"><a href="#L-50"><span class="linenos"> 50</span></a>
</span><span id="L-51"><a href="#L-51"><span class="linenos"> 51</span></a> <span class="k">if</span> <span class="n">name</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-52"><a href="#L-52"><span class="linenos"> 52</span></a> <span class="n">devices</span> <span class="o">=</span> <span class="k">await</span> <span class="n">BleakScanner</span><span class="o">.</span><span class="n">discover</span><span class="p">()</span>
</span><span id="L-53"><a href="#L-53"><span class="linenos"> 53</span></a> <span class="n">found</span> <span class="o">=</span> <span class="nb">next</span><span class="p">((</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">devices</span> <span class="k">if</span> <span class="n">x</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="n">name</span><span class="p">),</span> <span class="kc">None</span><span class="p">)</span>
</span><span id="L-54"><a href="#L-54"><span class="linenos"> 54</span></a> <span class="k">if</span> <span class="n">found</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-55"><a href="#L-55"><span class="linenos"> 55</span></a> <span class="n">context</span><span class="o">.</span><span class="n">fail</span><span class="p">(</span><span class="s2">&quot;No device found with given name&quot;</span><span class="p">)</span>
</span><span id="L-56"><a href="#L-56"><span class="linenos"> 56</span></a> <span class="n">address</span> <span class="o">=</span> <span class="n">found</span><span class="o">.</span><span class="n">address</span>
</span><span id="L-57"><a href="#L-57"><span class="linenos"> 57</span></a>
</span><span id="L-58"><a href="#L-58"><span class="linenos"> 58</span></a> <span class="n">context</span><span class="o">.</span><span class="n">obj</span> <span class="o">=</span> <span class="k">await</span> <span class="n">context</span><span class="o">.</span><span class="n">with_async_resource</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
</span><span id="L-58"><a href="#L-58"><span class="linenos"> 58</span></a> <span class="k">assert</span> <span class="n">address</span>
</span><span id="L-59"><a href="#L-59"><span class="linenos"> 59</span></a>
</span><span id="L-60"><a href="#L-60"><span class="linenos"> 60</span></a>
</span><span id="L-61"><a href="#L-61"><span class="linenos"> 61</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-62"><a href="#L-62"><span class="linenos"> 62</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-63"><a href="#L-63"><span class="linenos"> 63</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">info</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-64"><a href="#L-64"><span class="linenos"> 64</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Get device info and battery level&quot;&quot;&quot;</span>
</span><span id="L-65"><a href="#L-65"><span class="linenos"> 65</span></a>
</span><span id="L-66"><a href="#L-66"><span class="linenos"> 66</span></a> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;device info&quot;</span><span class="p">,</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_device_info</span><span class="p">())</span>
</span><span id="L-67"><a href="#L-67"><span class="linenos"> 67</span></a> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;battery:&quot;</span><span class="p">,</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_battery</span><span class="p">())</span>
</span><span id="L-68"><a href="#L-68"><span class="linenos"> 68</span></a>
</span><span id="L-60"><a href="#L-60"><span class="linenos"> 60</span></a> <span class="n">client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="n">address</span><span class="p">,</span> <span class="n">record_to</span><span class="o">=</span><span class="n">record_to</span><span class="p">)</span>
</span><span id="L-61"><a href="#L-61"><span class="linenos"> 61</span></a>
</span><span id="L-62"><a href="#L-62"><span class="linenos"> 62</span></a> <span class="n">context</span><span class="o">.</span><span class="n">obj</span> <span class="o">=</span> <span class="k">await</span> <span class="n">context</span><span class="o">.</span><span class="n">with_async_resource</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
</span><span id="L-63"><a href="#L-63"><span class="linenos"> 63</span></a>
</span><span id="L-64"><a href="#L-64"><span class="linenos"> 64</span></a>
</span><span id="L-65"><a href="#L-65"><span class="linenos"> 65</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-66"><a href="#L-66"><span class="linenos"> 66</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-67"><a href="#L-67"><span class="linenos"> 67</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">info</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-68"><a href="#L-68"><span class="linenos"> 68</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Get device info and battery level&quot;&quot;&quot;</span>
</span><span id="L-69"><a href="#L-69"><span class="linenos"> 69</span></a>
</span><span id="L-70"><a href="#L-70"><span class="linenos"> 70</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-71"><a href="#L-71"><span class="linenos"> 71</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span>
</span><span id="L-72"><a href="#L-72"><span class="linenos"> 72</span></a> <span class="s2">&quot;--target&quot;</span><span class="p">,</span>
</span><span id="L-73"><a href="#L-73"><span class="linenos"> 73</span></a> <span class="nb">type</span><span class="o">=</span><span class="n">click</span><span class="o">.</span><span class="n">DateTime</span><span class="p">(),</span>
</span><span id="L-74"><a href="#L-74"><span class="linenos"> 74</span></a> <span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span><span id="L-75"><a href="#L-75"><span class="linenos"> 75</span></a> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;The date you want logs for&quot;</span><span class="p">,</span>
</span><span id="L-76"><a href="#L-76"><span class="linenos"> 76</span></a><span class="p">)</span>
</span><span id="L-77"><a href="#L-77"><span class="linenos"> 77</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-78"><a href="#L-78"><span class="linenos"> 78</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">get_heart_rate_log</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">,</span> <span class="n">target</span><span class="p">:</span> <span class="n">datetime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-79"><a href="#L-79"><span class="linenos"> 79</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Get heart rate for given date&quot;&quot;&quot;</span>
</span><span id="L-80"><a href="#L-80"><span class="linenos"> 80</span></a>
</span><span id="L-81"><a href="#L-81"><span class="linenos"> 81</span></a> <span class="n">log</span> <span class="o">=</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_heart_rate_log</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>
</span><span id="L-82"><a href="#L-82"><span class="linenos"> 82</span></a> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Data:&quot;</span><span class="p">,</span> <span class="n">log</span><span class="p">)</span>
</span><span id="L-83"><a href="#L-83"><span class="linenos"> 83</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">log</span><span class="p">,</span> <span class="n">HeartRateLog</span><span class="p">):</span>
</span><span id="L-84"><a href="#L-84"><span class="linenos"> 84</span></a> <span class="k">for</span> <span class="n">hr</span><span class="p">,</span> <span class="n">ts</span> <span class="ow">in</span> <span class="n">log</span><span class="o">.</span><span class="n">heart_rates_with_times</span><span class="p">():</span>
</span><span id="L-85"><a href="#L-85"><span class="linenos"> 85</span></a> <span class="k">if</span> <span class="n">hr</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span>
</span><span id="L-86"><a href="#L-86"><span class="linenos"> 86</span></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">ts</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">&#39;%H:%M&#39;</span><span class="p">)</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">hr</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</span><span id="L-87"><a href="#L-87"><span class="linenos"> 87</span></a>
</span><span id="L-88"><a href="#L-88"><span class="linenos"> 88</span></a>
</span><span id="L-89"><a href="#L-89"><span class="linenos"> 89</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-90"><a href="#L-90"><span class="linenos"> 90</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span>
</span><span id="L-91"><a href="#L-91"><span class="linenos"> 91</span></a> <span class="s2">&quot;--when&quot;</span><span class="p">,</span>
</span><span id="L-92"><a href="#L-92"><span class="linenos"> 92</span></a> <span class="nb">type</span><span class="o">=</span><span class="n">click</span><span class="o">.</span><span class="n">DateTime</span><span class="p">(),</span>
</span><span id="L-93"><a href="#L-93"><span class="linenos"> 93</span></a> <span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span><span id="L-94"><a href="#L-94"><span class="linenos"> 94</span></a> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;The date and time you want to set the ring to&quot;</span><span class="p">,</span>
</span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</span></a><span class="p">)</span>
</span><span id="L-96"><a href="#L-96"><span class="linenos"> 96</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">set_time</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">,</span> <span class="n">when</span><span class="p">:</span> <span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a><span class="sd"> Set the time on the ring, required if you want to be able to interpret any of the logged data</span>
</span><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a>
</span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a> <span class="k">if</span> <span class="n">when</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-103"><a href="#L-103"><span class="linenos">103</span></a> <span class="n">when</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">(</span><span class="n">tz</span><span class="o">=</span><span class="n">timezone</span><span class="o">.</span><span class="n">utc</span><span class="p">)</span>
</span><span id="L-104"><a href="#L-104"><span class="linenos">104</span></a> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">set_time</span><span class="p">(</span><span class="n">when</span><span class="p">)</span>
</span><span id="L-70"><a href="#L-70"><span class="linenos"> 70</span></a> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;device info&quot;</span><span class="p">,</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_device_info</span><span class="p">())</span>
</span><span id="L-71"><a href="#L-71"><span class="linenos"> 71</span></a> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;battery:&quot;</span><span class="p">,</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_battery</span><span class="p">())</span>
</span><span id="L-72"><a href="#L-72"><span class="linenos"> 72</span></a>
</span><span id="L-73"><a href="#L-73"><span class="linenos"> 73</span></a>
</span><span id="L-74"><a href="#L-74"><span class="linenos"> 74</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-75"><a href="#L-75"><span class="linenos"> 75</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span>
</span><span id="L-76"><a href="#L-76"><span class="linenos"> 76</span></a> <span class="s2">&quot;--target&quot;</span><span class="p">,</span>
</span><span id="L-77"><a href="#L-77"><span class="linenos"> 77</span></a> <span class="nb">type</span><span class="o">=</span><span class="n">click</span><span class="o">.</span><span class="n">DateTime</span><span class="p">(),</span>
</span><span id="L-78"><a href="#L-78"><span class="linenos"> 78</span></a> <span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span><span id="L-79"><a href="#L-79"><span class="linenos"> 79</span></a> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;The date you want logs for&quot;</span><span class="p">,</span>
</span><span id="L-80"><a href="#L-80"><span class="linenos"> 80</span></a><span class="p">)</span>
</span><span id="L-81"><a href="#L-81"><span class="linenos"> 81</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-82"><a href="#L-82"><span class="linenos"> 82</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">get_heart_rate_log</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">,</span> <span class="n">target</span><span class="p">:</span> <span class="n">datetime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-83"><a href="#L-83"><span class="linenos"> 83</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Get heart rate for given date&quot;&quot;&quot;</span>
</span><span id="L-84"><a href="#L-84"><span class="linenos"> 84</span></a>
</span><span id="L-85"><a href="#L-85"><span class="linenos"> 85</span></a> <span class="n">log</span> <span class="o">=</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_heart_rate_log</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>
</span><span id="L-86"><a href="#L-86"><span class="linenos"> 86</span></a> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Data:&quot;</span><span class="p">,</span> <span class="n">log</span><span class="p">)</span>
</span><span id="L-87"><a href="#L-87"><span class="linenos"> 87</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">log</span><span class="p">,</span> <span class="n">HeartRateLog</span><span class="p">):</span>
</span><span id="L-88"><a href="#L-88"><span class="linenos"> 88</span></a> <span class="k">for</span> <span class="n">hr</span><span class="p">,</span> <span class="n">ts</span> <span class="ow">in</span> <span class="n">log</span><span class="o">.</span><span class="n">heart_rates_with_times</span><span class="p">():</span>
</span><span id="L-89"><a href="#L-89"><span class="linenos"> 89</span></a> <span class="k">if</span> <span class="n">hr</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span>
</span><span id="L-90"><a href="#L-90"><span class="linenos"> 90</span></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">ts</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">&#39;%H:%M&#39;</span><span class="p">)</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">hr</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</span><span id="L-91"><a href="#L-91"><span class="linenos"> 91</span></a>
</span><span id="L-92"><a href="#L-92"><span class="linenos"> 92</span></a>
</span><span id="L-93"><a href="#L-93"><span class="linenos"> 93</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-94"><a href="#L-94"><span class="linenos"> 94</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span>
</span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</span></a> <span class="s2">&quot;--when&quot;</span><span class="p">,</span>
</span><span id="L-96"><a href="#L-96"><span class="linenos"> 96</span></a> <span class="nb">type</span><span class="o">=</span><span class="n">click</span><span class="o">.</span><span class="n">DateTime</span><span class="p">(),</span>
</span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a> <span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;The date and time you want to set the ring to&quot;</span><span class="p">,</span>
</span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a><span class="p">)</span>
</span><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">set_time</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">,</span> <span class="n">when</span><span class="p">:</span> <span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-103"><a href="#L-103"><span class="linenos">103</span></a><span class="sd"> Set the time on the ring, required if you want to be able to interpret any of the logged data</span>
</span><span id="L-104"><a href="#L-104"><span class="linenos">104</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-105"><a href="#L-105"><span class="linenos">105</span></a>
</span><span id="L-106"><a href="#L-106"><span class="linenos">106</span></a>
</span><span id="L-107"><a href="#L-107"><span class="linenos">107</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-108"><a href="#L-108"><span class="linenos">108</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-109"><a href="#L-109"><span class="linenos">109</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">get_heart_rate_log_settings</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-110"><a href="#L-110"><span class="linenos">110</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Get heart rate log settings&quot;&quot;&quot;</span>
</span><span id="L-111"><a href="#L-111"><span class="linenos">111</span></a>
</span><span id="L-112"><a href="#L-112"><span class="linenos">112</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">&quot;heart rate log settings:&quot;</span><span class="p">)</span>
</span><span id="L-113"><a href="#L-113"><span class="linenos">113</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_heart_rate_log_settings</span><span class="p">())</span>
</span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a>
</span><span id="L-106"><a href="#L-106"><span class="linenos">106</span></a> <span class="k">if</span> <span class="n">when</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-107"><a href="#L-107"><span class="linenos">107</span></a> <span class="n">when</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">(</span><span class="n">tz</span><span class="o">=</span><span class="n">timezone</span><span class="o">.</span><span class="n">utc</span><span class="p">)</span>
</span><span id="L-108"><a href="#L-108"><span class="linenos">108</span></a> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">set_time</span><span class="p">(</span><span class="n">when</span><span class="p">)</span>
</span><span id="L-109"><a href="#L-109"><span class="linenos">109</span></a>
</span><span id="L-110"><a href="#L-110"><span class="linenos">110</span></a>
</span><span id="L-111"><a href="#L-111"><span class="linenos">111</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-112"><a href="#L-112"><span class="linenos">112</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-113"><a href="#L-113"><span class="linenos">113</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">get_heart_rate_log_settings</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Get heart rate log settings&quot;&quot;&quot;</span>
</span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a>
</span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s2">&quot;--enable/--disable&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">show_default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;Logging status&quot;</span><span class="p">)</span>
</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span>
</span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a> <span class="s2">&quot;--interval&quot;</span><span class="p">,</span>
</span><span id="L-120"><a href="#L-120"><span class="linenos">120</span></a> <span class="nb">type</span><span class="o">=</span><span class="n">click</span><span class="o">.</span><span class="n">IntRange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">255</span><span class="p">),</span>
</span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;Interval in minutes to measure heart rate&quot;</span><span class="p">,</span>
</span><span id="L-122"><a href="#L-122"><span class="linenos">122</span></a> <span class="n">default</span><span class="o">=</span><span class="mi">60</span><span class="p">,</span>
</span><span id="L-123"><a href="#L-123"><span class="linenos">123</span></a> <span class="n">show_default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span><span id="L-124"><a href="#L-124"><span class="linenos">124</span></a><span class="p">)</span>
</span><span id="L-125"><a href="#L-125"><span class="linenos">125</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-126"><a href="#L-126"><span class="linenos">126</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">set_heart_rate_log_settings</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">,</span> <span class="n">enable</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span> <span class="n">interval</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-127"><a href="#L-127"><span class="linenos">127</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Get heart rate log settings&quot;&quot;&quot;</span>
</span><span id="L-128"><a href="#L-128"><span class="linenos">128</span></a>
</span><span id="L-129"><a href="#L-129"><span class="linenos">129</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">&quot;Changing heart rate log settings&quot;</span><span class="p">)</span>
</span><span id="L-130"><a href="#L-130"><span class="linenos">130</span></a> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">set_heart_rate_log_settings</span><span class="p">(</span><span class="n">enable</span><span class="p">,</span> <span class="n">interval</span><span class="p">)</span>
</span><span id="L-131"><a href="#L-131"><span class="linenos">131</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_heart_rate_log_settings</span><span class="p">())</span>
</span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">&quot;Done&quot;</span><span class="p">)</span>
</span><span id="L-133"><a href="#L-133"><span class="linenos">133</span></a>
</span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a>
</span><span id="L-135"><a href="#L-135"><span class="linenos">135</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-136"><a href="#L-136"><span class="linenos">136</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-137"><a href="#L-137"><span class="linenos">137</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">get_real_time_heart_rate</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-138"><a href="#L-138"><span class="linenos">138</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Get real time heart rate.</span>
</span><span id="L-139"><a href="#L-139"><span class="linenos">139</span></a>
</span><span id="L-140"><a href="#L-140"><span class="linenos">140</span></a><span class="sd"> TODO: add number of readings</span>
</span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-142"><a href="#L-142"><span class="linenos">142</span></a>
</span><span id="L-143"><a href="#L-143"><span class="linenos">143</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">&quot;Starting reading, please wait.&quot;</span><span class="p">)</span>
</span><span id="L-144"><a href="#L-144"><span class="linenos">144</span></a> <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_realtime_heart_rate</span><span class="p">()</span>
</span><span id="L-145"><a href="#L-145"><span class="linenos">145</span></a> <span class="k">if</span> <span class="n">result</span><span class="p">:</span>
</span><span id="L-146"><a href="#L-146"><span class="linenos">146</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
</span><span id="L-147"><a href="#L-147"><span class="linenos">147</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="L-148"><a href="#L-148"><span class="linenos">148</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">&quot;Error, no HR detected. Is the ring being worn?&quot;</span><span class="p">)</span>
</span><span id="L-149"><a href="#L-149"><span class="linenos">149</span></a>
</span><span id="L-150"><a href="#L-150"><span class="linenos">150</span></a>
</span><span id="L-151"><a href="#L-151"><span class="linenos">151</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-152"><a href="#L-152"><span class="linenos">152</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-153"><a href="#L-153"><span class="linenos">153</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span>
</span><span id="L-154"><a href="#L-154"><span class="linenos">154</span></a> <span class="s2">&quot;--when&quot;</span><span class="p">,</span>
</span><span id="L-155"><a href="#L-155"><span class="linenos">155</span></a> <span class="nb">type</span><span class="o">=</span><span class="n">click</span><span class="o">.</span><span class="n">DateTime</span><span class="p">(),</span>
</span><span id="L-156"><a href="#L-156"><span class="linenos">156</span></a> <span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span><span id="L-157"><a href="#L-157"><span class="linenos">157</span></a> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;The date you want steps for&quot;</span><span class="p">,</span>
</span><span id="L-158"><a href="#L-158"><span class="linenos">158</span></a><span class="p">)</span>
</span><span id="L-159"><a href="#L-159"><span class="linenos">159</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">get_steps</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">,</span> <span class="n">when</span><span class="p">:</span> <span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-160"><a href="#L-160"><span class="linenos">160</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Get step data&quot;&quot;&quot;</span>
</span><span id="L-161"><a href="#L-161"><span class="linenos">161</span></a>
</span><span id="L-162"><a href="#L-162"><span class="linenos">162</span></a> <span class="k">if</span> <span class="n">when</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-163"><a href="#L-163"><span class="linenos">163</span></a> <span class="n">when</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">(</span><span class="n">tz</span><span class="o">=</span><span class="n">timezone</span><span class="o">.</span><span class="n">utc</span><span class="p">)</span>
</span><span id="L-164"><a href="#L-164"><span class="linenos">164</span></a> <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_steps</span><span class="p">(</span><span class="n">when</span><span class="p">)</span>
</span><span id="L-165"><a href="#L-165"><span class="linenos">165</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
</span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">&quot;heart rate log settings:&quot;</span><span class="p">)</span>
</span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_heart_rate_log_settings</span><span class="p">())</span>
</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a>
</span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a>
</span><span id="L-120"><a href="#L-120"><span class="linenos">120</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s2">&quot;--enable/--disable&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">show_default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;Logging status&quot;</span><span class="p">)</span>
</span><span id="L-122"><a href="#L-122"><span class="linenos">122</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span>
</span><span id="L-123"><a href="#L-123"><span class="linenos">123</span></a> <span class="s2">&quot;--interval&quot;</span><span class="p">,</span>
</span><span id="L-124"><a href="#L-124"><span class="linenos">124</span></a> <span class="nb">type</span><span class="o">=</span><span class="n">click</span><span class="o">.</span><span class="n">IntRange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">255</span><span class="p">),</span>
</span><span id="L-125"><a href="#L-125"><span class="linenos">125</span></a> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;Interval in minutes to measure heart rate&quot;</span><span class="p">,</span>
</span><span id="L-126"><a href="#L-126"><span class="linenos">126</span></a> <span class="n">default</span><span class="o">=</span><span class="mi">60</span><span class="p">,</span>
</span><span id="L-127"><a href="#L-127"><span class="linenos">127</span></a> <span class="n">show_default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span><span id="L-128"><a href="#L-128"><span class="linenos">128</span></a><span class="p">)</span>
</span><span id="L-129"><a href="#L-129"><span class="linenos">129</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-130"><a href="#L-130"><span class="linenos">130</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">set_heart_rate_log_settings</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">,</span> <span class="n">enable</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span> <span class="n">interval</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-131"><a href="#L-131"><span class="linenos">131</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Get heart rate log settings&quot;&quot;&quot;</span>
</span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a>
</span><span id="L-133"><a href="#L-133"><span class="linenos">133</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">&quot;Changing heart rate log settings&quot;</span><span class="p">)</span>
</span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">set_heart_rate_log_settings</span><span class="p">(</span><span class="n">enable</span><span class="p">,</span> <span class="n">interval</span><span class="p">)</span>
</span><span id="L-135"><a href="#L-135"><span class="linenos">135</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_heart_rate_log_settings</span><span class="p">())</span>
</span><span id="L-136"><a href="#L-136"><span class="linenos">136</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">&quot;Done&quot;</span><span class="p">)</span>
</span><span id="L-137"><a href="#L-137"><span class="linenos">137</span></a>
</span><span id="L-138"><a href="#L-138"><span class="linenos">138</span></a>
</span><span id="L-139"><a href="#L-139"><span class="linenos">139</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-140"><a href="#L-140"><span class="linenos">140</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">get_real_time_heart_rate</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-142"><a href="#L-142"><span class="linenos">142</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Get real time heart rate.</span>
</span><span id="L-143"><a href="#L-143"><span class="linenos">143</span></a>
</span><span id="L-144"><a href="#L-144"><span class="linenos">144</span></a><span class="sd"> TODO: add number of readings</span>
</span><span id="L-145"><a href="#L-145"><span class="linenos">145</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-146"><a href="#L-146"><span class="linenos">146</span></a>
</span><span id="L-147"><a href="#L-147"><span class="linenos">147</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">&quot;Starting reading, please wait.&quot;</span><span class="p">)</span>
</span><span id="L-148"><a href="#L-148"><span class="linenos">148</span></a> <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_realtime_heart_rate</span><span class="p">()</span>
</span><span id="L-149"><a href="#L-149"><span class="linenos">149</span></a> <span class="k">if</span> <span class="n">result</span><span class="p">:</span>
</span><span id="L-150"><a href="#L-150"><span class="linenos">150</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
</span><span id="L-151"><a href="#L-151"><span class="linenos">151</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="L-152"><a href="#L-152"><span class="linenos">152</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">&quot;Error, no HR detected. Is the ring being worn?&quot;</span><span class="p">)</span>
</span><span id="L-153"><a href="#L-153"><span class="linenos">153</span></a>
</span><span id="L-154"><a href="#L-154"><span class="linenos">154</span></a>
</span><span id="L-155"><a href="#L-155"><span class="linenos">155</span></a><span class="nd">@cli_client</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-156"><a href="#L-156"><span class="linenos">156</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">pass_obj</span>
</span><span id="L-157"><a href="#L-157"><span class="linenos">157</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span>
</span><span id="L-158"><a href="#L-158"><span class="linenos">158</span></a> <span class="s2">&quot;--when&quot;</span><span class="p">,</span>
</span><span id="L-159"><a href="#L-159"><span class="linenos">159</span></a> <span class="nb">type</span><span class="o">=</span><span class="n">click</span><span class="o">.</span><span class="n">DateTime</span><span class="p">(),</span>
</span><span id="L-160"><a href="#L-160"><span class="linenos">160</span></a> <span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span><span id="L-161"><a href="#L-161"><span class="linenos">161</span></a> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;The date you want steps for&quot;</span><span class="p">,</span>
</span><span id="L-162"><a href="#L-162"><span class="linenos">162</span></a><span class="p">)</span>
</span><span id="L-163"><a href="#L-163"><span class="linenos">163</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s2">&quot;--as-csv&quot;</span><span class="p">,</span> <span class="n">is_flag</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;Print as CSV&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span><span id="L-164"><a href="#L-164"><span class="linenos">164</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">get_steps</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">Client</span><span class="p">,</span> <span class="n">when</span><span class="p">:</span> <span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">as_csv</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-165"><a href="#L-165"><span class="linenos">165</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Get step data&quot;&quot;&quot;</span>
</span><span id="L-166"><a href="#L-166"><span class="linenos">166</span></a>
</span><span id="L-167"><a href="#L-167"><span class="linenos">167</span></a>
</span><span id="L-168"><a href="#L-168"><span class="linenos">168</span></a><span class="n">DEVICE_NAME_PREFIXES</span> <span class="o">=</span> <span class="p">[</span>
</span><span id="L-169"><a href="#L-169"><span class="linenos">169</span></a> <span class="s2">&quot;R01&quot;</span><span class="p">,</span>
</span><span id="L-170"><a href="#L-170"><span class="linenos">170</span></a> <span class="s2">&quot;R02&quot;</span><span class="p">,</span>
</span><span id="L-171"><a href="#L-171"><span class="linenos">171</span></a> <span class="s2">&quot;R03&quot;</span><span class="p">,</span>
</span><span id="L-172"><a href="#L-172"><span class="linenos">172</span></a> <span class="s2">&quot;R04&quot;</span><span class="p">,</span>
</span><span id="L-173"><a href="#L-173"><span class="linenos">173</span></a> <span class="s2">&quot;R05&quot;</span><span class="p">,</span>
</span><span id="L-174"><a href="#L-174"><span class="linenos">174</span></a> <span class="s2">&quot;R06&quot;</span><span class="p">,</span>
</span><span id="L-175"><a href="#L-175"><span class="linenos">175</span></a> <span class="s2">&quot;R07&quot;</span><span class="p">,</span>
</span><span id="L-176"><a href="#L-176"><span class="linenos">176</span></a> <span class="s2">&quot;VK-5098&quot;</span><span class="p">,</span>
</span><span id="L-177"><a href="#L-177"><span class="linenos">177</span></a> <span class="s2">&quot;MERLIN&quot;</span><span class="p">,</span>
</span><span id="L-178"><a href="#L-178"><span class="linenos">178</span></a> <span class="s2">&quot;Hello Ring&quot;</span><span class="p">,</span>
</span><span id="L-179"><a href="#L-179"><span class="linenos">179</span></a> <span class="s2">&quot;RING1&quot;</span><span class="p">,</span>
</span><span id="L-180"><a href="#L-180"><span class="linenos">180</span></a> <span class="s2">&quot;boAtring&quot;</span><span class="p">,</span>
</span><span id="L-181"><a href="#L-181"><span class="linenos">181</span></a> <span class="s2">&quot;TR-R02&quot;</span><span class="p">,</span>
</span><span id="L-182"><a href="#L-182"><span class="linenos">182</span></a> <span class="s2">&quot;SE&quot;</span><span class="p">,</span>
</span><span id="L-183"><a href="#L-183"><span class="linenos">183</span></a> <span class="s2">&quot;EVOLVEO&quot;</span><span class="p">,</span>
</span><span id="L-184"><a href="#L-184"><span class="linenos">184</span></a> <span class="s2">&quot;GL-SR2&quot;</span><span class="p">,</span>
</span><span id="L-185"><a href="#L-185"><span class="linenos">185</span></a> <span class="s2">&quot;Blaupunkt&quot;</span><span class="p">,</span>
</span><span id="L-186"><a href="#L-186"><span class="linenos">186</span></a> <span class="s2">&quot;KSIX RING&quot;</span><span class="p">,</span>
</span><span id="L-187"><a href="#L-187"><span class="linenos">187</span></a><span class="p">]</span>
</span><span id="L-188"><a href="#L-188"><span class="linenos">188</span></a>
</span><span id="L-189"><a href="#L-189"><span class="linenos">189</span></a>
</span><span id="L-190"><a href="#L-190"><span class="linenos">190</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">group</span><span class="p">()</span>
</span><span id="L-191"><a href="#L-191"><span class="linenos">191</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">util</span><span class="p">():</span>
</span><span id="L-192"><a href="#L-192"><span class="linenos">192</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Generic utilities for the R02 that don&#39;t need an address.&quot;&quot;&quot;</span>
</span><span id="L-193"><a href="#L-193"><span class="linenos">193</span></a>
</span><span id="L-194"><a href="#L-194"><span class="linenos">194</span></a>
</span><span id="L-195"><a href="#L-195"><span class="linenos">195</span></a><span class="nd">@util</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-196"><a href="#L-196"><span class="linenos">196</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">scan</span><span class="p">():</span>
</span><span id="L-197"><a href="#L-197"><span class="linenos">197</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Scan for possible devices based on known prefixes and print the bluetooth address.&quot;&quot;&quot;</span>
</span><span id="L-198"><a href="#L-198"><span class="linenos">198</span></a>
</span><span id="L-199"><a href="#L-199"><span class="linenos">199</span></a> <span class="c1"># TODO maybe bluetooth specific stuff like this should be in another package?</span>
</span><span id="L-200"><a href="#L-200"><span class="linenos">200</span></a> <span class="n">devices</span> <span class="o">=</span> <span class="k">await</span> <span class="n">BleakScanner</span><span class="o">.</span><span class="n">discover</span><span class="p">()</span>
</span><span id="L-201"><a href="#L-201"><span class="linenos">201</span></a>
</span><span id="L-202"><a href="#L-202"><span class="linenos">202</span></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">devices</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
</span><span id="L-203"><a href="#L-203"><span class="linenos">203</span></a> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Found device(s)&quot;</span><span class="p">)</span>
</span><span id="L-204"><a href="#L-204"><span class="linenos">204</span></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="s1">&#39;Name&#39;</span><span class="si">:</span><span class="s2">&gt;20</span><span class="si">}</span><span class="s2"> | Address&quot;</span><span class="p">)</span>
</span><span id="L-205"><a href="#L-205"><span class="linenos">205</span></a> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;-&quot;</span> <span class="o">*</span> <span class="mi">44</span><span class="p">)</span>
</span><span id="L-206"><a href="#L-206"><span class="linenos">206</span></a> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">devices</span><span class="p">:</span>
</span><span id="L-207"><a href="#L-207"><span class="linenos">207</span></a> <span class="n">name</span> <span class="o">=</span> <span class="n">d</span><span class="o">.</span><span class="n">name</span>
</span><span id="L-208"><a href="#L-208"><span class="linenos">208</span></a> <span class="k">if</span> <span class="n">name</span> <span class="ow">and</span> <span class="nb">any</span><span class="p">(</span><span class="n">name</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">DEVICE_NAME_PREFIXES</span> <span class="k">if</span> <span class="n">name</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="n">p</span><span class="p">)):</span>
</span><span id="L-209"><a href="#L-209"><span class="linenos">209</span></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">name</span><span class="si">:</span><span class="s2">&gt;20</span><span class="si">}</span><span class="s2"> | </span><span class="si">{</span><span class="n">d</span><span class="o">.</span><span class="n">address</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</span><span id="L-210"><a href="#L-210"><span class="linenos">210</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="L-211"><a href="#L-211"><span class="linenos">211</span></a> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;No devices found. Try moving the ring closer to computer&quot;</span><span class="p">)</span>
</span><span id="L-167"><a href="#L-167"><span class="linenos">167</span></a> <span class="k">if</span> <span class="n">when</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-168"><a href="#L-168"><span class="linenos">168</span></a> <span class="n">when</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">(</span><span class="n">tz</span><span class="o">=</span><span class="n">timezone</span><span class="o">.</span><span class="n">utc</span><span class="p">)</span>
</span><span id="L-169"><a href="#L-169"><span class="linenos">169</span></a> <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get_steps</span><span class="p">(</span><span class="n">when</span><span class="p">)</span>
</span><span id="L-170"><a href="#L-170"><span class="linenos">170</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">steps</span><span class="o">.</span><span class="n">NoData</span><span class="p">):</span>
</span><span id="L-171"><a href="#L-171"><span class="linenos">171</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">&quot;No results for day&quot;</span><span class="p">)</span>
</span><span id="L-172"><a href="#L-172"><span class="linenos">172</span></a> <span class="k">return</span>
</span><span id="L-173"><a href="#L-173"><span class="linenos">173</span></a>
</span><span id="L-174"><a href="#L-174"><span class="linenos">174</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">as_csv</span><span class="p">:</span>
</span><span id="L-175"><a href="#L-175"><span class="linenos">175</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="n">pretty_print</span><span class="o">.</span><span class="n">print_dataclasses</span><span class="p">(</span><span class="n">result</span><span class="p">))</span>
</span><span id="L-176"><a href="#L-176"><span class="linenos">176</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="L-177"><a href="#L-177"><span class="linenos">177</span></a> <span class="n">out</span> <span class="o">=</span> <span class="n">StringIO</span><span class="p">()</span>
</span><span id="L-178"><a href="#L-178"><span class="linenos">178</span></a> <span class="n">writer</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictWriter</span><span class="p">(</span><span class="n">out</span><span class="p">,</span> <span class="n">fieldnames</span><span class="o">=</span><span class="p">[</span><span class="n">f</span><span class="o">.</span><span class="n">name</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">dataclasses</span><span class="o">.</span><span class="n">fields</span><span class="p">(</span><span class="n">steps</span><span class="o">.</span><span class="n">SportDetail</span><span class="p">)])</span>
</span><span id="L-179"><a href="#L-179"><span class="linenos">179</span></a> <span class="n">writer</span><span class="o">.</span><span class="n">writeheader</span><span class="p">()</span>
</span><span id="L-180"><a href="#L-180"><span class="linenos">180</span></a> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
</span><span id="L-181"><a href="#L-181"><span class="linenos">181</span></a> <span class="n">writer</span><span class="o">.</span><span class="n">writerow</span><span class="p">(</span><span class="n">dataclasses</span><span class="o">.</span><span class="n">asdict</span><span class="p">(</span><span class="n">r</span><span class="p">))</span>
</span><span id="L-182"><a href="#L-182"><span class="linenos">182</span></a> <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="n">out</span><span class="o">.</span><span class="n">getvalue</span><span class="p">())</span>
</span><span id="L-183"><a href="#L-183"><span class="linenos">183</span></a>
</span><span id="L-184"><a href="#L-184"><span class="linenos">184</span></a>
</span><span id="L-185"><a href="#L-185"><span class="linenos">185</span></a><span class="n">DEVICE_NAME_PREFIXES</span> <span class="o">=</span> <span class="p">[</span>
</span><span id="L-186"><a href="#L-186"><span class="linenos">186</span></a> <span class="s2">&quot;R01&quot;</span><span class="p">,</span>
</span><span id="L-187"><a href="#L-187"><span class="linenos">187</span></a> <span class="s2">&quot;R02&quot;</span><span class="p">,</span>
</span><span id="L-188"><a href="#L-188"><span class="linenos">188</span></a> <span class="s2">&quot;R03&quot;</span><span class="p">,</span>
</span><span id="L-189"><a href="#L-189"><span class="linenos">189</span></a> <span class="s2">&quot;R04&quot;</span><span class="p">,</span>
</span><span id="L-190"><a href="#L-190"><span class="linenos">190</span></a> <span class="s2">&quot;R05&quot;</span><span class="p">,</span>
</span><span id="L-191"><a href="#L-191"><span class="linenos">191</span></a> <span class="s2">&quot;R06&quot;</span><span class="p">,</span>
</span><span id="L-192"><a href="#L-192"><span class="linenos">192</span></a> <span class="s2">&quot;R07&quot;</span><span class="p">,</span>
</span><span id="L-193"><a href="#L-193"><span class="linenos">193</span></a> <span class="s2">&quot;VK-5098&quot;</span><span class="p">,</span>
</span><span id="L-194"><a href="#L-194"><span class="linenos">194</span></a> <span class="s2">&quot;MERLIN&quot;</span><span class="p">,</span>
</span><span id="L-195"><a href="#L-195"><span class="linenos">195</span></a> <span class="s2">&quot;Hello Ring&quot;</span><span class="p">,</span>
</span><span id="L-196"><a href="#L-196"><span class="linenos">196</span></a> <span class="s2">&quot;RING1&quot;</span><span class="p">,</span>
</span><span id="L-197"><a href="#L-197"><span class="linenos">197</span></a> <span class="s2">&quot;boAtring&quot;</span><span class="p">,</span>
</span><span id="L-198"><a href="#L-198"><span class="linenos">198</span></a> <span class="s2">&quot;TR-R02&quot;</span><span class="p">,</span>
</span><span id="L-199"><a href="#L-199"><span class="linenos">199</span></a> <span class="s2">&quot;SE&quot;</span><span class="p">,</span>
</span><span id="L-200"><a href="#L-200"><span class="linenos">200</span></a> <span class="s2">&quot;EVOLVEO&quot;</span><span class="p">,</span>
</span><span id="L-201"><a href="#L-201"><span class="linenos">201</span></a> <span class="s2">&quot;GL-SR2&quot;</span><span class="p">,</span>
</span><span id="L-202"><a href="#L-202"><span class="linenos">202</span></a> <span class="s2">&quot;Blaupunkt&quot;</span><span class="p">,</span>
</span><span id="L-203"><a href="#L-203"><span class="linenos">203</span></a> <span class="s2">&quot;KSIX RING&quot;</span><span class="p">,</span>
</span><span id="L-204"><a href="#L-204"><span class="linenos">204</span></a><span class="p">]</span>
</span><span id="L-205"><a href="#L-205"><span class="linenos">205</span></a>
</span><span id="L-206"><a href="#L-206"><span class="linenos">206</span></a>
</span><span id="L-207"><a href="#L-207"><span class="linenos">207</span></a><span class="nd">@click</span><span class="o">.</span><span class="n">group</span><span class="p">()</span>
</span><span id="L-208"><a href="#L-208"><span class="linenos">208</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">util</span><span class="p">():</span>
</span><span id="L-209"><a href="#L-209"><span class="linenos">209</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Generic utilities for the R02 that don&#39;t need an address.&quot;&quot;&quot;</span>
</span><span id="L-210"><a href="#L-210"><span class="linenos">210</span></a>
</span><span id="L-211"><a href="#L-211"><span class="linenos">211</span></a>
</span><span id="L-212"><a href="#L-212"><span class="linenos">212</span></a><span class="nd">@util</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
</span><span id="L-213"><a href="#L-213"><span class="linenos">213</span></a><span class="k">async</span> <span class="k">def</span> <span class="nf">scan</span><span class="p">():</span>
</span><span id="L-214"><a href="#L-214"><span class="linenos">214</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Scan for possible devices based on known prefixes and print the bluetooth address.&quot;&quot;&quot;</span>
</span><span id="L-215"><a href="#L-215"><span class="linenos">215</span></a>
</span><span id="L-216"><a href="#L-216"><span class="linenos">216</span></a> <span class="c1"># TODO maybe bluetooth specific stuff like this should be in another package?</span>
</span><span id="L-217"><a href="#L-217"><span class="linenos">217</span></a> <span class="n">devices</span> <span class="o">=</span> <span class="k">await</span> <span class="n">BleakScanner</span><span class="o">.</span><span class="n">discover</span><span class="p">()</span>
</span><span id="L-218"><a href="#L-218"><span class="linenos">218</span></a>
</span><span id="L-219"><a href="#L-219"><span class="linenos">219</span></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">devices</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
</span><span id="L-220"><a href="#L-220"><span class="linenos">220</span></a> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Found device(s)&quot;</span><span class="p">)</span>
</span><span id="L-221"><a href="#L-221"><span class="linenos">221</span></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="s1">&#39;Name&#39;</span><span class="si">:</span><span class="s2">&gt;20</span><span class="si">}</span><span class="s2"> | Address&quot;</span><span class="p">)</span>
</span><span id="L-222"><a href="#L-222"><span class="linenos">222</span></a> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;-&quot;</span> <span class="o">*</span> <span class="mi">44</span><span class="p">)</span>
</span><span id="L-223"><a href="#L-223"><span class="linenos">223</span></a> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">devices</span><span class="p">:</span>
</span><span id="L-224"><a href="#L-224"><span class="linenos">224</span></a> <span class="n">name</span> <span class="o">=</span> <span class="n">d</span><span class="o">.</span><span class="n">name</span>
</span><span id="L-225"><a href="#L-225"><span class="linenos">225</span></a> <span class="k">if</span> <span class="n">name</span> <span class="ow">and</span> <span class="nb">any</span><span class="p">(</span><span class="n">name</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">DEVICE_NAME_PREFIXES</span> <span class="k">if</span> <span class="n">name</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="n">p</span><span class="p">)):</span>
</span><span id="L-226"><a href="#L-226"><span class="linenos">226</span></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">name</span><span class="si">:</span><span class="s2">&gt;20</span><span class="si">}</span><span class="s2"> | </span><span class="si">{</span><span class="n">d</span><span class="o">.</span><span class="n">address</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</span><span id="L-227"><a href="#L-227"><span class="linenos">227</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="L-228"><a href="#L-228"><span class="linenos">228</span></a> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;No devices found. Try moving the ring closer to computer&quot;</span><span class="p">)</span>
</span></pre></div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,43 @@
from dataclasses import dataclass
from colmi_r02_client.pretty_print import print_lists, print_dicts, print_dataclasses
@dataclass
class FooBar:
foo: str
bar: int
def test_print_lists_simple():
lists = ["aaa", "b"], ["c", "dd"]
expected = "aaa | b\n c | dd"
actual = print_lists(lists)
assert actual == expected
def test_print_lists_header():
lists = ["aaa", "b"], ["c", "dd"]
expected = "aaa | b\n--------\n c | dd"
actual = print_lists(lists, header=True)
assert actual == expected
def test_print_dicts():
dicts = [{"a": 1, "b": 1000}, {"a": 2, "b": 3}]
expected = "a | b\n--------\n1 | 1000\n2 | 3"
actual = print_dicts(dicts)
assert actual == expected
def test_print_dataclasses():
dcs = [FooBar("a", 1), FooBar("aaaaaa", 10000)]
expected = " foo | bar\n--------------\n a | 1\naaaaaa | 10000"
actual = print_dataclasses(dcs)
assert actual == expected
# TODO add some nice juicy property tests