初始化奇妙小屏幕控制器项目

This commit is contained in:
2026-09-08 22:56:52 +08:00
commit 8d368de3b5
491 changed files with 67678 additions and 0 deletions
@@ -0,0 +1,207 @@
from __future__ import annotations
import math
from dataclasses import dataclass
from decimal import Decimal, ROUND_FLOOR
LOW_VOLTAGE_CRITICAL_THRESHOLD = 4.5
LOW_VOLTAGE_LIMIT_THRESHOLD = 4.8
LOW_VOLTAGE_CRITICAL_BRIGHTNESS_PERCENT = 35
PROTECTION_MODE_DISABLED = "disabled"
PROTECTION_MODE_UNAVAILABLE = "unavailable"
PROTECTION_MODE_INACTIVE = "inactive"
PROTECTION_MODE_LIMITING = "limiting"
PROTECTION_MODE_CRITICAL = "critical"
NORMAL_SAMPLING_INTERVAL_SECONDS = 5.0
LIMITING_SAMPLING_INTERVAL_SECONDS = 1.0
FIRST_CRITICAL_SAMPLING_INTERVAL_SECONDS = 0.5
MIN_CRITICAL_SAMPLING_INTERVAL_SECONDS = 0.5
MAX_CRITICAL_SAMPLING_INTERVAL_SECONDS = 2.0
MAX_CRITICAL_SLOWDOWN_STEP_SECONDS = 0.5
ERROR_RETRY_INTERVALS_SECONDS = (1.0, 2.0, 5.0)
@dataclass(frozen=True)
class LowVoltageProtectionDirective:
sequence: int
enabled: bool
mode: str
brightness_limit_percent: int | None
reading_stale: bool
def brightness_limit_for_voltage(volts: float) -> int | None:
"""Return the output cap for a calibrated, unrounded voltage reading."""
voltage = float(volts)
if not math.isfinite(voltage):
raise ValueError("voltage must be finite")
if voltage > LOW_VOLTAGE_LIMIT_THRESHOLD:
return None
if voltage < LOW_VOLTAGE_CRITICAL_THRESHOLD:
return LOW_VOLTAGE_CRITICAL_BRIGHTNESS_PERCENT
if voltage == LOW_VOLTAGE_LIMIT_THRESHOLD:
return 100
if voltage == LOW_VOLTAGE_CRITICAL_THRESHOLD:
return 50
decimal_voltage = Decimal(str(voltage))
limit = int(
(
Decimal(50)
+ Decimal(50)
* (decimal_voltage - Decimal("4.5"))
/ Decimal("0.3")
).to_integral_value(rounding=ROUND_FLOOR)
)
return max(50, min(100, limit))
def protection_directive_for_voltage(
sequence: int,
enabled: bool,
volts: float | None,
*,
reading_stale: bool = False,
) -> LowVoltageProtectionDirective:
if not enabled:
return LowVoltageProtectionDirective(
sequence=sequence,
enabled=False,
mode=PROTECTION_MODE_DISABLED,
brightness_limit_percent=None,
reading_stale=False,
)
if volts is None:
return LowVoltageProtectionDirective(
sequence=sequence,
enabled=True,
mode=PROTECTION_MODE_UNAVAILABLE,
brightness_limit_percent=None,
reading_stale=reading_stale,
)
limit = brightness_limit_for_voltage(volts)
if volts > LOW_VOLTAGE_LIMIT_THRESHOLD:
mode = PROTECTION_MODE_INACTIVE
limit = None
elif volts < LOW_VOLTAGE_CRITICAL_THRESHOLD:
mode = PROTECTION_MODE_CRITICAL
else:
mode = PROTECTION_MODE_LIMITING
return LowVoltageProtectionDirective(
sequence=sequence,
enabled=True,
mode=mode,
brightness_limit_percent=limit,
reading_stale=reading_stale,
)
def same_protection_level(
left: LowVoltageProtectionDirective,
right: LowVoltageProtectionDirective,
) -> bool:
return (
left.enabled == right.enabled
and left.mode == right.mode
and left.brightness_limit_percent == right.brightness_limit_percent
)
def is_more_restrictive(
candidate: LowVoltageProtectionDirective,
current: LowVoltageProtectionDirective,
) -> bool:
ranks = {
PROTECTION_MODE_DISABLED: 0,
PROTECTION_MODE_UNAVAILABLE: 0,
PROTECTION_MODE_INACTIVE: 0,
PROTECTION_MODE_LIMITING: 1,
PROTECTION_MODE_CRITICAL: 2,
}
candidate_rank = ranks[candidate.mode]
current_rank = ranks[current.mode]
if candidate_rank != current_rank:
return candidate_rank > current_rank
if candidate.mode == PROTECTION_MODE_LIMITING:
assert candidate.brightness_limit_percent is not None
assert current.brightness_limit_percent is not None
return candidate.brightness_limit_percent < current.brightness_limit_percent
return False
def more_conservative(
left: LowVoltageProtectionDirective,
right: LowVoltageProtectionDirective,
) -> LowVoltageProtectionDirective:
"""Choose the stricter directive while retaining the newest sequence on a tie."""
if is_more_restrictive(left, right):
return left
if is_more_restrictive(right, left):
return right
return right if right.sequence >= left.sequence else left
def error_retry_interval(consecutive_errors: int) -> float:
if consecutive_errors <= 0:
return NORMAL_SAMPLING_INTERVAL_SECONDS
index = min(consecutive_errors, len(ERROR_RETRY_INTERVALS_SECONDS)) - 1
return ERROR_RETRY_INTERVALS_SECONDS[index]
def successful_sampling_interval(
*,
enabled: bool,
mode: str,
volts: float,
previous_volts: float | None,
elapsed_seconds: float | None,
previous_interval_seconds: float,
first_critical_sample: bool,
) -> float:
"""Return the next group-start interval for a successful voltage sample."""
if not enabled:
return NORMAL_SAMPLING_INTERVAL_SECONDS
if mode == PROTECTION_MODE_LIMITING:
return LIMITING_SAMPLING_INTERVAL_SECONDS
if mode == PROTECTION_MODE_CRITICAL:
if first_critical_sample:
return FIRST_CRITICAL_SAMPLING_INTERVAL_SECONDS
rate = _voltage_rate(volts, previous_volts, elapsed_seconds)
target = _clamp(
MIN_CRITICAL_SAMPLING_INTERVAL_SECONDS,
MAX_CRITICAL_SAMPLING_INTERVAL_SECONDS,
0.02 / max(abs(rate), 0.01),
)
if target > previous_interval_seconds:
return min(
target,
previous_interval_seconds + MAX_CRITICAL_SLOWDOWN_STEP_SECONDS,
)
return target
if mode == PROTECTION_MODE_INACTIVE:
rate = _voltage_rate(volts, previous_volts, elapsed_seconds)
if rate < 0:
seconds_to_limit = (volts - LOW_VOLTAGE_LIMIT_THRESHOLD) / -rate
return _clamp(1.0, NORMAL_SAMPLING_INTERVAL_SECONDS, seconds_to_limit)
return NORMAL_SAMPLING_INTERVAL_SECONDS
def _voltage_rate(
volts: float,
previous_volts: float | None,
elapsed_seconds: float | None,
) -> float:
if (
previous_volts is None
or elapsed_seconds is None
or not math.isfinite(elapsed_seconds)
or elapsed_seconds <= 0
):
return 0.0
return (volts - previous_volts) / elapsed_seconds
def _clamp(minimum: float, maximum: float, value: float) -> float:
return max(minimum, min(maximum, value))