Skip to main content

Mysa Client

Unofficial and unaffiliated with Mysa. Use at your own risk.

mysa-client is an asynchronous Python library for the reverse-engineered Mysa cloud API, thermostat HomeKit interface, and optional legacy MQTT client. It exposes these protocols independently; standalone callers must explicitly create an MQTT client and request live reporting. The package also provides reusable Mysa device semantics and opt-in workflows for state reconciliation, command validation and confirmation, routing, telemetry freshness, schedules, holds, and account cleanup. These helpers do not start polling, connect transports, or choose an application's persistence and lifecycle policy.

Powers Mysa Local for Home Assistant. For Home Assistant / HACS installation, setup, and thermostat entities, use that integration. This repository owns shared protocol communication, Mysa-specific device semantics and workflows, opt-in runtime helpers, API documentation, and standalone Python examples. The integration owns Home Assistant lifecycle, entities, durable storage adapters, polling cadence, and presentation.

The API is based on behavior observed in the Mysa apps and, where noted, on Baseboard Lite hardware. It is not a vendor API contract. The only hardware validation recorded so far is on two Baseboard Lite BB-V2-0-L thermostats running firmware 3.17.5.13. Other model behavior is app/code-derived or simulated and should be treated as experimental until checked on matching hardware. See the cloud protocol guide and HomeKit protocol guide for limits and evidence.

API support and goals

60% of known Mysa API operations fully implemented (66/110)

60% of known Mysa API operations fully implemented (66/110).

Cloud & account APIs: 54/88 (61.4%); Local & provisioning APIs: 12/22 (54.5%).

The API inventory tracks known operations and bounded operation families. Only fully implemented rows count; partial support earns no credit. This measures API breadth, not hardware validation or unit-test coverage.

Testing goal: 100% unit-test coverage of client business logic, including edge cases and failure paths.

Installation

Python 3.11 or newer is required. Install the cloud client from PyPI:

python -m pip install mysa-client

That installs the cloud API and its aiohttp dependency. HomeKit support is an optional extra:

python -m pip install 'mysa-client[homekit]'

Direct MQTT support is also an optional extra:

python -m pip install 'mysa-client[mqtt]'

MQTT remains opt-in in the library: standalone callers explicitly create the client and choose the device IDs to subscribe to in its devices mapping. That mapping is the per-device allowlist; the library does not manage user settings. Mysa Local for Home Assistant provides global and per-thermostat switches, both enabled by default, and passes only enabled account devices to the client. The integration uses MQTT for read-only telemetry when cloud access and both switches are enabled. Standalone use never opens a connection automatically; see the MQTT reference for protocol details.

To run the examples or develop the library, clone this repository and install from its checkout:

git clone https://github.com/SokolskyNikita/mysa-client.git
cd mysa-client
python -m pip install -e '.[homekit,mqtt]' --group test --group lint --group build

Import from mysa_client.cloud, mysa_client.homekit, or mysa_client.mqtt. Importing the package root does not load HomeKit or MQTT's optional transport dependencies.

Cloud example

The cloud example signs in with SRP, saves the refresh token through a caller-owned callback, discovers devices, and reads state. It sends a setpoint command only when MYSA_SET_CELSIUS is explicitly set in the environment. Never put an account password or token in source control. The example creates its token file with owner-only permissions.

export MYSA_EMAIL='account@example.com'
export MYSA_PASSWORD='your-password'
export MYSA_REFRESH_TOKEN_FILE="$HOME/.config/mysa-client/refresh-token"
python examples/cloud_basic.py

To request a heating target, explicitly set a safe value for your device and run the example again:

MYSA_SET_CELSIUS=20.5 python examples/cloud_basic.py

The command's successful HTTP response means the API accepted the request. It does not prove that the thermostat applied it. Read reported state separately and use an application-specific confirmation policy.

Device semantics and optional runtime example

The runtime example uses synthetic, in-memory state to show DeviceView, semantic command construction, validation, and reported-state confirmation. It makes no network requests and needs no credentials:

python examples/runtime_basic.py

mysa_client.runtime contains optional composition helpers. Importing it does not import HomeKit or MQTT transports, connect to a device, or start a task. Callers explicitly construct each protocol client and pass the transports, policy choices, callbacks, clocks, and persistence they want to use. See the runtime guide for ownership and composition details.

MQTT example

The MQTT example authenticates through the existing cloud client, opens an explicitly requested MQTT session, and prints decoded device events. It can request live status and run an MQTT echo check without changing thermostat settings. A setpoint command is sent only when both MYSA_DEVICE_ID and MYSA_SET_CELSIUS are explicitly set; the result distinguishes broker acceptance from a matching device acknowledgement. MQTT command support is experimental and has only been validated on Baseboard Lite hardware. The Home Assistant integration uses the client for read-only telemetry when account access, cloud use, and its global and per-thermostat Live MQTT readings options are enabled. See the MQTT reference for evidence and limits.

Run the read-only example after setting the same authentication variables used by the cloud example:

python examples/mqtt_basic.py

To explicitly request a target, name the device and Celsius value:

MYSA_DEVICE_ID='your-device-id' MYSA_SET_CELSIUS=20.5 python examples/mqtt_basic.py

HomeKit example

The HomeKit example discovers nearby accessories, can complete PIN pairing and persist the returned credentials, and can load those credentials for reads, events, and an explicitly requested target write. It creates and closes its own asynchronous Zeroconf instance and stops the protocol controller and device session on exit. Pairing credentials are secret key material; keep the JSON file private and make a protected backup.

List discovered accessories:

python examples/homekit_basic.py --discover

Pair using the accessory ID shown by discovery and the code printed on the thermostat's faceplate:

python examples/homekit_basic.py --pair-id 'AA:BB:CC:DD:EE:FF' --pin 123-45-678

Load the saved pairing, observe events, and read semantic values:

python examples/homekit_basic.py --pairing-file "$HOME/.config/mysa-client/pairing.json"

HomeKit write acceptance also is not physical confirmation. The example reads back the target after a requested write, but the caller remains responsible for freshness and application policy.

Ownership and error handling

Cloud MysaAuth and MysaClient share a caller-owned aiohttp.ClientSession; close it with an async with block. The cloud client uses a 20-second request timeout and refreshes/retries once after a 401. It does not automatically retry an ambiguous command after a timeout, connection loss, cancellation, 429, or server error. MysaRateLimitError.retry_after carries the server's backoff hint when available. Authentication, connection, rate-limit, not-found, and API errors derive from MysaError.

HomeKitProtocol receives an externally managed asynchronous Zeroconf instance. It creates missing HomeKit discovery listeners and reuses existing shared browsers. Start and stop the protocol within that instance's lifetime, close each loaded HomeKitDevice, and then close Zeroconf. Reads have a default three-second deadline; controller discovery/pairing and accessory metadata operations have bounded internal timeouts. Writes have no fixed caller deadline and are not replayed automatically. HomeKit errors derive from HomeKitError, including typed read and rejected-write errors. Pairing completion awaits the caller's credential-save callback before fetching accessory details; if saving fails, the library attempts bounded key removal. That cleanup is best effort if the accessory is unreachable.

MysaMqttClient owns its Paho connection and reconnect loop inside an async with block and performs bounded cleanup on exit. Its event queue is bounded and has one async-iterator consumer. The client does not poll or issue commands by itself: callers explicitly request live reporting, echo checks, or Lite setpoint/mode commands. A CommandResult reports broker acceptance and device confirmation separately; a matching device acknowledgement still does not prove physical heater operation.

The client provides reusable helpers for capability validation, independent observation reconciliation, pending-command tracking, device-state selection, and optional command routing. The application still chooses when to poll and read back, which source and freshness policy to use, how long to retain commands, and how to persist workflow journals and credentials. HomeKit state is a cached view, not a freshness guarantee. Cloud reported state can lag behind a successful response. A matching report is evidence of device state, but does not prove physical operation.

Public API

The public cloud surface is exported from mysa_client.cloud: MysaAuth, Tokens, MysaClient, response models, model and command enums, typed errors, CloudCommand, state_command, settings_command, reconcile, PendingCommand, PendingCommandTracker, and the documented command helpers. MysaClient.execute_command() validates and sends one explicit semantic command using caller-supplied device context; it does not fetch capabilities or read state automatically. HomeKit's public semantic API is exported from mysa_client.homekit: HomeKitProtocol, HomeKitDevice, PairingSession, Field, mode/action and event models, discovery records, and typed errors. The optional MQTT API is exported from mysa_client.mqtt: MysaMqttClient, MqttMessage, MqttTelemetry, DeviceCommandState, echo/publish/command result types, message kinds, and typed errors.

Reusable cloud-domain helpers are available from their documented modules: cloud.reconciliation for per-field state selection and pending command tracking; cloud.commands, .device_commands, and .validation for semantic commands and capability checks; cloud.device for model/device interpretation; and cloud.schedule_workflow, .holds, and .account_workflow for opt-in Mysa workflows. runtime.state.DeviceView, runtime.routing.CommandRouter, and runtime.telemetry compose caller-owned state sources and transports. Import these modules explicitly. None starts a connection or background task.

The Home Assistant consumer also uses supported helpers from mysa_client.cloud.commands, .const, .observations, .trace, and .validation. Those submodule helpers are documented in the cloud API surface. They are part of the maintained consumer API even when they are not re-exported at mysa_client.cloud. Other underscored names and implementation details are private.

See the documentation index for cloud and HomeKit APIs, the optional runtime, Bluetooth/SoftAP, MQTT, firmware/connectivity, Matter research, raw API coverage, and diagnostic tools. Runnable scripts and sanitized protocol exchanges live in examples. See the changelog for releases.

Development and release

The project is licensed under MIT; see LICENSE. Protocol behavior and test fixtures are maintained in this repository. Automated tests and documentation checks use simulated data and do not contact Mysa or local thermostats. Hardware validation must be performed separately with explicit operator intent and reversible commands.

Release order, tag requirements, and PyPI trusted-publisher setup are documented in releasing.

Metadata

Release files for mysa-client 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mysa-client 0.2.1
File Size Uploaded
mysa_client-0.2.1.tar.gz 242.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mysa-client 0.2.1
File Interpreter ABI Platform
mysa_client-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 362.3 kB

Release files / mysa_client-0.2.1.tar.gz

Download URL mysa_client-0.2.1.tar.gz
Size 242.1 kB
Tags Source
SHA-256 checksum
How to use checksums
8d852ef122150aacd1242f687e7c62e5191c62fb0a74a1cee67ef87e025ddb03
BLAKE2b-256 checksum
How to use checksums
4b185b40b2a9e864b834fb01f5a0b143c96947b06f7e8b22a35c84fb2230d694
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.14.8

Release files / mysa_client-0.2.1-py3-none-any.whl

Download URL mysa_client-0.2.1-py3-none-any.whl
Size 120.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a7fcf741c334e56894691f8d5e79d2093e8c9d3f0364fc962ed1fe879e6fbf11
BLAKE2b-256 checksum
How to use checksums
33057e4282a0c3954639210cf6c38cae6c0267657c11efa6ee505b4dd5e9ceb9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.14.8

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page