Metadata-Version: 2.4
Name: PyCfeMx
Version: 0.1.0
Summary: Cliente Python para el portal de CFE (Comisión Federal de Electricidad) México
Project-URL: Homepage, https://github.com/oamilkar/PyCfeMx
Project-URL: Documentation, https://github.com/oamilkar/PyCfeMx#readme
Project-URL: Repository, https://github.com/oamilkar/PyCfeMx.git
Project-URL: Issues, https://github.com/oamilkar/PyCfeMx/issues
Author: OAmilkar
License-Expression: MIT
License-File: LICENSE
Keywords: cfe,electricity,energy,home-assistant,mexico,utility
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Home Automation
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: aiohttp>=3.8.0
Requires-Dist: beautifulsoup4>=4.11.0
Requires-Dist: certifi>=2023.0.0
Provides-Extra: dev
Requires-Dist: mypy>=1.0.0; extra == 'dev'
Requires-Dist: pytest-aiohttp>=1.0.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Requires-Dist: types-beautifulsoup4>=4.11.0; extra == 'dev'
Description-Content-Type: text/markdown

# PyCfeMx

Cliente Python para el portal de CFE (Comisión Federal de Electricidad) México.

Permite consultar información de servicios de electricidad desde el portal "Mi Espacio" de CFE.

## Instalación

```bash
pip install pycfemx
```

## Uso

### Async

```python
import asyncio
from pycfemx import CFEClient

async def main():
    async with CFEClient() as client:
        await client.login("tu_usuario", "tu_password")

        # Obtener información de un servicio específico
        info = await client.get_info()
        print(f"Monto: {info.amount_due}")

asyncio.run(main())
```

### Sync

```python
from pycfemx import CFESyncClient

with CFESyncClient() as client:
    client.login("tu_usuario", "tu_password")

    info = client.get_info()
    print(f"Monto: {info.amount_due}")
```

### Múltiples servicios

Un usuario de CFE puede tener varios servicios (domicilios) asociados a su cuenta:

```python
import asyncio
from pycfemx import CFEClient

async def main():
    async with CFEClient() as client:
        await client.login("tu_usuario", "tu_password")

        # Listar todos los servicios
        services = await client.get_services()

        # Obtener información de cada servicio
        for service in services:
            info = await client.get_info(service.service_number)
            print(f"\n{service.alias}:")
            print(f"  Monto: {info.amount_due}")
            print(f"  Vence: {info.due_date}")
            print(f"  Estado: {info.payment_status}")

asyncio.run(main())
```

### Historial de recibos

```python
import asyncio
from pycfemx import CFEClient

async def main():
    async with CFEClient() as client:
        await client.login("tu_usuario", "tu_password")

        info = await client.get_info()

        print("Últimos recibos:")
        for receipt in info.receipts:
            pdf = "PDF" if receipt.pdf_available else ""
            xml = "XML" if receipt.xml_available else ""
            print(f"  {receipt.period}: {pdf} {xml}")

asyncio.run(main())
```

## API

### CFEClient (async) / CFESyncClient (sync)

Ambos clientes exponen los mismos métodos. `CFEClient` es async, `CFESyncClient` es su equivalente síncrono.

| Método | Descripción |
|--------|-------------|
| `login(username, password)` | Inicia sesión en el portal de CFE |
| `get_services()` | Devuelve la lista de servicios disponibles |
| `get_info(service_number=None)` | Devuelve información del servicio especificado (o el actual) |
| `close()` | Cierra la sesión |

### Modelos

#### Service

| Atributo | Tipo | Descripción |
|----------|------|-------------|
| `service_number` | `str` | Número de servicio (12 dígitos) |
| `alias` | `str` | Nombre corto del servicio |
| `display_name` | `str` | Nombre completo (alias - número) |

#### ServiceInfo

| Atributo | Tipo | Descripción |
|----------|------|-------------|
| `service_number` | `str` | Número de servicio |
| `owner_name` | `str` | Nombre del titular |
| `address` | `str` | Dirección del servicio |
| `amount_due` | `str` | Monto a pagar (ej: "$65") |
| `consumption_period_text` | `str` | Período de consumo (ej: "10 DIC 25 al 09 FEB 26") |
| `due_date_text` | `str` | Fecha límite de pago (ej: "26 FEB 26") |
| `payment_status` | `str` | Estado: VIGENTE, PAGADO o VENCIDO |
| `receipts` | `list[Receipt]` | Historial de recibos |
| `user_type` | `str \| None` | Tipo de usuario (ej: "CFECONTIGO") |
| `due_date` | `date \| None` | Fecha límite de pago parseada |
| `consumption_start` | `date \| None` | Inicio del período de consumo |
| `consumption_end` | `date \| None` | Fin del período de consumo |

#### Receipt

| Atributo | Tipo | Descripción |
|----------|------|-------------|
| `period` | `str` | Período del recibo (ej: "FEB 2026") |
| `pdf_available` | `bool` | Si el PDF está disponible |
| `xml_available` | `bool` | Si el XML (CFDI) está disponible |

### Excepciones

| Excepción | Descripción |
|-----------|-------------|
| `CFEError` | Excepción base |
| `CFEAuthError` | Error de autenticación |
| `CFEConnectionError` | Error de conexión |
| `CFESessionExpiredError` | Sesión expirada |
| `CFEServiceNotFoundError` | Servicio no encontrado |

## Requisitos

- Python 3.10+
- aiohttp
- beautifulsoup4

## Licencia

MIT
