Skip to content

Commit 1b17515

Browse files
Merge pull request #31 from Valar-Systems/fix/motor-direction-persist
fix(firmware): persist Motor Direction across power loss; show as a dropdown
2 parents d4b8b2f + c510efa commit 1b17515

5 files changed

Lines changed: 65 additions & 27 deletions

File tree

‎docs/Ropener-User-Guide.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Ropener Curtain Controller — User Guide
22

3-
*Firmware 2.6.1*
3+
*Firmware 2.6.3*
44

55
---
66

@@ -261,7 +261,7 @@ These settings are optional. The defaults work for a typical installation; chang
261261
| Centimeters | Total travel distance of the curtain, in cm. | Set this to your curtain's open-to-closed travel. Default 30 cm. |
262262
| Speed | How fast the motor runs (steps/second). | Higher is faster but louder. Effective max is 2000. |
263263
| Acceleration | How quickly the motor speeds up / slows down. | Higher is snappier; too high can skip or be noisy. |
264-
| Motor Direction | Which way the motor winds the rope. | Flip this if Open and Close are reversed for your install. |
264+
| Motor Direction | Which way the motor winds the rope (**Normal** / **Reversed ↺**). | Set to **Reversed** if Open and Close are backwards for your install. Your choice is saved and survives a power loss. |
265265
| IRUN value | Motor running current / torque (1–31). | Raise for more pulling force; lower if the driver runs hot. Default 25. |
266266
| SGTHRS value | Sensitivity of the stall detection used for homing (0–255). | See tuning note below. |
267267
| TCOOLTHRS value | Speed threshold above which stall detection is active. | See tuning note below. |
@@ -293,7 +293,7 @@ When first added, Home Assistant may warn that communication is not encrypted. T
293293
| --- | --- |
294294
| Can't find the web page | Make sure your phone/PC is on the same Wi-Fi as the device. Try the device's IP address instead of the `.local` name. Confirm it joined Wi-Fi (the setup hotspot should be gone). |
295295
| No setup hotspot appears | Wait a full minute after power-on. If it already joined a network, hold Button 3 for 3–10 seconds to reset Wi-Fi and try again. |
296-
| Open/Close are reversed | Toggle the “Motor Direction” switch. |
296+
| Open/Close are reversed | Set the “Motor Direction” setting to **Reversed**. |
297297
| Position is wrong / drifted | Run homing (Section 5) to recalibrate. |
298298
| Schedule fires at the wrong time | Check the Timezone value (Section 7/8) and that the device has internet for time sync. |
299299
| Schedule doesn't run | Confirm “Schedule Enabled” is ON and that Open/Close times are set. |

‎docs/wiki-Firmware-Guide.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ At a high level, the curtain hardware is an **ESP32** microcontroller driving a
5353
| `ota:` | Over-the-air update support, so later updates don't need a USB cable. |
5454
| `stepper:` + `cover:` | The motion engine. Position is tracked in motor *steps* and reported to the UI as a 0–1 (closed→open) ratio. |
5555
| `binary_sensor:` (buttons) | The three physical buttons (close/home, open, Wi-Fi reset). |
56-
| `number:` / `switch:` / `text:` / `datetime:` | The runtime-tunable settings — travel distance, speed, motor direction, schedule times, timezone, latitude/longitude, StallGuard thresholds. |
56+
| `number:` / `select:` / `switch:` / `text:` / `datetime:` | The runtime-tunable settings — travel distance, speed, motor direction, schedule times, timezone, latitude/longitude, StallGuard thresholds. |
5757
| `time:` + `sun:` + `interval:` | The daily schedule, including the optional sunrise/sunset mode. |
5858

5959
You don't need to understand every line to update the firmware — but it's all commented in the file itself if you want to dig in.
File renamed without changes.
File renamed without changes.

‎firmware/common/ropener-core.yaml‎

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@ external_components:
150150
# Persistent state
151151
# -----------------------------------------------------------------------------
152152
# All globals use restore_value so settings survive reboots. They are mirrored
153-
# by `number` / `switch` entities further down — editing in Home Assistant
154-
# updates the global AND pushes the value to the appropriate TMC2209 register.
153+
# by `number` / `select` / `switch` entities further down — editing in Home
154+
# Assistant updates the global AND pushes the value to the TMC2209 / stepper.
155155
globals:
156156
# Motor run current (TMC2209 IRUN field, 0-31). Higher = more torque + heat.
157157
# 25 is a moderate setting; reduce if the driver overheats or skips cooldown.
@@ -206,7 +206,8 @@ globals:
206206
initial_value: '12732'
207207

208208
# Motor shaft direction. Persisted so the unit comes up the same way after
209-
# a reboot. Toggled by the "Motor Direction" switch entity.
209+
# a reboot. Set by the "Motor Direction" select entity, which mirrors this
210+
# global rather than holding its own state (see the select for why).
210211
- id: global_stepper_direction
211212
type: esphome::tmc2209::ShaftDirection
212213
restore_value: yes
@@ -481,7 +482,7 @@ substitutions:
481482

482483
# Firmware version — single source of truth. Feeds project.version (below) and
483484
# the "Firmware Version" diagnostic sensor shown on the web UI / in HA.
484-
firmware_version: "2.6.2"
485+
firmware_version: "2.6.3"
485486

486487
# NOTE: board-specific substitutions — board_variant, board_id, the GPIO pin
487488
# map (pin_uart_tx/rx, pin_enn/index/diag, pin_btn1/btn2/btn_wifi) and
@@ -1192,34 +1193,71 @@ button:
11921193

11931194

11941195
# -----------------------------------------------------------------------------
1195-
# Configuration switches
1196+
# Configuration selects
11961197
# -----------------------------------------------------------------------------
1197-
# Motor Direction: flips the shaft direction so the same close/open commands
1198-
# wind the rope the right way regardless of how the motor was mounted.
1199-
# OFF -> CLOCKWISE
1200-
# ON -> COUNTERCLOCKWISE
1201-
# `optimistic: true` is fine here because the action is idempotent and we
1202-
# persist the truth in `global_stepper_direction`.
1203-
switch:
1198+
# Motor Direction: picks the shaft direction so the same close/open commands
1199+
# wind the rope the right way regardless of how the motor was mounted. The value
1200+
# is just the motor's physical spin direction; flipping it reverses open and
1201+
# close together. Labelled by OUTCOME rather than CW/CCW, because "clockwise" has
1202+
# no defined viewpoint here (front vs. spindle side) and doesn't single out open
1203+
# or close on its own:
1204+
# "Normal" -> CLOCKWISE (default; open/close as-is)
1205+
# "Reversed ↺" -> COUNTERCLOCKWISE (pick this if open and close are backwards)
1206+
#
1207+
# This entity is a pure MIRROR of `global_stepper_direction`, exactly like the
1208+
# number entities mirror their globals: `lambda` reports the current option from
1209+
# the global, and `set_action` writes the global + pushes the new direction to
1210+
# the driver. The global (restore_value: yes) is the single source of truth and
1211+
# is applied to the driver in on_boot.
1212+
#
1213+
# Crucially this select carries NO optimistic/restore state of its own, so it
1214+
# never writes the global at startup. That startup write is precisely what the
1215+
# old "Motor Direction" *switch* did wrong: a template switch defaults to an
1216+
# ALWAYS_OFF restore, so every power cycle re-ran its turn_off_action and reset
1217+
# the restored direction back to CLOCKWISE. Mirroring the global instead removes
1218+
# that second source of truth.
1219+
#
1220+
# set_action ALSO flushes the change to flash immediately. ESPHome batches
1221+
# preference writes (default flash_write_interval 60s) and does not flush on an
1222+
# abrupt power loss, so a global.set alone can be lost if the user changes the
1223+
# direction and pulls power within that window — exactly what happens while
1224+
# mounting/testing. update() pushes the changed global into the pending-save
1225+
# buffer; global_preferences->sync() writes it to NVS right away. The 60s batch
1226+
# is left intact for everything else, so the 200 ms position writes during
1227+
# motion don't hammer flash.
1228+
select:
12041229
- platform: template
12051230
name: "Motor Direction"
12061231
web_server:
12071232
sorting_weight: 2
12081233
sorting_group_id: group_setup
12091234
entity_category: CONFIG
1210-
optimistic: true
1211-
turn_on_action:
1212-
- globals.set:
1213-
id: global_stepper_direction
1214-
value: 'esphome::tmc2209::ShaftDirection::COUNTERCLOCKWISE'
1215-
- tmc2209.configure:
1216-
direction: !lambda return id(global_stepper_direction);
1217-
turn_off_action:
1218-
- globals.set:
1219-
id: global_stepper_direction
1220-
value: 'esphome::tmc2209::ShaftDirection::CLOCKWISE'
1235+
update_interval: 1s
1236+
options:
1237+
- "Normal"
1238+
- "Reversed ↺"
1239+
lambda: |-
1240+
if (id(global_stepper_direction) == esphome::tmc2209::ShaftDirection::COUNTERCLOCKWISE)
1241+
return std::string("Reversed ↺");
1242+
return std::string("Normal");
1243+
set_action:
1244+
- lambda: |-
1245+
id(global_stepper_direction) = (x.find("Reversed") != std::string::npos)
1246+
? esphome::tmc2209::ShaftDirection::COUNTERCLOCKWISE
1247+
: esphome::tmc2209::ShaftDirection::CLOCKWISE;
12211248
- tmc2209.configure:
12221249
direction: !lambda return id(global_stepper_direction);
1250+
- lambda: |-
1251+
// Persist immediately (see the note above the select). update() moves
1252+
// the changed value into the pending-save buffer; sync() flushes that
1253+
// buffer to NVS now, so the choice survives an unplug seconds later.
1254+
global_stepper_direction->update();
1255+
global_preferences->sync();
1256+
1257+
# -----------------------------------------------------------------------------
1258+
# Configuration switches
1259+
# -----------------------------------------------------------------------------
1260+
switch:
12231261

12241262
# Schedule Enabled: master on/off for the daily schedule. When OFF, neither
12251263
# schedule moves the cover. When ON, the "Sun Schedule" switch below selects

0 commit comments

Comments
 (0)