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

1#!/usr/bin/env python3 

2""" 

3rasp-shutter 制御用設定定数 

4 

5時間定数、パス定数など制御に関わる設定を集約管理します。 

6""" 

7 

8import os 

9import pathlib 

10 

11import my_lib.webapp.config 

12 

13 

14def _get_stat_dir() -> pathlib.Path: 

15 """STAT_DIR_PATHを動的に取得(Noneの場合はデフォルトパスを返す) 

16 

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") 

23 

24 

25# ====================================================================== 

26# パス定数(プロパティ形式 - 動的評価) 

27# ====================================================================== 

28class _DynamicPath(os.PathLike[str]): 

29 """動的に評価されるPathプロパティ 

30 

31 モジュールレベル定数として使用しながら、アクセス時に 

32 my_lib.webapp.config.STAT_DIR_PATH を参照する。 

33 

34 os.PathLike[str] を継承しているため、pathlib.Path() で変換可能。 

35 """ 

36 

37 def __init__(self, subpath: str): 

38 self._subpath = subpath 

39 

40 def __fspath__(self) -> str: 

41 return str(_get_stat_dir() / self._subpath) 

42 

43 def __truediv__(self, other: str) -> pathlib.Path: 

44 return pathlib.Path(self) / other 

45 

46 def __str__(self) -> str: 

47 return self.__fspath__() 

48 

49 def __repr__(self) -> str: 

50 return f"_DynamicPath({self._subpath!r})" 

51 

52 @property 

53 def parent(self) -> pathlib.Path: 

54 return pathlib.Path(self).parent 

55 

56 def exists(self) -> bool: 

57 return pathlib.Path(self).exists() 

58 

59 def unlink(self, missing_ok: bool = False) -> None: 

60 pathlib.Path(self).unlink(missing_ok=missing_ok) 

61 

62 def to_path(self) -> pathlib.Path: 

63 """pathlib.Pathとして返す(型チェッカー対応用)""" 

64 return pathlib.Path(self) 

65 

66 

67STAT_PENDING_OPEN = _DynamicPath("pending/open") 

68STAT_AUTO_CLOSE = _DynamicPath("auto/close") 

69 

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 

81 

82# ====================================================================== 

83# 経過時間定数(秒) 

84# ====================================================================== 

85# 暗くて開けるのを延期中と判定する最大経過時間(6時間) 

86ELAPSED_PENDING_OPEN_MAX_SEC = 6 * 60 * 60 

87# 自動で閉めた履歴の有効期間(12時間) 

88ELAPSED_AUTO_CLOSE_MAX_SEC = 12 * 60 * 60 

89 

90# ====================================================================== 

91# 制御間隔定数 

92# ====================================================================== 

93# この時間(分)内では自動制御で開閉しない 

94EXEC_INTERVAL_AUTO_MIN = 2 

95# この時間(時間)内に同じ制御がスケジューラで再度リクエストされた場合、実行をやめる 

96EXEC_INTERVAL_SCHEDULE_HOUR = 12 

97# この時間(分)内に同じ制御が手動で再度リクエストされた場合、実行をやめる 

98EXEC_INTERVAL_MANUAL_MINUTES = 1 

99 

100 

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 

110 

111 

112# ====================================================================== 

113# パス生成関数 

114# ====================================================================== 

115def get_exec_stat_path(state: str, index: int) -> pathlib.Path: 

116 """制御実行状態ファイルのパスを取得 

117 

118 Args: 

119 ---- 

120 state: シャッター状態 ("open" または "close") 

121 index: シャッターのインデックス 

122 

123 Returns: 

124 ------- 

125 pathlib.Path: 状態ファイルのパス 

126 

127 """ 

128 return _get_stat_dir() / "exe" / f"{index}_{state}"