Skip to content

controls: per-door unlatch (VCSEC_requests 0x1F9) + forward door status - #89

Merged
wpmed92 merged 9 commits into
softwiredtech:mainfrom
ehoeve786:door-unlatch
Nov 5, 2026
Merged

wpmed92 merged 9 commits into
softwiredtech:mainfrom
ehoeve786:door-unlatch

Conversation

@ehoeve786

@ehoeve786 ehoeve786 commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Adds VC_CMD_DOOR_UNLATCH (0x50; value 0–3 = front left / front right / rear left / rear right), the CAN equivalent of the Tesla app's Unlatch Door, multi-finger actions 10–13 for the four doors, and forwards per-door/trunk latch state (VCLEFT_doorStatus 0x102, VCRIGHT_doorStatus 0x103) and powered-trunk state/position (VCLEFT_liftgateStatus 0x142) to the app. Single commit, no new files.

Derived from 12 app-triggered unlatches captured on the car (3 per door): each is VCSEC_requests 0x1F9 with that door's ClosureRequest = 3 (OPEN) and RequestReason = 1 (RKE) held ~800 ms; the latch flips CLOSED→OPENED ~100 ms after the first frame.

Door Frame
FL 60 00 10 00 00 00 00 00
FR 00 03 80 00 00 00 00 00
RL 00 18 00 04 00 00 00 00
RR 00 C0 00 20 00 00 00 00

Injection: RMW on the live 0x1F9 frame, phase-locked to the car. can_manager calls vehicle_control_on_frame(); while an unlatch is active each of VCSEC's own 0x1F9 frames gives a semaphore and ours is sent immediately after (its NONE is overwritten within ~1 ms), with a 20 ms fill between. Tested on a 2023 Model Y as the most consistent variant; a plain 20 ms burst also worked but less reliably.

Gate: refused only in R/N/D. A parked car whose drive system has gone to standby (PRND gone from the screen) stops reporting P; a "must be P" gate blocked exactly that case during testing.

DBC: VCSEC_requests was a 1-byte stub; replaced by the 8-byte definition + VAL tables from dzid26/ESP32-DualCAN (CERN-OHL-W) and marked decode. Bus-1 HW filters 21 → 25. dbc_generated.{c,h} regenerated with tools/gen_dbc.py (output matches) and the host DBC test (tools/test/test_dbc.c) passes.

Pairs with softwiredtech/dashpilot#272, which adds the four controls on Android and iOS and decodes the forwarded door/trunk/liftgate state into CarState for dashboards.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CiTeuLpxE64AAygE8U6A5F

…tatus

VC_CMD_DOOR_UNLATCH (0x50, value 0-3 = FL/FR/RL/RR), the CAN equivalent of
the Tesla app's Unlatch Door. Captured from 12 app-triggered unlatches on a
2023 Model Y: each is VCSEC_requests with that door's ClosureRequest = OPEN
and RequestReason = RKE, held ~800 ms, and the door's latch flips
CLOSED->OPENED ~100 ms after the first frame.

Injection is phase-locked to the car: can_manager calls a small RX hook, and
while an unlatch is in progress each of VCSEC's own 0x1F9 frames releases a
semaphore so ours is sent right after it (its all-zero NONE is overwritten
within ~1 ms), with a 20 ms fill in between. Refused only while in R/N/D: a
parked car whose drive system has gone to standby no longer reports P, and
that is the main case this is for. Multi-finger actions 10-13 map to the
four doors.

VCLEFT_doorStatus (0x102) and VCRIGHT_doorStatus (0x103) are now forwarded
to the app so it can show per-door and trunk latch state.

VCSEC_requests in bus_1_tesla_vehicle.dbc was a 1-byte stub; replaced with
the 8-byte definition (+ VAL tables) from dzid26/ESP32-DualCAN (CERN-OHL-W)
and marked decode so its signals are generated. Bus-1 HW filters 21 -> 25.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiTeuM9buJMg6fPxajubfe
@ehoeve786 ehoeve786 changed the title controls: per-door unlatch via VCSEC_requests (0x1F9); forward door s… controls: per-door unlatch (VCSEC_requests 0x1F9) + forward door status Nov 3, 2026
- Refuse unlatch above 0.5 kph as well as in R/N/D (DI_speed now decoded).
- Build the 0x1F9 frame from scratch instead of the live bytes so other
  VCSEC requests are never replayed.
- Credit dzid26/ESP32-DualCAN in the DBC; sender VEH like the rest.
- Comments: 800 ms hold, drop fork PR reference.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiTeuNGK1Ev4AkBBNFW1CT
ehoeve786 added a commit to ehoeve786/dashpilot that referenced this pull request Nov 3, 2026
The firmware (softwiredtech/dashkit-firmware#89) refuses the unlatch in
R/N/D or above 0.5 kph, not "outside Park": a parked car in drive-system
standby no longer reports P. The first commit of this PR pairs with that
upstream PR, not with fork PR #9 as its message says.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiTeuNGK1Ev4AkBBNFW1CT
ehoeve786 and others added 4 commits November 3, 2026 16:34
Restore the can_frame_live path that was tested on the car; the zero-frame
variant from the previous commit is untested. Speed gate stays.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiTeuNGK1Ev4AkBBNFW1CT
Speed-gated live-frame build tested on the car (2023 Model Y, all four
doors). Build from scratch now so other VCSEC requests present on the live
frame are never replayed for the 800 ms hold.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiTeuNGK1Ev4AkBBNFW1CT
Reinstates 14cfc22 after on-car testing: all four doors unlatch with the
frame built from scratch, so other VCSEC requests on the live frame are
never replayed during the 800 ms hold.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiTeuNGK1Ev4AkBBNFW1CT
@wpmed92

wpmed92 commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

@ehoeve786 nice work, one safety thing:

The R/N/D + speed gate in door_unlatch() allows the unlatch when it can't read the car's state. The DI_speed can_get result isn't checked, so kph stays 0 when no frame has been cached, and gear() returns -1 on failure, which passes the R/N/D check. Before any bus-0 frame has arrived (just after boot), nothing blocks it. Could we refuse when either read fails, like sport_kickdown.c does?

ehoeve786 and others added 2 commits November 4, 2026 21:12
Review feedback: an unread DI_speed defaulted to 0 and an unread DI_gear
(-1) passed the R/N/D check, so right after boot, before any DI frame,
nothing blocked the unlatch. Both reads must now succeed, as in
sport_kickdown.c. A parked car whose drive system has gone to standby still
works: the value cache keeps the last P frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiTeuL5dzb3mcxzhffpXu8
… asleep

With no DI_systemStatus/DI_speed frame since boot (DashKit restarted while
the car sits in Accessory and the drive inverter is in standby), allow the
unlatch only if both EPB calipers report PARK; otherwise refuse. With DI
data the R/N/D + speed gate is unchanged. Adds EPBL/EPBR_internalStatus
(0x288/0x228) to the bus-1 decode set (filters 25 -> 27 of 32).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiTeuL5dzb3mcxzhffpXu8
@ehoeve786

Copy link
Copy Markdown
Contributor Author

Fixed in 29e2797 and 43ba49d: door_unlatch() now fails closed. With DI data it keeps the R/N/D + speed gate, and both reads must succeed. With no DI frame since boot (DashKit restarted while the drive inverter is in standby), it unlatches only if both EPB calipers report PARK (EPBL/EPBR_internalStatus, added to the bus-1 decode set, 27/32 filters).

@wpmed92
wpmed92 merged commit 4964a97 into softwiredtech:main Nov 5, 2026
2 checks passed
ehoeve786 added a commit to ehoeve786/dashpilot that referenced this pull request Nov 8, 2026
Four momentary controls on Android and iOS: Unlatch Driver / Passenger /
Rear Left / Rear Right Door. Each sends CMD_DOOR_UNLATCH (0x50) with the
door index 0-3; gesture values 10-13 let them be bound to multi-finger
taps like the other controls. Strings in en/de/hu on both platforms.

The firmware (softwiredtech/dashkit-firmware#89, merged) replays the
VCSEC_requests 0x1F9 closure request the Tesla app uses and refuses it
in R/N/D or while moving; older firmware rejects the opcode as unknown.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
wpmed92 pushed a commit to softwiredtech/dashpilot that referenced this pull request Nov 8, 2026
… dashboards (#273)

* controls: per-door unlatch (DashKit opcode 0x50, gestures 10-13)

Four momentary controls on Android and iOS: Unlatch Driver / Passenger /
Rear Left / Rear Right Door. Each sends CMD_DOOR_UNLATCH (0x50) with the
door index 0-3; gesture values 10-13 let them be bound to multi-finger
taps like the other controls. Strings in en/de/hu on both platforms.

The firmware (softwiredtech/dashkit-firmware#89, merged) replays the
VCSEC_requests 0x1F9 closure request the Tesla app uses and refuses it
in R/N/D or while moving; older firmware rejects the opcode as unknown.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* door status: per-door, trunk and liftgate state in CarState for dashboards

The firmware forwards VCLEFT_doorStatus 0x102, VCRIGHT_doorStatus 0x103
and VCLEFT_liftgateStatus 0x142. The shared bridge decodes them into six
CarState fields, exposed to web and Rive dash apps on both platforms:

- doorOpenFL/FR/RL/RR, trunkOpen: 1 while the latch reports OPENED,
  OPENING, AJAR or CLOSING; 0 for CLOSED, SNA and the fault states.
- trunkPosition: powered liftgate angle in degrees from mux 1, kept
  across mux-0 frames, clamped at 0 (closed reads slightly negative).

bridge: DOOR_OFFSET = 47, FIELD_COUNT = 53; BridgeCarState carries the
fields for iOS. Only TeslaDashKitMapper is wired (new_gen_juniper.dbc
has no definitions for these messages yet).
Android: CarState, CanFrameDecoder, Rive dashValues, WebView getters.
iOS: CarState (bridge + Codable), Rive dashValues, WebView JSON.
dash-apps: README table, web-compose signals (five warning booleans and
the trunk angle), host getter map, en/hu/de labels.

Host test tesla_closure_mapper_test covers latch mapping, liftgate mux
handling and the array layout.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* door status: frunk latch as frunkOpen

VCFRONT_status mux 0 (already forwarded for anyDoorOpen) carries the
frunk latch status. Decode it with the same rule as the doors into
frunkOpen (0/1; the frunk has no position signal): CarState slot
DOOR_OFFSET + 6, FIELD_COUNT = 54, carried through the iOS bridge, both
apps, Rive dashValues, the WebView getter / JSON, the web-compose signal
catalog and the README. Host test covers mux 0 only and the array slot.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
@ehoeve786
ehoeve786 deleted the door-unlatch branch November 13, 2026 22:33
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.

3 participants