Metadata-Version: 2.4
Name: pycmcontrol-mqtt
Version: 0.2.0
Summary: Cliente MQTT para Driver CmControl v1.00 (MQTT + MQTT+REST + OAuth2) com QoS=0 e retained=false
Project-URL: Repository, https://github.com/marcostulliosouza/pycmcontrol-mqtt
Author-email: Marcos Tullio Silva de Souza <marcostullio.s@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Marcos Tullio
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: paho-mqtt>=1.6
Provides-Extra: env
Requires-Dist: python-dotenv>=1.0; extra == 'env'
Description-Content-Type: text/markdown

# pycmcontrol-mqtt

Biblioteca Python para integração com o **Driver Dispositivo CmControl v1.00** via MQTT, implementando o protocolo oficial do sistema.

Permite que aplicações Python atuem como um dispositivo CmControl totalmente compatível, suportando comunicação MQTT nativa, proxy MQTT+REST e autenticação OAuth2.

---

## Recursos

* Comunicação MQTT conforme especificação oficial do driver
* Subscrição automática em `.../get/#`
* Publicação com QoS = 0 e retained = false
* Handlers automáticos obrigatórios:

  * PING → PONG
  * STATE → status online
* Suporte completo ao proxy MQTT+REST
* Autenticação OAuth2 (Basic → Bearer JWT)
* Execução de endpoints REST via MQTT
* Apontamentos (`setup.apontamento`)
* Envio de seriais e evidências
* Tratamento robusto de erros de rede e negócio
* Cliente context manager (`with`)
* Debug detalhado opcional
* Tipagem estática (PEP 561)
* Compatível com TLS

---

## Instalação

```bash
pip install pycmcontrol-mqtt
```

---

## Uso rápido

```python
from pycmcontrol_mqtt import CmControlClient, CmControlConfig

cfg = CmControlConfig(
    device_addr="device001",
    broker_host="cmcontrol.example.com",
    broker_port=1883,
    mqtt_user="usuario",
    mqtt_pass="senha",
    api_user="api_user",
    api_pass="api_pass",
)

with CmControlClient(cfg, debug=True) as cmc:
    cmc.ensure_login()
```

---

## Autenticação OAuth2 (MQTT+REST)

O cliente executa automaticamente:

1. Login BASIC
2. Recebimento de token JWT
3. Uso de Bearer Token nas chamadas REST

```python
with CmControlClient(cfg) as cmc:
    cmc.ensure_login()
```

Logout opcional:

```python
cmc.logout_oauth2()
```

---

## Eventos obrigatórios do driver

Quando conectado, o cliente responde automaticamente:

| Evento recebido | Resposta enviada           |
| --------------- | -------------------------- |
| `/get/ping`     | `/set/pong` com timestamp  |
| `/get/state`    | `/set/state {"state":"1"}` |

Também envia `state=1` ao conectar.

---

## O que você pode fazer com CmControlClient

### Ciclo de vida

Criação do cliente (sem conectar):

```python
cmc = CmControlClient(cfg, debug=True)
```

Opções importantes:

* `debug=True` → log detalhado de trocas MQTT
* `request_timeout_s_default` → timeout padrão
* `strict_business_errors` → transforma erros de negócio em exceção

---

### Conexão

* `connect()` → conecta e envia `state=1`
* `disconnect()` → envia `state=0` e desconecta

Uso recomendado com context manager:

```python
with CmControlClient(cfg) as cmc:
    ...
```

---

### Comunicação MQTT direta

* `publish_set(endpoint, payload)`
* `request(endpoint, payload, timeout_s=None)`
* `ping(timeout_s=None)`

Implementa o padrão RPC do driver:

```
SET → GET correspondente
```

---


### OAuth2

* `login_oauth2()`
* `ensure_login()`
* `logout_oauth2()`
* `token()`
* `is_token_valid()`

---

### Apontamento

* `setup_apontamento(setup)`
* `apontar_serial(serial, evidencias=None)`
* `validar_rota(serial)`
* `apontar_lote_1porreq(seriais)`

---

### Debug e diagnóstico

```python
print(cmc.last_exchange())
```

Retorna a última troca MQTT completa.

---

## Apontamento simples

```python
with CmControlClient(cfg) as cmc:
    cmc.ensure_login()
    resp = cmc.apontar_serial("00000203030300")
    print(resp)
```

Payload equivalente:

```json
{
  "enderecoDispositivo": "device001",
  "apontamentos": [
    {
      "ok": true,
      "seriais": [
        { "codigo": "00000203030300" }
      ]
    }
  ]
}
```

---

## Apontamento com evidência

### Evidência a partir de texto

```python
from pycmcontrol_mqtt import Evidence

evi = Evidence.from_text(
    nome="log_teste",
    extensao="txt",
    texto="Conteúdo da evidência",
    descricao="Log de teste"
)

cmc.apontar_serial("00000203030300", evidencias=[evi])
```

### Evidência a partir de arquivo

```python
evi = Evidence.from_file("foto.png")

cmc.apontar_serial("00000203030300", evidencias=[evi])
```

---

## Validação de rota

```python
resp = cmc.validar_rota("00000203030300")
```

---

## Apontamento em lote

Um serial por requisição:

```python
seriais = ["001", "002", "003"]

cmc.apontar_lote_1porreq(seriais)
```

---

## Debug detalhado

Ative logs de comunicação:

```python
with CmControlClient(cfg, debug=True) as cmc:
    cmc.ensure_login()
```

Exemplo:

```
[pycmcontrol] -> SET .../set/rest/oauth2/login
[pycmcontrol] <- GET .../get/rest/oauth2/login status=200 log=OK
```

---

## Tratamento de erros

Exceções específicas:

```python
from pycmcontrol_mqtt.errors import (
    CmcConnectionError,
    CmcLoginError,
    CmcApontamentoError,
    CmcTimeout,
)

try:
    with CmControlClient(cfg) as cmc:
        cmc.ensure_login()
        cmc.apontar_serial("00000203030300")

except CmcConnectionError as e:
    print("Falha de conexão:", e)

except CmcLoginError as e:
    print("Falha de login:", e)

except CmcApontamentoError as e:
    print("Erro de negócio:", e.status, e.log)

except CmcTimeout:
    print("Timeout aguardando resposta")
```

---

## Inspeção da última troca MQTT

```python
print(cmc.last_exchange())
```

Retorno:

```bash
{
  "last_request": {...},
  "last_response": {...},
  "disconnect_rc": None
}
```

---

## TLS (opcional)

Para brokers seguros (porta 8883):

```python
from pycmcontrol_mqtt import BrokerTLS

tls = BrokerTLS(
    ca_certs="ca.pem",
    certfile="client.crt",
    keyfile="client.key",
)

with CmControlClient(cfg, tls=tls) as cmc:
    cmc.ensure_login()
```

---

## Estrutura do pacote

```bash
pycmcontrol_mqtt/
 ├── client.py
 ├── config.py
 ├── models.py
 ├── errors.py
 └── utils.py
```

---

## Requisitos

* Python ≥ 3.9
* Broker MQTT compatível com CmControl
* Dispositivo previamente cadastrado no sistema

---

## Licença

Distribuído sob licença MIT. Acesse [LICENSE](LICENSE) para mais informações.

---

## Autor

**Marcos Tullio Silva de Souza**
