|
| 1 | +import os |
1 | 2 | import signal
|
2 | 3 | import sys
|
3 | 4 | import threading
|
|
12 | 13 | from sun_forecast_handler import SunForecastHandler
|
13 | 14 | from time_handler import TimeHandler
|
14 | 15 |
|
| 16 | +LOCK_FILE_PATH = "/tmp/inverter_charge_controller.lock" # nosec B108 |
| 17 | + |
15 | 18 | logger = LoggerMixin("Main")
|
16 | 19 |
|
17 | 20 |
|
| 21 | +def lock() -> None: |
| 22 | + """ |
| 23 | + Writes the current process ID to a lock file to indicate the process is active. |
| 24 | + """ |
| 25 | + with open(LOCK_FILE_PATH, "w") as lock_file: |
| 26 | + lock_file.write(str(os.getpid())) |
| 27 | + logger.log.debug("Lock file created") |
| 28 | + |
| 29 | + |
| 30 | +def unlock() -> None: |
| 31 | + """ |
| 32 | + Removes the lock file if it exists and thus unlocking the process. |
| 33 | + """ |
| 34 | + if not os.path.exists(LOCK_FILE_PATH): |
| 35 | + return |
| 36 | + |
| 37 | + os.remove(LOCK_FILE_PATH) |
| 38 | + logger.log.debug("Lock file removed") |
| 39 | + |
| 40 | + |
18 | 41 | def write_solar_forecast_and_history_to_db() -> None:
|
19 | 42 | sun_forecast_handler = SunForecastHandler()
|
20 | 43 | morning_time = time(hour=5, minute=0, second=0, microsecond=0, tzinfo=TimeHandler.get_timezone())
|
@@ -77,25 +100,35 @@ def handle_stop_signal(signal_number: int, _frame: FrameType) -> None:
|
77 | 100 | """
|
78 | 101 | logger.write_newlines_to_log_file()
|
79 | 102 | logger.log.info(f"Received {signal.Signals(signal_number).name}. Exiting now...")
|
80 |
| - inverter_charge_controller.unlock() |
| 103 | + unlock() |
81 | 104 | sys.exit(0)
|
82 | 105 |
|
83 | 106 |
|
84 | 107 | for signal_to_catch in [signal.SIGINT, signal.SIGTERM]:
|
85 | 108 | signal.signal(signal_to_catch, handle_stop_signal)
|
86 | 109 |
|
| 110 | + |
87 | 111 | if __name__ == "__main__":
|
88 |
| - logger.write_newlines_to_log_file() |
89 |
| - started_by_systemd = " by systemd" if EnvironmentVariableGetter.get("INVOCATION_ID", "") else "" |
90 |
| - logger.log.info(f"Starting application{started_by_systemd}") |
| 112 | + if os.path.exists(LOCK_FILE_PATH): |
| 113 | + logger.write_newlines_to_log_file() |
| 114 | + logger.log.error("Attempted to start the inverter charge controller, but it is already running.") |
| 115 | + sys.exit(1) |
| 116 | + |
| 117 | + try: |
| 118 | + lock() |
| 119 | + logger.write_newlines_to_log_file() |
| 120 | + started_by_systemd = " by systemd" if EnvironmentVariableGetter.get("INVOCATION_ID", "") else "" |
| 121 | + logger.log.info(f"Starting application{started_by_systemd}") |
91 | 122 |
|
92 |
| - solar_protocol_thread = threading.Thread(target=write_solar_forecast_and_history_to_db, daemon=True) |
93 |
| - solar_protocol_thread.start() |
| 123 | + solar_protocol_thread = threading.Thread(target=write_solar_forecast_and_history_to_db, daemon=True) |
| 124 | + solar_protocol_thread.start() |
94 | 125 |
|
95 |
| - # Let the thread calculate and log its next wakeup time before logging all the info of the InverterChargeController |
96 |
| - pause.seconds(1) |
| 126 | + # Let the thread calculate and log its next wakeup time before logging all the info of the InverterChargeController |
| 127 | + pause.seconds(1) |
97 | 128 |
|
98 |
| - inverter_charge_controller = InverterChargeController() |
99 |
| - inverter_charge_controller_thread = threading.Thread(target=inverter_charge_controller.start) |
100 |
| - inverter_charge_controller_thread.start() |
101 |
| - inverter_charge_controller_thread.join() |
| 129 | + inverter_charge_controller = InverterChargeController() |
| 130 | + inverter_charge_controller_thread = threading.Thread(target=inverter_charge_controller.start) |
| 131 | + inverter_charge_controller_thread.start() |
| 132 | + inverter_charge_controller_thread.join() |
| 133 | + finally: |
| 134 | + unlock() |
0 commit comments