aio-panasonic-comfort-cloud
aio-panasonic-comfort-cloud: Asynchronous Python library for Panasonic Comfort Cloud API
This library provides asynchronous access to the Panasonic Comfort Cloud API, enabling developers to interact with Panasonic air conditioning units.
Installation
pip install aio-panasonic-comfort-cloud
Quick Start
Basic Usage
import asyncio
import aiohttp
from aio_panasonic_comfort_cloud import ApiClient
async def main():
async with aiohttp.ClientSession() as session:
client = ApiClient("your_email@example.com", "your_password", session)
# Start the session (authenticate and fetch devices)
await client.start_session()
# Get list of devices
devices = client.get_devices()
for device_info in devices:
print(f"Device: {device_info.name}")
# Get full device status
device = await client.get_device(device_info)
params = device.parameters
print(f" Power: {params.power.name}")
print(f" Mode: {params.mode.name}")
print(f" Fan Speed: {params.fan_speed.name}")
print(f" Target Temp: {params.target_temperature}°C")
print(f" Inside Temp: {params.inside_temperature}°C")
# Clean up the session
await client.stop_session()
asyncio.run(main())
Controlling a Device
Use ChangeRequestBuilder for a fluent API to build and apply changes:
from aio_panasonic_comfort_cloud import ApiClient, ChangeRequestBuilder, constants
# ... (start session as above)
device = await client.get_device(devices[0])
builder = ChangeRequestBuilder(device)
builder.set_power_mode(constants.Power.On)
builder.set_hvac_mode(constants.OperationMode.Cool)
builder.set_target_temperature(24)
builder.set_fan_speed(constants.FanSpeed.Auto)
if builder.has_changes:
await client.set_device_raw(device, builder.build())
Available Enums
| Category | Values |
|---|---|
| Power | Off, On |
| OperationMode | Auto, Dry, Cool, Heat, Fan |
| FanSpeed | Auto, Low, LowMid, Mid, HighMid, High |
| EcoMode | Auto, Powerful, Quiet |
| AirSwingUD | Auto, Up, UpMid, Mid, DownMid, Down, Swing |
| AirSwingLR | Auto, Left, LeftMid, Mid, RightMid, Right, Unavailable |
| NanoeMode | Unavailable, Off, On, ModeG, All |
ChangeRequestBuilder Methods
set_power_mode(value)— Set power on/offset_hvac_mode(value)— Set operation mode (cool, heat, etc.)set_target_temperature(value)— Set target temperature in °Cset_fan_speed(value)— Set fan speedset_eco_mode(value)— Set eco modeset_horizontal_swing(value)— Set horizontal air swingset_vertical_swing(value)— Set vertical air swingset_nanoe_mode(value)— Set Nanoe modeset_eco_navi_mode(value)— Set EcoNavi modeset_eco_function_mode(value)— Set EcoFunction mode
Getting Energy History
from datetime import date
from aio_panasonic_comfort_cloud import constants
today = date.today().strftime("%Y%m%d")
history = await client.history(device_info.id, constants.DataMode.Day, today)
Aquarea (Air to Water heat pump) Support
Aquarea units show up in the same account/group listing as air conditioners,
but expose a different status shape (hot water tank + heating/cooling zones
instead of a single parameters object), so they're kept separate from
get_devices():
devices = client.get_devices() # air conditioners
aquarea_devices = client.aquarea_devices # Aquarea heat pumps
for device_info in aquarea_devices:
device = await client.get_aquarea_device(device_info)
params = device.parameters
print(f"{device_info.name}: {params.operation_status.name} / {params.operation_mode.name}")
if params.has_tank:
print(f" Tank: {params.tank.temperature}°C -> {params.tank.heat_set}°C")
for zone in params.zones:
print(f" Zone {zone.id} ({zone.name}): {zone.temperature}°C -> {zone.heat_set}°C")
# Refresh status in place
await client.try_update_aquarea_device(device)
Controlling a unit:
from aio_panasonic_comfort_cloud import constants
await client.set_aquarea_operation_status(device_info, constants.AquareaOperationStatus.On)
await client.set_aquarea_operation_mode(device_info, constants.AquareaUpdateOperationMode.Heat)
await client.set_aquarea_tank_temperature(device_info, 55)
await client.set_aquarea_tank_operation_status(device_info, constants.AquareaOperationStatus.On)
await client.set_aquarea_zone_temperature(device_info, zone_id=1, temperature=22, mode="heat")
await client.set_aquarea_quiet_mode(device_info, constants.AquareaQuietMode.Level1)
await client.set_aquarea_force_dhw(device_info, constants.AquareaForceDHW.On)
Eco/Comfort "special status" applies a per-zone temperature offset on top of
the current setpoint rather than being a simple flag, so setting it needs
the full AquareaDevice (not just its PanasonicDeviceInfo) to know the
current setpoints/status to offset from:
device = await client.get_aquarea_device(device_info)
await client.set_aquarea_special_status(device, constants.AquareaSpecialStatus.Eco)
# ... or constants.AquareaSpecialStatus.Comfort, or None to turn it off
Energy consumption/cost history (heat/cool/tank breakdown) uses a separate
endpoint from air conditioners, with its own AquareaDataMode (Day/Month/Year
— no "Week", and different values from the AC-only DataMode):
from datetime import date
today = date.today().strftime("%Y%m%d")
consumption = await client.async_get_aquarea_consumption(
device_info, constants.AquareaDataMode.Day, today
)
for entry in consumption:
print(f"{entry.data_time}: heat={entry.heat_consumption}kWh cool={entry.cool_consumption}kWh "
f"tank={entry.tank_consumption}kWh total={entry.total_consumption}kWh")
set_aquarea_special_status is unverified/best-effort like the HWS control
methods above — see its docstring for why.
HWS (Standalone Heat Pump Hot Water Tank) Support
Some accounts have a standalone hot water heat pump (e.g. an HE-UM40CR),
distinct from an Aquarea combi unit — it has no heating/cooling zones, just
a tank. These report deviceType: "11" and, confusingly, do have a
parameters object like an air conditioner, but with tank-specific fields
(tankTemperature, hpuOperationStatus, operationMode, boostMode)
instead — and the usual deviceStatus/deviceHistoryData calls reject them
with a 403. They're kept separate from get_devices()/aquarea_devices:
hws_devices = client.hws_devices
for device_info in hws_devices:
device = client.get_hws_device(device_info) # no network call — built
# from the group listing
params = device.parameters
print(f"{device_info.name}: {params.tank_temperature}°C, boost={params.boost_mode.name}")
# Refresh (re-fetches /device/group, there's no per-device status call)
await client.try_update_hws_device(device)
Reading status this way is confirmed working against a real device. Control
(set_hws_tank_temperature, set_hws_boost_mode, set_hws_operation_status,
set_hws_operation_mode) targets /device/a2wInfoUpdate, reported from a
Comfort Cloud app capture but not yet verified against a live account —
please open an issue if it doesn't work as-is.
Terms / Privacy Policy Agreements
Panasonic occasionally updates its Terms of Use, Privacy Policy or Cookie
Policy; when that happens, API calls start failing with error code 4103
until the account re-accepts them. You can fetch and handle this yourself:
# Fetch the current documents (set include_content=True to get the full text)
documents = await client.get_agreement_documents(include_content=True)
for doc in documents:
print(doc["type"], doc["version"], doc.get("content", "")[:80])
# See what's already been accepted on this account
accepted = await client.get_agreement_status()
# Auto-accept anything outdated/missing (Terms, Privacy, Cookie Policy —
# the Turkey-only Service Agreement is intentionally excluded, matching
# the official app's behavior of only surfacing it to a subset of accounts)
await client.ensure_all_agreements_accepted()
This isn't called automatically on login — auto-accepting legal agreements
is a decision your application should make deliberately, not something the
library does silently. A typical pattern is to catch
AgreementNotAcceptedError from start_session()/_get_groups() and call
ensure_all_agreements_accepted() (or show the fetched document text to the
user first) in response.
2FA / MFA Support
If your account has two-factor authentication enabled, start_session()
raises MFARequiredError instead of logging in. Catch it, prompt the user
for the OTP code from their authenticator app, and retry with it:
from aio_panasonic_comfort_cloud.exceptions import MFARequiredError
try:
await client.start_session()
except MFARequiredError:
otp_code = input("Enter the 2FA code: ")
await client.start_session(otp_code=otp_code)
Alternative: Browser-Based Authentication
start_session() drives Panasonic's login page itself — it POSTs your
credentials and scrapes the resulting HTML/redirects, which has to correctly
handle whatever Auth0 renders for every connection type (password, MFA,
social login, ...). As an alternative that sidesteps all of that, you can let
a real browser (a WebView, the system browser, etc.) handle the login instead
and just hand the result back to the library:
# 1. Build the URL and open it in any browser
auth_url, code_verifier = client.get_browser_authorization_url()
print(f"Open this URL and log in: {auth_url}")
# 2. After login, the browser is redirected to a URL starting with
# "panasonic-iot-cfc://...callback?code=...". Capture that redirect
# (however your application observes it — a WebView navigation listener,
# a custom URI scheme handler, pasting it in, etc.) and finish the login:
redirect_url = input("Paste the redirect URL here: ")
await client.complete_browser_authentication(redirect_url, code_verifier)
# From here on, the client behaves exactly as if start_session() had been
# called — get_devices(), get_device(), etc. all work normally.
devices = client.get_devices()
This is entirely separate from start_session()/authenticate() — it
doesn't change how the default username/password flow behaves, it's just
another way to obtain the same tokens. Because Auth0's own hosted page
handles the actual login, this path naturally supports MFA, social login,
etc. without any special-casing in the library.
Full Example
See example.py for a complete working example.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aio_panasonic_comfort_cloud-2026.8.2.tar.gz.
File metadata
- Download URL: aio_panasonic_comfort_cloud-2026.8.2.tar.gz
- Upload date:
- Size: 49.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b31d0dbc4fea799436f48472e2f1075b9ae7f29e07723b472e03cbda8c4a456e
|
|
| MD5 |
999d0aac0f425ec4b70f8d7c40174e86
|
|
| BLAKE2b-256 |
4e25769e2ef5af0d2efc84d8e392791f62c4a1f1a8fe29cb32c7ff61a7117bbd
|
Provenance
The following attestation bundles were made for aio_panasonic_comfort_cloud-2026.8.2.tar.gz:
Publisher:
python-publish.yml on sockless-coding/aio-panasonic-comfort-cloud
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aio_panasonic_comfort_cloud-2026.8.2.tar.gz -
Subject digest:
b31d0dbc4fea799436f48472e2f1075b9ae7f29e07723b472e03cbda8c4a456e - Sigstore transparency entry: 2477738139
- Sigstore integration time:
-
Permalink:
sockless-coding/aio-panasonic-comfort-cloud@e31c32a593ed50ace6088402f17a02e2e7dc3b2e -
Branch / Tag:
refs/tags/2026.8.2 - Owner: https://github.com/sockless-coding
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@e31c32a593ed50ace6088402f17a02e2e7dc3b2e -
Trigger Event:
release
-
Statement type:
File details
Details for the file aio_panasonic_comfort_cloud-2026.8.2-py3-none-any.whl.
File metadata
- Download URL: aio_panasonic_comfort_cloud-2026.8.2-py3-none-any.whl
- Upload date:
- Size: 48.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
50be0a1aee1ffae7a1848274bd30836fcfc8b4376d6ef70a429bf4880e0e3360
|
|
| MD5 |
0b9f7f0993e44455851129c070148a02
|
|
| BLAKE2b-256 |
f16e801678e31fbe1019661910e3202f418c3a3691203b7a27b0f610428194ef
|
Provenance
The following attestation bundles were made for aio_panasonic_comfort_cloud-2026.8.2-py3-none-any.whl:
Publisher:
python-publish.yml on sockless-coding/aio-panasonic-comfort-cloud
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aio_panasonic_comfort_cloud-2026.8.2-py3-none-any.whl -
Subject digest:
50be0a1aee1ffae7a1848274bd30836fcfc8b4376d6ef70a429bf4880e0e3360 - Sigstore transparency entry: 2477738165
- Sigstore integration time:
-
Permalink:
sockless-coding/aio-panasonic-comfort-cloud@e31c32a593ed50ace6088402f17a02e2e7dc3b2e -
Branch / Tag:
refs/tags/2026.8.2 - Owner: https://github.com/sockless-coding
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@e31c32a593ed50ace6088402f17a02e2e7dc3b2e -
Trigger Event:
release
-
Statement type: