Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Documentation

on:
push:
branches:
- main
pull_request:
paths:
- mkdocs.yml
- docs/**
- requirements-dev.txt
- Taskfile.yaml
workflow_dispatch:

permissions:
contents: write

jobs:
docs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt

- name: Build documentation
run: mkdocs build --strict

- name: Deploy to GitHub Pages
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
mkdocs gh-deploy --strict --force
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ This integration follows best practices for code quality and maintainability:
- **Type Hints**: Full type annotations throughout the codebase for improved IDE support and type checking.
- **Test Coverage**: Dedicated tests for each vacuum model with full coverage.

### Documentation

For more detailed information, please visit our [MkDocs documentation site](https://damacus.github.io/robovac/).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [linkspector] reported by reviewdog 🐶
Cannot reach https://damacus.github.io/robovac/ Status: 404


### Running Tests

```bash
Expand Down
20 changes: 20 additions & 0 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,26 @@ tasks:
cmds:
- markdownlint-cli2 "**/*.md" "!vendor" "!.venv" --fix

docs-build:
desc: Build MkDocs documentation
cmds:
- uv run mkdocs build --strict

docs-serve:
desc: Serve MkDocs documentation locally
cmds:
- uv run mkdocs serve --strict --dev-addr=127.0.0.1:8000

docs-docker-build:
desc: Build MkDocs documentation in Docker
cmds:
- docker run --rm -v "$PWD":/docs -w /docs python:3.11-slim /bin/sh -c "pip install mkdocs && mkdocs build --strict"

docs-docker-serve:
desc: Serve MkDocs documentation in Docker
cmds:
- docker run --rm -v "$PWD":/docs -w /docs -p 8000:8000 python:3.11-slim /bin/sh -c "pip install mkdocs && mkdocs serve --dev-addr=0.0.0.0:8000"

ha-start:
desc: Start Home assistant, run from dev container
cmds:
Expand Down
32 changes: 31 additions & 1 deletion custom_components/robovac/robovac.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .case_insensitive_lookup import case_insensitive_lookup
from .tuyalocalapi import TuyaDevice
from .vacuums import ROBOVAC_MODELS
from .vacuums.base import RobovacCommand, RobovacModelDetails
from .vacuums.base import RobovacModelDetails, RobovacCommand

import logging

Expand Down Expand Up @@ -47,6 +47,36 @@ def __init__(self, model_code: str, *args: Any, **kwargs: Any):
)
current_model_details = ROBOVAC_MODELS[model_code]

# Determine protocol version: prefer model-defined, else default to (3, 3)
def _coerce_version(v: Any) -> tuple[int, int]:
try:
# Already a tuple[int,int]
if isinstance(v, tuple) and len(v) == 2:
major, minor = v
return (int(major), int(minor))
# Float like 3.4 or 3.5
if isinstance(v, float) or isinstance(v, int):
major = int(v)
minor = int(round((float(v) - major) * 10))
return (major, minor)
# String like "3.5"
if isinstance(v, str):
parts = v.split(".")
if len(parts) >= 2:
return (int(parts[0]), int(parts[1]))
return (int(parts[0]), 0)
except Exception:
pass
# Fallback default
return (3, 3)

# Only honor protocol_version if explicitly set on the model class.
# Using __dict__ avoids inheriting the Protocol's typed default (3.1).
model_version: Any = current_model_details.__dict__.get("protocol_version", None)
coerced_version = _coerce_version(model_version) if model_version is not None else (3, 3)
if "version" not in kwargs:
kwargs["version"] = coerced_version

super().__init__(current_model_details, *args, **kwargs)

self.model_code = model_code
Expand Down
3 changes: 1 addition & 2 deletions custom_components/robovac/vacuums/T2194.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@

class T2194(RobovacModelDetails):
homeassistant_features = (
VacuumEntityFeature.BATTERY
| VacuumEntityFeature.CLEAN_SPOT
VacuumEntityFeature.CLEAN_SPOT
| VacuumEntityFeature.FAN_SPEED
| VacuumEntityFeature.LOCATE
| VacuumEntityFeature.PAUSE
Expand Down
157 changes: 157 additions & 0 deletions docs/PROTOCOL_35_SUPPORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Protocol 3.5 Support

## Overview

The RoboVac integration now supports Tuya protocol versions 3.4 and 3.5, which use HMAC-SHA256 for message authentication instead of CRC32. This is required for newer devices like the X8 Pro SES (T2276).

## Protocol Versions

| Version | Authentication | Encoding | Notes |
|---------|--------------------------|----------|--------------------------|
| 3.1 | CRC32 (payload only) | Base64 | Legacy protocol |
| 3.2 | CRC32 (payload only) | Base64 | Same as 3.1 with type_0d |
| 3.3 | CRC32 (header + payload) | Raw | Most common |
| 3.4 | HMAC-SHA256 | Raw | Newer devices |
| 3.5 | HMAC-SHA256 | Raw | Latest protocol |

## Implementation Details

### HMAC-SHA256 (Protocol 3.4+)

For protocol versions 3.4 and above, messages use HMAC-SHA256 for authentication:

1. **Message Structure:**

```text
[Header: 16 bytes] + [Payload: variable] + [HMAC: 32 bytes] + [Suffix: 4 bytes]
```

2. **HMAC Calculation:**
- Key: Device local key (16 characters)
- Data: Header + Payload
- Algorithm: HMAC-SHA256
- Output: 32 bytes

3. **Verification:**
- Received messages are validated by computing HMAC and comparing
- Invalid HMAC results in message rejection

### CRC32 (Protocol < 3.4)

Earlier protocols use CRC32 for checksums:

1. **Protocol 3.3:**
- CRC32 calculated on: Header + Payload
- 4-byte checksum

2. **Protocol < 3.3:**
- CRC32 calculated on: Payload only
- 4-byte checksum
- Payload is base64 encoded

## Using Protocol 3.5

### In Code

The `TuyaDevice` class accepts a `version` parameter:

```python
from custom_components.robovac.tuyalocalapi import TuyaDevice

# Protocol 3.5
device = TuyaDevice(
model_details=model,
device_id="your_device_id",
host="192.168.1.100",
local_key="your_local_key",
timeout=10.0,
ping_interval=30.0,
update_entity_state=callback,
version=(3, 5) # Specify protocol version
)
```

### For Model Definitions

Models can specify their required protocol version in the model file:

```python
# In custom_components/robovac/vacuums/T2276.py
class T2276(RobovacModelDetails):
# Model uses protocol 3.5
protocol_version = (3, 5)
```

Then in `RoboVac.__init__()`:

```python
# Get protocol version from model details
protocol_version = getattr(
self.model_details,
'protocol_version',
(3, 3) # Default to 3.3
)

# Pass to TuyaDevice
TuyaDevice.__init__(
self,
model_details=self.model_details,
device_id=device_id,
host=host,
local_key=local_key,
timeout=timeout,
ping_interval=ping_interval,
update_entity_state=update_entity_state,
version=protocol_version,
port=port,
)
```

## Troubleshooting

### "HMAC verification failed"

This error indicates:

- Wrong local key
- Protocol version mismatch
- Corrupted message

**Solution:** Verify the local key and protocol version for your device.

### "Incomplete read" errors

For devices that previously had incomplete read errors (like T2276), upgrading to protocol 3.5 should resolve the issue.

**Steps:**

1. Add `protocol_version = (3, 5)` to the model file
2. Update `RoboVac.__init__()` to use the protocol version
3. Test with your device

### Determining Protocol Version

To find the correct protocol version for your device:

1. **Check device documentation** - Newer devices typically use 3.4+
2. **Try incrementally:**
- Start with 3.3 (most common)
- If incomplete reads occur, try 3.4
- If still issues, try 3.5
3. **Check logs** - Look for authentication or checksum errors

## Testing

All protocol versions are tested with the existing test suite:

```bash
task test
```

The implementation maintains backward compatibility, so existing devices using protocols 3.1-3.3 continue to work without changes.

## References

- [TinyTuya Protocol Documentation](https://github.com/jasonacox/tinytuya)
- [Tuya IoT Protocol](https://developer.tuya.com/)
- Issue #42: X8 Pro SES incomplete read errors
2 changes: 1 addition & 1 deletion docs/archive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ This directory contains historical documentation from completed improvement init

## Reference

These documents are kept for historical reference and to understand the evolution of the codebase. For current development guidance, see the main [DEVELOPMENT.md](../DEVELOPMENT.md) file in the project root.
These documents are kept for historical reference and to understand the evolution of the codebase. For current development guidance, see the main [Development Workflow](../development/index.md) section.
Loading
Loading