1
|
|
|
#!/usr/bin/python3 |
2
|
|
|
|
3
|
|
|
""" Main file for scooter program with Handler class. """ |
4
|
|
|
|
5
|
|
|
import sys |
6
|
|
|
import inspect |
7
|
|
|
import time |
8
|
|
|
from threading import Thread |
9
|
|
|
from datetime import datetime, timedelta |
10
|
|
|
|
11
|
|
|
from src.api import ApiData |
12
|
|
|
from src.scooter import Scooter |
13
|
|
|
|
14
|
|
|
|
15
|
|
|
class Handler(): |
16
|
|
|
""" Handler class """ |
17
|
|
|
|
18
|
|
|
## menu options |
19
|
|
|
_OPTIONS = { |
20
|
|
|
"1": "start_scooter", |
21
|
|
|
"2": "stop_running", |
22
|
|
|
"3": "get_scooter_info", |
23
|
|
|
"4": "return_scooter", |
24
|
|
|
"5": "charge_scooter", |
25
|
|
|
} |
26
|
|
|
|
27
|
|
|
## scooter status |
28
|
|
|
_running = False |
29
|
|
|
|
30
|
|
|
## Leave the scooter, stop the thread |
31
|
|
|
_return = False |
32
|
|
|
|
33
|
|
|
## start renting time, a list of integers [H:M:S] |
34
|
|
|
_start_time = None |
35
|
|
|
|
36
|
|
|
|
37
|
|
|
def __init__(self) -> None: |
38
|
|
|
""" Initialize class """ |
39
|
|
|
self.scooter = Scooter() |
40
|
|
|
self.api = ApiData(user_id = 1) ## user id (random user) |
41
|
|
|
|
42
|
|
|
## create a Thread |
43
|
|
|
self._thread = Thread(target=self.run, name="Move scooter") |
44
|
|
|
|
45
|
|
|
|
46
|
|
|
def _get_method(self, method_name): |
47
|
|
|
""" Uses function getattr() to dynamically get value of an attribute. """ |
48
|
|
|
return getattr(self, self._OPTIONS[method_name]) |
49
|
|
|
|
50
|
|
|
|
51
|
|
|
def _print_menu(self) -> None: |
52
|
|
|
""" Prints options for the program. """ |
53
|
|
|
menu = "" |
54
|
|
|
|
55
|
|
|
for key in sorted(self._OPTIONS): |
56
|
|
|
method = self._get_method(key) |
57
|
|
|
docstring = inspect.getdoc(method) |
58
|
|
|
|
59
|
|
|
menu += "{choice}: {explanation}\n".format( |
60
|
|
|
choice = key, |
61
|
|
|
explanation = docstring |
62
|
|
|
) |
63
|
|
|
|
64
|
|
|
print(chr(27) + "[2J" + chr(27) + "[;H") |
65
|
|
|
print(menu) |
66
|
|
|
|
67
|
|
|
|
68
|
|
|
def run(self) -> None: |
69
|
|
|
""" Start a Thread. """ |
70
|
|
|
while True: |
71
|
|
|
if self._return: |
72
|
|
|
break |
73
|
|
|
if self.scooter.check_scooter_in_city() is False: |
74
|
|
|
print("\nScooter is outside of the city") |
75
|
|
|
print("You can't use the scooter anymore. Press 4 to cancel the rental.") |
76
|
|
|
|
77
|
|
|
self.stop_running() |
78
|
|
|
time.sleep(10) |
79
|
|
|
elif self._running: |
80
|
|
|
self.battery_check() |
81
|
|
|
time.sleep(5) |
82
|
|
|
|
83
|
|
|
|
84
|
|
|
def battery_check(self) -> None: |
85
|
|
|
""" Check battery level, if battery < 20% print warning message and stop the scooter. """ |
86
|
|
|
if self.scooter.check_battery(): |
87
|
|
|
self.stop_running() |
88
|
|
|
print("\n\033[1;31m*\033[1;0m Low battery!! the scooter needs to be charged.") |
89
|
|
|
else: |
90
|
|
|
self.scooter.change_location() |
91
|
|
|
self.scooter.move_scooter() |
92
|
|
|
|
93
|
|
|
## update API |
94
|
|
|
#self.api.update_scooter() |
95
|
|
|
|
96
|
|
|
|
97
|
|
|
def start_scooter(self) -> None: |
98
|
|
|
""" Move the scooter to a random location if battery > 20%. """ |
99
|
|
|
if self.scooter.check_battery(): |
100
|
|
|
print("\n\033[1;31m*\033[1;0m Low battery!! the scooter needs to be charged.") |
101
|
|
|
print("\nPress 4 to end the rental and leave the scooter at charging station.") |
102
|
|
|
print("Or you can press 5 to fully charge the scooter and end the rental.") |
103
|
|
|
else: |
104
|
|
|
self._running = True |
105
|
|
|
|
106
|
|
|
|
107
|
|
|
def stop_running(self) -> None: |
108
|
|
|
""" Stop the scooter. """ |
109
|
|
|
if self._running is True: |
110
|
|
|
self._running = False |
111
|
|
|
self.scooter.stop_scooter() |
112
|
|
|
|
113
|
|
|
## update API |
114
|
|
|
#self.api.update_scooter() |
115
|
|
|
|
116
|
|
|
|
117
|
|
|
def rental_time(self) -> timedelta: |
118
|
|
|
""" Returns the time the scooter has been rented by a user. """ |
119
|
|
|
current = datetime.now().time().strftime("%H:%M:%S") |
120
|
|
|
|
121
|
|
|
current_time = timedelta( |
122
|
|
|
hours = int(current[0:2]), |
123
|
|
|
minutes = int(current[3:5]), |
124
|
|
|
seconds=int(current[6:8]) |
125
|
|
|
) |
126
|
|
|
|
127
|
|
|
start_time = timedelta( |
128
|
|
|
hours = self._start_time[0], |
129
|
|
|
minutes = self._start_time[1], |
130
|
|
|
seconds = self._start_time[2] |
131
|
|
|
) |
132
|
|
|
|
133
|
|
|
return current_time - start_time |
134
|
|
|
|
135
|
|
|
|
136
|
|
|
def get_scooter_info(self) -> None: |
137
|
|
|
""" Get the scooter information. """ |
138
|
|
|
if self._running: |
139
|
|
|
print("\nScooter is running.") |
140
|
|
|
else: |
141
|
|
|
print("\nScooter is in sleep mode.") |
142
|
|
|
|
143
|
|
|
print(self.scooter.__str__()) |
144
|
|
|
print("Rent time: " + str(self.rental_time())) |
145
|
|
|
|
146
|
|
|
|
147
|
|
|
def charge_scooter(self): |
148
|
|
|
"""Charge the scooter and end the rental. """ |
149
|
|
|
## Stop thread |
150
|
|
|
self._return = True |
151
|
|
|
self._running = False |
152
|
|
|
self._thread.join() |
153
|
|
|
|
154
|
|
|
## Fully charges the battery and leave it at the charging Station |
155
|
|
|
#charging = self.api.get_station("Charging Station") |
156
|
|
|
|
157
|
|
|
self.scooter.data["battery"] = 100 |
158
|
|
|
self.scooter.stop_scooter("available") |
159
|
|
|
#self.scooter.move_to_station(charging) |
160
|
|
|
|
161
|
|
|
## update API |
162
|
|
|
#self.api.update_scooter() |
163
|
|
|
#self.api.update_log() |
164
|
|
|
#self.api.remove_user_connection() |
165
|
|
|
sys.exit() |
166
|
|
|
|
167
|
|
|
|
168
|
|
|
def return_scooter(self): |
169
|
|
|
""" Stop the rental and leave the scooter. """ |
170
|
|
|
## Stop thread |
171
|
|
|
self._return = True |
172
|
|
|
self._running = False |
173
|
|
|
self._thread.join() |
174
|
|
|
self.end_rental() |
175
|
|
|
|
176
|
|
|
#self.get_scooter_info() |
177
|
|
|
#print(self.scooter.data["status"]) |
178
|
|
|
|
179
|
|
|
## update API |
180
|
|
|
#self.api.update_scooter() |
181
|
|
|
#self.api.update_log() |
182
|
|
|
#self.api.remove_user_connection() |
183
|
|
|
sys.exit() |
184
|
|
|
|
185
|
|
|
|
186
|
|
|
def end_rental(self) -> None: |
187
|
|
|
""" Checks scooter's battery/maintenance/zone and stops the scooter. """ |
188
|
|
|
if self.scooter.check_scooter_in_city() is False: |
189
|
|
|
self.scooter.stop_scooter("unavailable") |
190
|
|
|
elif self.scooter.check_battery(): |
191
|
|
|
#charging = self.api.get_station("Charging Station") |
192
|
|
|
|
193
|
|
|
self.scooter.stop_scooter("charge") |
194
|
|
|
#self.scooter.move_to_station(charging) |
195
|
|
|
elif self.scooter.check_maintenance(): |
196
|
|
|
#maintenance = self.api.get_station("Maintenance Station") |
197
|
|
|
|
198
|
|
|
self.scooter.stop_scooter("maintenance") |
199
|
|
|
#self.scooter.move_to_station(maintenance) |
200
|
|
|
else: |
201
|
|
|
self.scooter.stop_scooter("available") |
202
|
|
|
|
203
|
|
|
|
204
|
|
|
def rent_scooter(self): |
205
|
|
|
""" Print menu """ |
206
|
|
|
while True: |
207
|
|
|
self._print_menu() |
208
|
|
|
choice = input("What do you want to do: ") |
209
|
|
|
|
210
|
|
|
try: |
211
|
|
|
self._get_method(choice.lower())() |
212
|
|
|
except KeyError: |
213
|
|
|
print("\nInvalid choice!") |
214
|
|
|
|
215
|
|
|
input("\nPress any key to continue ...") |
216
|
|
|
|
217
|
|
|
|
218
|
|
|
def main(self): |
219
|
|
|
""" Main method """ |
220
|
|
|
try: |
221
|
|
|
print("\n************ Welcome to Scooter program **************\n") |
222
|
|
|
|
223
|
|
|
while True: |
224
|
|
|
scooter = int(input("Enter scooter id: ")) |
225
|
|
|
|
226
|
|
|
if self.api.check_scooter_status(scooter): |
227
|
|
|
current = datetime.now().time().strftime("%H:%M:%S") |
228
|
|
|
self._start_time = [int(current[:2]), int(current[3:5]), int(current[6:8])] |
229
|
|
|
break |
230
|
|
|
|
231
|
|
|
print("\n\033[1;31m*\033[1;0m Scooter is not available.\n") |
232
|
|
|
|
233
|
|
|
## connect user and create log |
234
|
|
|
#self.api.connect_user() |
235
|
|
|
#self.api.create_log() |
236
|
|
|
#self.api.get_city_data() |
237
|
|
|
|
238
|
|
|
## start a Thread |
239
|
|
|
self._thread.start() |
240
|
|
|
self.rent_scooter() |
241
|
|
|
|
242
|
|
|
except ValueError: |
243
|
|
|
print("\nScooter id must be a number.") |
244
|
|
|
|
245
|
|
|
|
246
|
|
|
if __name__ == "__main__": |
247
|
|
|
Handler().main() |
248
|
|
|
|