2
2
Applet: NS Timetable
3
3
Author: tim-hanssen
4
4
Summary: NS Timetable
5
- Description: Shows a timetable for a station in the Dutch Railways .
5
+ Description: Shows a timetable for a station in the Netherlands (NS) .
6
6
"""
7
7
8
8
load ("cache.star" , "cache" )
@@ -21,6 +21,10 @@ INFO_BACKGROUND_COLOR = "#FF7700"
21
21
MAINTENANCE_BACKGROUND_COLOR = "#FFB519"
22
22
CANCELED_BACKGROUND_COLOR = "#DB0029"
23
23
24
+ TIME_GREEN = "#5fdb00"
25
+ TIME_ORANGE = "#FF7700"
26
+ TIME_RED = "#DB0029"
27
+
24
28
BLACK_TEXT_COLOR = "#000"
25
29
CORE_TEXT_COLOR = "#FFFFFF"
26
30
NORMAL_TEXT_COLOR = "#FFC917"
@@ -34,30 +38,31 @@ DEFAULT_STATION = "ehv"
34
38
def main (config ):
35
39
station_id = config .str ("station" )
36
40
station_dest = config .str ("dest_station" )
37
- skiptime = config .get ("skiptime" , 0 )
41
+ skip_time = config .get ("skiptime" , 0 )
42
+ time_to_leave = config .bool ("time_to_leave" , False )
38
43
39
44
if station_id == None :
40
45
station_id = DEFAULT_STATION
41
46
else :
42
47
station_id = json .decode (station_id )["value" ]
43
48
44
- # Check if we need to convert the skiptime to Int
45
- if (skiptime ):
46
- if type (skiptime ) == "string" :
47
- skiptime = int (skiptime )
49
+ # Check if we need to convert the skip_time to Int
50
+ if (skip_time ):
51
+ if type (skip_time ) == "string" :
52
+ skip_time = int (skip_time )
48
53
49
54
# Check that the skip time is valid
50
- if skiptime < 0 :
51
- skiptime = 0
55
+ if skip_time < 0 :
56
+ skip_time = 0
52
57
53
58
# If we don't have a Trip, list trains for station.
54
59
if station_dest == None :
55
60
# Normal Train Operations
56
- stops = getTrains (station_id , skiptime )
61
+ stops = getTrains (station_id , skip_time )
57
62
58
63
else :
59
64
station_dest = json .decode (station_dest )["value" ]
60
- stops = getTrip (station_id , station_dest , skiptime )
65
+ stops = getTrip (station_id , station_dest , skip_time )
61
66
62
67
if stops == None or len (stops ) == 0 :
63
68
return render .Root (
@@ -70,24 +75,24 @@ def main(config):
70
75
)
71
76
72
77
if len (stops ) == 1 :
73
- return render .Root (child = renderTrain (stops [0 ]))
78
+ return render .Root (child = renderTrain (stops [0 ], skip_time , time_to_leave ))
74
79
75
80
return render .Root (
76
81
show_full_animation = True ,
77
82
child = render .Column (
78
83
children = [
79
- renderTrain (stops [0 ]),
84
+ renderTrain (stops [0 ], skip_time , time_to_leave ),
80
85
render .Box (
81
86
color = "#ffffff" ,
82
87
width = 64 ,
83
88
height = 1 ,
84
89
),
85
- renderTrain (stops [1 ]),
90
+ renderTrain (stops [1 ], skip_time , time_to_leave ),
86
91
],
87
92
),
88
93
)
89
94
90
- def renderTrain (stop_info ):
95
+ def renderTrain (stop_info , skip_time , time_to_leave ):
91
96
backgroundColor = CORE_BACKGROUND_COLOR
92
97
textColor = CORE_TEXT_COLOR
93
98
@@ -103,8 +108,6 @@ def renderTrain(stop_info):
103
108
departureTimeText = re .sub ("(minutes|minute)" , "min" , departureTimeText )
104
109
departureTimeText = re .sub ("(seconds|second)" , "sec" , departureTimeText )
105
110
106
- # destination = train + " " + destination
107
-
108
111
# Info messages.
109
112
message = None
110
113
@@ -198,35 +201,71 @@ def renderTrain(stop_info):
198
201
199
202
departureTimeRender = render .Animation (children = renderTimeChild )
200
203
201
- return render .Row (
202
- expanded = True ,
203
- main_align = "space_between" ,
204
- cross_align = "end" ,
205
- children = [
204
+ # Render Time To Leave indicator
205
+ timeToLeaveColor = TIME_GREEN
206
+
207
+ if time_to_leave == True :
208
+ departureTimeInSeconds = (parse_time (stop_info ["actualDateTime" ]) - time .now ()).seconds
209
+
210
+ # LESS THAN SKIP TIME + 3 MIN
211
+ if departureTimeInSeconds < ((skip_time * 60 ) + 180 ):
212
+ timeToLeaveColor = TIME_RED
213
+
214
+ # LESS THAN SKIP TIME + 6 MIN
215
+ if departureTimeInSeconds < ((skip_time * 60 ) + 360 ):
216
+ if departureTimeInSeconds > ((skip_time * 60 ) + 180 ):
217
+ timeToLeaveColor = TIME_ORANGE
218
+
219
+ # Hide TTL indicator if cancelled
220
+ if stop_info ["cancelled" ] == True :
221
+ timeToLeaveColor = BLACK_TEXT_COLOR
222
+
223
+ # Render Final rows
224
+ renderTrainFinal = []
225
+
226
+ if time_to_leave == True :
227
+ renderTrainFinal .extend ([
206
228
render .Padding (
207
- pad = 2 ,
229
+ pad = ( 0 , 0 , 0 , 2 ) ,
208
230
child = render .Box (
209
- width = 10 ,
231
+ width = 2 ,
210
232
height = 10 ,
211
- color = backgroundColor ,
212
- child = render .Text (
213
- color = textColor ,
214
- content = stop_info .get ("actualTrack" , "-" ),
215
- ),
233
+ color = timeToLeaveColor ,
216
234
),
217
235
),
218
- render .Column (
219
- children = [
220
- render .Marquee (
221
- width = 64 - 13 ,
222
- child = render .Text (
223
- content = destination .upper (),
224
- ),
225
- ),
226
- departureTimeRender ,
227
- ],
236
+ ])
237
+
238
+ renderTrainFinal .extend ([
239
+ render .Padding (
240
+ pad = 2 ,
241
+ child = render .Box (
242
+ width = 10 ,
243
+ height = 10 ,
244
+ color = backgroundColor ,
245
+ child = render .Text (
246
+ color = textColor ,
247
+ content = stop_info .get ("actualTrack" , "-" ),
248
+ ),
228
249
),
229
- ],
250
+ ),
251
+ render .Column (
252
+ children = [
253
+ render .Marquee (
254
+ width = 64 - 14 ,
255
+ child = render .Text (
256
+ content = destination .upper (),
257
+ ),
258
+ ),
259
+ departureTimeRender ,
260
+ ],
261
+ ),
262
+ ])
263
+
264
+ return render .Row (
265
+ expanded = True ,
266
+ main_align = "space_between" ,
267
+ cross_align = "end" ,
268
+ children = renderTrainFinal ,
230
269
)
231
270
232
271
def format_duration (d ):
@@ -245,7 +284,7 @@ def parse_time(time_string):
245
284
time_obj = time .parse_time (time_string [0 :19 ], format = "2006-01-02T15:04:05" , location = "Europe/Amsterdam" )
246
285
return time_obj
247
286
248
- def getTrip (station_id , station_dest , skiptime ):
287
+ def getTrip (station_id , station_dest , skip_time ):
249
288
resp = http .get ("https://gateway.apiportal.ns.nl/reisinformatie-api/api/v3/trips" , params = {"fromStation" : station_id , "toStation" : station_dest }, headers = {"Ocp-Apim-Subscription-Key" : API_KEY }, ttl_seconds = 30 )
250
289
251
290
if resp .status_code != 200 :
@@ -267,8 +306,8 @@ def getTrip(station_id, station_dest, skiptime):
267
306
continue
268
307
269
308
# Skip trains that are not in allowed frame.
270
- if skiptime > 0 :
271
- timeStart = time .parse_duration ("%im" % skiptime ) + time .now ()
309
+ if skip_time > 0 :
310
+ timeStart = time .parse_duration ("%im" % skip_time ) + time .now ()
272
311
timeDepart = time .parse_time (originTime [0 :19 ], format = "2006-01-02T15:04:05" , location = "Europe/Amsterdam" )
273
312
if timeDepart >= timeStart :
274
313
stops .append (
@@ -299,7 +338,7 @@ def getTrip(station_id, station_dest, skiptime):
299
338
300
339
return stops
301
340
302
- def getTrains (station_id , skiptime ):
341
+ def getTrains (station_id , skip_time ):
303
342
resp = http .get ("https://gateway.apiportal.ns.nl/reisinformatie-api/api/v2/departures" , params = {"station" : station_id }, headers = {"Ocp-Apim-Subscription-Key" : API_KEY }, ttl_seconds = 30 )
304
343
305
344
if resp .status_code != 200 :
@@ -314,8 +353,8 @@ def getTrains(station_id, skiptime):
314
353
315
354
startID = 0
316
355
317
- if skiptime > 0 :
318
- timeStart = time .parse_duration ("%im" % skiptime ) + time .now ()
356
+ if skip_time > 0 :
357
+ timeStart = time .parse_duration ("%im" % skip_time ) + time .now ()
319
358
320
359
for i , train in enumerate (departuresTrains ):
321
360
timeDepart = time .parse_time (train ["actualDateTime" ][0 :19 ], format = "2006-01-02T15:04:05" , location = "Europe/Amsterdam" )
@@ -388,5 +427,11 @@ def get_schema():
388
427
desc = "Shows the connections starting n minutes in the future." ,
389
428
icon = "clock" ,
390
429
),
430
+ schema .Toggle (
431
+ id = "time_to_leave" ,
432
+ name = "Time To Leave" ,
433
+ desc = "Shows a green/orange/red line to indicate how soon you need to leave your house to catch the train. (uses Departure Offset to render the indicator)." ,
434
+ icon = "personWalking" ,
435
+ ),
391
436
],
392
437
)
0 commit comments