Skip to content

feat(T2276): Add Eufy T2276 (X8 Pro SES) model support#341

Merged
damacus merged 11 commits intodamacus:mainfrom
stevendejongnl:eufy-t2276-support
Feb 17, 2026
Merged

feat(T2276): Add Eufy T2276 (X8 Pro SES) model support#341
damacus merged 11 commits intodamacus:mainfrom
stevendejongnl:eufy-t2276-support

Conversation

@stevendejongnl
Copy link
Contributor

@stevendejongnl stevendejongnl commented Feb 13, 2026

Summary

Adds full support for the Eufy T2276 (X8 Pro SES) including native protocol 3.5 session key negotiation and physical command execution. The previous config used protobuf-encoded values on DPS 152–173 which caused "Incomplete read" errors (#42). The actual device uses human-readable DPS values on codes 1–135 (same structure as T2128).

All commands tested live on T2276 hardware: start clean, return home, locate beep, pause, room clean.

Changes

T2276.py (model definition)

  • Corrected DPS mappings: human-readable values on codes 2, 5, 15, 101–110, 118
  • DPS 101 (RETURN_HOME) and DPS 103 (LOCATE) are boolean triggers — send true to activate
  • DPS 5 (MODE) uses lowercase "auto" (confirmed via protocol capture, unlike T2128's "Auto")
  • Fan speed DPS 102: "pure" maps to "Quiet" (device value)

vacuum.py

  • async_return_to_base: now includes DPS 2 (START_PAUSE) as execution trigger for models with boolean start/pause, matching the async_start pattern

tuyalocalapi.py

  • Native protocol 3.5 session key negotiation (3-step SESS_KEY_NEG handshake, AES-GCM)
  • v3.5 command codes: CONTROL_NEW (0x0d) for SET with {"protocol": 5, "t": …, "data": {"dps": {…}}} payload
  • v3.5 version header: b"3.5" + 12 zero bytes prepended before GCM encryption
  • Gratuitous update parsing: finds first { to handle variable-length binary prefix (retcode + version header)
  • v3.5 DPS state extraction from nested {"protocol": 4, "data": {"dps": {…}}} format
  • async_get for v3.4+: connect-only (device pushes state via gratuitous updates 0x08)
  • Added SET_COMMAND (0x07) and UPDATEDPS (0x12) to gratuitous update handlers
  • Reconnect cooldown: 5s (device idles out at ~30s)
  • Disabled heartbeats for v3.5 (device closes TCP on ping)
  • Connection hardening: backoff cap, failure counter reset on successful handshake

DPS Reference (T2276)

DPS Name Type Values
2 Start/Pause bool true=start, false=pause
5 Mode string auto, Edge, SmallRoom, Nosweep, room
15 Status string Running, Locating, Recharge, Charging, standby, Paused, completed
101 Return Home bool true triggers return to dock
102 Fan Speed string Quiet, Standard, Turbo, Boost
103 Locate bool true triggers beep
104 Battery int percentage
106 Error int error code
109 Clean Time int minutes
110 Clean Area int
118 Boost IQ bool on/off
122 Clean Mode string Continue, Pause, Nosweep
137 Unknown int observed values: 31, 3013
142 Events base64 start_clean, clean_result, reloc, key events

Test plan

  • All 326 existing tests pass
  • Start clean ({5: "auto", 2: true}) — confirmed physically working
  • Return home ({101: true, 2: true}) — confirmed physically working
  • Locate beep ({103: true}) — confirmed physically working
  • Pause ({2: false}) — confirmed working
  • Room clean ({124: base64, 2: true}) — confirmed working (earlier session)
  • Gratuitous DPS updates received and parsed correctly
  • v3.5 session key negotiation stable across reconnects

- Add T2276.py vacuum definition for Freddy
Copilot AI review requested due to automatic review settings February 13, 2026 11:59
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds/updates the model definition for Eufy Clean X8 Pro SES (T2276) to use Tuya protocol 3.5 and standard (human-readable) DPS codes, replacing the prior protobuf/base64-style DPS mapping referenced in Issue #42.

Changes:

  • Set protocol_version = 3.5 for T2276.
  • Replace DPS codes (152–173) with standard Tuya DPS codes (1–135 range, e.g., 2/5/15/101/102…).
  • Add support for additional reported datapoints/features (cleaning time/area, DND, BoostIQ).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

stevendejongnl and others added 9 commits February 13, 2026 13:11
- Add DPS 2 activation after DPS 124 room selection in roomClean handler.
  The vacuum ACKs the selectRoomsClean payload on DPS 124 but requires
  DPS 2 = true to actually start navigating and cleaning.
- Accept both "roomClean" and "room_clean" command names
- Accept both "roomIds" and "room_ids" parameter names
- Add RoboVacEntityFeature.ROOM to T2276 features
- Add comment explaining T2276 uses lowercase "auto" (confirmed via
  protocol 3.5 packet capture, unlike T2128's "Auto")
- Rename fan speed key "quiet" to "pure" for UI consistency — the
  display logic maps device value "Quiet" to "Pure"
- Rewrite test_t2276_command_mappings.py to match new protocol 3.5
  DPS codes, replacing old protobuf-encoded assertions
Implements the 3-step SESS_KEY_NEG handshake required by protocol 3.5
devices (SESS_KEY_NEG_START → SESS_KEY_NEG_RESP → SESS_KEY_NEG_FINISH)
directly in TuyaDevice, enabling the T2276 to connect without relying
on an external library.

Also adds protocol 3.4/3.5 message framing (AES-GCM, GCM tag, magic
prefix/suffix 0x6699/0x9966) and TuyaCipher.set_session_key support.

Tested against a live T2276 (Eufy X8 Pro SES) device.
The vacuum needs to ACK DPS 124 (room selection) before receiving
DPS 2 (start). Without the delay both commands arrive almost
simultaneously and the vacuum ignores the start command.
Two changes:
- Reset failure counter after successful session key negotiation so a
  subsequent clean disconnect (EOF) doesn't compound with prior failures
- Cap maximum backoff at 30s instead of 600s so HA reconnects quickly
  even after many consecutive failures (e.g. when the EufyHome app holds
  the device connection)
The asyncio.sleep(1) added in 45067a3 requires the asyncio import.
Use CONTROL_NEW (0x0d) for SET and DP_QUERY_NEW (0x10) for GET on
protocol 3.4+ devices, matching TinyTuya's implementation. Prepend
the v3.5 version header (b"3.5" + 12 zero bytes) to payloads for
commands not in the NO_PROTOCOL_HEADER_CMDS exemption set.

Additional v3.5 reliability improvements:
- Reset cipher to local key before session negotiation so stale
  session keys don't corrupt the handshake
- Enforce 30s cooldown between connection attempts to prevent
  rapid reconnect storms after EOF
- Disable heartbeats for v3.5 (device closes connection on ping)
- Skip pong timeout check for v3.5 (no pings sent)
- Auto-detect 4-byte retcode prefix in v3.5 response decryption
- Reset backoff flag after sleep so next cycle can reconnect
- Add _dps_to_request() helper for device22-style status queries
- Use v3.5 SET payload format: {"protocol":5, "t":…, "data":{"dps":…}}
Key fixes:
- T2276 RETURN_HOME (DPS 101) now sends boolean true instead of string
  "return" — device requires boolean type for physical action triggers
- T2276 LOCATE (DPS 103) values mapping added for consistency
- async_return_to_base includes DPS 2 (START_PAUSE) trigger for models
  with boolean start/pause, matching async_start pattern
- Gratuitous update parsing: find first '{' instead of fixed 4-byte
  offset — handles retcode(4) + version_header(15) prefix correctly
- v3.5 DPS state extraction from nested {"protocol":4,"data":{"dps":{}}}
- async_get for v3.4+: connect-only (device pushes state via 0x08),
  no explicit GET/UPDATEDPS which cause "json obj data unvalid"
- Reconnect cooldown reduced to 5s (was 30s, matching device idle timeout)
- Added SET_COMMAND and UPDATEDPS to gratuitous update handlers

All changes tested live on Eufy X8 Pro SES (T2276) via protocol 3.5:
start clean, return home, locate beep all confirmed working physically.
@damacus
Copy link
Owner

damacus commented Feb 15, 2026

👍 thanks.

Have you tried this on your vacuum? All the reviewing in the world is useless here.
The best thing is a real vacuum.

Resolves mypy no-untyped-def error in tuyalocalapi.py:1265.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@stevendejongnl
Copy link
Contributor Author

👍 thanks.

Have you tried this on your vacuum? All the reviewing in the world is useless here. The best thing is a real vacuum.

Yes, the whole weekend was dedicated to finally getting this vacuum working. With plenty of trial and error, we finally got it fully functional.
Do you need more information?

@damacus damacus changed the title Add Eufy T2276 (X8 Pro SES) model support feat(T2276): Add Eufy T2276 (X8 Pro SES) model support Feb 17, 2026
@damacus
Copy link
Owner

damacus commented Feb 17, 2026

@stevendejongnl no more info required, thanks. You are the most incentivised to get your vacuum working ;)

I really just need to check it for dodgy code at this point 😆

These DPS code are absolutely bonkers

@codecov
Copy link

codecov bot commented Feb 17, 2026

Codecov Report

❌ Patch coverage is 18.02326% with 141 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.04%. Comparing base (09ef40e) to head (bc2e1f0).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
custom_components/robovac/tuyalocalapi.py 15.52% 136 Missing ⚠️
custom_components/robovac/vacuum.py 50.00% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #341      +/-   ##
==========================================
- Coverage   73.25%   69.04%   -4.22%     
==========================================
  Files          56       56              
  Lines        1866     2016     +150     
==========================================
+ Hits         1367     1392      +25     
- Misses        499      624     +125     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@damacus damacus merged commit eaa7040 into damacus:main Feb 17, 2026
7 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants