Coverage for src/controller.py: 97%
50 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-28 11:45 +0000
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-28 11:45 +0000
1#!/usr/bin/env python3
2"""
3エアコン室外機の冷却モードの指示を出します。
5Usage:
6 cooler_controller.py [-c CONFIG] [-p SERVER_PORT] [-r REAL_PORT] [-N] [-n COUNT] [-t SPEEDUP] [-d] [-D]
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"""
19import logging
20import os
21import pathlib
22import threading
23import traceback
25import my_lib.footprint
27import unit_cooler.controller.engine
28import unit_cooler.controller.message
29import unit_cooler.pubsub.publish
30import unit_cooler.util
32SCHEMA_CONFIG = "config.schema"
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 )
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()
53 return thread
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"]))
60 return control_msg
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()
75 return thread
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)
91 logging.info("Start controller (port: %d", setting["server_port"])
93 if setting["dummy_mode"]:
94 logging.warning("DUMMY mode")
95 os.environ["DUMMY_MODE"] = "true"
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 )
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())
119 return (control_thread, proxy_thread)
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()
128 logging.warning("Terminate cooler_controller")
130 return 0
133if __name__ == "__main__":
134 import sys
136 import docopt
137 import my_lib.config
138 import my_lib.logger
140 args = docopt.docopt(__doc__)
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"]
151 my_lib.logger.init("hems.unit_cooler", level=logging.DEBUG if debug_mode else logging.INFO)
153 config = my_lib.config.load(config_file, pathlib.Path(SCHEMA_CONFIG))
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 )