Coverage for src / rasp_shutter / control / config.py: 85%
46 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-02-13 00:10 +0900
« prev ^ index » next coverage.py v7.13.1, created at 2026-02-13 00:10 +0900
1#!/usr/bin/env python3
2"""
3rasp-shutter 制御用設定定数
5時間定数、パス定数など制御に関わる設定を集約管理します。
6"""
8import os
9import pathlib
11import my_lib.webapp.config
14def _get_stat_dir() -> pathlib.Path:
15 """STAT_DIR_PATHを動的に取得(Noneの場合はデフォルトパスを返す)
17 NOTE: モジュール読み込み時ではなく、呼び出し時に評価する。
18 これにより、pytest-xdist並列実行時にワーカー固有のパスを使用できる。
19 """
20 if my_lib.webapp.config.STAT_DIR_PATH is not None: 20 ↛ 22line 20 didn't jump to line 22 because the condition on line 20 was always true
21 return my_lib.webapp.config.STAT_DIR_PATH
22 return pathlib.Path("data")
25# ======================================================================
26# パス定数(プロパティ形式 - 動的評価)
27# ======================================================================
28class _DynamicPath(os.PathLike[str]):
29 """動的に評価されるPathプロパティ
31 モジュールレベル定数として使用しながら、アクセス時に
32 my_lib.webapp.config.STAT_DIR_PATH を参照する。
34 os.PathLike[str] を継承しているため、pathlib.Path() で変換可能。
35 """
37 def __init__(self, subpath: str):
38 self._subpath = subpath
40 def __fspath__(self) -> str:
41 return str(_get_stat_dir() / self._subpath)
43 def __truediv__(self, other: str) -> pathlib.Path:
44 return pathlib.Path(self) / other
46 def __str__(self) -> str:
47 return self.__fspath__()
49 def __repr__(self) -> str:
50 return f"_DynamicPath({self._subpath!r})"
52 @property
53 def parent(self) -> pathlib.Path:
54 return pathlib.Path(self).parent
56 def exists(self) -> bool:
57 return pathlib.Path(self).exists()
59 def unlink(self, missing_ok: bool = False) -> None:
60 pathlib.Path(self).unlink(missing_ok=missing_ok)
62 def to_path(self) -> pathlib.Path:
63 """pathlib.Pathとして返す(型チェッカー対応用)"""
64 return pathlib.Path(self)
67STAT_PENDING_OPEN = _DynamicPath("pending/open")
68STAT_AUTO_CLOSE = _DynamicPath("auto/close")
70# ======================================================================
71# 時間帯定数(時)
72# ======================================================================
73# 朝の開始時刻
74HOUR_MORNING_START = 5
75# 自動で開ける処理の終了時刻
76HOUR_AUTO_OPEN_END = 12
77# 暗くて延期されていた開け制御の終了時刻
78HOUR_PENDING_OPEN_END = 13
79# 自動で閉める処理の終了時刻
80HOUR_AUTO_CLOSE_END = 20
82# ======================================================================
83# 経過時間定数(秒)
84# ======================================================================
85# 暗くて開けるのを延期中と判定する最大経過時間(6時間)
86ELAPSED_PENDING_OPEN_MAX_SEC = 6 * 60 * 60
87# 自動で閉めた履歴の有効期間(12時間)
88ELAPSED_AUTO_CLOSE_MAX_SEC = 12 * 60 * 60
90# ======================================================================
91# 制御間隔定数
92# ======================================================================
93# この時間(分)内では自動制御で開閉しない
94EXEC_INTERVAL_AUTO_MIN = 2
95# この時間(時間)内に同じ制御がスケジューラで再度リクエストされた場合、実行をやめる
96EXEC_INTERVAL_SCHEDULE_HOUR = 12
97# この時間(分)内に同じ制御が手動で再度リクエストされた場合、実行をやめる
98EXEC_INTERVAL_MANUAL_MINUTES = 1
101# ======================================================================
102# デフォルトスケジュール値
103# ======================================================================
104DEFAULT_OPEN_TIME = "08:00"
105DEFAULT_CLOSE_TIME = "17:00"
106DEFAULT_OPEN_SOLAR_RAD = 150
107DEFAULT_OPEN_LUX = 1000
108DEFAULT_CLOSE_SOLAR_RAD = 80
109DEFAULT_CLOSE_LUX = 1200
112# ======================================================================
113# パス生成関数
114# ======================================================================
115def get_exec_stat_path(state: str, index: int) -> pathlib.Path:
116 """制御実行状態ファイルのパスを取得
118 Args:
119 ----
120 state: シャッター状態 ("open" または "close")
121 index: シャッターのインデックス
123 Returns:
124 -------
125 pathlib.Path: 状態ファイルのパス
127 """
128 return _get_stat_dir() / "exe" / f"{index}_{state}"