diff --git a/esphome/esp-astroclockstepper1.yaml b/esphome/esp-astroclockstepper1.yaml index 6083da2..ce9af11 100644 --- a/esphome/esp-astroclockstepper1.yaml +++ b/esphome/esp-astroclockstepper1.yaml @@ -6,6 +6,7 @@ # https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-astroclockstepper.yaml #:########################################################################################:# # VERSIONS: +# V1.6 2026-06-22 Fixed auto-position cycle calculation to use rotation_days / solar-year cycle # V1.5 2026-06-22 Changed Motor Stop to OFF on boot and added shortest-path auto-positioning # V1.4 2026-06-22 Added Motor Stop switch, swapped reverse buttons 3/4, and separated auto-position motor direction # V1.3 2026-06-22 Added SNTP year auto-positioning button and restored boot auto-position switch @@ -53,6 +54,8 @@ # - No holding torque is used. # - Web template switches mimic held physical buttons. # - Manual movement only applies while a physical button or web switch is held/on. +# - Manual forward increases the remembered year position. +# - Manual reverse decreases the remembered year position. # - Position counter wraps back to zero after one full rotation. # - Onboard D1 Mini LED flashes briefly every time a motor step is issued. # - After WiFi connects, the onboard LED flashes the DHCP IPv4 address. @@ -60,6 +63,7 @@ # - A digit of 0 is represented as 10 flashes. # - SNTP is used for current year-position calculation. # - User should manually align the dial to year-zero, then press Zero Position Counter. +# - Auto Position Now calculates the target using the configured 365.2422-day rotation cycle. # - Auto Position Now moves to the current calculated year position by the shortest path. # - Auto Position can move clockwise or anti-clockwise, whichever is quicker. # - Auto-position motor direction is separately adjustable from normal/manual movement. @@ -98,7 +102,7 @@ substitutions: # Project Naming project_name: "zorruno.Astronomical Clock Stepper" - project_version: "v1.5" + project_version: "v1.6" # Passwords & Secrets (Unfortunately, you cannot use substitutions inside secret names) api_key: !secret esp-api_key @@ -528,6 +532,11 @@ globals: restore_value: no initial_value: "1" + - id: auto_position_cycle_seconds + type: double + restore_value: no + initial_value: "0.0" + #:########################################################################################:# # OUTPUT: @@ -622,6 +631,9 @@ script: const int STEPS_PER_ROTATION = ${steps_per_rotation}; const bool AUTO_POSITION_USE_SHORTEST_PATH = ${auto_position_use_shortest_path}; + const double ROTATION_SECONDS = + ${rotation_days} * 24.0 * 60.0 * 60.0; + auto now = id(sntp_time).now(); if (!now.is_valid()) { @@ -642,8 +654,6 @@ script: ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); - const int days_in_year = is_leap_year ? 366 : 365; - const int days_before_month_common[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; @@ -676,17 +686,23 @@ script: (is_leap_year ? days_before_month_leap[safe_month - 1] : days_before_month_common[safe_month - 1]) + safe_day_of_month; - const uint32_t seconds_elapsed_this_year = + const uint32_t seconds_elapsed_this_calendar_year = ((uint32_t) (day_of_year - 1) * 86400UL) + ((uint32_t) now.hour * 3600UL) + ((uint32_t) now.minute * 60UL) + ((uint32_t) now.second); - const double seconds_in_year = (double) days_in_year * 86400.0; + // The date/time gives seconds since the local year-zero mark. + // The dial cycle itself is the configured solar-year length, not 365 or 366 days. + double cycle_seconds = + fmod((double) seconds_elapsed_this_calendar_year, ROTATION_SECONDS); + + if (cycle_seconds < 0.0) { + cycle_seconds += ROTATION_SECONDS; + } int target_step = - (int) (((double) seconds_elapsed_this_year / seconds_in_year) * - (double) STEPS_PER_ROTATION); + (int) ((cycle_seconds / ROTATION_SECONDS) * (double) STEPS_PER_ROTATION); target_step = target_step % STEPS_PER_ROTATION; @@ -713,12 +729,13 @@ script: id(auto_position_target_step) = target_step; id(auto_position_steps_remaining) = chosen_steps; id(auto_position_logical_direction) = chosen_logical_direction; + id(auto_position_cycle_seconds) = cycle_seconds; if (chosen_steps == 0) { id(auto_position_active) = false; ESP_LOGI( "auto_position", - "Already at correct year position. Year: %d, target step: %d.", + "Already at correct solar-year position. Year: %d, target step: %d.", year, target_step ); @@ -729,10 +746,11 @@ script: ESP_LOGI( "auto_position", - "Auto positioning started. Year: %d, day_of_year: %d/%d, target step: %d, current step: %d, forward steps: %d, reverse steps: %d, chosen direction: %s, moving %d logical steps.", + "Auto positioning started. Year: %d, day_of_year: %d, cycle_seconds: %.2f / %.2f, target step: %d, current step: %d, forward steps: %d, reverse steps: %d, chosen direction: %s, moving %d logical steps.", year, day_of_year, - days_in_year, + cycle_seconds, + ROTATION_SECONDS, target_step, current_step, forward_steps, @@ -997,6 +1015,9 @@ button: - globals.set: id: auto_position_logical_direction value: "1" + - globals.set: + id: auto_position_cycle_seconds + value: "0.0" - logger.log: level: INFO format: "Position counter zeroed." @@ -1099,6 +1120,16 @@ sensor: lambda: |- return ((double) id(auto_position_target_step) * ${rotation_days}) / ${steps_per_rotation}; + - platform: template + name: "Auto Position Cycle Days" + id: auto_position_cycle_days_sensor + icon: mdi:calendar-today + unit_of_measurement: "days" + accuracy_decimals: 4 + update_interval: "${sensor_update_interval}" + lambda: |- + return id(auto_position_cycle_seconds) / 86400.0; + #:########################################################################################:# # TEXT SENSOR: