feat(python): add command for reading out telemetry data
What changed, and why it matters
This commit adds a new command-line tool feature that lets users read non-sensitive telemetry data (like device temperature and battery status) from a Trezor hardware wallet. It is a straightforward read-only feature addition with no apparent security implications.
No security action required. Review as a normal feature addition.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change introduces a new telemetry CLI group in trezorctl and a device.get_telemetry() helper that calls the existing TelemetryGet/Telemetry protocol messages. The CLI only prints temperature ranges and decoded battery error flags. No new device-side code, no authentication bypass, no privilege escalation, and no sensitive data exposure is visible in the diff.
Changed components
python/src/trezorlib/cli/telemetry.pypython/src/trezorlib/cli/trezorctl.pypython/src/trezorlib/device.pyInspect captured patch +68 / −0
diff --git a/python/src/trezorlib/cli/telemetry.py b/python/src/trezorlib/cli/telemetry.py
new file mode 100644
index 000000000..3228f4c46
--- /dev/null
+++ b/python/src/trezorlib/cli/telemetry.py
@@ -0,0 +1,62 @@
+# This file is part of the Trezor project.
+#
+# Copyright (C) SatoshiLabs and contributors
+#
+# This library is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the License along with this library.
+# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
+
+from __future__ import annotations
+
+import typing as t
+
+import click
+
+from .. import device
+from . import with_session
+
+if t.TYPE_CHECKING:
+ from ..transport.session import Session
+
+BATTERY_ERRORS = {
+ 0x01: "NTC disconnected",
+ 0x02: "Charging limited",
+ 0x04: "Temperature control active",
+ 0x08: "Battery disconnected",
+ 0x10: "Battery temperature jump detected",
+ 0x20: "Battery OCV jump detected",
+}
+
+
+@click.group(name="telemetry")
+def cli() -> None:
+ """Telemetry commands."""
+
+
+@cli.command()
+@with_session(seedless=True)
+def get(session: Session) -> None:
+ """Read telemetry data from the device."""
+ res = device.get_telemetry(session)
+
+ if res.min_temp_c is not None:
+ click.echo(f"Min temperature: {res.min_temp_c / 1000:.2f} °C")
+ if res.max_temp_c is not None:
+ click.echo(f"Max temperature: {res.max_temp_c / 1000:.2f} °C")
+
+ if res.battery_errors is not None:
+ if res.battery_errors == 0:
+ click.echo("Battery errors: None")
+ else:
+ click.echo("Battery errors:")
+ for bit, name in BATTERY_ERRORS.items():
+ if res.battery_errors & bit:
+ click.echo(f" - {name}")
diff --git a/python/src/trezorlib/cli/trezorctl.py b/python/src/trezorlib/cli/trezorctl.py
index 431767dca..4cf9bf584 100755
--- a/python/src/trezorlib/cli/trezorctl.py
+++ b/python/src/trezorlib/cli/trezorctl.py
@@ -51,6 +51,7 @@ from . import (
settings,
solana,
stellar,
+ telemetry,
tezos,
tron,
with_session,
@@ -436,6 +437,7 @@ cli.add_command(ripple.cli)
cli.add_command(settings.cli)
cli.add_command(solana.cli)
cli.add_command(stellar.cli)
+cli.add_command(telemetry.cli)
cli.add_command(tezos.cli)
cli.add_command(tron.cli)
diff --git a/python/src/trezorlib/device.py b/python/src/trezorlib/device.py
index 779bd30e8..ff7336614 100644
--- a/python/src/trezorlib/device.py
+++ b/python/src/trezorlib/device.py
@@ -652,3 +652,7 @@ def set_brightness(session: "Session", value: Optional[int] = None) -> str | Non
def get_serial_number(session: "Session") -> str:
ret = session.call(messages.GetSerialNumber(), expect=messages.SerialNumber)
return ret.serial_number
+
+
+def get_telemetry(session: "Session") -> messages.Telemetry:
+ return session.call(messages.TelemetryGet(), expect=messages.Telemetry)
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.