├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── Package.resolved
├── Package.swift
├── README.md
├── Sources
└── Train-API
│ ├── Debug Data
│ ├── ice.json
│ ├── paris.json
│ ├── sbahnStuttgart.json
│ ├── status.json
│ ├── tripInfo1.json
│ └── tripInfo2.json
│ ├── ICE Baureihen
│ ├── BR401.pdf
│ ├── BR402.pdf
│ ├── BR403 Serie 1.pdf
│ ├── BR403 Serie 2.pdf
│ ├── BR406.pdf
│ ├── BR407.pdf
│ ├── BR411 Serie 1.pdf
│ ├── BR411 Serie 2.pdf
│ ├── BR412.pdf
│ └── BR415.pdf
│ ├── ICEConnection.swift
│ ├── InternetConnection.swift
│ ├── JourneyStop.swift
│ ├── Media.xcassets
│ ├── BR401.imageset
│ │ ├── Contents.json
│ │ └── ice 1.png
│ ├── BR402.imageset
│ │ ├── Contents.json
│ │ └── ice 2.png
│ ├── BR403.imageset
│ │ ├── BR403.png
│ │ └── Contents.json
│ ├── BR406.imageset
│ │ ├── BR406.png
│ │ └── Contents.json
│ ├── BR407.imageset
│ │ ├── BR407.png
│ │ └── Contents.json
│ ├── BR411.imageset
│ │ ├── BR411.png
│ │ └── Contents.json
│ ├── BR412.imageset
│ │ ├── Contents.json
│ │ └── ice 4.png
│ ├── BR415.imageset
│ │ ├── BR415.png
│ │ └── Contents.json
│ └── Contents.json
│ ├── TrainMetaData.swift
│ ├── TrainType.swift
│ └── TripData.swift
└── Tests
└── Train-APITests
└── Train_APITests.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 | DerivedData/
7 | .swiftpm/config/registries.json
8 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
9 | .netrc
10 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "pins" : [
3 | {
4 | "identity" : "alamofire",
5 | "kind" : "remoteSourceControl",
6 | "location" : "https://github.com/Alamofire/Alamofire",
7 | "state" : {
8 | "revision" : "354dda32d89fc8cd4f5c46487f64957d355f53d8",
9 | "version" : "5.6.1"
10 | }
11 | },
12 | {
13 | "identity" : "fredkit",
14 | "kind" : "remoteSourceControl",
15 | "location" : "https://github.com/frogg/FredKit",
16 | "state" : {
17 | "revision" : "bb465a18b47ed01c8487e08c3a106e89e6ad0b81",
18 | "version" : "0.1.42"
19 | }
20 | }
21 | ],
22 | "version" : 2
23 | }
24 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.6
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "Train-API-Swift-Package",
8 | platforms: [
9 | .macOS(.v10_12),
10 | .iOS(.v12)
11 | ],
12 | products: [
13 | // Products define the executables and libraries a package produces, and make them visible to other packages.
14 | .library(
15 | name: "Train-API-Swift-Package",
16 | targets: ["Train-API"]),
17 | ],
18 | dependencies: [
19 | // Dependencies declare other packages that this package depends on.
20 | .package(url: "https://github.com/Alamofire/Alamofire", from: "5.0.0"),
21 | .package(url: "https://github.com/frogg/FredKit", from: "0.1.0")
22 | ],
23 | targets: [
24 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
25 | // Targets can depend on other targets in this package, and on products in packages this package depends on.
26 | .target(
27 | name: "Train-API",
28 | dependencies: [
29 | "Alamofire",
30 | "FredKit"
31 | ],
32 | resources: [
33 | .process("Debug Data/ice.json"),
34 | .process("Debug Data/paris.json")
35 | ]
36 | ),
37 | .testTarget(
38 | name: "Train-APITests",
39 | dependencies: ["Train-API"]),
40 | ]
41 | )
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Train-API
2 |
3 | Offering a simple Swift API for real-time tain/travel-information.
4 |
5 | ## ICE API
6 | This Swift Package has been developed to power [ICE Buddy](https://ice-buddy.riedel.wtf).
7 |
8 | ### On-Board Server
9 | This Swift Package connects to the on-board server of ICE trains, so connecting to the WiFi@DB or WiFionICE is mandatory.
10 |
11 | Then, REST-Requests are sent to the following endpoints:
12 | - https://iceportal.de/api1/rs/status
13 | - https://iceportal.de/api1/rs/tripInfo/trip
14 |
15 | ### Available Data Points
16 | - Current speed (km/h)
17 | - Train name and journey title (e.g., ICE 643: Düsseldorf Hbf -> Berlin Ostbahnhof)
18 | - Train model (e.g., ICE 4)
19 | - Train model image
20 | - Journey (all train stations), incluing:
21 | - Track
22 | - Planned arrival time
23 | - Actual arrival time (delay)
24 | - Current internet quality (stable / unstable)
25 |
26 |
27 |
28 | ## TGV, ÖBB, SBB CFF FFS?
29 | We encourage all thrain enthusiasts from all over the world to contribute to this open-source project!
30 |
--------------------------------------------------------------------------------
/Sources/Train-API/Debug Data/ice.json:
--------------------------------------------------------------------------------
1 | {"connection":true,"serviceLevel":"AVAILABLE_SERVICE","gpsStatus":"VALID","internet":"HIGH","latitude":49.2987785,"longitude":11.361207,"tileY":-78,"tileX":125,"series":"411","serverTime":1647438292926,"speed":120.0,"trainType":"ICE","tzn":"ICE0334","wagonClass":"SECOND","connectivity":{"currentState":"UNSTABLE","nextState":"HIGH","remainingTimeSeconds":1200},"bapInstalled":true}
2 |
--------------------------------------------------------------------------------
/Sources/Train-API/Debug Data/paris.json:
--------------------------------------------------------------------------------
1 | {"trip":{"tripDate":"2022-03-23","trainType":"ICE","vzn":"9557","actualPosition":0,"distanceFromLastStop":0,"totalDistance":524136,"stopInfo":{"scheduledNext":"8700011_00","actualNext":"8700011_00","actualLast":"","actualLastStarted":"","finalStationName":"Frankfurt (Main) Hbf","finalStationEvaNr":"8000105_00"},"stops":[{"station":{"evaNr":"8700011_00","name":"Paris Est","code":null,"geocoordinates":{"latitude":48.876976,"longitude":2.35912}},"timetable":{"scheduledArrivalTime":null,"actualArrivalTime":null,"showActualArrivalTime":null,"arrivalDelay":"","scheduledDepartureTime":1648058640000,"actualDepartureTime":null,"showActualDepartureTime":false,"departureDelay":""},"track":{"scheduled":null,"actual":""},"info":{"status":0,"passed":true,"positionStatus":"arrived","distance":0,"distanceFromStart":0},"delayReasons":null},{"station":{"evaNr":"8700271_00","name":"Forbach (F)","code":null,"geocoordinates":{"latitude":49.189217,"longitude":6.900258}},"timetable":{"scheduledArrivalTime":1648064820000,"actualArrivalTime":null,"showActualArrivalTime":false,"arrivalDelay":"","scheduledDepartureTime":1648064880000,"actualDepartureTime":null,"showActualDepartureTime":false,"departureDelay":""},"track":{"scheduled":null,"actual":""},"info":{"status":0,"passed":false,"positionStatus":"future","distance":332916,"distanceFromStart":332916},"delayReasons":null},{"station":{"evaNr":"8000323_00","name":"Saarbrücken Hbf","code":null,"geocoordinates":{"latitude":49.241065,"longitude":6.991021}},"timetable":{"scheduledArrivalTime":1648065420000,"actualArrivalTime":null,"showActualArrivalTime":false,"arrivalDelay":"","scheduledDepartureTime":1648065540000,"actualDepartureTime":null,"showActualDepartureTime":false,"departureDelay":""},"track":{"scheduled":"5","actual":"5"},"info":{"status":0,"passed":false,"positionStatus":"future","distance":8760,"distanceFromStart":341676},"delayReasons":null},{"station":{"evaNr":"8000189_00","name":"Kaiserslautern Hbf","code":null,"geocoordinates":{"latitude":49.436137,"longitude":7.768716}},"timetable":{"scheduledArrivalTime":1648067700000,"actualArrivalTime":null,"showActualArrivalTime":false,"arrivalDelay":"","scheduledDepartureTime":1648067820000,"actualDepartureTime":null,"showActualDepartureTime":false,"departureDelay":""},"track":{"scheduled":"4","actual":"4"},"info":{"status":0,"passed":false,"positionStatus":"future","distance":60394,"distanceFromStart":402070},"delayReasons":null},{"station":{"evaNr":"8000244_00","name":"Mannheim Hbf","code":null,"geocoordinates":{"latitude":49.479354,"longitude":8.468921}},"timetable":{"scheduledArrivalTime":1648070220000,"actualArrivalTime":null,"showActualArrivalTime":false,"arrivalDelay":"","scheduledDepartureTime":1648070340000,"actualDepartureTime":null,"showActualDepartureTime":false,"departureDelay":""},"track":{"scheduled":"3","actual":"3"},"info":{"status":0,"passed":false,"positionStatus":"future","distance":50851,"distanceFromStart":452921},"delayReasons":null},{"station":{"evaNr":"8000105_00","name":"Frankfurt (Main) Hbf","code":null,"geocoordinates":{"latitude":50.107145,"longitude":8.663789}},"timetable":{"scheduledArrivalTime":1648072860000,"actualArrivalTime":null,"showActualArrivalTime":false,"arrivalDelay":"","scheduledDepartureTime":null,"actualDepartureTime":null,"showActualDepartureTime":null,"departureDelay":""},"track":{"scheduled":"18","actual":"18"},"info":{"status":0,"passed":false,"positionStatus":"future","distance":71215,"distanceFromStart":524136},"delayReasons":null}]},"connection":null,"selectedRoute":{"conflictInfo":{"status":"NO_CONFLICT","text":null},"mobility":null},"active":null}
--------------------------------------------------------------------------------
/Sources/Train-API/Debug Data/sbahnStuttgart.json:
--------------------------------------------------------------------------------
1 | {"journeyId":"a513f057-5b20-493f-b3a5-7b2ab2738144","administrationId":"800643","tenantId":"badenwuerttemberg","name":"S 2","no":7855,"category":"S","date":"2021-12-22","stops":[{"station":{"evaNo":"8005424","name":"Schorndorf"},"status":"Normal","track":{"target":"1","prediction":"1"},"departureTime":{"target":"2021-12-22T18:03:00.000Z","predicted":"2021-12-22T18:03:23.000Z","predictedTimeInMs":1640196203000,"targetTimeInMs":1640196180000,"timeType":"REAL","diff":0},"messages":[]},{"station":{"evaNo":"8006277","name":"Weiler(Rems)"},"status":"Normal","track":{"target":"2","prediction":"2"},"arrivalId":"f65b0923-60ee-4d91-b962-9fa88f92686e","arrivalTime":{"target":"2021-12-22T18:06:00.000Z","predicted":"2021-12-22T18:06:00.000Z","predictedTimeInMs":1640196360000,"targetTimeInMs":1640196360000,"timeType":"REAL","diff":0},"messages":[],"departureTime":{"target":"2021-12-22T18:06:00.000Z","predicted":"2021-12-22T18:06:28.000Z","predictedTimeInMs":1640196388000,"targetTimeInMs":1640196360000,"timeType":"REAL","diff":0}},{"station":{"evaNo":"8006485","name":"Winterbach(Schorndorf)"},"status":"Normal","track":{"target":"1","prediction":"1"},"arrivalId":"4cf1cb9c-b99a-4555-ad7c-a79fcbb91e0b","arrivalTime":{"target":"2021-12-22T18:08:00.000Z","predicted":"2021-12-22T18:08:08.000Z","predictedTimeInMs":1640196488000,"targetTimeInMs":1640196480000,"timeType":"REAL","diff":0},"messages":[],"departureTime":{"target":"2021-12-22T18:08:00.000Z","predicted":"2021-12-22T18:08:34.000Z","predictedTimeInMs":1640196514000,"targetTimeInMs":1640196480000,"timeType":"REAL","diff":1}},{"station":{"evaNo":"8002240","name":"Geradstetten"},"status":"Normal","track":{"target":"1","prediction":"1"},"arrivalId":"b7e65e58-1764-4ac8-81e8-7bc6cb63ac71","arrivalTime":{"target":"2021-12-22T18:10:00.000Z","predicted":"2021-12-22T18:11:09.000Z","predictedTimeInMs":1640196669000,"targetTimeInMs":1640196600000,"timeType":"REAL","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:11:00.000Z","predicted":"2021-12-22T18:11:46.000Z","predictedTimeInMs":1640196706000,"targetTimeInMs":1640196660000,"timeType":"REAL","diff":1}},{"station":{"evaNo":"8002448","name":"Grunbach"},"status":"Normal","track":{"target":"2","prediction":"2"},"arrivalId":"c5a1fecc-eeda-45f7-a34c-cbddbdb535f2","arrivalTime":{"target":"2021-12-22T18:12:00.000Z","predicted":"2021-12-22T18:13:15.000Z","predictedTimeInMs":1640196795000,"targetTimeInMs":1640196720000,"timeType":"REAL","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:13:00.000Z","predicted":"2021-12-22T18:13:48.000Z","predictedTimeInMs":1640196828000,"targetTimeInMs":1640196780000,"timeType":"REAL","diff":1}},{"station":{"evaNo":"8000934","name":"Beutelsbach"},"status":"Normal","track":{"target":"2","prediction":"2"},"arrivalId":"c82d7766-ea19-439e-ad98-8d7445a7f7e7","arrivalTime":{"target":"2021-12-22T18:15:00.000Z","predicted":"2021-12-22T18:15:53.000Z","predictedTimeInMs":1640196953000,"targetTimeInMs":1640196900000,"timeType":"REAL","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:15:00.000Z","predicted":"2021-12-22T18:16:21.000Z","predictedTimeInMs":1640196981000,"targetTimeInMs":1640196900000,"timeType":"REAL","diff":1}},{"station":{"evaNo":"8001785","name":"Endersbach"},"status":"Normal","track":{"target":"3","prediction":"3"},"arrivalId":"04d84c4b-30b5-4769-83e0-ed2a0c37fb95","arrivalTime":{"target":"2021-12-22T18:17:00.000Z","predicted":"2021-12-22T18:17:37.000Z","predictedTimeInMs":1640197057000,"targetTimeInMs":1640197020000,"timeType":"REAL","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:17:00.000Z","predicted":"2021-12-22T18:18:08.000Z","predictedTimeInMs":1640197088000,"targetTimeInMs":1640197020000,"timeType":"REAL","diff":1}},{"station":{"evaNo":"8005726","name":"Stetten-Beinstein"},"status":"Normal","track":{"target":"2","prediction":"2"},"arrivalId":"b06a157f-f958-4dc9-899f-1aaa36e8f000","arrivalTime":{"target":"2021-12-22T18:19:00.000Z","predicted":"2021-12-22T18:19:29.000Z","predictedTimeInMs":1640197169000,"targetTimeInMs":1640197140000,"timeType":"REAL","diff":0},"messages":[],"departureTime":{"target":"2021-12-22T18:19:00.000Z","predicted":"2021-12-22T18:20:07.000Z","predictedTimeInMs":1640197207000,"targetTimeInMs":1640197140000,"timeType":"REAL","diff":1}},{"station":{"evaNo":"8005157","name":"Rommelshausen"},"status":"Normal","track":{"target":"2","prediction":"2"},"arrivalId":"e5440928-7610-4316-8969-61110a56ddf8","arrivalTime":{"target":"2021-12-22T18:21:00.000Z","predicted":"2021-12-22T18:22:25.000Z","predictedTimeInMs":1640197345000,"targetTimeInMs":1640197260000,"timeType":"REAL","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:22:00.000Z","predicted":"2021-12-22T18:23:23.000Z","predictedTimeInMs":1640197403000,"targetTimeInMs":1640197320000,"timeType":"REAL","diff":1}},{"station":{"evaNo":"8000180","name":"Waiblingen"},"status":"Normal","track":{"target":"5","prediction":"5"},"arrivalId":"9675173f-28eb-44bd-8f5c-323b1f9e2218","arrivalTime":{"target":"2021-12-22T18:24:00.000Z","predicted":"2021-12-22T18:25:18.000Z","predictedTimeInMs":1640197518000,"targetTimeInMs":1640197440000,"timeType":"REAL","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:25:00.000Z","predicted":"2021-12-22T18:25:33.000Z","predictedTimeInMs":1640197533000,"targetTimeInMs":1640197500000,"timeType":"REAL","diff":1}},{"station":{"evaNo":"8001974","name":"Fellbach"},"status":"Normal","track":{"target":"4","prediction":"4"},"arrivalId":"5f8deb4a-26f2-4ab4-b036-c94d05ae2618","arrivalTime":{"target":"2021-12-22T18:27:00.000Z","predicted":"2021-12-22T18:27:46.000Z","predictedTimeInMs":1640197666000,"targetTimeInMs":1640197620000,"timeType":"REAL","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:28:00.000Z","predicted":"2021-12-22T18:28:16.000Z","predictedTimeInMs":1640197696000,"targetTimeInMs":1640197680000,"timeType":"REAL","diff":0}},{"station":{"evaNo":"8005774","name":"Stuttgart-Sommerrain"},"status":"Normal","track":{"target":"1","prediction":"1"},"arrivalId":"a51e7615-3319-408f-814d-7bb90dd3366f","arrivalTime":{"target":"2021-12-22T18:30:00.000Z","predicted":"2021-12-22T18:29:58.000Z","predictedTimeInMs":1640197798000,"targetTimeInMs":1640197800000,"timeType":"REAL","diff":0},"messages":[],"departureTime":{"target":"2021-12-22T18:30:00.000Z","predicted":"2021-12-22T18:30:59.000Z","predictedTimeInMs":1640197859000,"targetTimeInMs":1640197800000,"timeType":"REAL","diff":1}},{"station":{"evaNo":"8004357","name":"Nürnberger Str."},"status":"Normal","track":{"target":"1","prediction":"1"},"arrivalId":"97cb3ccd-dc53-443b-8287-053d4cffa89b","arrivalTime":{"target":"2021-12-22T18:32:00.000Z","predicted":"2021-12-22T18:32:38.000Z","predictedTimeInMs":1640197958000,"targetTimeInMs":1640197920000,"timeType":"REAL","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:33:00.000Z","predicted":"2021-12-22T18:33:18.000Z","predictedTimeInMs":1640197998000,"targetTimeInMs":1640197980000,"timeType":"REAL","diff":0}},{"station":{"evaNo":"8005769","name":"S-Bad Cannstatt"},"status":"Normal","track":{"target":"2","prediction":"2"},"arrivalId":"02c6d5e7-5291-44ff-bf19-afa4ac62a112","arrivalTime":{"target":"2021-12-22T18:35:00.000Z","predicted":"2021-12-22T18:35:58.000Z","predictedTimeInMs":1640198158000,"targetTimeInMs":1640198100000,"timeType":"REAL","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:36:00.000Z","predicted":"2021-12-22T18:36:35.000Z","predictedTimeInMs":1640198195000,"targetTimeInMs":1640198160000,"timeType":"REAL","diff":1}},{"station":{"evaNo":"8098096","name":"Stuttgart Hbf (tief)"},"status":"Normal","track":{"target":"101","prediction":"101"},"arrivalId":"f05bcca6-6f4f-4ab5-ba35-c224c4f9056b","arrivalTime":{"target":"2021-12-22T18:40:00.000Z","predicted":"2021-12-22T18:41:09.000Z","predictedTimeInMs":1640198469000,"targetTimeInMs":1640198400000,"timeType":"REAL","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:40:00.000Z","predicted":"2021-12-22T18:41:58.000Z","predictedTimeInMs":1640198518000,"targetTimeInMs":1640198400000,"timeType":"REAL","diff":2}},{"station":{"evaNo":"8006700","name":"Stuttgart Stadtmitte"},"status":"Normal","track":{"target":"1","prediction":"1"},"arrivalId":"b3b63f3d-85aa-4768-ac46-57e218b8350d","arrivalTime":{"target":"2021-12-22T18:42:00.000Z","predicted":"2021-12-22T18:43:04.000Z","predictedTimeInMs":1640198584000,"targetTimeInMs":1640198520000,"timeType":"REAL","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:42:00.000Z","predicted":"2021-12-22T18:43:42.000Z","predictedTimeInMs":1640198622000,"targetTimeInMs":1640198520000,"timeType":"REAL","diff":2}},{"station":{"evaNo":"8006699","name":"Stuttgart Feuersee"},"status":"Normal","track":{"target":"1","prediction":"1"},"arrivalId":"eec2c82c-5586-4d89-9175-a6cd3680df24","arrivalTime":{"target":"2021-12-22T18:43:00.000Z","predicted":"2021-12-22T18:44:43.000Z","predictedTimeInMs":1640198683000,"targetTimeInMs":1640198580000,"timeType":"REAL","diff":2},"messages":[],"departureTime":{"target":"2021-12-22T18:44:00.000Z","predicted":"2021-12-22T18:45:00.000Z","predictedTimeInMs":1640198700000,"targetTimeInMs":1640198640000,"timeType":"PREVIEW","diff":1}},{"station":{"evaNo":"8006698","name":"Stuttgart Schwabstr."},"status":"Normal","track":{"target":"1","prediction":"1"},"arrivalId":"fb316746-de7e-4070-9c14-d59efae08b52","arrivalTime":{"target":"2021-12-22T18:45:00.000Z","predicted":"2021-12-22T18:46:00.000Z","predictedTimeInMs":1640198760000,"targetTimeInMs":1640198700000,"timeType":"PREVIEW","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:45:00.000Z","predicted":"2021-12-22T18:46:00.000Z","predictedTimeInMs":1640198760000,"targetTimeInMs":1640198700000,"timeType":"PREVIEW","diff":1}},{"station":{"evaNo":"8006513","name":"Stuttgart Universität"},"status":"Normal","track":{"target":"1","prediction":"1"},"arrivalId":"5183aec4-cb6f-470d-9387-cf19c57f2dad","arrivalTime":{"target":"2021-12-22T18:50:00.000Z","predicted":"2021-12-22T18:50:00.000Z","predictedTimeInMs":1640199000000,"targetTimeInMs":1640199000000,"timeType":"PREVIEW","diff":0},"messages":[],"departureTime":{"target":"2021-12-22T18:50:00.000Z","predicted":"2021-12-22T18:51:00.000Z","predictedTimeInMs":1640199060000,"targetTimeInMs":1640199000000,"timeType":"PREVIEW","diff":1}},{"station":{"evaNo":"8005779","name":"Stuttgart-Österfeld"},"status":"Normal","track":{"target":"1","prediction":"1"},"arrivalId":"aba98ed5-744d-4193-b9d3-0167effdb1bf","arrivalTime":{"target":"2021-12-22T18:52:00.000Z","predicted":"2021-12-22T18:52:00.000Z","predictedTimeInMs":1640199120000,"targetTimeInMs":1640199120000,"timeType":"PREVIEW","diff":0},"messages":[],"departureTime":{"target":"2021-12-22T18:52:00.000Z","predicted":"2021-12-22T18:53:00.000Z","predictedTimeInMs":1640199180000,"targetTimeInMs":1640199120000,"timeType":"PREVIEW","diff":1}},{"station":{"evaNo":"8005776","name":"Stuttgart-Vaihingen"},"status":"Normal","track":{"target":"2","prediction":"2"},"arrivalId":"0f48dd54-ed3c-4363-b4bd-179a6796c3c8","arrivalTime":{"target":"2021-12-22T18:54:00.000Z","predicted":"2021-12-22T18:55:00.000Z","predictedTimeInMs":1640199300000,"targetTimeInMs":1640199240000,"timeType":"PREVIEW","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:55:00.000Z","predicted":"2021-12-22T18:56:00.000Z","predictedTimeInMs":1640199360000,"targetTimeInMs":1640199300000,"timeType":"PREVIEW","diff":1}},{"station":{"evaNo":"8005773","name":"Stuttgart-Rohr"},"status":"Normal","track":{"target":"2","prediction":"2"},"arrivalId":"28293b3e-56fa-4e59-8c22-04a82fc70b67","arrivalTime":{"target":"2021-12-22T18:56:00.000Z","predicted":"2021-12-22T18:57:00.000Z","predictedTimeInMs":1640199420000,"targetTimeInMs":1640199360000,"timeType":"PREVIEW","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:57:00.000Z","predicted":"2021-12-22T18:58:00.000Z","predictedTimeInMs":1640199480000,"targetTimeInMs":1640199420000,"timeType":"PREVIEW","diff":1}},{"station":{"evaNo":"8004496","name":"Oberaichen"},"status":"Normal","track":{"target":"1","prediction":"1"},"arrivalId":"1b1a9a32-70b2-4ad9-a0a4-fa876f71826f","arrivalTime":{"target":"2021-12-22T18:59:00.000Z","predicted":"2021-12-22T19:00:00.000Z","predictedTimeInMs":1640199600000,"targetTimeInMs":1640199540000,"timeType":"PREVIEW","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T18:59:00.000Z","predicted":"2021-12-22T19:00:00.000Z","predictedTimeInMs":1640199600000,"targetTimeInMs":1640199540000,"timeType":"PREVIEW","diff":1}},{"station":{"evaNo":"8003622","name":"Leinfelden"},"status":"Normal","track":{"target":"1","prediction":"1"},"arrivalId":"cd59f9e5-f3c7-471b-80e7-1cefa110e84c","arrivalTime":{"target":"2021-12-22T19:01:00.000Z","predicted":"2021-12-22T19:02:00.000Z","predictedTimeInMs":1640199720000,"targetTimeInMs":1640199660000,"timeType":"PREVIEW","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T19:02:00.000Z","predicted":"2021-12-22T19:03:00.000Z","predictedTimeInMs":1640199780000,"targetTimeInMs":1640199720000,"timeType":"PREVIEW","diff":1}},{"station":{"evaNo":"8001650","name":"Echterdingen"},"status":"Normal","track":{"target":"1","prediction":"1"},"arrivalId":"0f06b36b-3e6d-42a6-b1db-545298a9fc01","arrivalTime":{"target":"2021-12-22T19:04:00.000Z","predicted":"2021-12-22T19:05:00.000Z","predictedTimeInMs":1640199900000,"targetTimeInMs":1640199840000,"timeType":"PREVIEW","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T19:05:00.000Z","predicted":"2021-12-22T19:06:00.000Z","predictedTimeInMs":1640199960000,"targetTimeInMs":1640199900000,"timeType":"PREVIEW","diff":1}},{"station":{"evaNo":"8005768","name":"Flughafen/Messe"},"status":"Normal","track":{"target":"1","prediction":"1"},"arrivalId":"d2cd9715-aa7e-4296-a55c-e7018c0d662e","arrivalTime":{"target":"2021-12-22T19:07:00.000Z","predicted":"2021-12-22T19:08:00.000Z","predictedTimeInMs":1640200080000,"targetTimeInMs":1640200020000,"timeType":"PREVIEW","diff":1},"messages":[],"departureTime":{"target":"2021-12-22T19:08:00.000Z","predicted":"2021-12-22T19:09:00.000Z","predictedTimeInMs":1640200140000,"targetTimeInMs":1640200080000,"timeType":"PREVIEW","diff":1}},{"station":{"evaNo":"8001984","name":"Filderstadt"},"status":"Normal","track":{"target":"2","prediction":"2"},"arrivalId":"0364faf0-1026-48f9-8f6d-e9e1d05d2a1e","arrivalTime":{"target":"2021-12-22T19:12:00.000Z","predicted":"2021-12-22T19:12:00.000Z","predictedTimeInMs":1640200320000,"targetTimeInMs":1640200320000,"timeType":"PREVIEW","diff":0},"messages":[]}],"hims":[{"id":"e80b183a19b720b7cdbf3cb8e2e37836d1a0086965b302bc0682981e97dca84c","caption":"In Stadtmitte wird der Aufzug zum S-Bahnsteig ausgetauscht. Der vorhandene Schrägaufzug wird komplett abgebaut und ein neuer Aufzug eingebuat. Der neue Aufzug soll nach derzeitiger Planung Ende Februar 2022 in Betrieb gehen. Die Deutsche Bahn empfiehlt mobilitätseingeschränkten Reisenden während den Bauarbeiten ihre Reise vorher (spätestens einen Werktag) bei der DB Mobilitätsservice-Zentrale (Telefon 030 / 6521 2888) anzumelden oder auf die S-Bahnhöfe Stuttgart Hbf (tief) oder Schwabstraße auszuweichen.
","shortText":"Die Deutsche Bahn erneuert am S-Bahnhof Stuttgart-Stadtmitte bis vsl. Ende Februar 2022 den Aufzug am Abgang Rotebühlplatz zur S-Bahn Station."},{"id":"83bc96354f39b0362a727387cf41d6131b9770b6fdf3dc4472bb5ee433f9b834","caption":"Momentan finden Aufzugsarbeiten am S-Bahnhof Feuersee statt. Während der Arbeiten stehen nicht alle Aufzüge bis voraussichtlich Mitte Februar 2022 zur Verfügung. Die Deutsche Bahn empfiehlt mobilitätseingeschränkten Reisenden während den Bauarbeiten ihre Reise vorher (spätestens einen Werktag) bei der DB Mobilitätsservice-Zentrale (Telefon 030 / 6521 2888) anzumelden oder auf die S-Bahnhöfe Schwabstraße oder Stuttgart Hbf (tief) auszuweichen.","shortText":"Die Deutsche Bahn erneuert die Aufzüge im S-Bahnhof Stuttgart-Feuersee bis vsl. Mitte Februar 2022"},{"id":"830711cadea4b14c8672022ef5c3f705ce2e681ff5b79ae43a12102815421b98","caption":"Am S-Bahnhof Winterbach werden beide Aufzüge erneuert. Während den Arbeiten stehen beide Aufzüge nicht zur Verfügung, der Fußgängersteg bleibt geöffnet. Ein stufenfreier Zugang zu beiden Bahnsteigen ist über die Straßenunterführung Oberdorf weiterhin möglich.","shortText":"Aufzugsarbeiten S-Bahnhof Winterbach, eingeschränkte Nutzungsmöglichkeit"}],"validFrom":"2021-12-22T17:53:23.000Z","validUntil":"2021-12-22T19:22:00.000Z","uic":"948004300661","trainNo":"7855 2021-12-22"}
2 |
--------------------------------------------------------------------------------
/Sources/Train-API/Debug Data/status.json:
--------------------------------------------------------------------------------
1 | {"connection":true,"serviceLevel":"AVAILABLE_SERVICE","gpsStatus":"VALID","internet":"HIGH","latitude":52.534493,"longitude":13.197972833333333,"tileY":281,"tileX":256,"series":"807","serverTime":1637085624340,"speed":265.0,"trainType":"ICE","tzn":"Tz9001","wagonClass":"SECOND","connectivity":{"currentState":"HIGH","nextState":"UNSTABLE","remainingTimeSeconds":600},"bapInstalled":true}
2 |
--------------------------------------------------------------------------------
/Sources/Train-API/Debug Data/tripInfo1.json:
--------------------------------------------------------------------------------
1 | {"trip":{"tripDate":"2021-11-16","trainType":"ICE","vzn":"542","actualPosition":251312,"distanceFromLastStop":8181,"totalDistance":507326,"stopInfo":{"scheduledNext":"8000036_00","actualNext":"8000036_00","actualLast":"8000152_00","actualLastStarted":"8000036","finalStationName":"Düsseldorf Hbf","finalStationEvaNr":"8000085_00"},"stops":[{"station":{"evaNr":"8010255_00","name":"Berlin Ostbahnhof","code":null,"geocoordinates":{"latitude":52.510488,"longitude":13.434681}},"timetable":{"scheduledArrivalTime":null,"actualArrivalTime":null,"showActualArrivalTime":null,"arrivalDelay":"","scheduledDepartureTime":1637084100000,"actualDepartureTime":1637084100000,"showActualDepartureTime":true,"departureDelay":""},"track":{"scheduled":"6","actual":"6"},"info":{"status":0,"passed":true,"positionStatus":"passed","distance":0,"distanceFromStart":0},"delayReasons":null},{"station":{"evaNr":"8011160_00","name":"Berlin Hbf","code":null,"geocoordinates":{"latitude":52.525592,"longitude":13.369545}},"timetable":{"scheduledArrivalTime":1637084520000,"actualArrivalTime":1637084580000,"showActualArrivalTime":true,"arrivalDelay":"+1","scheduledDepartureTime":1637084760000,"actualDepartureTime":1637084820000,"showActualDepartureTime":true,"departureDelay":"+1"},"track":{"scheduled":"13","actual":"13"},"info":{"status":0,"passed":true,"positionStatus":"passed","distance":4718,"distanceFromStart":4718},"delayReasons":null},{"station":{"evaNr":"8010404_00","name":"Berlin-Spandau","code":null,"geocoordinates":{"latitude":52.534648,"longitude":13.196898}},"timetable":{"scheduledArrivalTime":1637085540000,"actualArrivalTime":1637085600000,"showActualArrivalTime":true,"arrivalDelay":"+1","scheduledDepartureTime":1637085720000,"actualDepartureTime":1637085720000,"showActualDepartureTime":true,"departureDelay":""},"track":{"scheduled":"4","actual":"444"},"info":{"status":0,"passed":true,"positionStatus":"passed","distance":11725,"distanceFromStart":16443},"delayReasons":null},{"station":{"evaNr":"8000152_00","name":"Hannover Hbf","code":null,"geocoordinates":{"latitude":52.376761,"longitude":9.741021}},"timetable":{"scheduledArrivalTime":1637090880000,"actualArrivalTime":1637091120000,"showActualArrivalTime":true,"arrivalDelay":"+4","scheduledDepartureTime":1637091060000,"actualDepartureTime":1637091360000,"showActualDepartureTime":true,"departureDelay":"+5"},"track":{"scheduled":"12","actual":"12"},"info":{"status":0,"passed":true,"positionStatus":"departed","distance":234869,"distanceFromStart":251312},"delayReasons":null},{"station":{"evaNr":"8000036_00","name":"Bielefeld Hbf","code":null,"geocoordinates":{"latitude":52.029261,"longitude":8.532722}},"timetable":{"scheduledArrivalTime":1637094060000,"actualArrivalTime":1637094240000,"showActualArrivalTime":true,"arrivalDelay":"+3","scheduledDepartureTime":1637094180000,"actualDepartureTime":1637094360000,"showActualDepartureTime":true,"departureDelay":"+3"},"track":{"scheduled":"4","actual":"4"},"info":{"status":0,"passed":false,"positionStatus":"future","distance":90982,"distanceFromStart":342294},"delayReasons":null},{"station":{"evaNr":"8000149_00","name":"Hamm (Westf) Hbf","code":null,"geocoordinates":{"latitude":51.678078,"longitude":7.807821}},"timetable":{"scheduledArrivalTime":1637095680000,"actualArrivalTime":1637095860000,"showActualArrivalTime":true,"arrivalDelay":"+3","scheduledDepartureTime":1637095860000,"actualDepartureTime":1637096040000,"showActualDepartureTime":true,"departureDelay":"+3"},"track":{"scheduled":"10","actual":"10"},"info":{"status":0,"passed":false,"positionStatus":"future","distance":63292,"distanceFromStart":405586},"delayReasons":null},{"station":{"evaNr":"8000080_00","name":"Dortmund Hbf","code":null,"geocoordinates":{"latitude":51.517896,"longitude":7.45929}},"timetable":{"scheduledArrivalTime":1637097000000,"actualArrivalTime":1637097120000,"showActualArrivalTime":true,"arrivalDelay":"+2","scheduledDepartureTime":1637097120000,"actualDepartureTime":1637097240000,"showActualDepartureTime":true,"departureDelay":"+2"},"track":{"scheduled":"20","actual":"20"},"info":{"status":0,"passed":false,"positionStatus":"future","distance":29955,"distanceFromStart":435541},"delayReasons":null},{"station":{"evaNr":"8000041_00","name":"Bochum Hbf","code":null,"geocoordinates":{"latitude":51.478609,"longitude":7.223275}},"timetable":{"scheduledArrivalTime":1637097780000,"actualArrivalTime":1637097960000,"showActualArrivalTime":true,"arrivalDelay":"+3","scheduledDepartureTime":1637097900000,"actualDepartureTime":1637098020000,"showActualDepartureTime":true,"departureDelay":"+2"},"track":{"scheduled":"3","actual":"3"},"info":{"status":0,"passed":false,"positionStatus":"future","distance":16916,"distanceFromStart":452457},"delayReasons":null},{"station":{"evaNr":"8000098_00","name":"Essen Hbf","code":null,"geocoordinates":{"latitude":51.451355,"longitude":7.014793}},"timetable":{"scheduledArrivalTime":1637098500000,"actualArrivalTime":1637098500000,"showActualArrivalTime":true,"arrivalDelay":"","scheduledDepartureTime":1637098620000,"actualDepartureTime":1637098620000,"showActualDepartureTime":true,"departureDelay":""},"track":{"scheduled":"1","actual":"1"},"info":{"status":0,"passed":false,"positionStatus":"future","distance":14761,"distanceFromStart":467218},"delayReasons":null},{"station":{"evaNr":"8000086_00","name":"Duisburg Hbf","code":null,"geocoordinates":{"latitude":51.429785,"longitude":6.775903}},"timetable":{"scheduledArrivalTime":1637099280000,"actualArrivalTime":1637099400000,"showActualArrivalTime":true,"arrivalDelay":"+2","scheduledDepartureTime":1637099460000,"actualDepartureTime":1637099580000,"showActualDepartureTime":true,"departureDelay":"+2"},"track":{"scheduled":"4","actual":"4"},"info":{"status":0,"passed":false,"positionStatus":"future","distance":16735,"distanceFromStart":483953},"delayReasons":null},{"station":{"evaNr":"8000085_00","name":"Düsseldorf Hbf","code":null,"geocoordinates":{"latitude":51.219962,"longitude":6.794319}},"timetable":{"scheduledArrivalTime":1637100900000,"actualArrivalTime":1637100900000,"showActualArrivalTime":true,"arrivalDelay":"","scheduledDepartureTime":null,"actualDepartureTime":null,"showActualDepartureTime":null,"departureDelay":""},"track":{"scheduled":"5","actual":"5"},"info":{"status":0,"passed":false,"positionStatus":"future","distance":23373,"distanceFromStart":507326},"delayReasons":null}]},"connection":null,"selectedRoute":{"conflictInfo":{"status":"NO_CONFLICT","text":null},"mobility":null},"active":null}
2 |
--------------------------------------------------------------------------------
/Sources/Train-API/Debug Data/tripInfo2.json:
--------------------------------------------------------------------------------
1 | {
2 | "trip":{
3 | "tripDate":"2021-11-16",
4 | "trainType":"ICE",
5 | "vzn":"542",
6 | "actualPosition":251312,
7 | "distanceFromLastStop":8181,
8 | "totalDistance":507326,
9 | "stopInfo":{
10 | "scheduledNext":"8000036_00",
11 | "actualNext":"8000036_00",
12 | "actualLast":"8000152_00",
13 | "actualLastStarted":"8000036",
14 | "finalStationName":"Düsseldorf Hbf",
15 | "finalStationEvaNr":"8000085_00"
16 | },
17 | "stops":[
18 | {
19 | "station":{
20 | "evaNr":"8010255_00",
21 | "name":"Berlin Hundbrunnen",
22 | "code":null,
23 | "geocoordinates":{
24 | "latitude":52.510488,
25 | "longitude":13.434681
26 | }
27 | },
28 | "timetable":{
29 | "scheduledArrivalTime":null,
30 | "actualArrivalTime":null,
31 | "showActualArrivalTime":null,
32 | "arrivalDelay":"",
33 | "scheduledDepartureTime":1637084100000,
34 | "actualDepartureTime":1637084100000,
35 | "showActualDepartureTime":true,
36 | "departureDelay":""
37 | },
38 | "track":{
39 | "scheduled":"6",
40 | "actual":"6"
41 | },
42 | "info":{
43 | "status":0,
44 | "passed":true,
45 | "positionStatus":"passed",
46 | "distance":0,
47 | "distanceFromStart":0
48 | },
49 | "delayReasons":null
50 | },
51 | {
52 | "station":{
53 | "evaNr":"8010255_00",
54 | "name":"Berlin Reichenberger Str.",
55 | "code":null,
56 | "geocoordinates":{
57 | "latitude":52.510488,
58 | "longitude":13.434681
59 | }
60 | },
61 | "timetable":{
62 | "scheduledArrivalTime":null,
63 | "actualArrivalTime":null,
64 | "showActualArrivalTime":null,
65 | "arrivalDelay":"",
66 | "scheduledDepartureTime":1637084100000,
67 | "actualDepartureTime":1637084100000,
68 | "showActualDepartureTime":true,
69 | "departureDelay":""
70 | },
71 | "track":{
72 | "scheduled":"6",
73 | "actual":"6"
74 | },
75 | "info":{
76 | "status":0,
77 | "passed":true,
78 | "positionStatus":"passed",
79 | "distance":0,
80 | "distanceFromStart":0
81 | },
82 | "delayReasons":null
83 | },
84 | {
85 | "station":{
86 | "evaNr":"8011160_00",
87 | "name":"Berlin Hbf",
88 | "code":null,
89 | "geocoordinates":{
90 | "latitude":52.525592,
91 | "longitude":13.369545
92 | }
93 | },
94 | "timetable":{
95 | "scheduledArrivalTime":1637084520000,
96 | "actualArrivalTime":1637084580000,
97 | "showActualArrivalTime":true,
98 | "arrivalDelay":"+1",
99 | "scheduledDepartureTime":1637084760000,
100 | "actualDepartureTime":1637084820000,
101 | "showActualDepartureTime":true,
102 | "departureDelay":"+1"
103 | },
104 | "track":{
105 | "scheduled":"13",
106 | "actual":"13"
107 | },
108 | "info":{
109 | "status":0,
110 | "passed":true,
111 | "positionStatus":"passed",
112 | "distance":4718,
113 | "distanceFromStart":4718
114 | },
115 | "delayReasons":null
116 | },
117 | {
118 | "station":{
119 | "evaNr":"8010404_00",
120 | "name":"Berlin-Spandau",
121 | "code":null,
122 | "geocoordinates":{
123 | "latitude":52.534648,
124 | "longitude":13.196898
125 | }
126 | },
127 | "timetable":{
128 | "scheduledArrivalTime":1637085540000,
129 | "actualArrivalTime":1637085600000,
130 | "showActualArrivalTime":true,
131 | "arrivalDelay":"+1",
132 | "scheduledDepartureTime":1637085720000,
133 | "actualDepartureTime":1637085720000,
134 | "showActualDepartureTime":true,
135 | "departureDelay":""
136 | },
137 | "track":{
138 | "scheduled":"4",
139 | "actual":"4"
140 | },
141 | "info":{
142 | "status":0,
143 | "passed":true,
144 | "positionStatus":"passed",
145 | "distance":11725,
146 | "distanceFromStart":16443
147 | },
148 | "delayReasons":null
149 | },
150 | {
151 | "station":{
152 | "evaNr":"8000152_00",
153 | "name":"Hannover Hbf",
154 | "code":null,
155 | "geocoordinates":{
156 | "latitude":52.376761,
157 | "longitude":9.741021
158 | }
159 | },
160 | "timetable":{
161 | "scheduledArrivalTime":1637090880000,
162 | "actualArrivalTime":1637091120000,
163 | "showActualArrivalTime":true,
164 | "arrivalDelay":"+4",
165 | "scheduledDepartureTime":1637091060000,
166 | "actualDepartureTime":1637091360000,
167 | "showActualDepartureTime":true,
168 | "departureDelay":"+5"
169 | },
170 | "track":{
171 | "scheduled":"12",
172 | "actual":"12"
173 | },
174 | "info":{
175 | "status":0,
176 | "passed":true,
177 | "positionStatus":"departed",
178 | "distance":234869,
179 | "distanceFromStart":251312
180 | },
181 | "delayReasons":null
182 | },
183 | {
184 | "station":{
185 | "evaNr":"8000036_00",
186 | "name":"Bielefeld Hbf",
187 | "code":null,
188 | "geocoordinates":{
189 | "latitude":52.029261,
190 | "longitude":8.532722
191 | }
192 | },
193 | "timetable":{
194 | "scheduledArrivalTime":1637094060000,
195 | "actualArrivalTime":1637094240000,
196 | "showActualArrivalTime":true,
197 | "arrivalDelay":"+3",
198 | "scheduledDepartureTime":1637094180000,
199 | "actualDepartureTime":1637094360000,
200 | "showActualDepartureTime":true,
201 | "departureDelay":"+3"
202 | },
203 | "track":{
204 | "scheduled":"4",
205 | "actual":"4"
206 | },
207 | "info":{
208 | "status":0,
209 | "passed":false,
210 | "positionStatus":"future",
211 | "distance":90982,
212 | "distanceFromStart":342294
213 | },
214 | "delayReasons":null
215 | },
216 | {
217 | "station":{
218 | "evaNr":"8000149_00",
219 | "name":"Hamm (Westf) Hbf",
220 | "code":null,
221 | "geocoordinates":{
222 | "latitude":51.678078,
223 | "longitude":7.807821
224 | }
225 | },
226 | "timetable":{
227 | "scheduledArrivalTime":1637095680000,
228 | "actualArrivalTime":1637095860000,
229 | "showActualArrivalTime":true,
230 | "arrivalDelay":"+3",
231 | "scheduledDepartureTime":1637095860000,
232 | "actualDepartureTime":1637096040000,
233 | "showActualDepartureTime":true,
234 | "departureDelay":"+3"
235 | },
236 | "track":{
237 | "scheduled":"10",
238 | "actual":"10"
239 | },
240 | "info":{
241 | "status":0,
242 | "passed":false,
243 | "positionStatus":"future",
244 | "distance":63292,
245 | "distanceFromStart":405586
246 | },
247 | "delayReasons":null
248 | },
249 | {
250 | "station":{
251 | "evaNr":"8000080_00",
252 | "name":"Dortmund Hbf",
253 | "code":null,
254 | "geocoordinates":{
255 | "latitude":51.517896,
256 | "longitude":7.45929
257 | }
258 | },
259 | "timetable":{
260 | "scheduledArrivalTime":1637097000000,
261 | "actualArrivalTime":1637097120000,
262 | "showActualArrivalTime":true,
263 | "arrivalDelay":"+2",
264 | "scheduledDepartureTime":1637097120000,
265 | "actualDepartureTime":1637097240000,
266 | "showActualDepartureTime":true,
267 | "departureDelay":"+2"
268 | },
269 | "track":{
270 | "scheduled":"20",
271 | "actual":"20"
272 | },
273 | "info":{
274 | "status":0,
275 | "passed":false,
276 | "positionStatus":"future",
277 | "distance":29955,
278 | "distanceFromStart":435541
279 | },
280 | "delayReasons":null
281 | },
282 | {
283 | "station":{
284 | "evaNr":"8000041_00",
285 | "name":"Bochum Hbf",
286 | "code":null,
287 | "geocoordinates":{
288 | "latitude":51.478609,
289 | "longitude":7.223275
290 | }
291 | },
292 | "timetable":{
293 | "scheduledArrivalTime":1637097780000,
294 | "actualArrivalTime":1637097960000,
295 | "showActualArrivalTime":true,
296 | "arrivalDelay":"+3",
297 | "scheduledDepartureTime":1637097900000,
298 | "actualDepartureTime":1637098020000,
299 | "showActualDepartureTime":true,
300 | "departureDelay":"+2"
301 | },
302 | "track":{
303 | "scheduled":"3",
304 | "actual":"3"
305 | },
306 | "info":{
307 | "status":0,
308 | "passed":false,
309 | "positionStatus":"future",
310 | "distance":16916,
311 | "distanceFromStart":452457
312 | },
313 | "delayReasons":null
314 | },
315 | {
316 | "station":{
317 | "evaNr":"8000098_00",
318 | "name":"Essen Hbf",
319 | "code":null,
320 | "geocoordinates":{
321 | "latitude":51.451355,
322 | "longitude":7.014793
323 | }
324 | },
325 | "timetable":{
326 | "scheduledArrivalTime":1637098500000,
327 | "actualArrivalTime":1637098500000,
328 | "showActualArrivalTime":true,
329 | "arrivalDelay":"",
330 | "scheduledDepartureTime":1637098620000,
331 | "actualDepartureTime":1637098620000,
332 | "showActualDepartureTime":true,
333 | "departureDelay":"+22"
334 | },
335 | "track":{
336 | "scheduled":"1",
337 | "actual":"1"
338 | },
339 | "info":{
340 | "status":0,
341 | "passed":false,
342 | "positionStatus":"future",
343 | "distance":14761,
344 | "distanceFromStart":467218
345 | },
346 | "delayReasons":null
347 | },
348 | {
349 | "station":{
350 | "evaNr":"8000086_00",
351 | "name":"Duisburg Hbf",
352 | "code":null,
353 | "geocoordinates":{
354 | "latitude":51.429785,
355 | "longitude":6.775903
356 | }
357 | },
358 | "timetable":{
359 | "scheduledArrivalTime":1637099280000,
360 | "actualArrivalTime":1637099400000,
361 | "showActualArrivalTime":true,
362 | "arrivalDelay":"+2",
363 | "scheduledDepartureTime":1637099460000,
364 | "actualDepartureTime":1637099580000,
365 | "showActualDepartureTime":true,
366 | "departureDelay":"+2"
367 | },
368 | "track":{
369 | "scheduled":"4",
370 | "actual":"4"
371 | },
372 | "info":{
373 | "status":0,
374 | "passed":false,
375 | "positionStatus":"future",
376 | "distance":16735,
377 | "distanceFromStart":483953
378 | },
379 | "delayReasons":null
380 | },
381 | {
382 | "station":{
383 | "evaNr":"8000085_00",
384 | "name":"Düsseldorf Hbf",
385 | "code":null,
386 | "geocoordinates":{
387 | "latitude":51.219962,
388 | "longitude":6.794319
389 | }
390 | },
391 | "timetable":{
392 | "scheduledArrivalTime":1637100900000,
393 | "actualArrivalTime":1637100900000,
394 | "showActualArrivalTime":true,
395 | "arrivalDelay":"",
396 | "scheduledDepartureTime":null,
397 | "actualDepartureTime":null,
398 | "showActualDepartureTime":null,
399 | "departureDelay":""
400 | },
401 | "track":{
402 | "scheduled":"5",
403 | "actual":"5"
404 | },
405 | "info":{
406 | "status":0,
407 | "passed":false,
408 | "positionStatus":"future",
409 | "distance":23373,
410 | "distanceFromStart":507326
411 | },
412 | "delayReasons":null
413 | }
414 | ]
415 | },
416 | "connection":null,
417 | "selectedRoute":{
418 | "conflictInfo":{
419 | "status":"NO_CONFLICT",
420 | "text":null
421 | },
422 | "mobility":null
423 | },
424 | "active":null
425 | }
426 |
--------------------------------------------------------------------------------
/Sources/Train-API/ICE Baureihen/BR401.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/ICE Baureihen/BR401.pdf
--------------------------------------------------------------------------------
/Sources/Train-API/ICE Baureihen/BR402.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/ICE Baureihen/BR402.pdf
--------------------------------------------------------------------------------
/Sources/Train-API/ICE Baureihen/BR403 Serie 1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/ICE Baureihen/BR403 Serie 1.pdf
--------------------------------------------------------------------------------
/Sources/Train-API/ICE Baureihen/BR403 Serie 2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/ICE Baureihen/BR403 Serie 2.pdf
--------------------------------------------------------------------------------
/Sources/Train-API/ICE Baureihen/BR406.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/ICE Baureihen/BR406.pdf
--------------------------------------------------------------------------------
/Sources/Train-API/ICE Baureihen/BR407.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/ICE Baureihen/BR407.pdf
--------------------------------------------------------------------------------
/Sources/Train-API/ICE Baureihen/BR411 Serie 1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/ICE Baureihen/BR411 Serie 1.pdf
--------------------------------------------------------------------------------
/Sources/Train-API/ICE Baureihen/BR411 Serie 2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/ICE Baureihen/BR411 Serie 2.pdf
--------------------------------------------------------------------------------
/Sources/Train-API/ICE Baureihen/BR412.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/ICE Baureihen/BR412.pdf
--------------------------------------------------------------------------------
/Sources/Train-API/ICE Baureihen/BR415.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/ICE Baureihen/BR415.pdf
--------------------------------------------------------------------------------
/Sources/Train-API/ICEConnection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ICEConnection.swift
3 | // ICE Buddy
4 | //
5 | // Created by Frederik Riedel on 16.11.21.
6 | //
7 |
8 | import Foundation
9 | import Alamofire
10 | import CoreLocation
11 | import AppKit
12 | import FredKit
13 |
14 | public class ICEConnection {
15 |
16 | public static let shared = ICEConnection()
17 |
18 | public func loadCurrentTrainData(completion: @escaping (TrainMetaData?) -> Void) {
19 | AF.request("https://iceportal.de/api1/rs/status").responseJSON { response in
20 | if let result = response.value as? [String: Any] {
21 | let metaData = TrainMetaData(dict: result)
22 | completion(metaData)
23 | } else {
24 | #if DEBUG
25 | print(Bundle.module)
26 | if let data = try? Data(contentsOf: Bundle.module.url(forResource: "ice", withExtension: "json")!) {
27 | let jsonResult = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
28 | if let jsonResult = jsonResult as? [String: Any] {
29 | let metaData = TrainMetaData(dict: jsonResult)
30 | completion(metaData)
31 | }
32 | }
33 | #else
34 | // currently not connected to ICE?
35 | completion(nil)
36 | #endif
37 | }
38 | }
39 | }
40 |
41 | public func loadCurrentTripData(completion: @escaping (TripData?) -> Void) {
42 | AF.request("https://iceportal.de/api1/rs/tripInfo/trip").responseJSON { response in
43 | if let result = response.value as? [String: Any] {
44 | let metaData = TripData(dict: result)
45 |
46 |
47 |
48 | completion(metaData)
49 | } else {
50 | #if DEBUG
51 |
52 |
53 | if let data = try? Data(contentsOf: Bundle.module.url(forResource: "paris", withExtension: "json")!) {
54 | let jsonResult = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
55 | if let jsonResult = jsonResult as? [String: Any] {
56 | let metaData = TripData(dict: jsonResult)
57 |
58 | completion(metaData)
59 | }
60 | }
61 | #else
62 | // currently not connected to ICE?
63 | completion(nil)
64 | #endif
65 | }
66 | }
67 | }
68 |
69 | }
70 |
71 | extension Array where Element == Int {
72 | private func number(number: Int, matchesWithTzn tzn: String) -> Bool {
73 | tzn.lowercased() == "tz\(number)" || tzn.lowercased() == "tz \(number)" || tzn.lowercased() == "ice\(number)" || tzn.lowercased() == "ice \(number)" ||
74 | tzn.lowercased() == "tz0\(number)" || tzn.lowercased() == "tz 0\(number)" || tzn.lowercased() == "ice0\(number)" || tzn.lowercased() == "ice 0\(number)"
75 | }
76 |
77 | func contains(triebzugnummer: String) -> Bool {
78 | self.contains(where: { number in
79 | self.number(number: number, matchesWithTzn: triebzugnummer)
80 | })
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Sources/Train-API/InternetConnection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by Frederik Riedel on 05.06.22.
6 | //
7 |
8 | import Foundation
9 |
10 | public enum InternetConnection {
11 | case high, unstable
12 |
13 | static func from(rawString: String) -> InternetConnection {
14 | if rawString == "HIGH" {
15 | return .high
16 | }
17 | return .unstable
18 | }
19 |
20 | public var localizedString: String {
21 | switch self {
22 | case .high:
23 | return "High"
24 | case .unstable:
25 | return "Unstable"
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/Train-API/JourneyStop.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by Frederik Riedel on 05.06.22.
6 | //
7 |
8 | import Foundation
9 | import CoreLocation
10 |
11 | public struct JourneyStop {
12 | public let evaNr: String
13 | public let name: String
14 |
15 | public let actualDepartureTime: Date?
16 | public let actualArrivalTime: Date?
17 |
18 | public let scheduledDepartureTime: Date?
19 | let scheduledArrivalTime: Date?
20 |
21 | public let departureDelay: String
22 | public let scheduledTrack: String
23 | public let actualTrack: String
24 |
25 | public let passed: Bool
26 |
27 | public let coordinate: CLLocationCoordinate2D
28 |
29 | public var humanReadableArrivalTime: String {
30 | if let actualArrivalTime = actualArrivalTime {
31 | return actualArrivalTime.minuteTimeString
32 | }
33 |
34 | if let scheduledArrivalTime = scheduledArrivalTime {
35 | return scheduledArrivalTime.minuteTimeString
36 | }
37 |
38 | if let actualDepartureTime = actualDepartureTime {
39 | return actualDepartureTime.minuteTimeString
40 | }
41 |
42 | if let scheduledDepartureTime = scheduledDepartureTime {
43 | return scheduledDepartureTime.minuteTimeString
44 | }
45 |
46 |
47 | return "Time Unknown"
48 | }
49 |
50 | public init?(dict: [String: Any]) {
51 | if let station = dict["station"] as? [String: Any] {
52 |
53 | if let evaNr = station["evaNr"] as? String {
54 | self.evaNr = evaNr
55 | } else {
56 | return nil
57 | }
58 |
59 | if let stopName = station["name"] as? String {
60 | self.name = stopName
61 | } else {
62 | return nil
63 | }
64 |
65 | if let geocoordinates = station["geocoordinates"] as? [String: Double] {
66 | if let latitude = geocoordinates["latitude"], let longitude = geocoordinates["longitude"] {
67 | self.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
68 | } else {
69 | return nil
70 | }
71 | } else {
72 | return nil
73 | }
74 |
75 | } else {
76 | return nil
77 | }
78 |
79 | if let info = dict["info"] as? [String: Any] {
80 | if let passed = info["passed"] as? Bool {
81 | self.passed = passed
82 | } else {
83 | return nil
84 | }
85 | } else {
86 | return nil
87 | }
88 |
89 | if let track = dict["track"] as? [String: Any] {
90 |
91 | if let actualTrack = track["actual"] as? String {
92 | if actualTrack.isEmpty {
93 | self.actualTrack = "–"
94 | } else {
95 | self.actualTrack = actualTrack
96 | }
97 |
98 | } else {
99 | return nil
100 | }
101 |
102 | if let scheduledTrack = track["scheduled"] as? String {
103 | self.scheduledTrack = scheduledTrack
104 | } else {
105 | self.scheduledTrack = "–"
106 | }
107 |
108 | } else {
109 | return nil
110 | }
111 |
112 | if let timetable = dict["timetable"] as? [String: Any] {
113 | if let actualDepartureTime = timetable["actualDepartureTime"] as? Double {
114 | self.actualDepartureTime = Date(timeIntervalSince1970: actualDepartureTime / 1000.0)
115 | } else {
116 | self.actualDepartureTime = nil
117 | }
118 |
119 | if let actualArrivalTime = timetable["actualArrivalTime"] as? Double {
120 | self.actualArrivalTime = Date(timeIntervalSince1970: actualArrivalTime / 1000.0)
121 | } else {
122 | self.actualArrivalTime = nil
123 | }
124 |
125 | if let scheduledArrivalTime = timetable["scheduledArrivalTime"] as? Double {
126 | self.scheduledArrivalTime = Date(timeIntervalSince1970: scheduledArrivalTime / 1000.0)
127 | } else {
128 | self.scheduledArrivalTime = nil
129 | }
130 |
131 | if let scheduledDepartureTime = timetable["scheduledDepartureTime"] as? Double {
132 | self.scheduledDepartureTime = Date(timeIntervalSince1970: scheduledDepartureTime / 1000.0)
133 | } else {
134 | self.scheduledDepartureTime = nil
135 | }
136 |
137 | if let departureDelay = timetable["departureDelay"] as? String {
138 | self.departureDelay = departureDelay
139 | } else {
140 | return nil
141 | }
142 |
143 | } else {
144 | return nil
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR401.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "ice 1.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR401.imageset/ice 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/Media.xcassets/BR401.imageset/ice 1.png
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR402.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "ice 2.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR402.imageset/ice 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/Media.xcassets/BR402.imageset/ice 2.png
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR403.imageset/BR403.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/Media.xcassets/BR403.imageset/BR403.png
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR403.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "BR403.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR406.imageset/BR406.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/Media.xcassets/BR406.imageset/BR406.png
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR406.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "BR406.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR407.imageset/BR407.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/Media.xcassets/BR407.imageset/BR407.png
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR407.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "BR407.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR411.imageset/BR411.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/Media.xcassets/BR411.imageset/BR411.png
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR411.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "BR411.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR412.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "ice 4.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR412.imageset/ice 4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/Media.xcassets/BR412.imageset/ice 4.png
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR415.imageset/BR415.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ICE-Buddy/Train-API-Swift-Package/ea56a3e9b5a1738ecd2bbe7da0cfe02215550c43/Sources/Train-API/Media.xcassets/BR415.imageset/BR415.png
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/BR415.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "BR415.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Train-API/Media.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Sources/Train-API/TrainMetaData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by Frederik Riedel on 05.06.22.
6 | //
7 |
8 | import Foundation
9 | import CoreLocation
10 |
11 | public struct TrainMetaData {
12 | public let speed: Double
13 | public let internetConnection: InternetConnection
14 | public let trainType: TrainType
15 | public let trainId: String
16 | public let currentLocation: CLLocationCoordinate2D
17 | public let timestamp: Date
18 |
19 | public init?(dict: [String: Any]) {
20 |
21 | if let speed = dict["speed"] as? Double {
22 | self.speed = speed
23 | } else {
24 | return nil
25 | }
26 |
27 | if let internetConnectivity = dict["connectivity"] as? [String: Any] {
28 | if let currentState = internetConnectivity["currentState"] as? String {
29 | self.internetConnection = InternetConnection.from(rawString: currentState)
30 | } else {
31 | return nil
32 | }
33 | } else {
34 | return nil
35 | }
36 |
37 | if let triebZugNummer = dict["tzn"] as? String {
38 | self.trainType = TrainType.trainType(from: triebZugNummer)
39 | self.trainId = triebZugNummer
40 | } else {
41 | return nil
42 | }
43 |
44 | if let longitude = dict["longitude"] as? Double, let latitude = dict["latitude"] as? Double {
45 | let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
46 | self.currentLocation = coordinate
47 | } else {
48 | return nil
49 | }
50 |
51 | if let serverTime = dict["serverTime"] as? Double {
52 | self.timestamp = Date(timeIntervalSince1970: serverTime / 1000)
53 | } else {
54 | return nil
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Sources/Train-API/TrainType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by Frederik Riedel on 05.06.22.
6 | //
7 |
8 | import Foundation
9 | import AppKit
10 |
11 | public enum TrainType: CaseIterable {
12 |
13 | case BR401, BR402, BR403, BR406, BR407, BR408, BR411, BR415, BR412, unknown
14 |
15 | private var triebZugNummern: [Int] {
16 | switch self {
17 | case .BR401:
18 | return [Int](101...199)
19 | case .BR402:
20 | return [Int](201...299)
21 | case .BR403:
22 | return [Int](301...399)
23 | case .BR406:
24 | return [Int](4601...4699)
25 | case .BR407:
26 | return [Int](701...799) + [Int](4701...4799)
27 | case .BR408:
28 | return [Int](801...899)
29 | case .BR411:
30 | return [Int](1101...1199)
31 | case .BR415:
32 | return [Int](1501...1599)
33 | case .BR412:
34 | return [Int](9001...9999)
35 | case .unknown:
36 | return []
37 | }
38 | }
39 |
40 | public var humanReadableTrainType: String {
41 | switch self {
42 | case .BR401:
43 | return "ICE 1"
44 | case .BR402:
45 | return "ICE 2"
46 | case .BR403, .BR406, .BR407:
47 | return "ICE 3"
48 | case .BR408:
49 | return "ICE 3 Neo"
50 | case .BR411, .BR415:
51 | return "ICE T"
52 | case .BR412:
53 | return "ICE 4"
54 | case .unknown:
55 | return "Unknown Train Type"
56 | }
57 | }
58 |
59 |
60 | public static func trainType(from triebZugNummer: String) -> TrainType {
61 | return TrainType.allCases.first { trainType in
62 | trainType.triebZugNummern.contains(triebzugnummer: triebZugNummer)
63 | } ?? .unknown
64 | }
65 |
66 | #if SWIFT_PACKAGE
67 | public var trainIcon: NSImage {
68 |
69 |
70 | switch self {
71 | case .BR401:
72 | return Bundle.module.image(forResource: "BR401")!
73 | case .BR402:
74 | return Bundle.module.image(forResource: "BR402")!
75 | case .BR403:
76 | return Bundle.module.image(forResource: "BR403")!
77 | case .BR406:
78 | return Bundle.module.image(forResource: "BR406")!
79 | case .BR407:
80 | return Bundle.module.image(forResource: "BR407")!
81 | case .BR408:
82 | return Bundle.module.image(forResource: "BR408")!
83 | case .BR411:
84 | return Bundle.module.image(forResource: "BR411")!
85 | case .BR415:
86 | return Bundle.module.image(forResource: "BR415")!
87 | case .BR412:
88 | return Bundle.module.image(forResource: "BR412")!
89 | case .unknown:
90 | return Bundle.module.image(forResource: "BR401")!
91 | }
92 | }
93 | #endif
94 | }
95 |
--------------------------------------------------------------------------------
/Sources/Train-API/TripData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by Frederik Riedel on 05.06.22.
6 | //
7 |
8 | import Foundation
9 |
10 | public struct TripData {
11 | public let trainId: String
12 | public let stops: [JourneyStop]
13 |
14 | public var startStop: JourneyStop? {
15 | return stops.first
16 | }
17 |
18 | public var finalStop: JourneyStop? {
19 | return stops.last
20 | }
21 |
22 | public var nextStop: JourneyStop? {
23 | stops.first { stop in
24 | !stop.passed
25 | }
26 | }
27 |
28 |
29 |
30 | init?(dict: [String: Any]) {
31 | if let tripDict = dict["trip"] as? [String: Any] {
32 | if let trainType = tripDict["trainType"] as? String, let connectionId = tripDict["vzn"] as? String {
33 | self.trainId = "\(trainType) \(connectionId)"
34 | } else {
35 | return nil
36 | }
37 |
38 | if let stops = tripDict["stops"] as? [ [String: Any] ] {
39 | self.stops = stops.compactMap({ stopDict in
40 | return JourneyStop(dict: stopDict)
41 | })
42 | } else {
43 | return nil
44 | }
45 |
46 |
47 |
48 | } else {
49 | return nil
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Tests/Train-APITests/Train_APITests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import Train_API
3 |
4 | final class Train_APITests: XCTestCase {
5 | func testExample() throws {
6 | // This is an example of a functional test case.
7 | // Use XCTAssert and related functions to verify your tests produce the correct
8 | // results.
9 | ICEConnection.shared.loadCurrentTripData { tripData in
10 | print(tripData?.finalStop)
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------