-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutility_manager.py
More file actions
229 lines (186 loc) · 9.29 KB
/
Copy pathutility_manager.py
File metadata and controls
229 lines (186 loc) · 9.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
import os
import sqlite3
from datetime import datetime, timezone
# Safely import the Telegram function from the main app without breaking things
try:
from app import send_telegram_alert
except ImportError:
print("Warning: Could not import send_telegram_alert from app.py")
def send_telegram_alert(msg, reply_to_message_id=None):
print(f"[MOCK TELEGRAM] {msg}")
return None
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
DB_PATH = os.path.join(BASE_DIR, 'maintenance.db')
def check_machine_maintenance(machine_id, current_hrs, last_service_date_str=None):
"""
Checks if a machine requires maintenance based on its configured intervals.
Implements a 'whichever comes first' logic between usage (hours) and time (days).
:param machine_id: The ID linking to the machine in the DB
:param current_hrs: The total hours run since the last service
:param last_service_date_str: ISO string of the date the machine was last serviced
"""
try:
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
# Get all configurations for this machine (can be multiple, e.g. Half & Full)
configs = conn.execute(
"SELECT * FROM machine_config WHERE machine_id = ?",
(machine_id,)
).fetchall()
if not configs:
print(f"No configuration found for machine {machine_id}")
conn.close()
return
now = datetime.now(timezone.utc)
# Calculate days since last service
days_passed = None
if last_service_date_str:
try:
last_dt = datetime.fromisoformat(last_service_date_str.replace('Z', '+00:00'))
days_passed = (now - last_dt).days
except ValueError:
print(f"Invalid date format: {last_service_date_str}")
for config in configs:
machine_name = config['machine_name']
service_type = config['service_type']
# --- Check Usage (Hours) ---
hrs_alert_level = 0 # 0 = none, 1 = warning 1, 2 = warning 2, 3 = due
if config['interval_hrs'] and current_hrs is not None:
interval = config['interval_hrs']
n1 = config['notify_1_hrs_before'] or 0
n2 = config['notify_2_hrs_before'] or 0
if current_hrs >= interval:
hrs_alert_level = 3
elif current_hrs >= (interval - n2):
hrs_alert_level = 2
elif current_hrs >= (interval - n1):
hrs_alert_level = 1
# --- Check Time (Days) ---
days_alert_level = 0
if config['interval_days'] and days_passed is not None:
interval = config['interval_days']
n1 = config['notify_1_days_before'] or 0
n2 = config['notify_2_days_before'] or 0
if days_passed >= interval:
days_alert_level = 3
elif days_passed >= (interval - n2):
days_alert_level = 2
elif days_passed >= (interval - n1):
days_alert_level = 1
# --- Whichever Comes First Logic ---
final_alert_level = max(hrs_alert_level, days_alert_level)
if final_alert_level > 0:
cause_str = ""
if final_alert_level == hrs_alert_level and final_alert_level == days_alert_level:
cause_str = f"Usage ({current_hrs} hrs) and Time ({days_passed} days)"
elif final_alert_level == hrs_alert_level:
cause_str = f"Usage ({current_hrs} hrs)"
else:
cause_str = f"Time ({days_passed} days)"
alert_type = "DUE FOR" if final_alert_level == 3 else "UPCOMING"
urgency = "🚨" if final_alert_level == 3 else ("⚠️" if final_alert_level == 2 else "ℹ️")
msg = f"{urgency} {alert_type} MAINTENANCE: {machine_name}\n"
msg += f"Service Type: {service_type}\n"
msg += f"Triggered by: {cause_str}\n"
if config['interval_hrs']:
msg += f"- Usage Limit: {config['interval_hrs']} hrs\n"
if config['interval_days']:
msg += f"- Time Limit: {config['interval_days']} days\n"
send_telegram_alert(msg)
print(f"Alert sent for {machine_name} ({service_type}): Level {final_alert_level}")
else:
print(f"Machine {machine_name} ({service_type}) is within safe limits.")
conn.close()
except Exception as e:
print(f"Error in utility_manager: {e}")
def generate_daily_report():
import json
try:
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
# Get all machines
machines = conn.execute("SELECT * FROM machines").fetchall()
# Mocking some current hours for demonstration, in a real scenario this would come from an external system
import random
random.seed(datetime.now().strftime("%Y-%m-%d")) # keep it deterministic per day
report_data = []
now = datetime.now(timezone.utc)
for m in machines:
machine_id = m['id']
machine_name = m['name']
asset_tag = m['asset_tag']
last_maint = m['last_maintenance'] # e.g. '2026-05-15'
# mock hours between 0 and 7000
current_hrs = random.randint(100, 6500)
days_passed = None
if last_maint:
try:
last_dt = datetime.fromisoformat(last_maint)
# convert naive to utc
last_dt = last_dt.replace(tzinfo=timezone.utc)
days_passed = (now - last_dt).days
except Exception as e:
pass
configs = conn.execute(
"SELECT * FROM machine_config WHERE machine_id = ?",
(machine_id,)
).fetchall()
machine_alerts = []
for config in configs:
service_type = config['service_type']
hrs_alert_level = 0
if config['interval_hrs'] and current_hrs is not None:
interval = config['interval_hrs']
n1 = config['notify_1_hrs_before'] or 0
n2 = config['notify_2_hrs_before'] or 0
if current_hrs >= interval:
hrs_alert_level = 3
elif current_hrs >= (interval - n2):
hrs_alert_level = 2
elif current_hrs >= (interval - n1):
hrs_alert_level = 1
days_alert_level = 0
if config['interval_days'] and days_passed is not None:
interval = config['interval_days']
n1 = config['notify_1_days_before'] or 0
n2 = config['notify_2_days_before'] or 0
if days_passed >= interval:
days_alert_level = 3
elif days_passed >= (interval - n2):
days_alert_level = 2
elif days_passed >= (interval - n1):
days_alert_level = 1
final_alert_level = max(hrs_alert_level, days_alert_level)
if final_alert_level > 0:
machine_alerts.append({
"service_type": service_type,
"alert_level": final_alert_level,
"hrs_alert_level": hrs_alert_level,
"days_alert_level": days_alert_level,
"current_hrs": current_hrs,
"days_passed": days_passed,
"interval_hrs": config['interval_hrs'],
"interval_days": config['interval_days']
})
if machine_alerts:
report_data.append({
"machine_id": machine_id,
"machine_name": machine_name,
"asset_tag": asset_tag,
"last_maintenance": last_maint,
"alerts": machine_alerts
})
conn.close()
output_path = os.path.join(BASE_DIR, 'frontend', 'public', 'utility_report.json')
os.makedirs(os.path.dirname(output_path), exist_ok=True)
with open(output_path, 'w') as f:
json.dump({
"generated_at": now.isoformat(),
"reports": report_data
}, f, indent=2)
print(f"Daily report generated at {output_path}")
except Exception as e:
print(f"Error generating daily report: {e}")
if __name__ == '__main__':
generate_daily_report()
print("Testing utility_manager module loaded and report generated.")