Coverage for src/controller.py: 97%

50 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-28 11:45 +0000

1#!/usr/bin/env python3 

2""" 

3エアコン室外機の冷却モードの指示を出します。 

4 

5Usage: 

6 cooler_controller.py [-c CONFIG] [-p SERVER_PORT] [-r REAL_PORT] [-N] [-n COUNT] [-t SPEEDUP] [-d] [-D] 

7 

8Options: 

9 -c CONFIG : CONFIG を設定ファイルとして読み込んで実行します。 [default: config.yaml] 

10 -p SERVER_PORT : ZeroMQ の サーバーを動作させるポートを指定します。 [default: 2222] 

11 -r REAL_PORT : ZeroMQ の 本当のサーバーを動作させるポートを指定します。 [default: 2200] 

12 -N : プロキシの動作を行わないようにします。 

13 -n COUNT : n 回制御メッセージを生成したら終了します。0 は制限なし。 [default: 0] 

14 -t SPEEDUP : 時短モード。演算間隔を SPEEDUP 分の一にします。 [default: 1] 

15 -d : 冷却モードをランダムに生成するモードで動作します。 

16 -D : デバッグモードで動作します。 

17""" 

18 

19import logging 

20import os 

21import pathlib 

22import threading 

23import traceback 

24 

25import my_lib.footprint 

26 

27import unit_cooler.controller.engine 

28import unit_cooler.controller.message 

29import unit_cooler.pubsub.publish 

30import unit_cooler.util 

31 

32SCHEMA_CONFIG = "config.schema" 

33 

34 

35def test_client(server_host, server_port): 

36 logging.info("Start test client (host: %s:%d)", server_host, server_port) 

37 unit_cooler.controller.pubsub.start_client( 

38 server_host, 

39 server_port, 

40 lambda message: logging.info("receive: %s", message), 

41 1, 

42 ) 

43 

44 

45# NOTE: Last Value Caching Proxy 

46def cache_proxy_start(server_host, real_port, server_port, msg_count): 

47 thread = threading.Thread( 

48 target=unit_cooler.pubsub.publish.start_proxy, 

49 args=(server_host, real_port, server_port, msg_count), 

50 ) 

51 thread.start() 

52 

53 return thread 

54 

55 

56def gen_control_msg(config, dummy_mode, speedup): 

57 control_msg = unit_cooler.controller.engine.gen_control_msg(config, dummy_mode, speedup) 

58 my_lib.footprint.update(pathlib.Path(config["controller"]["liveness"]["file"])) 

59 

60 return control_msg 

61 

62 

63def control_server_start(config, real_port, dummy_mode, speedup, msg_count): 

64 thread = threading.Thread( 

65 target=unit_cooler.pubsub.publish.start_server, 

66 args=( 

67 real_port, 

68 lambda: gen_control_msg(config, dummy_mode, speedup), 

69 config["controller"]["interval_sec"] / speedup, 

70 msg_count, 

71 ), 

72 ) 

73 thread.start() 

74 

75 return thread 

76 

77 

78def start(config, arg): 

79 setting = { 

80 "server_host": "localhost", 

81 "server_port": 2222, 

82 "real_port": 2200, 

83 "dummy_mode": False, 

84 "disable_proxy": False, 

85 "speedup": 1, 

86 "msg_count": 0, 

87 "debug_mode": False, 

88 } 

89 setting.update(arg) 

90 

91 logging.info("Start controller (port: %d", setting["server_port"]) 

92 

93 if setting["dummy_mode"]: 

94 logging.warning("DUMMY mode") 

95 os.environ["DUMMY_MODE"] = "true" 

96 

97 proxy_thread = None 

98 control_thread = None 

99 try: 

100 if not setting["disable_proxy"]: 

101 proxy_thread = cache_proxy_start( 

102 setting["server_host"], 

103 setting["real_port"], 

104 setting["server_port"], 

105 setting["msg_count"], 

106 ) 

107 

108 control_thread = control_server_start( 

109 config, 

110 setting["real_port"], 

111 setting["dummy_mode"], 

112 setting["speedup"], 

113 setting["msg_count"], 

114 ) 

115 except Exception: 

116 logging.exception("Failed to start controller") 

117 unit_cooler.util.notify_error(config, traceback.format_exc()) 

118 

119 return (control_thread, proxy_thread) 

120 

121 

122def wait_and_term(control_thread, proxy_thread): 

123 if proxy_thread is not None: 

124 proxy_thread.join() 

125 if control_thread is not None: 

126 control_thread.join() 

127 

128 logging.warning("Terminate cooler_controller") 

129 

130 return 0 

131 

132 

133if __name__ == "__main__": 

134 import sys 

135 

136 import docopt 

137 import my_lib.config 

138 import my_lib.logger 

139 

140 args = docopt.docopt(__doc__) 

141 

142 config_file = args["-c"] 

143 server_port = int(os.environ.get("HEMS_SERVER_PORT", args["-p"])) 

144 real_port = int(args["-r"]) 

145 disable_proxy = args["-N"] 

146 msg_count = int(args["-n"]) 

147 speedup = int(args["-t"]) 

148 dummy_mode = os.environ.get("DUMMY_MODE", args["-d"]) 

149 debug_mode = args["-D"] 

150 

151 my_lib.logger.init("hems.unit_cooler", level=logging.DEBUG if debug_mode else logging.INFO) 

152 

153 config = my_lib.config.load(config_file, pathlib.Path(SCHEMA_CONFIG)) 

154 

155 sys.exit( 

156 wait_and_term( 

157 *start( 

158 config, 

159 { 

160 "real_port": real_port, 

161 "server_host": "localhost", 

162 "server_port": server_port, 

163 "dummy_mode": dummy_mode, 

164 "debug_mode": debug_mode, 

165 "disable_proxy": disable_proxy, 

166 "speedup": speedup, 

167 "msg_count": msg_count, 

168 }, 

169 ) 

170 ) 

171 )