Auto Blinds is an automation project that dynamically adjusts blind orientation based on the Sun's position (Auto Mode). It also includes a mobile interface for convenient remote manual control (Manual Mode).
Note: This README.md file includes the introduction of the project. For how to use the code, please visit SUPPORT.md.
Fig. 1. The blinds adjusts the orientation automatically based on time and the Sun's position.
Auto Blinds provides remote accessibility via smartphone from any distance. Fig. 2 illustrates the Auto Blinds (left) alongside a screen recording of the control interface (right). Users may utilize the on-screen buttons to adjust the blinds to preferred orientations; meanwhile, the dynamic animation provides a real-time preview of the blinds' status, orientation, and the current position of the sun.
Fig. 2. The Auto Blinds (left) alongside a screen recording of the control interface (right).
In my dorm room, my desk and a set of bunk beds are positioned next to a window fitted with east-facing horizontal blinds. The blinds are adjusted using an acrylic hexagonal prism wand. For clarity (Fig. 3), I define 0° as fully tilted down, 90° as horizontal (maximizing outward visibility), and 180° as fully tilted up (minimizing incoming sunlight).
Fig. 3. Auto Blinds angle definition. (a) fully tilted down - 0°. (b) horizontal - 90°. (c) fully tilted up - 180°
A nearby building partially affects lighting conditions. Its roof forms an altitude angle of approximately 12° relative to the window (Fig. 4. (a)), which blocks sunlight when the Sun’s altitude is below this threshold (Fig. 4. (b)). However, when the Sun rises above 12°, direct sunlight enters the room unless the blinds are tilted upward (Fig. 4. (c)). This makes it difficult to work comfortably at my desk. At night, exterior lighting shines upward into the room, reflecting off the ceiling (Fig. 4. (d)). In this case, the blinds must be tilted downward to block the light and maintain a suitable sleeping environment. During most of the daytime, however, both my roommate and I prefer the blinds to remain at 90° to allow visibility outside.
Fig. 4. (a) 12° altitude angle of the building. (b)(c) Different positions of the Sun. (d) Exterior lighting.
A practical limitation arises from the bunk bed design: the upper bunk obstructs most of the wand, leaving only about 0.5 inches (1.3 cm) accessible unless I climb onto the bed (Fig. 5). Since the furniture cannot be rearranged, manual adjustment is inconvenient. This motivated the development of a system that enables both autonomous operation (Auto Mode) and remote manual control (Manual Mode).
Fig. 5. The wand of the blinds.
In Auto Mode, a microcontroller retrieves the current date and time from the Internet and calculates the Sun’s position to determine the optimal blind angle. The system also incorporates a simple daily routine, automatically setting the blinds to 0° during sleep hours and 90° upon waking. In Manual Mode, users can remotely set the blind angle or switch between modes via a mobile interface.
To support reliable network connectivity, particularly with WPA2-Enterprise (university Wi-Fi), an ESP32 microcontroller is used. A 28BYJ-48 stepper motor provides sufficient torque and precise control for rotating the wand. Notion, via its API, serves as an intermediary “server”, enabling communication between mobile devices and the ESP32.
-
Motor: 28BYJ-48 stepper motor
-
Language: C++, Notion API
-
Directory: src/
-
Language: Notion, HTML, JavaScript, CSS
-
Directory: docs/status/
Note: A Notion page, where there are buttons and Notion database, is used as the interface for users to control the blinds on their phones. A github webpage is embedded in the Notion page to provide a real-time preview of the orientation of the blinds and the dynamic position of the Sun.
-
Language: Python
-
Directory: local_debug/
This 3D model (Fig. 6) illustrates the motorized blind system and its mounting assembly:
- Blue Frame: 3D-printed housing, secured to the bunk frame with M6x16mm bolts.
- Stepper Motor: A 28BYJ-48 motor (hidden) fastened using M4x8mm screws.
- Motor Driver: The green ULN2003 module, secured with M2x12mm screws.
- Gearing: Two blue 3D-printed gears (10:24 ratio) used to increase output torque.
- Wand: A transparent hexagonal prism that controls the blinds.
- Mounting: Attaches directly to the vertical white metal frame of the upper bunk.
Click here to download the 3D model.
The wiring diagram (Fig. 7) of this project is relatively straightforward.
- GPIO4 (D2) -> IN4
- GPIO5 (D3) -> IN3
- GPIO6 (D4) -> IN2
- GPIO7 (D5) -> IN1
Fig. 7. Auto Blinds wiring diagram
Fig. 8 illustrates the network architecture. The ESP32 retrieves commands from the Notion server while concurrently transmitting the blinds' status and the Sun's position. Simultaneously, the Notion app interface synchronizes with the server to reflect real-time updates. Upon user interaction, commands are transmitted from the interface directly to the Notion server. The infrastructure facilitates multi-user concurrency, enabling several individuals to manage the Auto Blinds at the same time.
Fig. 8. Network architecture for Auto Blinds. (a) Single-user configuration; (b) Multi-user configuration.
sequenceDiagram
participant user as User
participant app as Notion App
participant github as GitHub Webpage
participant server as Notion Server
participant esp32_notion as ESP32<br>request_handler.h
participant esp32_main as ESP32<br>main.cpp
participant esp32_calc as ESP32<br>sun_calculation.h
participant esp32_motor as ESP32<br>motor_controller.h
par ESP32 Notion API
esp32_main->>esp32_main: Connect to WiFi
esp32_main->>esp32_notion: Get current status
esp32_notion->>server: Get current status
server-->>esp32_notion: Return current status
esp32_notion->esp32_notion: Get blind angle <br> from current status
esp32_notion-->>esp32_main: Set "angle"
Note over server,esp32_main: ESP32 does not have non-volatile storage to <br>store current blind angle, so Notion Server is used <br>to store the angle when the ESP32 is being reset.
esp32_main->>esp32_notion: Get lastest command
esp32_notion->>server: Get command list
server-->>esp32_notion: Return command list
esp32_notion-->>esp32_notion: Get latest command
opt
esp32_notion-)server: Update lastest <br>command status
end
esp32_notion-->>esp32_main: Set "target" <br>and "auto_mode"
esp32_main->>esp32_calc: Get current <br> position of the Sun
esp32_calc->>esp32_calc: Calculate current <br> position of the Sun
esp32_calc-->>esp32_main: Set "sun_u", <br>"sun_v", "sun_w"
alt If auto mode is on
esp32_main->>esp32_calc: Get "target"
esp32_calc->>esp32_calc: Calculate "target"
esp32_calc-->>esp32_main: Set "target"
end
esp32_notion->>esp32_motor: Initialize motor
par ESP32 parallel thread: main.cpp
loop void loop() in main.cpp
esp32_main->>esp32_notion: Get lastest command
esp32_notion->>server: Get command list
server-->>esp32_notion: Return command list
esp32_notion-->>esp32_notion: Get latest command
esp32_notion-)server: Update lastest <br>command status
opt If Notion App is open
server-)app: Send updated database
app-)user: Show updated database
end
esp32_notion-->>esp32_main: Set "target" <br>and "auto_mode"
esp32_main->>esp32_calc: Get current <br> position of the Sun
esp32_calc->>esp32_calc: Calculate current <br> position of the Sun
esp32_calc-->>esp32_main: Set "sun_u", <br>"sun_v", "sun_w"
alt If auto mode is on
esp32_main->>esp32_calc: Get "target"
esp32_calc->>esp32_calc: Calculate "target"
esp32_calc-->>esp32_main: Set "target"
end
esp32_main->>esp32_notion: Send current status <br>to Notion
esp32_notion-)server: Update current status
opt If Notion App is open
server-)app: Send current status
app->>github: Update current status
github->>github: Render preview
github->>app: Embed rendered <br>prevew
app-)user: Show updated preview
end
end
and ESP32 parallel thread: motor_controller.h
loop while (true) in motor_controller.h
esp32_motor->>esp32_main: Get "target"
esp32_main->>esp32_motor: Return "target"
esp32_motor->>esp32_motor: Calculate next <br>motor step
esp32_motor->>esp32_motor: set_motor_phase()
esp32_motor->>esp32_main: Return "angle"
end
end
and User interference
opt
alt
user->>app: Click a button
else
user->>app: Set a specific angle
else
user->>app: Calibration
end
app->>server: Add command to Notion database
server-->>app: Return updated database
app-)user: Show updated database
end
end
Fig. 9. The sequence diagram of Auto Blinds.
Firstly, the ecliptic coordinate system is used to calculate the Sun’s declination (
Since
and
we have
where:
-
${\hat{r}}_{SE}$ is the unit vector pointing from the Sun to Earth in the ecliptic coordinate system -
${\hat{n}}_{NCP}$ is the unit vector pointing toward the north celestial pole (NCP) in the ecliptic coordinate system -
$\delta$ is the Sun’s declination -
$\lambda_\odot$ is the ecliptic longitude of Earth -
$\varepsilon$ is the obliquity of Earth
Since the subsolar latitude (
In the Earth-centered, Earth-fixed coordinate system (ECEF), the subsolar vector (
where:
-
$\phi_s$ is the subsolar latitude -
$\lambda_s$ is the subsolar longitude, which can be calculated according to the current time ($T_{UTC}$ ) using the following formula 4:
Similarly, the normalized observer vector (
where:
-
$\phi_o$ is the latitude of the observer -
$\lambda_o$ is the longitude of the observer
Note:
Then the coordinate system needs to be transformed into the observer’s coordinate system. The horizontal coordinate system is commonly used to represent the position of the sun 4 5. However, since the blinds and the roof edges mentioned in Background and Motivation are parallel to the lines of latitude and longitude, we should use the local east-north-up (ENU) coordinate system.
The unit vectors of the ENU coordinate system expressed in the ECEF coordinate system (
where:
Applying the Rotation Matrix (
Let
then:
Finally,
After the Sun rises from the top of the building, the blind target orientation (
For simplicity, we let
Fig. 10. A vertical cross section of the blinds and the sunlight.
In Fig. 10, The sunlight is represented by the red line with an arrow, and the cross section of the blinds is represented by the tilted black lines.
According to the geometric relations, we have
Based on the sum of the interior angles of triangle ABC,
Applying the Law of Sines in triangle ABC,
Therefore,
In this case,
Finally, since
Footnotes
-
“Getting Started with Seeed Studio XIAO ESP32C3 | Seeed Studio Wiki.” Accessed: Feb. 27, 2026. [Online]. Available: https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started/ ↩
-
“Amazon.com: Seeed Studio XIAO ESP32C3 - Tiny MCU Board with Wi-Fi and BLE for IoT Controlling Scenarios. Microcontroller with Battery Charge, Power Efficient, and Rich Interface for Tiny Machine Learning. … : Electronics.” Accessed: Feb. 27, 2026. [Online]. Available: https://www.amazon.com/gp/product/B0B94JZ2YF/?th=1 ↩
-
J. H. Meeus, Astronomical algorithms. Willmann-Bell, Incorporated, 1991. ↩
-
T. Zhang, P. W. Stackhouse Jr, B. Macpherson, and J. C. Mikovitz, “A solar azimuth formula that renders circumstantial treatment unnecessary without compromising mathematical rigor: Mathematical setup, application and extension of a formula based on the subsolar point and atan2 function,” Renew. Energy, vol. 172, pp. 1333–1340, 2021. ↩ ↩2
-
R. Walraven, “Calculating the position of the sun,” Sol. Energy, vol. 20, no. 5, pp. 393–397, 1978. ↩
-
“Geographic coordinate conversion,” Wikipedia. Dec. 22, 2025. Accessed: Mar. 04, 2026. [Online]. Available: https://en.wikipedia.org/w/index.php?title=Geographic_coordinate_conversion&oldid=1328905303#From_ECEF_to_ENU ↩
