-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvigilant_tracker_main.py
More file actions
422 lines (369 loc) · 16 KB
/
Copy pathvigilant_tracker_main.py
File metadata and controls
422 lines (369 loc) · 16 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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
import random
import time
from vigilant_tracker_sensor import UltrasonicSensor, CameraSensor, RadarSensor, TemperatureSensor, SpeedSensor
from loading_animation import loadingAnimation
def displayArray(sensorArray, status, metricSwitched):
"""
Displays formatted sensor data in a table-like structure with color-coded health indicators.
Args:
sensorArray (list): Array of sensor objects containing ID, health, temperature, and speed data
status (str): Current vehicle status (e.g., "Active", "IDLE")
metricSwitched (bool): True for metric units (C, KP/H), False for imperial (F, MP/H)
"""
# ANSI Color Codes for Terminal Output
GREEN = "\033[32m"
YELLOW = "\033[33m"
RED = "\033[31m"
print("\nSensor ID:", end=" ")
for i in range(len(sensorArray)):
print(f"| {GREEN}{sensorArray[i].sensorID}", end=f"{RESET} | ")
print("\n\nStatus:", end=" ")
for j in range(len(sensorArray)):
if(sensorArray[j].system_health < 5):
print(f"| {GREEN}Inactive", end=f"{RESET} | ")
else:
print(f"| {GREEN}{status}", end=f"{RESET} | ")
print("\n\nHealth:", end=" ")
for k in range(len(sensorArray)):
if(sensorArray[k].system_health >= 50):
print(f"| {GREEN}{sensorArray[k].system_health}%", end=f"{RESET} | ")
elif(sensorArray[k].system_health < 50 and sensorArray[k].system_health >= 5):
print(f"| {YELLOW}{sensorArray[k].system_health}%", end=f"{RESET} | ")
else:
print(f"| {RED}{sensorArray[k].system_health}%", end=f"{RESET} | ")
print("\n\nTemp:", end=" ")
for a in range(len(sensorArray)):
if(a == 3):
if(sensorArray[a].system_health < 5):
print(f"| {RED}ISSUE", end=f"{RESET} | ")
else:
if(sensorArray[a].currentTemp < 100):
if(not metricSwitched):
print(f"| {GREEN}{str(sensorArray[a].currentTemp)} F", end=f"{RESET} | ")
else:
print(f"| {GREEN}{str(round(convertDegree(sensorArray[a].currentTemp)))} C", end=f"{RESET} | ")
else:
if(not metricSwitched):
print(f"| {RED}{str(sensorArray[a].currentTemp)} F", end=f"{RESET} | ")
else:
print(f"| {RED}{str(round(convertDegree(sensorArray[a].currentTemp)))} C", end=f"{RESET} | ")
else:
print("| N/A", end=" | ")
print("\n\nSpeed:", end=" ")
for b in range(len(sensorArray)):
if(b == 4):
if(sensorArray[b].system_health < 5):
print(f"| {RED}ISSUE", end=f"{RESET} | ")
else:
if(sensorArray[b].currentSpeed < 80):
if(not metricSwitched):
print(f"| {GREEN}{sensorArray[b].currentSpeed} MP/H", end=f"{RESET} | ")
else:
print(f"| {GREEN}{str(round(convertSpeed(sensorArray[b].currentSpeed)))} KP/H", end=f"{RESET} | ")
else:
if(not metricSwitched):
print(f"| {RED}{sensorArray[b].currentSpeed} MP/H", end=f"{RESET} | ")
else:
print(f"| {RED}{str(round(convertSpeed(sensorArray[b].currentSpeed)))} KP/H", end=f"{RESET} | ")
else:
print("| N/A", end=" | ")
print()
def updateArray(sensorArray, count, initialTimer, currentTimer):
"""
Updates sensor health, temperature, and speed values with random variations to simulate real-time changes.
Args:
sensorArray (list): Array of sensor objects to update
count (int): Counter tracking number of critical sensors (health < 5%)
Returns:
int: Updated count of critical sensors, or 0 if none are critical
"""
if(not check and sensorArray[4].currentSpeed >= 20):
sensorArray[4].setSpeed(0)
if(not check and sensorArray[3].currentTemp < 90):
sensorArray[3].changeTemperature(90)
# realistic runtime system health updater
for e in range(len(sensorArray)):
if(not check):
sensorArray[e].fixSystemHealth()
if(sensorArray[e].system_health >= 5):
flip = random.randint(0, 1)
if(flip == 0):
sensorArray[e].decreaseSystemHealth(random.randint(0, 1))
else:
count += 1
if(count >= 5):
return count
flip = random.randint(0, 1)
# temperature control (realistically random)
if(flip == 0):
if(sensorArray[3].currentTemp < 180):
sensorArray[3].changeTemperature(sensorArray[3].currentTemp + random.randint(0, 2))
else:
sensorArray[3].changeTemperature(sensorArray[3].currentTemp / 2)
else:
if(sensorArray[3].currentTemp >= 15):
krand = random.randint(0, 1)
if(krand == 1):
sensorArray[3].changeTemperature(sensorArray[3].currentTemp - random.randint(0, 2))
else:
sensorArray[3].changeTemperature(sensorArray[3].currentTemp + random.randint(60, 100))
# speed control (increases in the first half then decreases in the second half)
flip = 0 if (currentTimer < (initialTimer / 2)) else 1
if (currentTimer == 0): # the vehicle must start from 0 speed
sensorArray[4].setSpeed(0)
if (flip == 0):
if (sensorArray[4].currentSpeed >= 3):
sensorArray[4].setSpeed(sensorArray[4].currentSpeed - random.randint(0, 3))
else:
if (sensorArray[4].currentSpeed < 165):
sensorArray[4].setSpeed(sensorArray[4].currentSpeed + random.randint(0, 3))
else:
sensorArray[4].setSpeed(sensorArray[4].currentSpeed - random.randint(10, 25))
return 0
def move_cursor_up(lines):
"""
Moves terminal cursor up by specified number of lines using ANSI escape codes.
Args:
lines (int): Number of lines to move cursor up
"""
print(f"\033[{lines}A", end='')
def move_cursor_down(lines):
"""
Moves terminal cursor down by specified number of lines using ANSI escape codes.
Args:
lines (int): Number of lines to move cursor down
"""
print(f"\033[{lines}B", end='')
def delayFunc():
"""
Pauses program execution for 1 second.
"""
time.sleep(1)
def fixFormat(userStr):
"""
Capitalizes the first letter of each word in a string.
Args:
userStr (str): Input string to format
Returns:
str: Formatted string with each word capitalized
"""
newStr = list(userStr.capitalize())
for r in range(1, len(newStr)):
if(newStr[r - 1] == " "):
newStr[r] = newStr[r].upper()
return "".join(newStr)
def introOutroAnimation(status):
"""
Displays an animated loading message for vehicle state transitions.
Args:
status (str): Vehicle status - "Active" for starting, any other value for stopping
"""
for seconds in range(0, 3):
if(status == "Active"):
print(f"\rStarting Vehicle to Motion{'.' * (seconds + 1)} ", end = " ")
else:
print(f"\rStopping Vehicle from Motion{'.' * (seconds + 1)} ", end=" ")
time.sleep(1)
def updateAveTemp(aveTemp):
"""
Adds current temperature reading to cumulative average temperature.
Args:
aveTemp (float): Current cumulative temperature sum
Returns:
float: Updated cumulative temperature sum
"""
aveTemp += sensorArray[3].currentTemp
return aveTemp
def updateAveSpeed(aveSpeed):
"""
Adds current speed reading to cumulative average speed.
Args:
aveSpeed (float): Current cumulative speed sum
Returns:
float: Updated cumulative speed sum
"""
aveSpeed += sensorArray[4].currentSpeed
return aveSpeed
def convertDegree(currentTemp):
"""
Converts temperature from Fahrenheit to Celsius.
Args:
currentTemp (float): Temperature in Fahrenheit
Returns:
float: Temperature in Celsius
"""
return (currentTemp - 32) * (5/9)
def convertSpeed(currentSpeed):
"""
Converts speed from miles per hour to kilometers per hour.
Args:
currentSpeed (float): Speed in MP/H
Returns:
float: Speed in KP/H
"""
return currentSpeed * 1.609
def reprompt_for_errors(user_response):
"""
Confirms user input and allows them to re-enter if incorrect.
Args:
user_response (str, int, or bool): The original input from the user to confirm
Returns:
str: The confirmed or corrected user input
"""
while True:
# Ask for confirmation
confirmation = input(f"You entered: '{user_response.capitalize() if isinstance(user_response, str) else user_response}'. "
f"Is this correct? (yes/no): ").lower().strip()
# Validate yes/no response
if confirmation == "yes" or confirmation == "y":
return user_response
elif confirmation == "no" or confirmation == "n":
# Ask user to re-enter
user_response = input("Please re-enter your response: ").strip()
else:
# Invalid response, ask again
print("Invalid input. Please enter 'yes' or 'no'.")
# ========================================
# GLOBAL VARIABLES
# ========================================
sensorArray = [UltrasonicSensor(), CameraSensor(), RadarSensor(), TemperatureSensor(), SpeedSensor()]
metricSwitched = False
BRIGHT_MAGENTA = "\033[95m"
BG_YELLOW = "\033[43m"
BLUE = "\033[34m"
BOLD = "\033[1m"
RESET = "\033[0m"
# ========================================
# PROGRAM INTRODUCTION
# ========================================
print("\t\t\t\tVigilantTrack: Dynamic Vehicle Health Monitor\n")
print("In this program, you will add one vehicle of your choice to do a sensor reading where you will see the sensor data live (as it is changing).")
print("If all the sensor's health percent were to reach below 5%, the vehicle would stop immediately and give you the next steps.")
print("The vehicle would be in motion and active while the sensor reading is in progress.")
print("Simulation has been SCALED, meaning the health of the sensor goes down faster than in real-life for a quicker analysis and better gist.\n")
print("Advanced Feature Overview:\n> Predictive Maintenance Module\n> Adaptive Sensor Calibration\n> Fault Tolerant Framework\n> Real-time Data Visualization\n> Sensor Fusion Algorithm\n")
# ========================================
# USER INPUT: VEHICLE DETAILS
# ========================================
make = fixFormat(input("Enter the make of the vehicle: "))
make = reprompt_for_errors(make).capitalize()
model = fixFormat(input("Enter the model of the vehicle: "))
model = reprompt_for_errors(model).capitalize()
electric = fixFormat(input(f"Is the {make} {model} electric (True/False): "))
while(electric != "True" and electric != "False"):
electric = fixFormat(input("Make sure to enter either True or False: "))
electric = reprompt_for_errors(electric)
color = fixFormat(input(f"What color is the {make} {model}: "))
while(color.isdigit()):
color = fixFormat(input("Please enter a valid color. A color cannot be expressed in numbers: "))
color = reprompt_for_errors(color).capitalize()
while True:
try:
year = int(input(f"What year is the {make} {model}: "))
while(year < 1880 or year > 2030):
year = int(input(f"Please enter a valid year for {make} {model}: "))
year = reprompt_for_errors(year)
break
except ValueError:
print("You entered string instead of numbers. Please enter the year again.\n")
continue
# ========================================
# DISPLAY VEHICLE DATA
# ========================================
loadingAnimation()
# Vehicle detail printed in an arrowhead format
print(f"\n\nVEHICLE DATA:\n\t\t\t[Vehicle Make: {make}]\n\n\t\t\t\t\t\t[Vehicle Model: {model}]\n\n\t\t\t\t\t\t\t\t\t[Electric: {electric}]\n\n\t\t\t\t\t\t[Vehicle Color: {color}]\n\n\t\t\t[Vehicle Year: {year}]\n\n")
# ========================================
# USER INPUT: SENSOR READING CONFIGURATION
# ========================================
# Get duration and metric performance
while True:
try:
num = int(input("How long do you want the sensor reading to measure for in seconds (>0): "))
initialNum = num
while(initialNum == 0):
initialNum = int(input("Input must not be 0. Only seconds greater than 0 are accepted: "))
try:
needMetric = (input("Type 'True' for metric convertion (KP/H, C) or press enter for default (MP/H, F): ")).lower()
if(needMetric == "true"):
metricSwitched = True
except ValueError:
print("Type either 'True' or 'False'. No other input is accepted.")
break
except ValueError:
print("Cannot input string instead of numbers. Try again\n")
# ========================================
# SENSOR MONITORING LOOP
# ========================================
status = "Active"
introOutroAnimation(status)
# Display header
print(f"\n\n{BLUE}{year} {make} {model} (before complete){RESET}:")
print("\t UltraSonic Camera Radar Temperature Speed")
aveSpeed = aveTemp = 0
check = False
count = 0
# Real-time sensor monitoring
while (num > 0):
# Display countdown timer
print(f"\r{BOLD}{BRIGHT_MAGENTA}{BG_YELLOW}{int(num / 60)} minute(s) and {num % 60} second(s) remain{RESET}",end=" ")
# Update sensor data
count = updateArray(sensorArray, count, initialNum, num)
aveTemp = updateAveTemp(aveTemp)
aveSpeed = updateAveSpeed(aveSpeed)
# Check if all sensors are critical
if (count >= 5):
allSensorsDown = displayArray(sensorArray, status, metricSwitched)
break
else:
# Display current sensor readings
displayArray(sensorArray, status, metricSwitched)
check = True
delayFunc()
num -= 1
# Move cursor up for live animation effect
if (num != 0):
move_cursor_up(10)
# ========================================
# POST-MONITORING SUMMARY
# ========================================
# Normal completion (sensors still functional)
if(count < 5):
print("\n")
status = "IDLE"
# Calculate averages
aveTemp /= initialNum
aveSpeed /= initialNum
# Stop vehicle animation
introOutroAnimation(status)
print("\n")
# Reset sensor values to idle state
sensorArray[4].setSpeed(0)
if(sensorArray[3].currentTemp >= 100):
sensorArray[3].changeTemperature(sensorArray[3].currentTemp - random.randint(30, 60))
# Display final sensor state
print(f"\n\n{BLUE}{year} {make} {model} (after complete){RESET}:")
displayArray(sensorArray, status, metricSwitched)
# Count sensors by condition
criticalCount = 0
moderateCount = 0
for u in range(len(sensorArray)):
if(sensorArray[u].system_health < 5):
criticalCount += 1
elif(sensorArray[u].system_health >= 5 and sensorArray[u].system_health < 50):
moderateCount += 1
# Display summary statistics
print(f"\n\nAll sensor reading tests are completed for the {year} {make} {model}.")
print(f"\n{BLUE}Conditions:{RESET}")
print(f"* {criticalCount} sensor(s) in a critical condition (% < 5 [RED]).\n* {moderateCount} sensor(s) in a moderate condition (% >= 5 & < 50 [YELLOW]).\n* {5 - (criticalCount + moderateCount)} sensor(s) in a good condition (% >= 50 [GREEN])")
print(f"\n{BLUE}Averages:{RESET}")
if(not metricSwitched):
print(f"* Ave Speed - {round(aveSpeed, 2)} MP/H")
print(f"* Ave Temperature - {round(aveTemp, 2)} F")
else:
print(f"* Ave Speed - {round(convertSpeed(aveSpeed), 2)} KP/H")
print(f"* Ave Temperature - {round(convertDegree(aveTemp), 2)} C")
# Critical failure (all sensors failed)
elif(count >= 5):
move_cursor_down(10)
print(f"\nThe system health of all sensor's are critical. Replace the sensor's with new ones and then re-run for further sensor reading and safe utilization of the {year} {make} {model}.")