|
|
@@ -0,0 +1,62 @@ |
|
|
|
#!/usr/bin/python3 |
|
|
|
import requests |
|
|
|
import sys |
|
|
|
import textwrap |
|
|
|
import pprint |
|
|
|
from pathlib import Path |
|
|
|
try: |
|
|
|
from simplejson.errors import JSONDecodeError |
|
|
|
except ImportError: |
|
|
|
from json.decoder import JSONDecodeError |
|
|
|
|
|
|
|
api = 'http://parkering.linkoping.se/' |
|
|
|
key = Path('key-parking').read_text().strip() |
|
|
|
|
|
|
|
# Fetch JSON from url and run it through transform, pretty printing errors |
|
|
|
# and the data worked on as exhaustively as possible. |
|
|
|
def json_query(url, transform, params={}): |
|
|
|
try: |
|
|
|
result = requests.get(url, params) |
|
|
|
except requests.exceptions.ConnectionError: |
|
|
|
print("Network connection error.") |
|
|
|
sys.exit(1) |
|
|
|
try: |
|
|
|
data = result.json() |
|
|
|
except JSONDecodeError as err: |
|
|
|
print('Error when decoding JSON:\nFrom endpoint ' + url + ':\n' + str(err) + '\n' + str(result) + '\n') |
|
|
|
sys.exit(1) |
|
|
|
try: |
|
|
|
return transform(data) |
|
|
|
except (IndexError, KeyError) as err: |
|
|
|
print('Error when traversing JSON:\nFrom endpoint ' + url + ':\n' + str(err)) |
|
|
|
pprint.PrettyPrinter(indent=2).pprint(data) |
|
|
|
sys.exit(1) |
|
|
|
|
|
|
|
# Get parking lots from the municipal server. |
|
|
|
# The timestamp part of this API does not work as expected, if non-zero it will return all computer parking terminal lots |
|
|
|
# in ParkingAreaUpdateList regardless of their status, up to a timestamp of less than one hour into the future, after which it will return nothing. |
|
|
|
def get_parking_lots(): |
|
|
|
return json_query(api + 'Parkeringsdata/ParkeringsdataV1.svc/GetParkeringsytaList/' + key + '/0', lambda data: data['ParkingAreaNewList'], {}) |
|
|
|
|
|
|
|
# The key ParkingSpacesAvailable is only present for those lots that are tracked by computer parking terminals. |
|
|
|
# All other lots only have static information available. |
|
|
|
def computerized(lot): |
|
|
|
return 'ParkingSpacesAvailable' in lot |
|
|
|
|
|
|
|
# The parking type '4' means handicap spots, whoever organized this put handicap spots as separate lots with duplicate names. |
|
|
|
def only_has_handicap_spots(lot): |
|
|
|
return lot['ParkingTypes'] == [4] |
|
|
|
|
|
|
|
# The downtown parking lots are equipped with electric charging stations and the API has a parking type for this |
|
|
|
# but the lot data has not been updated to reflect this, so this function always returns False. |
|
|
|
def electric_car_lot(lot): |
|
|
|
return 3 in lot['ParkingTypes'] |
|
|
|
|
|
|
|
def main(): |
|
|
|
print('Parking spaces available:') |
|
|
|
for lot in sorted(get_parking_lots(), key=lambda lot: lot['Name']): |
|
|
|
if computerized(lot) and not only_has_handicap_spots(lot): |
|
|
|
print("{Name}: {ParkingSpacesAvailable}/{ParkingSpaces}".format(**lot)) |
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
main() |