KRoperUK/uw-py
GitHub: KRoperUK/uw-py
用于 Utility Warehouse 客户门户 API 的异步 Python 客户端,封装认证与 GraphQL 查询以获取能源账单和账户数据。
Stars: 0 | Forks: 0
# uw-api
用于 Utility Warehouse 客户门户 API 的异步 Python 客户端。
Endpoint 是硬编码的(从 `myaccount.uw.co.uk/` 发现)并且不需要
配置——只需提供凭证。
## 安装说明
```
pip install uw-api
```
## 用法
```
import asyncio
from uw_api import UWClient
async def main():
async with UWClient(email="user@example.com", password="secret") as client:
await client.login()
account = await client.gql.get_account()
print(f"Account: {account.account_number}")
bills = await client.gql.get_bills()
for bill in bills:
print(f"Bill {bill.bill_id}: £{bill.total_amount_gbp}")
consumption = await client.gql.get_consumption()
print(f"Electricity: {consumption.electricity_kwh} kWh")
print(f"Gas: {consumption.gas_kwh} kWh")
meters = await client.gql.get_meters()
for meter in meters:
print(f"{meter.meter_type}: {meter.meter_number} (smart={meter.is_smart})")
tariff = await client.gql.get_tariff()
if tariff:
print(f"Tariff: {tariff.tariff_name}")
asyncio.run(main())
```
## API 参考
### 认证
```
client = UWClient(email="...", password="...")
await client.login()
```
通过 `account.uw.co.uk/v2/login` 的 OAuth2 PKCE 进行身份验证。Session cookie 会
自动管理。该库会在收到 401 响应时自动重新进行身份验证。
### 账户
```
account = await client.gql.get_account()
```
返回包含 `account_id` 和 `account_number` 的 `UWAccount`。
### 能源
```
consumption = await client.gql.get_consumption()
services = await client.gql.get_energy_services()
usage = await client.gql.get_energy_usage()
```
- `get_consumption()` → `EnergyConsumption`(最新的用电量/用气量 kWh)
- `get_energy_services()` → 能源服务 dict 的原始列表
- `get_energy_usage()` → 包含各表读数的 `EnergyUsage` 列表
### 仪表
```
meters = await client.gql.get_meters()
readings = await client.gql.get_meter_readings()
```
- `get_meters()` → `Meter` 列表(类型、序列号、智能状态、最后读数日期)
- `get_meter_readings()` → `MeterReading` 列表(数值、类型、日期、来源)
### 账单
```
bills = await client.gql.get_bills()
pdf_url = await client.gql.get_pdf_url(month=1, year=2026)
```
- `get_bills()` → `Bill` 列表(ID、日期、金额、状态、PDF URL)
- `get_pdf_url(month, year)` → 账单 PDF 的字符串 URL
### 财务
```
balance = await client.gql.get_balance()
services = await client.gql.get_live_services()
tariff = await client.gql.get_tariff()
```
- `get_balance()` → `{"due": float, "overdue": float}`
- `get_live_services()` → 服务状态的 dict
- `get_tariff()` → `EnergyTariff`(名称、代码、费率)
## 硬编码 Endpoint
| 用途 | URL |
|---------|-----|
| 登录页面 | `https://account.uw.co.uk/v2/login` |
| GraphQL API | `https://myaccount.uw.co.uk/server/graphql` |
11 个 GraphQL 操作被嵌入在 `uw_api/graphql/queries.py` 中。
## 发现脚本(可选)
包含一个基于 HAR 的发现脚本,用于验证或重新发现 endpoint:
```
python scripts/discover_api.py parse-har capture.har
```
这在正常使用中**不是必需的**——该库自带了 2026 年 7 月从 `myaccount.uw.co.uk/` 发现的
硬编码 endpoint。
## 架构
```
UWClient → UWAuth (OAuth2 PKCE)
→ UWGraphQL → /server/graphql (POST)
→ Pydantic v2 models
```
- **认证**:从登录页面 HTML 中提取 CSRF token,使用
Castle.io 设备 token 进行表单编码的 POST 请求
- **GraphQL**:所有数据均通过 `POST /server/graphql` 以面向操作的查询获取
- **重试**:收到 429/5xx 时进行 3 次指数退避重试,收到 401 时重新认证
- **模型**:`UWAccount`、`EnergyUsage`、`EnergyConsumption`、`EnergyTariff`、
`Meter`、`MeterReading`、`Bill`、`BillPDFMetadata`
标签:API客户端, OAuth2, Python, 异步编程, 无后门, 智能家居, 能源管理, 计算机取证, 逆向工具