Repository navigation
Firmware Guide
For advanced users β what the Ropener firmware actually is, how it works, and how to flash or update it from the YAML file.
Ropener runs on ESPHome, an open-source firmware framework. The entire behaviour of the device β the web page, the motor logic, the buttons, the schedule β is described in a single human-readable YAML file and compiled into a binary that runs on the on-board ESP32. There is no closed-source blob and no cloud account: if you can read the YAML, you can see (and change) everything the device does.
π‘ If you only want to use the device, you don't need any of this β see the User Guide. This page is for people who want to recompile, update, or modify the firmware themselves.
- What is ESPHome?
- How the Ropener firmware is built
- Which YAML file is mine?
- What you may and may not change
- Tools for flashing
- Updating the firmware from the YAML
- First flash vs. over-the-air (OTA) updates
- secrets.yaml and API encryption (optional)
- External components
- After flashing
- Troubleshooting
ESPHome turns a YAML description of a device into real firmware. You write what the device should expose β a cover, some buttons, a few numbers, a web server β and ESPHome generates the C++, compiles it for the ESP32, and flashes it.
A few ideas worth knowing before you touch the file:
- The YAML is the source of truth. Nothing is configured by clicking around after the fact at the firmware level β every pin, entity, and behaviour comes from the file. Re-flashing the same YAML reproduces the same firmware exactly.
-
Entities, not screens. ESPHome thinks in entities: a
cover, aswitch, anumber, asensor, etc. The built-in web page and Home Assistant both render whatever entities the YAML declares β that's why the web UI and Home Assistant always show the same controls. -
It runs locally. The device serves its own control page (
web_server:) and talks to Home Assistant directly over the local network (api:). No internet round-trip is needed to move the curtain; the only thing that needs the network is clock sync for the schedule. - Two kinds of settings. Compile-time values (like the gear ratio) are baked into the binary and need a re-flash to change. Runtime values (speed, travel distance, timezoneβ¦) are exposed as entities you edit in the browser, and they persist in flash across reboots and updates. See Section 4.
If you've never used ESPHome, the official Getting Started guide is a good companion to this page.
At a high level, the curtain hardware is an ESP32 microcontroller driving a TMC2209 silent stepper driver, which turns a NEMA-17 motor and an MK8 gear that pulls the poly rope. The YAML wires all of that together. The main building blocks in the file:
| YAML section | What it does |
|---|---|
esphome: / esp32:
|
Device name, firmware version, board variant, and the on_boot: sequence that restores saved settings into the motor driver. |
external_components: |
Pulls in the TMC2209 stepper component (see Section 9). |
wifi: / captive_portal: / improv_serial:
|
Wi-Fi provisioning. The firmware ships with no saved network, so a fresh unit broadcasts a ropener-XXXXXX setup hotspot. |
web_server: |
The built-in control page at http://ropener-XXXXXX.local, grouped into Control / Setup / Schedule / Motion / StallGuard / Diagnostics. |
api: |
The native ESPHome API used by Home Assistant (optional, unencrypted by default). |
ota: |
Over-the-air update support, so later updates don't need a USB cable. |
stepper: + cover:
|
The motion engine. Position is tracked in motor steps and reported to the UI as a 0β1 (closedβopen) ratio. |
binary_sensor: (buttons) |
The three physical buttons (close/home, open, Wi-Fi reset). |
number: / switch: / text: / datetime:
|
The runtime-tunable settings β travel distance, speed, motor direction, schedule times, timezone, latitude/longitude, StallGuard thresholds. |
time: + sun: + interval:
|
The daily schedule, including the optional sunrise/sunset mode. |
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.
The YAML source for each board lives in its own sub-folder under firmware/; the matching pre-built binaries are attached to each release. Every release provides two binaries per board β a *.factory.bin (full image for the first USB flash) and a *.ota.bin (the over-the-air update image you upload from the device's web page). So you can build from source, flash the factory image with no tools, or update an already-running device straight from its browser (see Section 6). The v2.6.1 files:
| Board | Microcontroller | YAML source | Factory image β first USB flash | OTA image β Wi-Fi update |
|---|---|---|---|---|
| VAL3100 | ESP32-C6 | Ropener-VAL3100-2.6.1.yml |
Ropener-VAL3100-2.6.1.factory.bin |
Ropener-VAL3100-2.6.1.ota.bin |
| VAL3000 | ESP32-C3 | Ropener-VAL3000-2.6.1.yml |
Ropener-VAL3000-2.6.1.factory.bin |
Ropener-VAL3000-2.6.1.ota.bin |
β οΈ The board variants are not interchangeable. The C3 and C6 use different GPIO pin assignments, so flashing the wrong board's YAML or binary will leave the buttons and motor mis-wired. If you're not sure which board you have, check the silk-screen label on the PCB.
π Want Alexa / Apple Home / Google Home? You don't need a separate firmware for that β pair the standard build with Matterbridge to bridge the curtain into those ecosystems. See the README.
This section only matters if you build from the YAML (Path B). If you flash the ready-made binary (Path A), there's nothing to edit β skip to Section 6.
When building from source, the one thing most people change is the device name in the esphome: block, to give the unit a friendly label:
esphome:
name: ropener-bedroom-1 # optional β a friendly name
friendly_name: "Ropener Bedroom 1" # optionalYou don't have to rename it: name_add_mac_suffix: true already makes every unit unique as ropener-XXXXXX. Change it only if you want something more memorable.
Everything else should be left alone unless you know exactly what you're doing. In particular:
-
Don't touch the
substitutions:block (gear_distance_cm,steps_per_revolution). These are mechanical constants tied to the actual gear and microstepping; changing them breaks the distance calibration. -
Don't touch the pin numbers in
uart:,stepper:, and the buttonbinary_sensor:entries β they match the PCB. - You don't need to edit travel distance, speed, schedule, timezone, etc. in the YAML. Those are runtime settings: flash once, then set them from the web page (they persist across reboots and future updates). See the ESPHome Guide and User Guide.
π StallGuard warning. Do not enable or tune StallGuard-based auto-homing unless you have set it up correctly β it's finicky and needs exact
SGTHRS/TCOOLTHRSvalues. It is not required for the device to work; home the curtain manually instead (see the User Guide).
Only ESPHome itself can compile the YAML into firmware β a web page can't. Pick whichever tool fits how you work:
| Tool | What it does | Notes |
|---|---|---|
ESPHome CLI (pip install esphome) |
Compiles the YAML and flashes it |
esphome run file.yml β over USB or OTA. Needs Python. |
| ESPHome Dashboard | Compiles and flashes, via a local web UI | Standalone (esphome dashboard) or the Home Assistant ESPHome add-on. USB and OTA. |
| ESPHome Web (web.esphome.io) |
Flashes a pre-built .bin β does not compile |
Runs in Chrome/Edge, no install, USB only (no OTA). Flash the ready-made .factory.bin we ship (Section 3) β or one you compiled yourself. |
In short: the CLI and the Dashboard turn the YAML into firmware; ESPHome Web just writes a finished binary β and since we ship one in each board's folder, a standard install needs no compiling at all.
How you get firmware onto the device depends on its state β pick the matching method:
- Already running Ropener? Update it straight from its web page β no tools, no USB (see just below).
- New / blank board? Flash the factory image over USB β Path A.
- Want to customize the YAML or script updates? Build from source β Path B.
π¦ Two binary types. First-time USB flashing uses the factory image (
*.factory.bin). Over-the-air updates use the OTA image (*.ota.bin, ESPHome's "Modern format"). Each board folder ships both (Section 3) β don't upload a factory image to an OTA updater.
If the device already runs Ropener firmware and is on your network, this is the simplest way to update it β no USB cable and nothing to install:
- Open the device's control page (
http://ropener-XXXXXX.local) in any browser on the same network. - Scroll to the OTA Update card.
- Click Choose File and select the new OTA image β your board's
*.ota.bin(e.g.Ropener-VAL3100-2.6.1.ota.bin), not the*.factory.bin. - Click Update. The device flashes the new build and reboots; your Wi-Fi and saved settings are kept.
π‘ You can push the same OTA from the ESPHome CLI/Dashboard instead (Path B, over the network) β handy for scripting or bulk updates.
Each board folder ships a pre-compiled *.factory.bin, so you can flash without installing ESPHome or compiling anything.
- Download your board's
*.factory.binfrom Section 3 (e.g.Ropener-VAL3100-2.6.1.factory.bin). - Plug the device into your computer over USB.
- Go to web.esphome.io in Chrome or Edge and click Connect; pick the device's serial port.
- Click Install, choose the
.factory.binyou downloaded, and let it flash.
π‘ Nothing to configure first. The stock build names itself
ropenerplus a per-device MAC suffix, so every unit comes up unique asropener-XXXXXX. Want a custom friendly name, API encryption, or different motion defaults? Build from source instead (Path B).
Use this to customize the firmware, or to update over Wi-Fi (OTA) after the first flash.
- Install ESPHome:
pip install esphome(or use the Home Assistant ESPHome add-on /esphome dashboard). - Save the correct YAML for your board (Section 3) locally and edit the device name (Section 4).
- Compile and flash in one step:
The first time, choose the USB/serial port. Once the device is on your network the same command offers an OTA (Over-The-Air) option β no cable needed.
esphome run Ropener-VAL3100-2.6.1.yml
- Watch the boot log to confirm it came up cleanly:
esphome logs Ropener-VAL3100-2.6.1.yml
π§ Flashing a customized build through the browser? Run
esphome compile Ropener-VAL3100-2.6.1.ymlto produce your own*.factory.bin(ESPHome writes it under.esphome/build/<device-name>/β¦), then flash it with Path A from step 2.
π Wi-Fi survives updates. Re-flashing does not erase your saved Wi-Fi network or your runtime settings β they live in a separate area of flash. You only re-provision Wi-Fi after a deliberate Wi-Fi reset (hold Button 3, see the User Guide).
- First flash must be over USB. A brand-new or blank chip has no firmware to receive an OTA, so the very first install needs a cable.
-
Every update after that can be OTA β either upload the
*.ota.binin the device's OTA Update web card (Section 6), or push it from the ESPHome CLI/Dashboard (pick the device's network address instead of a serial port). Both use the*.ota.binimage, not the factory image. -
OTA requires the device to be on the same network and reachable at
ropener-XXXXXX.local(or its IP address).
The firmware compiles without a secrets.yaml out of the box β there are no hardcoded Wi-Fi credentials or keys to supply.
The only reason to create one is to enable encryption on the Home Assistant API. By default the native API is unencrypted, and Home Assistant shows a "Communication not encrypted" warning when you first add the device. The device still works normally. To silence the warning:
- Generate a 32-byte base64 key:
python3 -c "import secrets,base64; print(base64.b64encode(secrets.token_bytes(32)).decode())" - Put it in a
secrets.yamlnext to the firmware:api_key: "your-generated-key-here"
- Uncomment the encryption block in the
api:section of the YAML:api: encryption: key: !secret api_key
- Re-flash, then add the key in Home Assistant when prompted.
The TMC2209 stepper driver isn't part of core ESPHome, so the firmware pulls it from a community repository at compile time:
external_components:
- source: github://slimcdk/esphome-custom-components
components: [tmc2209_hub, tmc2209, stepper]ESPHome downloads and caches this automatically on the first build β you don't need to install anything by hand. It does mean the first compile needs an internet connection; later builds use the cached copy.
A successful flash gets you a running device, but it still needs to be set up:
-
Provision Wi-Fi β connect to the
ropener-XXXXXXhotspot (or use Improv over USB). See User Guide Β§2. - Configure the device β set travel distance (Centimeters), motor direction, and home the curtain. See the ESPHome Guide.
- Use it β schedule, positions, Home Assistant, etc. See the User Guide.
| Symptom | What to try |
|---|---|
| Compile fails on first build | Check your internet connection β ESPHome needs to download the external TMC2209 component once. |
| "Wrong" buttons or motor won't move | You may have flashed the wrong board's YAML. Confirm VAL3000 (C3) vs. VAL3100 (C6) and re-flash the matching file (Section 3). |
| Can't flash over USB | Try a different (data-capable) USB cable, and a Chromium-based browser for ESPHome Web. Some boards need to be put into bootloader mode. |
| OTA option doesn't appear | The device must already be running this firmware and reachable on the network. Do the first flash over USB. |
| OTA update rejected / "invalid image" | You picked the wrong file β the OTA Update card needs the *.ota.bin (Modern format), not the *.factory.bin (that's only for the initial USB flash). |
| Home Assistant says "not encrypted" | Expected β the device works anyway. Enable API encryption if you want to remove it (Section 8). |
| Lost Wi-Fi / settings after update | Re-flashing does not erase them; if Wi-Fi is gone, the device was likely Wi-Fi-reset. Re-provision via the hotspot (User Guide Β§2). |
Still stuck? Open an issue β and see the ESPHome Guide and User Guide for day-to-day configuration.
Getting Started
Build & Install
Firmware & Use
Links