A modern, fully asynchronous Python library for the Mitsubishi Electric MelCloudHome platform.
Project description
pymelcloudhome
A modern, fully asynchronous Python library for the Mitsubishi Electric "MelCloudHome" platform API, with persistent session handling.
Table of Contents
- Supported Devices
- Installation
- Usage
- Automatic Session Renewal
- Error Handling
- Example Usage
- Running Tests
- Contributing
Supported Devices
| Device Type | Read | Update |
|---|---|---|
| ATA | ✅ | ❌ |
| ATW | ✅ | ✅ |
| ERV | ❌ | ❌ |
Installation
For developers working on pymelcloudhome, you'll need Poetry to manage dependencies.
-
Clone the repository:
git clone https://github.com/MHultman/pymelcloudhome.git cd pymelcloudhome
-
Install all dependencies (production and development):
poetry install
This command will create a virtual environment and install all necessary packages, including those required for testing, linting, and type checking.
If you are a user and only want to install the library as a dependency in your project, you can use pip:
pip install pymelcloudhome
Usage
The MelCloudHomeClient provides the following asynchronous methods to interact with the MelCloud Home API:
login(email: str, password: str)
Logs in to the MelCloud Home platform. This method uses a headless browser (Playwright) to handle the login process, including any JavaScript-based authentication.
await client.login("your-email@example.com", "your-password")
list_devices() -> List[Device]
Retrieves a list of all devices associated with the logged-in user. Each Device object contains details about the unit, including its type (ataunit for Air-to-Air or atwunit for Air-to-Water) and current settings.
devices = await client.list_devices()
for device in devices:
print(f"Device ID: {device.id}, Name: {device.given_display_name}, Type: {device.device_type}")
get_device_state(device_id: str) -> Optional[Dict[str, Any]]
Retrieves the current operational state of a specific device from the cached data. This method does not make a new API call. It returns a dictionary of the device's settings or None if the device is not found.
device_id = "your-device-id" # e.g., "d3c4b5a6-f7e8-9012-cbad-876543210fed"
state = await client.get_device_state(device_id)
if state:
print(f"Device state: {state}")
set_device_state(device_id: str, device_type: str, state_data: dict) -> dict
Updates the operational state of a specific device.
device_id: The ID of the device to update.device_type: The type of the device, either "ataunit" or "atwunit".state_data: A dictionary containing the settings to update and their new values.
For ATW (Air-to-Water) devices, you can send a dictionary with the following keys:
{
"power": true, // or false
"setTankWaterTemperature": 55
"forcedHotWaterMode": true, // or false
"operationModeZone1": "HeatRoomTemperature", // "HeatFlowTemperature", "HeatCurve"
"setTemperatureZone1": 22,
"setHeatFlowTemperatureZone1": 45,
"setCoolFlowTemperatureZone1": 18,
"operationModeZone2": "HeatRoomTemperature", // "HeatFlowTemperature", "HeatCurve"
"setTemperatureZone2": 21,
"setHeatFlowTemperatureZone2": 40,
"setCoolFlowTemperatureZone2": 19
}
Sending value null will leave the setting unchanged.
Here is an example of how to use this method:
device_id = "your-device-id"
device_type = "atwunit"
new_state = {"power": True, "setTemperatureZone1": 23.5}
response = await client.set_device_state(device_id, device_type, new_state)
print(f"Set device state response: {response}")
close()
Closes the underlying aiohttp client session. This method is automatically called when using the client as an asynchronous context manager (async with).
await client.close()
Caching
To minimize API calls and improve performance, the MelCloudHomeClient caches the user profile data. By default, this cache lasts for 5 minutes. You can configure this duration by passing the cache_duration_minutes parameter when creating the client.
# Use a 10-minute cache
client = MelCloudHomeClient(cache_duration_minutes=10)
This means that subsequent calls to list_devices() and get_device_state() within this timeframe will use the cached data instead of making a new API request to fetch the user context.
Automatic Session Renewal
The client is designed to be resilient to session expiry. If an API call fails with a 401 Unauthorized status, the library will automatically attempt to re-authenticate using the credentials you provided during the initial login call. If the re-login is successful, the original request will be retried automatically.
This makes the client more robust for long-running applications, as you do not need to manually handle session expiry.
Error Handling
The library uses custom exceptions to indicate specific types of failures. It is best practice to wrap your client calls in a try...except block to handle these potential errors gracefully.
There are three main exceptions you should be prepared to handle:
-
LoginError: Raised when the initial authentication with MELCloud fails. This is typically caused by incorrect credentials (email or password) or a change in the MELCloud login page. It does not contain an HTTP status code, as it originates from the browser automation process. -
ApiError: Raised for any failed API call that does not resolve after a potential re-login attempt. This can happen if the API endpoint is not found, the server returns an error, or if a re-login attempt also fails. This exception contains a.statusattribute with the HTTP status code (e.g.,404,500) and a.messageattribute with the error details from the server. -
DeviceNotFound: Raised when an operation is attempted on a device that does not exist or is not properly configured.
Example of Handling Errors
import asyncio
from pymelcloudhome import MelCloudHomeClient
from pymelcloudhome.errors import LoginError, ApiError, DeviceNotFound
async def main():
async with MelCloudHomeClient() as client:
try:
# Attempt to log in
await client.login("your-email@example.com", "your-password")
print("Login successful!")
# Perform operations
devices = await client.list_devices()
if not devices:
print("No devices found.")
return
# ... your code to interact with devices ...
except LoginError:
print("Login failed. Please check your email and password.")
except ApiError as e:
print(f"An API error occurred: Status {e.status} - {e.message}")
except DeviceNotFound:
print("The specified device could not be found.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
if __name__ == "__main__":
asyncio.run(main())
Example Usage
import asyncio
from pymelcloudhome import MelCloudHomeClient
async def main():
async with MelCloudHomeClient() as client:
await client.login("your-email@example.com", "your-password")
# List all devices
devices = await client.list_devices()
print("Discovered Devices:")
for device in devices:
print(f" - ID: {device.id}, Name: {device.given_display_name}, Type: {device.device_type}")
if devices:
# Get state of the first device
first_device_id = devices[0].id
current_state = await client.get_device_state(first_device_id)
print(f"Current state of {devices[0].given_display_name}: {current_state}")
# Example: Set power and temperature for an ATW unit
if devices[0].device_type == "atwunit":
print(f"Attempting to set state for ATW unit: {devices[0].given_display_name}")
update_data = {"power": True, "setTemperatureZone1": 22.0}
set_response = await client.set_device_state(first_device_id, "atwunit", update_data)
print(f"Set state response: {set_response}")
if __name__ == "__main__":
asyncio.run(main())
Running Tests
To run the test suite, first install the development dependencies:
poetry install
Then, run pytest:
poetry run pytest
Development Workflow
Managing Dependencies
When you modify pyproject.toml (add/remove/update dependencies), you need to update the poetry.lock file:
# Update poetry.lock file
poetry lock
# Or use the provided scripts:
# Windows:
.\scripts\update-lock.bat
# Unix/Linux/macOS:
./scripts/update-lock.sh
# Or use Make (if available):
make lock-update
Automated Checks
This project includes several automation tools to prevent common issues:
- Pre-commit hooks: Automatically run linting, formatting, and dependency checks before commits
- CI/CD validation: GitHub Actions will check that
poetry.lockis up-to-date - VSCode tasks: Use
Ctrl+Shift+P→ "Tasks: Run Task" → "Poetry: Update Lock File"
Available Make Commands
make help # Show all available commands
make install # Install dependencies
make lock-check # Check if poetry.lock is up-to-date
make lock-update # Update poetry.lock
make test # Run tests
make lint # Run linting and type checking
make format # Format code
make check # Run all checks (lock, lint, test)
make update # Update lock and run tests
Linting and Type Checking
This project uses black and ruff for linting and mypy for type checking. To run them, ensure you have installed the development dependencies:
poetry install
Then, execute the following commands:
poetry run black .
poetry run ruff .
poetry run mypy .
Contributing
Contributions are welcome! Please read the contributing guidelines before submitting a pull request.
Project details
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 pymelcloudhome-0.2.0.tar.gz.
File metadata
- Download URL: pymelcloudhome-0.2.0.tar.gz
- Upload date:
- Size: 16.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.10.18 Linux/6.11.0-1018-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d4ca6aac8e2160c80dee905cddfb300b5a6952674814ce422023b0230d5cb926
|
|
| MD5 |
5d7b7dd069a9fbf890ae6cc53a2e8970
|
|
| BLAKE2b-256 |
b17e85f28def99db8d8a4fc9ed7481a8679ba0133b89dffc4d3186b3cbb1e4a0
|
File details
Details for the file pymelcloudhome-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pymelcloudhome-0.2.0-py3-none-any.whl
- Upload date:
- Size: 17.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.10.18 Linux/6.11.0-1018-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
77a8f1b0311d124a79d06f259dda154f104aec06b93c0b6e099fe6b3df786c60
|
|
| MD5 |
8a1355a434692d4ecb7fbed614e505d4
|
|
| BLAKE2b-256 |
b4e247cc8bc0888b37a9f5816e336dd09fa7733b04ceab34284ec603ccd23625
|