-
Notifications
You must be signed in to change notification settings - Fork 0
Command Transmitter sendCommand
Documents the decision logic of
SomfyCommandTransmitter::sendCommand,
the per-shade command dispatcher that translates a logical somfy_commands value
into the correct raw RF frame (via SomfyRemote::sendCommand) and updates the
shade's optimistic position/tilt targets.
Class name note: the file/class is
SomfyCommandTransmitter(notSomfyCommandTransceiver).
void sendCommand(somfy_commands cmd); // → sendCommand(cmd, shade->repeats)
void sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize = 0);The single-argument overload simply forwards to the full overload using the shade's
default repeats count. All the logic below lives in the full overload.
Several branches set p_target / p_tiltTarget / p_currentPos. These are
optimistic state updates — the shade assumes the motor will honour the command, so
the movement tracker and HomeKit/web feedback reflect the new intent immediately
(0.0 = fully open, 100.0 = fully closed in the internal convention).
flowchart TD
A["sendCommand(cmd, repeat, stepSize)"] --> B{"bitLength == 0?"}
B -- yes --> B1["bitLength = transceiver.config.type"]
B -- no --> C
B1 --> C{"cmd?"}
%% ---------- UP ----------
C -- Up --> U{"tiltType == euromode?"}
U -- yes --> U1["SomfyRemote::sendCommand(Up, TILT_REPEATS)<br/>target = 0"]
U -- no --> U2["SomfyRemote::sendCommand(Up, repeat)"]
U2 --> U3{"tiltType?"}
U3 -- tiltonly --> U3a["target = 100<br/>tiltTarget = 0<br/>currentPos = 100"]
U3 -- integrated --> U3b["target = 0<br/>tiltTarget = 0"]
U3 -- other --> U3c["target = 0"]
%% ---------- DOWN ----------
C -- Down --> D{"tiltType == euromode?"}
D -- yes --> D1["SomfyRemote::sendCommand(Down, TILT_REPEATS)<br/>target = 100"]
D -- no --> D2["SomfyRemote::sendCommand(Down, repeat)"]
D2 --> D3{"tiltType?"}
D3 -- tiltonly --> D3a["target = 100<br/>tiltTarget = 100<br/>currentPos = 100"]
D3 -- integrated --> D3b["target = 100<br/>tiltTarget = 100"]
D3 -- other --> D3c["target = 100"]
%% ---------- MY ----------
C -- My --> M{"isToggle() ||<br/>shadeType == drycontact?"}
M -- yes --> M1["SomfyRemote::sendCommand(My, repeat)"]
M -- no --> M2{"shadeType == drycontact2?"}
M2 -- yes --> M2a["return (no-op)"]
M2 -- no --> M3{"isIdle()?"}
M3 -- yes --> M3a["moveToMyPosition()<br/>return"]
M3 -- no --> M4["SomfyRemote::sendCommand(My, repeat)<br/>if tiltType != tiltonly: target = currentPos<br/>tiltTarget = currentTiltPos"]
%% ---------- TOGGLE ----------
C -- Toggle --> T{"bitLength != 80?"}
T -- yes --> T1["SomfyRemote::sendCommand(My, repeat, stepSize)"]
T -- no --> T2["SomfyRemote::sendCommand(Toggle, repeat)"]
%% ---------- PROG (toggle shades) ----------
C -- "Prog (and isToggle())" --> P1["SomfyRemote::sendCommand(Toggle, repeat, stepSize)"]
%% ---------- DEFAULT ----------
C -- "other / Prog (non-toggle)" --> X1["SomfyRemote::sendCommand(cmd, repeat, stepSize)"]
%% ---------- terminal styling ----------
U1 & U3a & U3b & U3c & D1 & D3a & D3b & D3c & M1 & M2a & M3a & M4 & T1 & T2 & P1 & X1 --> Z(["frame queued to RMT TX<br/>(or no-op / delegated)"])
cmd |
Condition | Raw frame sent | Optimistic state set |
|---|---|---|---|
Up |
tiltType == euromode |
Up, TILT_REPEATS
|
target = 0 |
Up |
tiltType == tiltonly |
Up, repeat
|
target = 100, tiltTarget = 0, currentPos = 100
|
Up |
tiltType == integrated |
Up, repeat
|
target = 0, tiltTarget = 0
|
Up |
otherwise |
Up, repeat
|
target = 0 |
Down |
tiltType == euromode |
Down, TILT_REPEATS
|
target = 100 |
Down |
tiltType == tiltonly |
Down, repeat
|
target = 100, tiltTarget = 100, currentPos = 100
|
Down |
tiltType == integrated |
Down, repeat
|
target = 100, tiltTarget = 100
|
Down |
otherwise |
Down, repeat
|
target = 100 |
My |
isToggle() or drycontact
|
My, repeat
|
— |
My |
drycontact2 |
none — early return
|
— |
My |
isIdle() |
none — delegates to moveToMyPosition() then return
|
(set by moveToMyPosition) |
My |
otherwise (moving) |
My, repeat (acts as Stop) |
target = currentPos (unless tiltonly), tiltTarget = currentTiltPos
|
Toggle |
bitLength != 80 |
My, repeat, stepSize
|
— |
Toggle |
bitLength == 80 |
Toggle, repeat
|
— |
Prog |
isToggle() |
Toggle, repeat, stepSize
|
— |
| any other | — |
cmd, repeat, stepSize (pass-through) |
— |
-
Myis overloaded. On an idle shade it means "go to the My/favourite position" (moveToMyPosition); on a moving shade the sameMyframe acts as Stop, so the optimistictargetis snapped to the current position to halt the movement tracker. -
drycontact2ignoresMyentirely (early return, no frame). -
TogglevsbitLength. For non-80-bit protocols aToggleis sent as aMyframe; only true 80-bit remotes emit a realTogglecommand. The same dual mapping is whyProgon a toggle-type shade is rewritten toToggle. -
Tilt types (
tilt_types, SomfyFrame.h:66):none,tiltmotor,integrated,tiltonly,euromode. Euromode and tilt-only shades have distinct position/tilt semantics, which is whyUp/Downfan out. - This method only dispatches the frame to
SomfyRemote::sendCommand, which itself is non-blocking and skips silently when the RMT TX is busy — see HomeKit Command Sequence for the surrounding queue/transmit flow.
-
main/somfy/shade/SomfyCommandTransmitter.cpp:20 —
sendCommand(full overload) -
main/somfy/shade/SomfyShade.cpp:332 —
isIdle -
main/somfy/shade/SomfyShade.cpp:552 —
isToggle -
main/somfy/SomfyFrame.h:47 —
shade_types -
main/somfy/SomfyFrame.h:66 —
tilt_types -
main/somfy/SomfyTransceiver.h:10 —
TILT_REPEATS(15)