Reorganize repository structure into logical folders

Structure:
- src/ - Python implementation (cobs_protocol.py, onecontrol_client.py)
- docs/ - All documentation markdown files
- scripts/ - Extraction scripts (for reference only)

Changes:
- Moved Python files to src/
- Moved all .md docs to docs/
- Moved extraction scripts to scripts/
- Updated README.md with new structure
- Updated import paths in README examples
- Added placeholder for future Quartz documentation URL

Benefits:
- Cleaner repository organization
- Easier to navigate
- Separates code from documentation
- Follows standard project conventions
This commit is contained in:
wes
2025-12-29 09:33:20 -05:00
parent c62fbf1bd4
commit 718a13c02f
11 changed files with 29 additions and 19 deletions
+261
View File
@@ -0,0 +1,261 @@
# Home Assistant Integration Plan for Lippert OneControl
## Overview
This document outlines the plan to create a Home Assistant integration for Lippert OneControl RV systems via Bluetooth.
## Integration Architecture
### Option 1: ESPHome Bluetooth Proxy (Recommended)
**Advantages:**
- No need to reverse engineer full protocol if we can relay commands
- Use ESP32 as Bluetooth<->WiFi bridge
- Native Home Assistant integration
- Reliable and well-supported
**Components:**
- ESP32 device with Bluetooth
- ESPHome firmware
- Home Assistant ESPHome integration
**Implementation:**
1. Configure ESP32 as Bluetooth proxy
2. Discover OneControl device
3. Create custom component for command sending
### Option 2: Python-Based Custom Integration
**Advantages:**
- Direct control from Home Assistant host
- Can run on Home Assistant server (if it has Bluetooth)
- Full protocol implementation
**Components:**
- Python library using `bleak` for BLE communication
- Home Assistant custom component (HACS)
- Configuration via YAML or UI
**Implementation:**
```python
# Key libraries needed
- bleak (Python BLE library)
- homeassistant.components (HA integration)
```
## Step-by-Step Implementation
### Phase 1: Protocol Discovery (Current Phase)
- [ ] Complete .NET assembly decompilation
- [ ] Capture Bluetooth packets using HCI snoop
- [ ] Document command structure
- [ ] Identify all GATT characteristics and UUIDs
### Phase 2: Python Library Development
Create a Python library `pylippert_onecontrol`:
```python
# pylippert_onecontrol/client.py
from bleak import BleakClient
import struct
from .cobs import encode_packet # Implement COBS + CRC8
# Confirmed UUIDs from Decompiled Code
SERVICE_UUID = "00000030-0200-A58E-E411-AFE28044E62C"
CHAR_READ_UUID = "00000034-0200-A58E-E411-AFE28044E62C"
CHAR_WRITE_UUID = "00000033-0200-A58E-E411-AFE28044E62C"
class OneControlClient:
def __init__(self, address):
self.address = address
self.client = None
self._seq = 0
async def connect(self):
self.client = BleakClient(self.address)
await self.client.connect()
def _next_seq(self):
self._seq = (self._seq + 1) & 0xFFFF
return self._seq
async def send_command(self, cmd_type, table_id, payload):
# 1. Build Packet
# [Seq (2)] [CmdType (1)] [TableID (1)] [Payload...]
seq = self._next_seq()
packet = struct.pack("<HB", seq, cmd_type) + bytes([table_id]) + payload
# 2. Append CRC8 (Init=0x55)
crc = calculate_crc8(packet, init=0x55)
packet += bytes([crc])
# 3. COBS Encode
encoded = cobs_encode(packet)
# 4. Write
await self.client.write_gatt_char(CHAR_WRITE_UUID, encoded)
async def turn_on_light(self, light_id):
# ActionSwitch (0x40), Table 1, On (1)
# Payload: [State=1] [DeviceID]
await self.send_command(0x40, 1, bytes([1, light_id]))
async def turn_off_light(self, light_id):
await self.send_command(0x40, 1, bytes([0, light_id]))
```
### Phase 3: Home Assistant Integration
#### Directory Structure:
```
custom_components/lippert_onecontrol/
├── __init__.py # Integration setup
├── manifest.json # Integration metadata
├── config_flow.py # Configuration UI
├── const.py # Constants
├── light.py # Light entities
├── switch.py # Switch entities (pumps, etc.)
├── sensor.py # Sensor entities (tanks)
├── cover.py # Cover entities (awnings, slides)
└── climate.py # Climate entities (heating)
```
#### Integration Code Skeleton:
```python
# custom_components/lippert_onecontrol/__init__.py
async def async_setup_entry(hass, entry):
"""Set up Lippert OneControl from a config entry."""
device = OneControlDevice(entry.data["address"])
await device.connect()
hass.data[DOMAIN] = device
# Forward setup to platforms
await hass.config_entries.async_forward_entry_setups(
entry, ["light", "switch", "cover", "sensor", "climate"]
)
return True
```
### Phase 4: Device Entities
#### Example: Light Control
```python
# custom_components/lippert_onecontrol/light.py
from homeassistant.components.light import LightEntity
class OneControlLight(LightEntity):
def __init__(self, device, light_id, name):
self._device = device
self._light_id = light_id
self._name = name
self._state = False
@property
def name(self):
return self._name
@property
def is_on(self):
return self._state
async def async_turn_on(self):
await self._device.control_light(self._light_id, True)
self._state = True
async def async_turn_off(self):
await self._device.control_light(self._light_id, False)
self._state = False
```
#### Example: Awning Control (Cover)
```python
# custom_components/lippert_onecontrol/cover.py
from homeassistant.components.cover import CoverEntity, CoverDeviceClass
class OneControlAwning(CoverEntity):
_attr_device_class = CoverDeviceClass.AWNING
async def async_open_cover(self):
await self._device.control_awning(self._awning_id, "extend")
async def async_close_cover(self):
await self._device.control_awning(self._awning_id, "retract")
```
## Next Steps
### Immediate Actions Needed:
1. **Bluetooth Packet Capture**
```bash
# On Android device with app
adb shell settings put secure bluetooth_hci_log 1
# Use the Lippert Connect app to control devices
adb pull /data/misc/bluetooth/logs/btsnoop_hci.log
# Analyze with Wireshark
```
2. **Extract .NET Assemblies**
- Need to properly extract DLLs from the Xamarin blob
- Decompile with dnSpy or ILSpy
- Document complete command structure
3. **Test BLE Connection**
```python
# Quick test script
import asyncio
from bleak import BleakScanner
async def scan():
devices = await BleakScanner.discover()
for d in devices:
print(f"{d.name}: {d.address}")
if "OneControl" in str(d.name) or "Lippert" in str(d.name):
print(f"Found potential device: {d}")
asyncio.run(scan())
```
4. **Manual BLE Exploration**
- Use nRF Connect app to explore OneControl device
- List all services and characteristics
- Try writing test values to understand command format
## Alternative: Existing Solutions
Before building from scratch, check:
1. **Lippert API**: Contact Lippert for official API/SDK
2. **Existing Projects**: Search GitHub for "OneControl", "Lippert", "MyRV"
3. **RV Forums**: Check iRV2, Forest River forums for existing integration work
## Resources
### Python Libraries
- `bleak` - Cross-platform BLE library
- `homeassistant` - HA development
### Tools
- **nRF Connect** - BLE explorer (Android/iOS)
- **Wireshark** - Packet analysis
- **dnSpy** / **ILSpy** - .NET decompiler
### Documentation
- [Home Assistant Integration Development](https://developers.home-assistant.io/)
- [ESPHome Bluetooth Proxy](https://esphome.io/components/bluetooth_proxy.html)
- [Bleak Documentation](https://bleak.readthedocs.io/)
## Timeline Estimate
- **Protocol Discovery**: 1-2 days
- **Python Library**: 2-3 days
- **HA Integration**: 3-5 days
- **Testing & Refinement**: 2-3 days
- **Total**: ~1-2 weeks
## Success Criteria
- [ ] Can discover OneControl device via BLE
- [ ] Can connect to device
- [ ] Can send commands (lights, pumps, awnings, etc.)
- [ ] Can read state/status from device
- [ ] Integration works in Home Assistant
- [ ] All RV systems controllable from HA
- [ ] Reliable operation over Bluetooth range