Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/import parking garages #352

Merged
merged 9 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions mobility_data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ To import data type:
```
./manage.py import_charging_stations
```
### Parking garages
To import data type:
```
./manage.py import_parking_garages
```
### Culture Routes
To import data type:
```
Expand Down
5 changes: 5 additions & 0 deletions mobility_data/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from mobility_data.importers.loading_unloading_places import (
CONTENT_TYPE_NAME as LOADING_UNLOADING_PLACE,
)
from mobility_data.importers.parking_garages import CONTENT_TYPE_NAME as PARKING_GARAGE
from mobility_data.importers.parking_machines import (
CONTENT_TYPE_NAME as PARKING_MACHINE,
)
Expand Down Expand Up @@ -55,4 +56,8 @@
"importer_name": "parking_machines",
"to_services_list": False,
},
PARKING_GARAGE: {
"importer_name": "parking_garages",
"to_services_list": False,
},
}
21 changes: 21 additions & 0 deletions mobility_data/data/parkkihallit.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Nimi;Osoite;N;E;Pysäköintipaikat;Invapaikat;Sähkölatauspaikat;Palvelut;Palvelut (ru);Palvelut (eng);Huom;Huom (ru);Huom (eng);Linkki sivuille
Auriga;Juhana Herttuan puistokatu 21;6703305;23457449;330;2;2 x Type 2 22 kW;Apuvirta, hissi, liikkumisesteisen pysäköintipaikka, sähköauton latauspiste;Elbilsladdning, hiss, parkeringsplats för funktionshindrade, startkablar;Disabled parking, elevator, EV charging, jump leads;;;;https://www.aimopark.fi/kaupungit/turku/auriga-/
Hansakortteli;Kristiinankatu 11;6704479;23459433;162;2;2 x Type 2 11kW, 2 x CSS 90kW;Apuvirta, hissi, kameratunnistus, kengänkiillotin, liikkumisesteisen pysäköintipaikka, ostoskärryt, rengaspumppu, sateenvarjon lainaus, sähköauton latauspiste, videovalvonta, yövartiointi;Elbilsladdning, hiss, kameraparkering, kameraövervakat, kundvagnar, nattlig övervakning, paraply, parkeringsplats för funktionshindrade, skoputs, startkablar, tryckluft;Automatic number-plate recognition (ANPR), CCTV, disabled parking, elevator, EV charging, jump leads, shoe polisher, shopping trolley, surveillance at night, tyre pump, umbrella hire;Parkkihallin omalla sivulla ja aimoparkin latausverkostokartalla eriävää tietoa latauspisteistä;Information angående elbilsladdning på parkeringshusets hemsida strider mot informationen på aimoparks laddningsnätverk karta;Information regarding EV charging on the parking garage's website conflicts with the information on aimopark's charging network map;https://www.aimopark.fi/kaupungit/turku/hansakortteli/
Harppuunaparkki;Vallihaudankatu 1;6702966;23457475;294;2;4 x Type 2 22 kW;Sähköauton latauspiste;Elbilsladdning;EV charging;Parkkihallin omalla sivulla ja aimoparkin latausverkostokartalla eriävää tietoa latauspisteistä;Information angående elbilsladdning på parkeringshusets hemsida strider mot informationen på aimoparks laddningsnätverk karta;Information regarding EV charging on the parking garage's website conflicts with the information on aimopark's charging network map;https://www.aimopark.fi/kaupungit/turku/harppuunaparkki/
Hesburger Kupittaa;Lemminkäisenkatu 13;6703912;23461509;48;1; ;Apuvirta, hissi, liikkumisesteisen pysäköintipaikka, sähköauton latauspiste;Elbilsladdning, hiss, parkeringsplats för funktionshindrade, startkablar;Disabled parking, elevator, EV charging, jump leads;;;;https://www.aimopark.fi/fi-fi/cities/turku/hesburger-kupittaa/
Itäharjun kenttä;Karjakatu 37;6704308;23461903;300;;;Apuvirta;Startkablar;Jump leads;;;;https://www.aimopark.fi/kaupungit/turku/itaharjun-kentta/
Julia;Brahenkatu 3;6704636;23459940;260;2;2 x Type 2 11 kW;Apuvirta, defibrillaattori, hissi, info, puhelimen kuuluvuusalue, sähköauton latauspiste, videovalvonta, yövartiointi;Elbilsladdning, hiss, hjärtstartare, information, kameraövervakat, mobiltäckning, nattlig övervakning, startkablar;Automated external defibrillator (AED), CCTV, elevator, EV charging, information, jump leads, mobile phone coverage, surveillance at night;;;;https://www.aimopark.fi/kaupungit/turku/julia/
Kivikukkaro;Yliopistonkatu 29;6704478;23459294;216;3;2 x Type 2 22kW;Apuvirta, julkinen liikenne, korttimaksu, käteismaksu, mobiilimaksu, pyöräparkki, sähköauton latauspiste, videovalvonta, yövartiointi;Cykelparkering, elbilsladdning, kameraövervakat, kollektivtrafik, kortbetalning, mobilbetalning, myntbetalning, nattlig övervakning, startkablar;Bicycle parking, CCTV, coin payment, credit card payment, EV charging, jump leads, mobile payment, public transportation, surveillance at night;;;;https://www.aimopark.fi/kaupungit/turku/kivikukkaro/
Kupittaanpuisto;Lenkkipolku;6704227;23461020;86;;;;;;;;;https://www.aimopark.fi/kaupungit/turku/kupittaanpuisto/
Louhi;Läntinen Pitkäkatu 12 B;6704994;23459306;608;10;10 x Type 2 22 kW, 2 x CSS 60kW;Apuvirta, autopesula, defibrillaattori, hissi, info, kameratunnistus, kengänkiilltoin, liikkumistesteisen pysäköintipaikka, ostoskärryt, sateenvarjon lainaus, sähköauton latauspiste, videovalvonta;Biltvätt, elbilsladdning, hiss, hjärtstartare, information, kameraparkering, kameraövervakat, kundvagnar, paraply, parkeringsplats för funktionshindrade, skoputs, startkablar;Automated external defibrillator (AED), automatic number plate recognition, carwash, CCTV, disabled parking, elevator, EV charging, information, jump leads, shoe polisher, shopping trolley, umbrella hire;Parkkihallin omalla sivulla ja aimoparkin latausverkostokartalla eriävää tietoa latauspisteistä;Information angående elbilsladdning på parkeringshusets hemsida strider mot informationen på aimoparks laddningsnätverk karta;Information regarding EV charging on the parking garage's website conflicts with the information on aimopark's charging network map;https://www.aimopark.fi/kaupungit/turku/louhi/
ParkCity;Joukahaisenkatu 8;6704372;23461311;990;;20 x Type 2 11 kW;Autovuokraamo, hissi, julkinen liikenne, kameratunnistus, pyöräparkki, sähköauton latauspiste, videovalvonta;Biluthyring, cykelparkering, elbilsladdning, hiss, kameraparkering, kameraövervakat, kollektivtrafik;Automatic number-plate recognition (ANPR), bicycle parking, car rental, CCTV, elevator, EV charging, public transportation;;;;https://www.aimopark.fi/kaupungit/turku/parkcity/
Pharmacity;Lemminkäisenkatu 9;6704134;23461240;220;;;Apuvirta;Startkablar;Jump leads;;;;https://www.aimopark.fi/kaupungit/turku/pharmacity/
P-Centrum;Kristiinankatu 8;6704432;23459438;88;;;;;;;;;https://www.europark.fi/pysakointi/p-centrum/
P-Puutori;Brahenkatu 13;6704995;23459698;100;;;;;;;;;https://www.p-puutori.fi/
Savitehtaankadun pysäköintitalo;Savitehtaankatu 7;6704694;23461306;100;;;;;;;;;
Scandic Plaza;Yliopistonkatu 29;6704504;23459333;42;;1 x Type 2 22 kW;Sähköauton latauspiste;Elbilsladdning;EV charging;;;;https://www.aimopark.fi/kaupungit/turku/scandic-plaza/
Tahkonaukio;Lemminkäisenkatu 9 D;6704136;23461236;120;;;;;;;;;https://www.aimopark.fi/kaupungit/turku/tahkonaukio/
Toriparkki;;6704748;23459727;620; ;20;Autopesula, sähköauton latauspiste;Biltvätt, elbilsladdning ;Carwash, EV charging;;;;https://www.turuntoriparkki.fi/
Turun teknologiakiinteistöt;Tykistökatu 6;6704371;23461176;800;;;;;;;;;https://www.aimopark.fi/kaupungit/turku/teknologiakiinteistot/
Trivium;Lemminkäisenkatu 32;6703957;23461524;461;2;4 x Type 2 22 kW;;;;;;;https://www.aimopark.fi/kaupungit/turku/trivium/
Wiklund;Brahenkatu 8;6704702;23459855;;4;;;;;;;;https://www.europark.fi/pysakointi/p-wiklund-turku/
12 changes: 2 additions & 10 deletions mobility_data/importers/charging_stations.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
from munigeo.models import Municipality

from .utils import (
get_file_name_from_data_source,
get_full_csv_file_name,
get_municipality_name,
get_postal_code,
get_root_dir,
get_street_name_translations,
LANGUAGES,
MobileUnitDataBase,
Expand Down Expand Up @@ -111,16 +110,9 @@ def get_number_of_rows(file_name):
return number_of_rows


def get_csv_file_name():
file_name = get_file_name_from_data_source(CONTENT_TYPE_NAME)
if file_name:
return file_name
return f"{get_root_dir()}/mobility_data/data/{SOURCE_DATA_FILE_NAME}"


def get_charging_station_objects():
# Store the imported stations to dict, the index is the key.
file_name = get_csv_file_name()
file_name = get_full_csv_file_name(SOURCE_DATA_FILE_NAME, CONTENT_TYPE_NAME)
charging_stations = {}
column_mappings = {}
number_of_rows = get_number_of_rows(file_name)
Expand Down
5 changes: 5 additions & 0 deletions mobility_data/importers/data/content_types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ content_types:
sv: Elladningsstation för bilar
en: Car e-charging point

- content_type_name: ParkingGarage
name:
fi: Parkkihalli
sv: Parkeringsgarage
en: Parking garage
- content_type_name: NoStaffParking
name:
fi: Yleiset pysäköintialueet
Expand Down
91 changes: 91 additions & 0 deletions mobility_data/importers/parking_garages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import csv
import logging

from django.conf import settings
from django.contrib.gis.geos import Point
from munigeo.models import Municipality

from .utils import (
get_full_csv_file_name,
get_municipality_name,
get_street_name_translations,
LANGUAGES,
MobileUnitDataBase,
split_string_at_first_digit,
)

logger = logging.getLogger("mobility_data")
SOURCE_DATA_SRID = 3877

CONTENT_TYPE_NAME = "ParkingGarage"
SOURCE_DATA_FILE_NAME = "parkkihallit.csv"
COLUMN_MAPPINGS = {
"name": 0,
"address": 1,
"N": 2,
"E": 3,
"parking_spaces": 4,
"disabled_spaces": 5,
"charging_stations": 6,
"services_fi": 7,
"services_sv": 8,
"services_en": 9,
"notes_fi": 10,
"notes_sv": 11,
"notes_en": 12,
}


class ParkingGarage(MobileUnitDataBase):

def __init__(self, values):
super().__init__()
x = float(values[COLUMN_MAPPINGS["E"]])
y = float(values[COLUMN_MAPPINGS["N"]])
self.geometry = Point(x, y, srid=SOURCE_DATA_SRID)
self.geometry.transform(settings.DEFAULT_SRID)
try:
self.municipality = Municipality.objects.get(
name=get_municipality_name(self.geometry)
)
except Municipality.DoesNotExist:
self.municipality = None
address = values[COLUMN_MAPPINGS["address"]]
street_name, street_number = split_string_at_first_digit(address)
# As the source data contains only Finnish street names, we need to get the translations
translated_street_names = get_street_name_translations(
street_name.strip(), self.municipality
)
self.extra["services"] = {}
self.extra["notes"] = {}
for lang in LANGUAGES:
self.name[lang] = values[COLUMN_MAPPINGS["name"]]
self.address[lang] = f"{translated_street_names[lang]} {street_number}"
self.extra["services"][lang] = values[COLUMN_MAPPINGS[f"services_{lang}"]]
self.extra["notes"][lang] = values[COLUMN_MAPPINGS[f"notes_{lang}"]]

try:
parking_spaces = int(values[COLUMN_MAPPINGS["parking_spaces"]])
except ValueError:
parking_spaces = None
self.extra["parking_spaces"] = parking_spaces

try:
disabled_spaces = int(values[COLUMN_MAPPINGS["disabled_spaces"]])
except ValueError:
disabled_spaces = None
self.extra["disabled_spaces"] = disabled_spaces
self.extra["charging_stations"] = values[COLUMN_MAPPINGS["charging_stations"]]


def get_parking_garage_objects():
file_name = get_full_csv_file_name(SOURCE_DATA_FILE_NAME, CONTENT_TYPE_NAME)
parking_garages = []
with open(file_name, encoding="utf-8-sig") as csv_file:
csv_reader = csv.reader(csv_file, delimiter=";")
for i, row in enumerate(csv_reader):
# Discard header row
if i > 0:
parking_garages.append(ParkingGarage(row))

return parking_garages
19 changes: 19 additions & 0 deletions mobility_data/importers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,3 +388,22 @@ def create_mobile_units_as_unit_references(service_id, content_type):
obj.unit_id = unit.id
objects.append(obj)
save_to_database(objects, content_type)


def get_full_csv_file_name(csv_file_name, content_type_name):
file_name = get_file_name_from_data_source(content_type_name)
if file_name:
return file_name
return f"{get_root_dir()}/mobility_data/data/{csv_file_name}"


def split_string_at_first_digit(s):
match = re.search(r"\d", s)
if match:
index = match.start()
return (
s[:index],
s[index:],
)
else:
return s, ""
24 changes: 24 additions & 0 deletions mobility_data/management/commands/import_parking_garages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import logging

from django.core.management import BaseCommand

from mobility_data.importers.parking_garages import (
CONTENT_TYPE_NAME,
get_parking_garage_objects,
)
from mobility_data.importers.utils import (
get_or_create_content_type_from_config,
log_imported_message,
save_to_database,
)

logger = logging.getLogger("mobility_data")


class Command(BaseCommand):
def handle(self, *args, **options):
logger.info("Importing parking garages...")
objects = get_parking_garage_objects()
content_type = get_or_create_content_type_from_config(CONTENT_TYPE_NAME)
num_created, num_deleted = save_to_database(objects, content_type)
log_imported_message(logger, content_type, num_created, num_deleted)
5 changes: 5 additions & 0 deletions mobility_data/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ def import_street_area_information(name="import_street_area_information"):
management.call_command("import_wfs", "StreetAreaInformation")


@shared_task_email
def import_parking_garages(name="import_parking_garages"):
management.call_command("import_parking_garages")


@shared_task_email
def delete_obsolete_data(name="delete_obsolete_data"):
MobileUnit.objects.filter(content_types__isnull=True).delete()
Expand Down
7 changes: 7 additions & 0 deletions mobility_data/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,13 @@ def streets():
name_sv="Bangårdsgatan",
municipality_id="turku",
)
Street.objects.create(
name="Juhana Herttuan puistokatu",
name_fi="Juhana Herttuan puistokatu",
name_sv="Hertig Johans parkgata",
name_en="Juhana Herttuan puistokatu",
municipality_id="turku",
)
return Street.objects.all()


Expand Down
3 changes: 3 additions & 0 deletions mobility_data/tests/data/parkkihallit_fixtures.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Nimi;Osoite;N;E;Pysäköintipaikat;Invapaikat;Sähkölatauspaikat;Palvelut;Palvelut (ru);Palvelut (eng);Huom;Huom (ru);Huom (eng);Linkki sivuille
Auriga;Juhana Herttuan puistokatu 21;6703305;23457449;330;2;2 x Type 2 22 kW;Apuvirta, hissi, liikkumisesteisen pysäköintipaikka, sähköauton latauspiste;Elbilsladdning, hiss, parkeringsplats för funktionshindrade, startkablar;Disabled parking, elevator, EV charging, jump leads;;;;https://www.aimopark.fi/kaupungit/turku/auriga-/
Hansakortteli;Kristiinankatu 11;6704479;23459433;162;2;2 x Type 2 11kW, 2 x CSS 90kW;Apuvirta, hissi, kameratunnistus, kengänkiillotin, liikkumisesteisen pysäköintipaikka, ostoskärryt, rengaspumppu, sateenvarjon lainaus, sähköauton latauspiste, videovalvonta, yövartiointi;Elbilsladdning, hiss, kameraparkering, kameraövervakat, kundvagnar, nattlig övervakning, paraply, parkeringsplats för funktionshindrade, skoputs, startkablar, tryckluft;Automatic number-plate recognition (ANPR), CCTV, disabled parking, elevator, EV charging, jump leads, shoe polisher, shopping trolley, surveillance at night, tyre pump, umbrella hire;Parkkihallin omalla sivulla ja aimoparkin latausverkostokartalla eriävää tietoa latauspisteistä;Information angående elbilsladdning på parkeringshusets hemsida strider mot informationen på aimoparks laddningsnätverk karta;Information regarding EV charging on the parking garage's website conflicts with the information on aimopark's charging network map;https://www.aimopark.fi/kaupungit/turku/hansakortteli/
8 changes: 4 additions & 4 deletions mobility_data/tests/test_import_charging_stations.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@


@pytest.mark.django_db
@patch("mobility_data.importers.charging_stations.get_csv_file_name")
@patch("mobility_data.importers.charging_stations.get_full_csv_file_name")
def test_import_charging_stations(
get_csv_file_name_mock,
get_full_csv_file_name_mock,
municipalities,
administrative_division_type,
administrative_division,
Expand All @@ -30,7 +30,7 @@ def test_import_charging_stations(
)

file_name = f"{get_root_dir()}/mobility_data/tests/data/charging_stations.csv"
get_csv_file_name_mock.return_value = file_name
get_full_csv_file_name_mock.return_value = file_name
content_type = get_or_create_content_type_from_config(CONTENT_TYPE_NAME)
objects = get_charging_station_objects()
num_created, num_deleted = save_to_database(objects, content_type)
Expand Down Expand Up @@ -79,7 +79,7 @@ def test_import_charging_stations(
== f"{CHARGING_STATION_SERVICE_NAMES['en']}, Ratapihankatu 53"
)
# Test that dublicates are not created
get_csv_file_name_mock.return_vale = file_name
get_full_csv_file_name_mock.return_vale = file_name
content_type = get_or_create_content_type_from_config(CONTENT_TYPE_NAME)
objects = get_charging_station_objects()
num_created, num_deleted = save_to_database(objects, content_type)
Expand Down
69 changes: 69 additions & 0 deletions mobility_data/tests/test_import_parking_garages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from unittest.mock import patch

import pytest

from mobility_data.importers.utils import (
get_content_type_config,
get_or_create_content_type_from_config,
get_root_dir,
save_to_database,
)
from mobility_data.models import ContentType, MobileUnit


@pytest.mark.django_db
@patch("mobility_data.importers.parking_garages.get_full_csv_file_name")
def test_import_parking_garages(
get_full_csv_file_name_mock,
municipalities,
administrative_division_type,
administrative_division,
administrative_division_geometry,
streets,
address,
):
from mobility_data.importers.parking_garages import (
CONTENT_TYPE_NAME,
get_parking_garage_objects,
)

file_name = f"{get_root_dir()}/mobility_data/tests/data/parkkihallit_fixtures.csv"
get_full_csv_file_name_mock.return_value = file_name
content_type = get_or_create_content_type_from_config(CONTENT_TYPE_NAME)
objects = get_parking_garage_objects()
num_created, num_deleted = save_to_database(objects, content_type)
assert num_created == 2
assert num_deleted == 0
assert ContentType.objects.filter(type_name=CONTENT_TYPE_NAME).count() == 1
assert (
MobileUnit.objects.filter(content_types__type_name=CONTENT_TYPE_NAME).count()
== 2
)
config = get_content_type_config(CONTENT_TYPE_NAME)
content_type = ContentType.objects.get(type_name=CONTENT_TYPE_NAME)
content_type.name_fi = config["name"]["fi"]
content_type.name_sv = config["name"]["sv"]
content_type.name_en = config["name"]["en"]

auriga = MobileUnit.objects.get(name="Auriga")
assert auriga.name_sv == "Auriga"
assert auriga.name_en == "Auriga"
assert auriga.address_fi == "Juhana Herttuan puistokatu 21"
assert auriga.address_sv == "Hertig Johans parkgata 21"
assert auriga.address_en == "Juhana Herttuan puistokatu 21"
assert auriga.municipality.name == "Turku"
assert auriga.extra["parking_spaces"] == 330
assert auriga.extra["disabled_spaces"] == 2
assert auriga.extra["charging_stations"] == "2 x Type 2 22 kW"
assert (
auriga.extra["services"]["fi"]
== "Apuvirta, hissi, liikkumisesteisen pysäköintipaikka, sähköauton latauspiste"
)
assert (
auriga.extra["services"]["sv"]
== "Elbilsladdning, hiss, parkeringsplats för funktionshindrade, startkablar"
)
assert (
auriga.extra["services"]["en"]
== "Disabled parking, elevator, EV charging, jump leads"
)
6 changes: 3 additions & 3 deletions smbackend_turku/tests/test_charging_stations.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@


@pytest.mark.django_db
@patch("mobility_data.importers.charging_stations.get_csv_file_name")
@patch("mobility_data.importers.charging_stations.get_full_csv_file_name")
def test_charging_stations_import(
get_csv_file_name_mock,
get_full_csv_file_name_mock,
municipality,
administrative_division,
administrative_division_type,
Expand All @@ -32,7 +32,7 @@ def test_charging_stations_import(
id=42, name="Vapaa-aika", last_modified_time=datetime.now(utc_timezone)
)
file_name = f"{settings.BASE_DIR}/mobility_data/tests/data/charging_stations.csv"
get_csv_file_name_mock.return_value = file_name
get_full_csv_file_name_mock.return_value = file_name
import_charging_stations(
logger=logger,
config=config,
Expand Down
Loading