Commit Graph
14 Commits
Author SHA1 Message Date
wesandClaude Fable 5 840cfaf5fc canbus: solve IDS-CAN command-auth cipher; add reference implementations
The CAN write gate (page-42/43 challenge/response) is a 32-round TEA/XTEA-family
Feistel keyed by a per-session 32-bit key; REMOTE_CONTROL = 0xB16B00B5. Verified
51/51 against captured challenge/response pairs across nodes 2A/61/75/F8 (one
global key, not per-node), so the CAN path can now actuate, not just sense.

- ids_can_auth.py         Python reference + self-test (51/51)
- esphome/ids_can_auth.h  C++ port for the ESP32 node (host-tested 8/8)
- sniff/analyze_auth.py   structural analysis (rules out affine; confirms keyed cipher)
- sniff/auth-pairs-multinode-2026-06-11.txt   +9 pairs across 4 nodes
- README                  document the cipher, session keys, unlock sequence

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 00:22:09 -04:00
wesandClaude Fable 5 85455e8631 canbus: add DSI-fault capture plan to open items
Close propane valve, force a water-heater lockout, capture + diff against
healthy baseline. Prime suspects: node 95 b1 (always FF) or node AE page-3
(always 00). Whichever flips becomes the DSI binary_sensor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 23:26:29 -04:00
wesandClaude Fable 5 b97401fec8 canbus: reverse-engineer OneControl IDS-CAN bus (read fully mapped, write auth-gated)
Tapped the X180T's CAN bus via CANable 2.0 at the monitor panel's terminator
port. The bus is NOT RV-C — it's Lippert's proprietary IDS-CAN (250k, 11-bit
IDs, (page<<8)|node, 1 Hz broadcasts).

Read side fully mapped from live captures:
- device classes (page-2 type byte: 0x0A tank, 0x1E switched load, 0x21 motor)
- node map for this rig (Catalina 263BHSCK): tanks 27/E2/7D/FE, lights 2A/F8,
  heater 95, pump 61, awning 75 (+ direction & live motor current)
- battery voltage on 29-bit extended frames

Write side: commands are DLC-0 ext frames 0006<node><op>, but auth-gated by a
rolling challenge-response (page 42/43). Replay confirmed dead (spoofed cansend
did not actuate). Not the BLE TEA cypher. response=f(challenge) is deterministic
(no session state) so crackable offline later — seeded 42 pairs in
sniff/2A-auth-pairs.txt.

Includes raw captures (sniff/*.log, force-added past *.log ignore), a read-only
esp32_can ESPHome skeleton, and the log-can.sh sniff helper. Full writeup in
canbus/README.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 23:20:49 -04:00
wesandClaude Opus 4.8 34155fd7f9 Add HA custom integration; fix bleak 3.x write-without-response regression
The OneControl panel's command characteristic is a streaming (Write Without
Response) endpoint. Bleak 3.x changed write_gatt_char to default to
write-with-response when the char advertises the "write" property, so every
command (incl. switch turn_on/off) got rejected by the panel with ATT 0x0E
(Unlikely Error), surfaced as BleakGATTProtocolError. Force response=False on
the command write (matching the auth key write) to restore control.

Also commits the productionized custom_components integration (config flow,
coordinator, switch/sensor/cover entities, key-seed TEA auth, COBS codec) and
the matching src/ RE client/COBS fixes (big-endian framing, table-driven CRC8,
status-event decoding) that were developed but never tracked.

Verified live on the campsite HAOS Pi: switch.exterior_lights / interior_lights
toggle the physical panel with no GATT error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 06:41:14 -04:00
wesandClaude Sonnet 4.6 b6d498c829 Implement key-seed auth handshake (service 0010)
Root cause of immediate disconnect after write: panel requires auth on
service 0010 before accepting commands on 0030. Protocol found by
decompiling Plugin.BLE.dll (BleDeviceUnlockManager.PerformKeySeedExchange).

Auth flow:
1. Read 4-byte seed from char 0012 (00000012-0200-a58e-e411-afe28044e62c)
2. Apply modified TEA with RV-specific cypher (612643285 / 0x248431D5)
3. Write 4-byte little-endian result to char 0013
4. Retries up to 3x if seed < 4 bytes (panel not yet ready)

connect() now calls perform_auth() before enabling 0034 notifications.
Also cleans up experimental auth attempts from campsite debugging session.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 19:56:36 -04:00
wesandClaude Sonnet 4.6 72f415e051 Add scratch.py (gitignored) for interactive device testing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 16:10:00 -04:00
wesandClaude Sonnet 4.6 5138d8a37e Fix bleak 3.x compatibility and code review cleanup
- Fix scan_for_onecontrol() to use return_adv=True and adv.service_uuids
  (device.metadata removed in bleak 3.x)
- Add missing _parse_get_devices_response() — was called but never defined,
  would crash on first real device response
- main() now auto-connects when exactly one device is found via scan
- Remove premature turn_on/off_light(5) calls from main() — device IDs
  unknown until get_devices() has been run against real hardware
- Guard send_command() and disconnect() against unconnected state
- control_awning() now takes MovementState enum instead of raw int
- Bump post-get_devices sleep from 2s to 5s for real device latency

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 16:04:20 -04:00
wes 275f08658f Feat: Implement correct response parsing and GetDevices decoder 2025-12-29 09:59:28 -05:00
wes eda93dc7fe Fix: Add trailing frame byte to COBS encoder 2025-12-29 09:55:46 -05:00
wes 1ce475f7dc Clean up documentation for public release
Changes:
- Rewrote PROTOCOL_FINDINGS.md to be clean protocol spec
  - Removed all DLL/assembly/class name references
  - Removed outdated "Next Steps" sections
  - Focused purely on protocol documentation
  - Added clear packet examples and command reference

- Removed outdated historical docs:
  - SUMMARY.md (investigation notes, now obsolete)
  - ANALYSIS_GUIDE.md (pre-completion guide, no longer needed)

- Created .claude.md for internal context
  - Contains all decompilation details
  - Lists specific DLL names and source locations
  - Preserves context for AI assistants
  - Added to .gitignore (not committed to repo)

Result:
- Public repo now has clean, legal documentation
- Internal context preserved for development
- Reduced legal surface area
- Docs focus on protocol, not implementation source

Remaining docs (all clean):
- PROTOCOL_FINDINGS.md - Protocol specification
- IMPLEMENTATION_GUIDE.md - Python implementation guide
- HOME_ASSISTANT_INTEGRATION.md - HA integration plan
- MISSION_ACCOMPLISHED.md - Project summary
2025-12-29 09:45:06 -05:00
wes 718a13c02f 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
2025-12-29 09:33:20 -05:00
wes c62fbf1bd4 Remove reference to decompiled source code from README
The decompiled code is not included in the repository (excluded via .gitignore).
Mentioning it in the README could create legal concerns and is misleading.
2025-12-29 09:29:10 -05:00
wes da2387e29c Add Apache 2.0 license and strengthen legal compliance
- Added Apache License 2.0 (full text)
- Strengthened README disclaimer with interoperability language
- Added references to DMCA 1201(f) and EU Software Directive Article 6
- Clarified what IS and IS NOT included in repo
- Added license badge to README
- Explicitly states purpose: legally purchased hardware integration

Compliance checklist:
 Clean room implementation (no decompiled code in repo)
 .gitignore excludes all binaries and extracted code
 Interoperability defense clearly stated
 Apache 2.0 license with patent grant clause
 Disclaimer for Lippert Components Inc.
2025-12-29 09:12:11 -05:00
wes 7dd4f55a0c Initial commit: Lippert OneControl protocol reverse engineering
 Protocol fully reversed from decompiled Xamarin app
 All 431 .NET assemblies extracted and decompiled
 COBS encoder/decoder implemented in Python
 CRC8 checksum implementation
 Complete BLE client for OneControl devices
 Comprehensive documentation

Files included:
- cobs_protocol.py: COBS encoding/decoding + CRC8
- onecontrol_client.py: Full BLE client implementation
- Complete protocol documentation
- Home Assistant integration guide
- ESPHome Bluetooth Proxy setup
- Extraction scripts for reference

Ready for testing with RV hardware (April 2025)
2025-12-29 08:50:16 -05:00