diff --git a/bicycle_network/api/views.py b/bicycle_network/api/views.py index 7fbd440e0..d7bb73423 100644 --- a/bicycle_network/api/views.py +++ b/bicycle_network/api/views.py @@ -82,11 +82,13 @@ def list(self, request): ) # Return elements that are inside bbox if "bbox" in filters: - ref = SpatialReference(4326) - val = self.request.query_params.get("bbox", None) - bbox_filter = munigeo_api.build_bbox_filter(ref, val, "geometry") - bbox_geometry_filter = munigeo_api.build_bbox_filter(ref, val, "geometry") - queryset = queryset.filter(Q(**bbox_filter) | Q(**bbox_geometry_filter)) + val = filters.get("bbox", None) + if val: + ref = SpatialReference(filters.get("bbox_srid", 4326)) + bbox_geometry_filter = munigeo_api.build_bbox_filter( + ref, val, "geometry" + ) + queryset = queryset.filter(Q(**bbox_geometry_filter)) page = self.paginate_queryset(queryset) if only_coords: diff --git a/config_dev.env.example b/config_dev.env.example index 4127bfee9..c7b6241cb 100644 --- a/config_dev.env.example +++ b/config_dev.env.example @@ -138,6 +138,13 @@ CELERY_BROKER_URL=redis://localhost:6379/0 # Cache location, e.g. redis on localhost using default port and database 0 CACHE_LOCATION=redis://localhost:6379/0 +# Email settings +EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend +EMAIL_HOST=smtp.example.com +EMAIL_HOST_USER=example@example.com +EMAIL_PORT=25 +EMAIL_USE_TLS=True + # Settings needed for enabling Turku area: #ADDITIONAL_INSTALLED_APPS=smbackend_turku,ptv #TURKU_API_KEY=secret @@ -161,10 +168,6 @@ TRAFFIC_COUNTER_OBSERVATIONS_BASE_URL=https://data.turku.fi/2yxpk2imqi2mzxpa6e6k LAM_COUNTER_STATIONS_URL=https://tie.digitraffic.fi/api/v3/metadata/tms-stations LAM_COUNTER_API_BASE_URL=https://tie-lam-test.digitraffic.fi -GAS_FILLING_STATIONS_IDS=service_node=200000,service=200000,units_offset=200000 -CHARGING_STATIONS_IDS=service_node=300000,service=300000,units_offset=300000 -BICYCLE_STANDS_IDS=service_node=400000,service=400000,units_offset=400000 -BIKE_SERVICE_STATIONS_IDS=service_node=500000,service=500000,units_offset=500000 MOBILITY_DATA_CHARGING_STATIONS_URL=https://services1.arcgis.com/rhs5fjYxdOG1Et61/ArcGIS/rest/services/GasFillingStations/FeatureServer/0/query?f=json&where=1%3D1&outFields=OPERATOR%2CLAT%2CLON%2CSTATION_NAME%2CADDRESS%2CCITY%2CZIP_CODE%2CLNG_CNG%2CObjectId MOBILITY_DATA_GAS_FILLING_STATIONS_URL=https://services1.arcgis.com/rhs5fjYxdOG1Et61/ArcGIS/rest/services/ChargingStations/FeatureServer/0/query?f=json&where=1%20%3D%201%20OR%201%20%3D%201&returnGeometry=true&spatialRel=esriSpatialRelIntersects&outFields=LOCATION_ID%2CNAME%2CADDRESS%2CURL%2COBJECTID%2CTYPE MOBILITY_DATA_GEOMETRY_URL=https://tie.digitraffic.fi/api/v3/data/traffic-messages/area-geometries?id=11&lastUpdated=false diff --git a/eco_counter/api/serializers.py b/eco_counter/api/serializers.py index 21d37b755..e0cbc80c8 100644 --- a/eco_counter/api/serializers.py +++ b/eco_counter/api/serializers.py @@ -31,6 +31,7 @@ class StationSerializer(serializers.ModelSerializer): y = serializers.SerializerMethodField() lon = serializers.SerializerMethodField() lat = serializers.SerializerMethodField() + sensor_types = serializers.SerializerMethodField() class Meta: model = Station @@ -47,6 +48,7 @@ class Meta: "y", "lon", "lat", + "sensor_types", ] def get_y(self, obj): @@ -63,6 +65,17 @@ def get_lon(self, obj): obj.geom.transform(4326) return obj.geom.x + def get_sensor_types(self, obj): + # Return the sensor types(car, bike etc) that has a total year value >0. + # i.e., there are sensors for counting the type of data. + types = ["at", "pt", "jt", "bt"] + result = [] + for type in types: + filter = {"station": obj, f"value_{type}__gt": 0} + if YearData.objects.filter(**filter).count() > 0: + result.append(type) + return result + class YearSerializer(serializers.ModelSerializer): station_name = serializers.PrimaryKeyRelatedField( diff --git a/eco_counter/tasks.py b/eco_counter/tasks.py index dd0e9a722..9b7fdb714 100644 --- a/eco_counter/tasks.py +++ b/eco_counter/tasks.py @@ -1,12 +1,13 @@ -from celery import shared_task from django.core import management +from smbackend.utils import shared_task_email -@shared_task + +@shared_task_email def import_counter_data(args, name="import_counter_data"): management.call_command("import_counter_data", "--counters", args) -@shared_task +@shared_task_email def initial_import_counter_data(args, name="initial_import_counter_data"): management.call_command("import_counter_data", "--init", args) diff --git a/eco_counter/tests/test_api.py b/eco_counter/tests/test_api.py index 3e870a5e8..4c10654fb 100644 --- a/eco_counter/tests/test_api.py +++ b/eco_counter/tests/test_api.py @@ -263,8 +263,9 @@ def test__months_multiple_years(api_client, years, test_timestamp): @pytest.mark.django_db -def test__station(api_client, station): +def test__station(api_client, station, year_datas): url = reverse("eco_counter:stations-list") response = api_client.get(url) assert response.status_code == 200 assert response.json()["results"][0]["name"] == station.name + assert response.json()["results"][0]["sensor_types"] == ["at"] diff --git a/iot/tasks.py b/iot/tasks.py index 7df693045..a4b7fd7d2 100644 --- a/iot/tasks.py +++ b/iot/tasks.py @@ -1,7 +1,8 @@ -from celery import shared_task from django.core import management +from smbackend.utils import shared_task_email -@shared_task + +@shared_task_email def import_iot_data(source_name, name="Import iot data"): management.call_command("import_iot_data", source_name) diff --git a/mobility_data/README.md b/mobility_data/README.md index 4a64680e3..95fc03ad8 100644 --- a/mobility_data/README.md +++ b/mobility_data/README.md @@ -160,12 +160,34 @@ To import data type: ./manage.py import_foli_stops ``` +### Barbecue places +``` +./manage.py import_wfs BarbecuePlace +``` + + +### Playgrounds +``` +./manage.py import_wfs PlayGround +``` + +### Föli park and ride stop +Imports park and ride stops for bikes and cars. +``` +./manage.py import_foli_parkandride_stops +``` + ### Outdoor gym devices Imports the outdoor gym devices from the services.unit model. i.e., sets references by id to the services.unit model. The data is then serialized from the services.unit model. ``` ./manage.py import_outdoor_gym_devices ``` +### Parking machines +``` +./manage.py import_parking_machines +``` + ## Deletion To delete mobile units for a content type. ``` diff --git a/mobility_data/api/serializers/mobile_unit.py b/mobility_data/api/serializers/mobile_unit.py index 8b0856440..6708eb514 100644 --- a/mobility_data/api/serializers/mobile_unit.py +++ b/mobility_data/api/serializers/mobile_unit.py @@ -42,7 +42,7 @@ class Meta: class MobileUnitSerializer(serializers.ModelSerializer): - content_type = ContentTypeSerializer(many=False, read_only=True) + content_types = ContentTypeSerializer(many=True, read_only=True) mobile_unit_group = MobileUnitGroupBasicInfoSerializer(many=False, read_only=True) geometry_coords = serializers.SerializerMethodField(read_only=True) @@ -64,13 +64,14 @@ class Meta: "description_fi", "description_sv", "description_en", - "content_type", + "content_types", "mobile_unit_group", "is_active", "created_time", "geometry", "geometry_coords", "extra", + "unit_id", ] # Contains the corresponding field names of the MobileUnit model if they differs @@ -84,10 +85,18 @@ class Meta: def to_representation(self, obj): representation = super().to_representation(obj) - # If mobile_unit has a unit_id we serialize the data from the services_unit table. - unit_id = obj.unit_id - if unit_id: - unit = Unit.objects.get(id=unit_id) + unit_id = getattr(obj, "unit_id", None) + # If serializing Unit instance or MobileUnit with unit_id. + if self.context.get("services_unit_instances", False) or unit_id: + if unit_id: + # When serializing the MobileUnit from the retrieve method + try: + unit = Unit.objects.get(id=unit_id) + except Unit.DoesNotExist: + return representation + else: + # The obj is a Unit instance. + unit = obj for field in self.fields: # lookup the field name in the service_unit table, as not all field names that contains # similar data has the same name. @@ -99,19 +108,34 @@ def to_representation(self, obj): if hasattr(unit, key): # unit.municipality is of type munigeo.models.Municipality and not serializable if key == "municipality": - representation[field] = unit.municipality.id + muni = getattr(unit, key, None) + representation[field] = muni.id if muni else None else: - representation[field] = getattr(unit, key) - + representation[field] = getattr(unit, key, None) + # Serialize the MobileUnit id, otherwise would serialize the serivce_unit id. + if field == "id": + try: + representation["id"] = MobileUnit.objects.get( + unit_id=unit.id + ).id + except MobileUnit.DoesNotExist: + representation["id"] = unit.id # The location field must be serialized with its wkt value. if unit.location: representation["geometry"] = unit.location.wkt return representation def get_geometry_coords(self, obj): - # If stored to Unit table, retrieve geometry from there. - if obj.unit_id: - geometry = Unit.objects.get(id=obj.unit_id).location + unit_id = getattr(obj, "unit_id", None) + if unit_id: + # If stored to Unit table, retrieve geometry from there. + try: + geometry = Unit.objects.get(id=unit_id).location + except Unit.DoesNotExist: + return None + # If serializing Unit object retrieved from the view. + elif self.context.get("services_unit_instances", False): + geometry = obj.location else: geometry = obj.geometry if isinstance(geometry, GEOSGeometry): @@ -130,7 +154,6 @@ def get_geometry_coords(self, obj): pos["lon"] = geometry.x pos["lat"] = geometry.y return pos - elif isinstance(geometry, LineString): if self.context["latlon"]: # Return LineString coordinates in (lat,lon) format @@ -142,7 +165,6 @@ def get_geometry_coords(self, obj): return coords else: return geometry.coords - elif isinstance(geometry, Polygon): if self.context["latlon"]: # Return Polygon coordinates in (lat,lon) format @@ -189,6 +211,5 @@ def get_geometry_coords(self, obj): return coords else: return geometry.coords - else: return "" diff --git a/mobility_data/api/views.py b/mobility_data/api/views.py index 5d671cd23..580710ed7 100644 --- a/mobility_data/api/views.py +++ b/mobility_data/api/views.py @@ -1,10 +1,16 @@ +import types from distutils.util import strtobool +from django.contrib.gis.gdal import SpatialReference from django.core.exceptions import ValidationError +from django.db.models import Q +from munigeo import api as munigeo_api from rest_framework import status, viewsets from rest_framework.exceptions import ParseError from rest_framework.response import Response +from services.models import Unit + from ..models import ContentType, GroupType, MobileUnit, MobileUnitGroup from .serializers import ( ContentTypeSerializer, @@ -14,6 +20,10 @@ MobileUnitSerializer, ) +FIELD_TYPES = types.SimpleNamespace() +FIELD_TYPES.FLOAT = float +FIELD_TYPES.INT = int +FIELD_TYPES.BOOL = bool # Mappings, so that deprecated type_names will work. # These will be removed when the front end is updated. group_name_mappings = {"CRE": "CultureRoute"} @@ -176,6 +186,7 @@ def list(self, request): and transforms to given srid. """ queryset = None + unit_ids = [] filters = self.request.query_params srid, latlon = get_srid_and_latlon(filters) if "type_name" in filters: @@ -187,10 +198,29 @@ def list(self, request): return Response( "type_name does not exist.", status=status.HTTP_400_BAD_REQUEST ) - queryset = MobileUnit.objects.filter(content_type__name=type_name) + queryset = MobileUnit.objects.filter(content_types__name=type_name) + # If the data locates in the services_unit table (i.e., MobileUnit has a unit_id) + # get the unit_ids to retrieve the Units for filtering(bbox and extra) + unit_ids = list( + queryset.filter(unit_id__isnull=False).values_list("unit_id", flat=True) + ) else: queryset = MobileUnit.objects.all() + services_unit_instances = True if len(unit_ids) > 0 else False + if services_unit_instances: + queryset = Unit.objects.filter(id__in=unit_ids) + + if "bbox" in filters: + val = filters.get("bbox", None) + geometry_field_name = "location" if services_unit_instances else "geometry" + if val: + ref = SpatialReference(filters.get("bbox_srid", 4326)) + bbox_geometry_filter = munigeo_api.build_bbox_filter( + ref, val, geometry_field_name + ) + queryset = queryset.filter(Q(**bbox_geometry_filter)) + for filter in filters: if filter.startswith("extra__"): if "type_name" not in filters: @@ -212,15 +242,27 @@ def list(self, request): f"extra field '{key}' does not exist", status=status.HTTP_400_BAD_REQUEST, ) - if field_type == float: - value = float(value) - elif field_type == int: - value = int(value) + + match field_type: + case FIELD_TYPES.FLOAT: + value = float(value) + case FIELD_TYPES.INT: + value = int(value) + case FIELD_TYPES.BOOL: + value = strtobool(value) + value = bool(value) + queryset = queryset.filter(**{filter: value}) page = self.paginate_queryset(queryset) serializer = MobileUnitSerializer( - page, many=True, context={"srid": srid, "latlon": latlon} + page, + many=True, + context={ + "srid": srid, + "latlon": latlon, + "services_unit_instances": services_unit_instances, + }, ) return self.get_paginated_response(serializer.data) diff --git a/mobility_data/constants.py b/mobility_data/constants.py index 3489e2c08..8d5a03033 100644 --- a/mobility_data/constants.py +++ b/mobility_data/constants.py @@ -12,6 +12,9 @@ from mobility_data.importers.loading_unloading_places import ( CONTENT_TYPE_NAME as LOADING_UNLOADING_PLACE, ) +from mobility_data.importers.parking_machines import ( + CONTENT_TYPE_NAME as PARKING_MACHINE, +) from mobility_data.importers.share_car_parking_places import ( CONTENT_TYPE_NAME as SHARE_CAR_PARKING_PLACE, ) @@ -48,4 +51,8 @@ "display_name": "berths", "to_services_list": False, }, + PARKING_MACHINE: { + "importer_name": "parking_machines", + "to_services_list": False, + }, } diff --git a/mobility_data/data/parking_machines.geojson b/mobility_data/data/parking_machines.geojson new file mode 100644 index 000000000..ef83f25ab --- /dev/null +++ b/mobility_data/data/parking_machines.geojson @@ -0,0 +1,103 @@ +{ + "type": "FeatureCollection", + "name": "Automaatit", + "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, + "features": [ + { "type": "Feature", "properties": { "id": 1, "Osoite": "Puutarhakatu 15", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "3.7.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Trädgårdsgatan 15", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "3.7.2022", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Puutarhakatu 15", "Installed": "3.7.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.255769473435137, 60.450812192929355 ] } }, + { "type": "Feature", "properties": { "id": 2, "Osoite": "Puutarhakatu 19", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "3.7.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Trädgårdsgatan 19", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "3.7.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Puutarhakatu 19", "Installed": "3.7.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.25417454427166, 60.450266480867569 ] } }, + { "type": "Feature", "properties": { "id": 3, "Osoite": "Puutarhakatu 20", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "3.7.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Trädgårdsgatan 20", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "3.7.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Puutarhakatu 20", "Installed": "3.7.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.252808192099611, 60.449604877035185 ] } }, + { "type": "Feature", "properties": { "id": 4, "Osoite": "Käsityöläiskatu 7", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "12.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Hantverkaregatan 7", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "12.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Käsityöläiskatu 7", "Installed": "12.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.257221846094581, 60.450184315580088 ] } }, + { "type": "Feature", "properties": { "id": 5, "Osoite": "Humalistonkatu 5", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "12.8.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Humlegårdsgatan 5", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "12.8.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Humalistonkatu 5", "Installed": "12.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.259980071100344, 60.450177339116053 ] } }, + { "type": "Feature", "properties": { "id": 6, "Osoite": "Eerikinkatu 21", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C", "Asennettu": "12.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "7\"", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Eriksgatan 21", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C", "Installerad": "12.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "7\"", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Eerikinkatu 21", "Installed": "12.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "7\"", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.26218847141747, 60.449239333253786 ] } }, + { "type": "Feature", "properties": { "id": 7, "Osoite": "Eerikinkatu 25", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "17.8.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Eriksgatan 25", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "17.8.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Eerikinkatu 25", "Installed": "17.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.259787917167984, 60.448419897985524 ] } }, + { "type": "Feature", "properties": { "id": 8, "Osoite": "Käsityöläiskatu 4", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "13.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Hantverkaregatan 4", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "13.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Käsityöläiskatu 4", "Installed": "13.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.258768788015548, 60.448817764771036 ] } }, + { "type": "Feature", "properties": { "id": 9, "Osoite": "Ursiininkatu 4", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "13.8.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Ursinsgatan 4", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "13.8.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Ursiininkatu 4", "Installed": "13.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.258686318669831, 60.446820115358349 ] } }, + { "type": "Feature", "properties": { "id": 10, "Osoite": "Rauhankatu 14", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "13.8.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Fredsgatan 14", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "13.8.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Rauhankatu 14", "Installed": "13.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.252106097225958, 60.450698403933671 ] } }, + { "type": "Feature", "properties": { "id": 11, "Osoite": "Rauhankatu 5", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "13.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Fredsgatan 5", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "13.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Rauhankatu 5", "Installed": "13.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.255241933856727, 60.451958158547647 ] } }, + { "type": "Feature", "properties": { "id": 12, "Osoite": "Rauhankatu 4", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "17.8.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Fredsgatan 4", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "17.8.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Rauhankatu 4", "Installed": "17.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.257154615291935, 60.452441782474324 ] } }, + { "type": "Feature", "properties": { "id": 13, "Osoite": "Humalistonkatu 14", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "17.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Humlegårdsgatan 14", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "17.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Humalistonkatu 14", "Installed": "17.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.257216154392239, 60.451862555940885 ] } }, + { "type": "Feature", "properties": { "id": 14, "Osoite": "Läntinen pitkäkatu 24", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "17.8.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Västerlånggatan 24", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "17.8.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Läntinen pitkäkatu 24", "Installed": "17.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.255051468343908, 60.452987302517734 ] } }, + { "type": "Feature", "properties": { "id": 15, "Osoite": "Läntinen pitkäkatu 22", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "17.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Västerlånggatan 22", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "17.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Läntinen pitkäkatu 22", "Installed": "17.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.256323063276643, 60.453437911269269 ] } }, + { "type": "Feature", "properties": { "id": 16, "Osoite": "Läntinen pitkäkatu 31", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "18.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Västerlånggatan 31", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "18.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Läntinen pitkäkatu 31", "Installed": "18.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.257994466697046, 60.454187956221354 ] } }, + { "type": "Feature", "properties": { "id": 17, "Osoite": "Läntinen pitkäkatu 23", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "18.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Västerlånggatan 23", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "18.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Läntinen pitkäkatu 23", "Installed": "18.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.261165193612193, 60.455262424830082 ] } }, + { "type": "Feature", "properties": { "id": 18, "Osoite": "Läntinen pitkäkatu 6", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "25.8.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Västerlånggatan 6", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "25.8.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Läntinen pitkäkatu 6", "Installed": "25.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.264365559509113, 60.456145444039713 ] } }, + { "type": "Feature", "properties": { "id": 19, "Osoite": "Läntinen pitkäkatu 9", "Sijainti": "Viheralue", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "25.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Västerlånggatan 9", "Tillverkare": "Cale", "Plats": "Grönomrode", "Modell": "CWT-C Touch", "Installerad": "25.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Läntinen pitkäkatu 9", "Installed": "25.8.2020", "Location": "Greenery", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.265258802895602, 60.456688407044439 ] } }, + { "type": "Feature", "properties": { "id": 20, "Osoite": "Linja-autoasema", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "25.8.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Busstationen", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "25.8.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Bus Station", "Installed": "25.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.26823862990101, 60.456618323168733 ] } }, + { "type": "Feature", "properties": { "id": 21, "Osoite": "Brahenkatu 18-20", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "25.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Brahegatan 18-20", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "25.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Brahenkatu 18-20", "Installed": "25.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.265432860869307, 60.45609461101597 ] } }, + { "type": "Feature", "properties": { "id": 22, "Osoite": "Tuureporinkatu 13", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "25.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Tureborgsgatan 13", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "25.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Tuureporinkatu 13", "Installed": "25.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.267508058545992, 60.455899614161197 ] } }, + { "type": "Feature", "properties": { "id": 23, "Osoite": "Tuureporinkatu 16", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "25.8.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Tureborgsgatan 16", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "25.8.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Tuureporinkatu 16", "Installed": "25.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.265579060229619, 60.45501128227162 ] } }, + { "type": "Feature", "properties": { "id": 24, "Osoite": "Kauppiaskatu 19", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "27.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Köpmansgatan 19", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "27.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Kauppiaskatu 19", "Installed": "27.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.263927120185748, 60.455138542084491 ] } }, + { "type": "Feature", "properties": { "id": 25, "Osoite": "Kauppiaskatu 17", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "27.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Köpmansgatan 17", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "27.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Kauppiaskatu 17", "Installed": "27.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.265027327999253, 60.454324227152817 ] } }, + { "type": "Feature", "properties": { "id": 26, "Osoite": "Puutori", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "26.8.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Trätorget", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "26.8.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Puutori", "Installed": "26.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.268197772640576, 60.455031569350027 ] } }, + { "type": "Feature", "properties": { "id": 27, "Osoite": "Maariankatu 2", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "27.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Mariegatan 2", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "27.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Maariankatu 2", "Installed": "27.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.269849896888495, 60.454839172502602 ] } }, + { "type": "Feature", "properties": { "id": 28, "Osoite": "Brahenkatu 10", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "27.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Brahegatan 10", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "27.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Brahenkatu 10", "Installed": "27.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.268764353572763, 60.453721815846308 ] } }, + { "type": "Feature", "properties": { "id": 29, "Osoite": "Brahenkatu 7", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "27.8.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Brahegatan 7", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "27.8.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Brahenkatu 7", "Installed": "27.8.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.270232241076812, 60.452956273815545 ] } }, + { "type": "Feature", "properties": { "id": 30, "Osoite": "Yliopistonkatu 11", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "9.9.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Universitetsgatan 11", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "9.9.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Yliopistonkatu 11", "Installed": "9.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.270612920328336, 60.453720163907732 ] } }, + { "type": "Feature", "properties": { "id": 31, "Osoite": "Nahkurinkatu 8", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "10.9.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Logarvaregatan 8", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "10.9.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Nahkurinkatu 8", "Installed": "10.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.27195361111416, 60.454879189541835 ] } }, + { "type": "Feature", "properties": { "id": 32, "Osoite": "Multavierunkatu 1", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "10.9.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Multavierugatan 1", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "10.9.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Multavierunkatu 1", "Installed": "10.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.274649677455383, 60.454469280317213 ] } }, + { "type": "Feature", "properties": { "id": 33, "Osoite": "Eerikinkatu 3 vp", "Sijainti": "Viherosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "9.9.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Eriksgatan 3 me", "Tillverkare": "Cale", "Plats": "Grönomrode", "Modell": "CWT-C Touch", "Installerad": "9.9.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Eerikinkatu 3 vp", "Installed": "9.9.2020", "Location": "Greenery", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.274411237269273, 60.453231364393154 ] } }, + { "type": "Feature", "properties": { "id": 34, "Osoite": "Aurakatu 22", "Sijainti": "Viherosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "10.9.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Auragatan 22", "Tillverkare": "Cale", "Plats": "Grönomrode", "Modell": "CWT-C Touch", "Installerad": "10.9.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Aurakatu 22", "Installed": "10.9.2020", "Location": "Greenery", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.26318967618387, 60.452955972059186 ] } }, + { "type": "Feature", "properties": { "id": 35, "Osoite": "Maariankatu 8", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "17.12.2021", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Mariegatan 8", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "17.12.2021", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Maariankatu 8", "Installed": "17.12.2021", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.266164317389642, 60.453604384909475 ] } }, + { "type": "Feature", "properties": { "id": 36, "Osoite": "Puolalankatu 5", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "9.9.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Puolalagatan 5", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "9.9.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Puolalankatu 5", "Installed": "9.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.261904591298897, 60.452405246993045 ] } }, + { "type": "Feature", "properties": { "id": 37, "Osoite": "Puolalankatu 2", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C", "Asennettu": "10.9.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "7\"", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Puolalagatan 2", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C", "Installerad": "10.9.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "7\"", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Puolalankatu 2", "Installed": "10.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "7\"", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.262568837946596, 60.451667570101037 ] } }, + { "type": "Feature", "properties": { "id": 38, "Osoite": "Kauppahalli", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "11.9.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Saluhallet", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "11.9.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Market Hall", "Installed": "11.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.265780082893588, 60.449524771568896 ] } }, + { "type": "Feature", "properties": { "id": 39, "Osoite": "Linnankatu 1", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C", "Asennettu": "11.9.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "7\"", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Slotsgatan 1", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C", "Installerad": "11.9.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "7\"", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Linnankatu 1", "Installed": "11.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "7\"", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.273690297937019, 60.451923978676078 ] } }, + { "type": "Feature", "properties": { "id": 40, "Osoite": "Aurakatu 2", "Sijainti": "Viherosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "10.9.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Auragatan 2", "Tillverkare": "Cale", "Plats": "Grönomrode", "Modell": "CWT-C Touch", "Installerad": "10.9.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Aurakatu 2", "Installed": "10.9.2020", "Location": "Greenery", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.268066143927651, 60.44930830363591 ] } }, + { "type": "Feature", "properties": { "id": 41, "Osoite": "Kauppiaskatu 2", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "10.9.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Köpmansgatan 2", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "10.9.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Kauppiaskatu 2", "Installed": "10.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.27064815615228, 60.450128994763617 ] } }, + { "type": "Feature", "properties": { "id": 42, "Osoite": "Linnankatu 5", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C", "Asennettu": "10.9.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "7\"", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Slottsgatan 5", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C", "Installerad": "10.9.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "7\"", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Linnankatu 5", "Installed": "10.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "7\"", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.271717105625264, 60.451106984503213 ] } }, + { "type": "Feature", "properties": { "id": 43, "Osoite": "Borenpuisto/aukio", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "15.9.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Boreparken/plan", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "15.9.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Borenpuisto/aukio", "Installed": "15.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.256426088884556, 60.445362011920302 ] } }, + { "type": "Feature", "properties": { "id": 44, "Osoite": "Eerikinkatu 38", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "15.9.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Eriksgatan 38", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "15.9.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Eerikinkatu 38", "Installed": "15.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.254031506456919, 60.446270987052962 ] } }, + { "type": "Feature", "properties": { "id": 45, "Osoite": "Eerikinkatu 40", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "15.9.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Eriksgatan 40", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "15.9.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Eerikinkatu 40", "Installed": "15.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.252807701852902, 60.44585626467363 ] } }, + { "type": "Feature", "properties": { "id": 46, "Osoite": "Sairashuoneenkatu 2", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "14.9.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Lasarattsgatan 2", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "14.9.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Sairashuoneenkatu 2", "Installed": "14.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.251775173461883, 60.444872332201818 ] } }, + { "type": "Feature", "properties": { "id": 47, "Osoite": "Puistokatu 12", "Sijainti": "Viherosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "14.9.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Allegatan 12", "Tillverkare": "Cale", "Plats": "Grönomrode", "Modell": "CWT-C Touch", "Installerad": "14.9.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Puistokatu 12", "Installed": "14.9.2020", "Location": "Greenery", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.250455226870177, 60.447872484202826 ] } }, + { "type": "Feature", "properties": { "id": 48, "Osoite": "Itsenäisyydenaukio 2 vp", "Sijainti": "Viherosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "1.12.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Självständighetsplan 2 me", "Tillverkare": "Cale", "Plats": "Grönomrode", "Modell": "CWT-C Touch", "Installerad": "1.12.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Itsenäisyydenaukio 2 vp", "Installed": "1.12.2020", "Location": "Greenery", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.262710182022698, 60.445569236961369 ] } }, + { "type": "Feature", "properties": { "id": 50, "Osoite": "Itäinen pitkäkatu/Olavinpuisto vp", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "15.9.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Östra Strandsgatan/Olafsparken", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "15.9.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Itäinen pitkäkatu/Olavinpuisto vp", "Installed": "15.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.269007832110184, 60.447885003377571 ] } }, + { "type": "Feature", "properties": { "id": 51, "Osoite": "Kaskenkatu 1", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "2.12.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Kaskisgatan 1", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "2.12.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Kaskenkatu 1", "Installed": "2.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.271248289746925, 60.447359092619095 ] } }, + { "type": "Feature", "properties": { "id": 52, "Osoite": "Hämeenkatu 28", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "1.12.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Tavastgatan 28", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "1.12.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Hämeenkatu 28", "Installed": "1.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.272740939586971, 60.448712477636697 ] } }, + { "type": "Feature", "properties": { "id": 53, "Osoite": "Hämeenkatu 21", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "14.9.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Tavastgatan 21", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "14.9.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Hämeenkatu 21", "Installed": "14.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.274129556670403, 60.449348582880177 ] } }, + { "type": "Feature", "properties": { "id": 54, "Osoite": "Hämeenkatu 19", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "14.9.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Tavastgatan 19", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "14.9.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Hämeenkatu 19", "Installed": "14.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.27594945421551, 60.449947345346075 ] } }, + { "type": "Feature", "properties": { "id": 55, "Osoite": "Nunnankatu 1", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "2.12.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Nunnegatan 1", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "2.12.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Nunnankatu 1", "Installed": "2.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.273923382374562, 60.450153277326237 ] } }, + { "type": "Feature", "properties": { "id": 56, "Osoite": "Uudenmaankatu 7", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "1.12.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Nylandsgatan 7", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "1.12.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Uudenmaankatu 7", "Installed": "1.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.279477989161659, 60.449038532856854 ] } }, + { "type": "Feature", "properties": { "id": 57, "Osoite": "Vähä Hämeenkatu 16", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "3.12.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Lilla Tavastgatan 16", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "3.12.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Vähä Hämeenkatu 16", "Installed": "3.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.279883914491133, 60.449633311242088 ] } }, + { "type": "Feature", "properties": { "id": 58, "Osoite": "Hovioikeudenkatu 2", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "14.12.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Hofrättsgatan 2", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "14.12.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Hovioikeudenkatu 2", "Installed": "14.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.280643577273363, 60.450943454869588 ] } }, + { "type": "Feature", "properties": { "id": 59, "Osoite": "Tuomiokirkontori 1-3", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "3.12.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Domkyrkotorget 1-3", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "3.12.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Tuomiokirkontori 1-3", "Installed": "3.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.277983862006817, 60.451173921939066 ] } }, + { "type": "Feature", "properties": { "id": 60, "Osoite": "Tuomiokirkonkatu 3", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "10.12.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Domkyrkogatan 3", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "10.12.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Tuomiokirkonkatu 3", "Installed": "10.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.280249199106677, 60.451952316001226 ] } }, + { "type": "Feature", "properties": { "id": 61, "Osoite": "Kerttulinkatu 6", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "7.12.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Gertrudsgatan 6", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "7.12.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Kerttulinkatu 6", "Installed": "7.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.282016000564631, 60.452352972963375 ] } }, + { "type": "Feature", "properties": { "id": 62, "Osoite": "Hämeenkatu 6-8", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "9.12.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Tavastgatan 6-8", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "9.12.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Hämeenkatu 6-8", "Installed": "9.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.283591614208678, 60.452205864044352 ] } }, + { "type": "Feature", "properties": { "id": 63, "Osoite": "Rehtorinpellonkatu 2", "Sijainti": "Viherosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "9.12.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Rektorsåkersgatan 2", "Tillverkare": "Cale", "Plats": "Grönomrode", "Modell": "CWT-C Touch", "Installerad": "9.12.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Rehtorinpellonkatu 2", "Installed": "9.12.2020", "Location": "Greenery", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.287462642661801, 60.453937416413524 ] } }, + { "type": "Feature", "properties": { "id": 64, "Osoite": "Vähä Hämeenkatu 2", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "9.12.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Lilla Tavastgatan 2", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "9.12.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Vähä Hämeenkatu 2", "Installed": "9.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.28764674597139, 60.452178003199926 ] } }, + { "type": "Feature", "properties": { "id": 65, "Osoite": "Lemminkäisenkatu 14", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "9.12.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Lemminkäinengatan 14", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "9.12.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Lemminkäisenkatu 14", "Installed": "9.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.294781520449281, 60.448205452316486 ] } }, + { "type": "Feature", "properties": { "id": 66, "Osoite": "Lemminkäisenkatu 22", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "10.12.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Lemminkäinengatan 22", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "10.12.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Lemminkäisenkatu 22", "Installed": "10.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.296182597025911, 60.447646306211979 ] } }, + { "type": "Feature", "properties": { "id": 67, "Osoite": "Puutarhakatu 6-8", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C", "Asennettu": "6.2.2019", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "7\"", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Trädgårdsgatan 6-8", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C", "Installerad": "6.2.2019", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "7\"", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Puutarhakatu 6-8", "Installed": "6.2.2019", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "7\"", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.260430472827235, 60.45216772994651 ] } }, + { "type": "Feature", "properties": { "id": 68, "Osoite": "Humalistonkatu 8", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C", "Asennettu": "29.1.2018", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "7\"", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Humlegårdsgatan 8", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C", "Installerad": "29.1.2018", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "7\"", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Humalistonkatu 8", "Installed": "29.1.2018", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "7\"", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.258675701953273, 60.450865575940362 ] } }, + { "type": "Feature", "properties": { "id": 69, "Osoite": "Puutarhakatu 3", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C", "Asennettu": "6.2.2019", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "7\"", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Trädgårdsgatan 3", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C", "Installerad": "6.2.2019", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "7\"", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Puutarhakatu 3", "Installed": "6.2.2019", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "7\"", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.26175837633734, 60.45287615088543 ] } }, + { "type": "Feature", "properties": { "id": 70, "Osoite": "Käsityöläiskatu 11", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C", "Asennettu": "27.2.2019", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "7\"", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Hantverkaregatan 11", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C", "Installerad": "27.2.2019", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "7\"", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Käsityöläiskatu 11", "Installed": "27.2.2019", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "7\"", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.25604659396264, 60.450985440937544 ] } }, + { "type": "Feature", "properties": { "id": 71, "Osoite": "Yliopistonkatu 5", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "11.10.2022", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Universitetsgatan 5", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "11.10.2022", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Yliopistonkatu 5", "Installed": "11.10.2022", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.273213346106335, 60.454614196330851 ] } }, + { "type": "Feature", "properties": { "id": 72, "Osoite": "Itäinen Rantakatu 72", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "8.12.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Östra Strandgatan 72", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "8.12.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Itäinen Rantakatu 72", "Installed": "8.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.243079545713517, 60.437818487078545 ] } }, + { "type": "Feature", "properties": { "id": 73, "Osoite": "Kasarminkatu 4", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "2.9.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Kaserngatan 4", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "2.9.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Kasarminkatu 4", "Installed": "2.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.280352370046622, 60.457669207319114 ] } }, + { "type": "Feature", "properties": { "id": 75, "Osoite": "Linnankatu 19", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "19.12.2022", "Virta": "Aurinkopaneeli", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 3.6, "Max.aika": null, "Maksuvyöhyke": "1", "Adress": "Slottsgatan 19", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "19.12.2022", "Ström": "Solcell", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 3.6, "Zon": "1", "Address": "Linnankatu 19", "Installed": "19.12.2022", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Solar panel", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "1", "Tariff/h": 3.6 }, "geometry": { "type": "Point", "coordinates": [ 22.264872376936172, 60.448691040677524 ] } }, + { "type": "Feature", "properties": { "id": 77, "Osoite": "Piispankatu 10", "Sijainti": "Viherosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "2.9.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Biskopsgatan 10", "Tillverkare": "Cale", "Plats": "Grönomrode", "Modell": "CWT-C Touch", "Installerad": "2.9.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Piispankatu 10", "Installed": "2.9.2020", "Location": "Greenery", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.279733274298824, 60.455020619216043 ] } }, + { "type": "Feature", "properties": { "id": 78, "Osoite": "Piispankatu 19", "Sijainti": "Katuosa", "Valmistaja": "Cale§", "Malli": "CWT-C Touch", "Asennettu": "3.9.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Biskopsgatan 19", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "3.9.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Piispankatu 19", "Installed": "3.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.277760964164081, 60.453216079342297 ] } }, + { "type": "Feature", "properties": { "id": 79, "Osoite": "Porthaninkatu 6", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "14.12.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Porthansgatan 6", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "14.12.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Porthaninkatu 6", "Installed": "14.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.28073811293207, 60.453918201523102 ] } }, + { "type": "Feature", "properties": { "id": 84, "Osoite": "Tehtaankatu 6", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "3.9.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Fabriksgatan 6", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "3.9.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Tehtaankatu 6", "Installed": "3.9.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.280930555107421, 60.45626865766279 ] } }, + { "type": "Feature", "properties": { "id": 87, "Osoite": "Ursiininkatu 9", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "19.12.2022", "Virta": "Aurinkopaneeli", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 1.8, "Max.aika": null, "Maksuvyöhyke": "2", "Adress": "Ursinsgatan 9", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "19.12.2022", "Ström": "Solcell", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 1.8, "Zon": "2", "Address": "Ursiininkatu 9", "Installed": "19.12.2022", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Solar panel", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "2", "Tariff/h": 1.8 }, "geometry": { "type": "Point", "coordinates": [ 22.256546650434711, 60.448655233433726 ] } }, + { "type": "Feature", "properties": { "id": 88, "Osoite": "Blomberginaukio", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "16.12.2020", "Virta": "Aurinkopaneeli", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Blombergsplan", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "16.12.2020", "Ström": "Solcell", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Blomberginaukio", "Installed": "16.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Solar panel", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.29275674703927, 60.443803487057082 ] } }, + { "type": "Feature", "properties": { "id": 89, "Osoite": "Blomberginaukio", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "16.12.2020", "Virta": "Aurinkopaneeli", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Blombergsplan", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "16.12.2020", "Ström": "Solcell", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Blomberginaukio", "Installed": "16.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Solar panel", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.294113833178297, 60.442723807754163 ] } }, + { "type": "Feature", "properties": { "id": 90, "Osoite": "Tahkonaukio", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "16.12.2020", "Virta": "Aurinkopaneeli", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Tahkoplan", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "16.12.2020", "Ström": "Solcell", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Tahkonaukio", "Installed": "16.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Solar panel", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.294175006719268, 60.446804509763439 ] } }, + { "type": "Feature", "properties": { "id": 91, "Osoite": "Teollisuuskatu 16", "Sijainti": "Viherosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "11.10.2022", "Virta": "Aurinkopaneeli", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": null, "Omistaja": "Turun kaupunki", "Taksa/h": 0.6, "Max.aika": null, "Maksuvyöhyke": "3", "Adress": "Industrigatan 16", "Tillverkare": "Cale", "Plats": "Grönomrode", "Modell": "CWT-C Touch", "Installerad": "11.10.2022", "Ström": "Solcell", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Ägare": "Åbo stad", "Taxa/t": 0.6, "Zon": "3", "Address": "Teollisuuskatu 16", "Installed": "11.10.2022", "Location": "Greenery", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Solar panel", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Owner": "City of Turku", "Zone": "3", "Tariff/h": 0.6 }, "geometry": { "type": "Point", "coordinates": [ 22.301980689265612, 60.449590340262404 ] } }, + { "type": "Feature", "properties": { "id": 300, "Osoite": "Kunnallissairaalantie 20", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "8.12.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": "Taksa 0,5 €/t ensimmäiset 8t, 0,2 €/t aika yli 8t", "Omistaja": "Turun kaupunki", "Taksa/h": 0.5, "Max.aika": null, "Maksuvyöhyke": "Sairaala", "Adress": "Kommunalsjukhusvägen 20", "Tillverkare": "Cale", "Plats": "Gata", "Modell": "CWT-C Touch", "Installerad": "8.12.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Tillägg": "Taxa 0,5 €/t första 8t, 0,2 €/t efter 8t", "Ägare": "Åbo stad", "Taxa/t": 0.5, "Zon": "Sjukhus", "Address": "Kunnallissairaalantie 20", "Installed": "8.12.2020", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Additional info": "Tariff 0,5 €/h first 8h, 0,2 €/h time over 8h", "Owner": "City of Turku", "Zone": "Hospital", "Tariff/h": 0.5 }, "geometry": { "type": "Point", "coordinates": [ 22.275377662478608, 60.440746141486549 ] } }, + { "type": "Feature", "properties": { "id": 301, "Osoite": "Luolavuorentie 2", "Sijainti": "Viherosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "8.12.2020", "Virta": "Verkko", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": "Taksa 0,5 €/t ensimmäiset 8t, 0,2 €/t aika yli 8t", "Omistaja": "Turun kaupunki", "Taksa/h": 0.5, "Max.aika": null, "Maksuvyöhyke": "Sairaala", "Adress": "Luolavuorivägen 2", "Tillverkare": "Cale", "Plats": "Grönomrode", "Modell": "CWT-C Touch", "Installerad": "8.12.2020", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Tillägg": "Taxa 0,5 €/t första 8t, 0,2 €/t efter 8t", "Ägare": "Åbo stad", "Taxa/t": 0.5, "Zon": "Sjukhus", "Address": "Luolavuorentie 2", "Installed": "8.12.2020", "Location": "Greenery", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Coin, card, contactless", "Screen": "9\", touch screen", "Additional info": "Tariff 0,5 €/h first 8h, 0,2 €/h time over 8h", "Owner": "City of Turku", "Zone": "Hospital", "Tariff/h": 0.5 }, "geometry": { "type": "Point", "coordinates": [ 22.274444434528675, 60.438998327974652 ] } }, + { "type": "Feature", "properties": { "id": 302, "Osoite": "Luolavuorentie 2", "Sijainti": "Viherosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "8.12.2020", "Virta": "Verkko", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": "Taksa 0,5 €/t ensimmäiset 8t, 0,2 €/t aika yli 8t", "Omistaja": "Turun kaupunki", "Taksa/h": 0.5, "Max.aika": null, "Maksuvyöhyke": "Sairaala", "Adress": "Luolavuorivägen 2", "Tillverkare": "Cale", "Plats": "Grönomrode", "Modell": "CWT-C Touch", "Installerad": "8.12.2020", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Tillägg": "Taxa 0,5 €/t första 8t, 0,2 €/t efter 8t", "Ägare": "Åbo stad", "Taxa/t": 0.5, "Zon": "Sjukhus", "Address": "Luolavuorentie 2", "Installed": "8.12.2020", "Location": "Greenery", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Power": "Mains", "Payment Method": "Card, contactless", "Screen": "9\", touch screen", "Additional info": "Tariff 0,5 €/h first 8h, 0,2 €/h time over 8h", "Owner": "City of Turku", "Zone": "Hospital", "Tariff/h": 0.5 }, "geometry": { "type": "Point", "coordinates": [ 22.274072124365258, 60.439409437701471 ] } }, + { "type": "Feature", "properties": { "id": 401, "Osoite": "4. linja ", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "18.10.2022", "Virta": "Verkkovirta", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": "16 € / 26 h", "Omistaja": "Turun kaupunki", "Taksa/h": 1.3, "Max.aika": null, "Adress": "4. linjen", "Plats": "Gata", "Tillverkare": "Cale", "Modell": "CWT-C Touch", "Installerad": "18.10.2022", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Tilläg": "16 € / 26 h", "Ägare": "Åbo stad", "Zon": "Hamn", "Taxa/t": 1.3, "Maksuvyöhyke": "Satama", "Address": "4. linja", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Installed": "18.10.2022", "Power": "Mains", "Payment method": "Coin, card, contactless", "Screen": "9\", touch screen", "Additional info": "16 € / 26 h", "Owner": "City of Turku", "Zone": "Harbour", "Tariff/h": 1.3 }, "geometry": { "type": "Point", "coordinates": [ 22.2227213543412, 60.435316415968622 ] } }, + { "type": "Feature", "properties": { "id": 403, "Osoite": "4. linja", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "18.10.2022", "Virta": "Verkkovirta", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": "16 € / 26h", "Omistaja": "Turun kaupunki", "Taksa/h": 1.3, "Max.aika": null, "Adress": "4. linjen", "Plats": "Gata", "Tillverkare": "Cale", "Modell": "CWT-C Touch", "Installerad": "18.10.2022", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Tilläg": "16 € / 26 h", "Ägare": "Åbo stad", "Zon": "Hamn", "Taxa/t": 1.3, "Maksuvyöhyke": "Satama", "Address": "4. linja", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Installed": "18.10.2022", "Power": "Mains", "Payment method": "Card, contactless", "Screen": "9\", touch screen", "Additional info": "16 € / 26 h", "Owner": "City of Turku", "Zone": "Harbour", "Tariff/h": 1.3 }, "geometry": { "type": "Point", "coordinates": [ 22.221447167201752, 60.435584779574739 ] } }, + { "type": "Feature", "properties": { "id": 404, "Osoite": "3. linja", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "11.10.2022", "Virta": "Verkkovirta", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": "16 € / 26h", "Omistaja": "Turun kaupunki", "Taksa/h": 1.3, "Max.aika": null, "Adress": "3. linjen", "Plats": "Gata", "Tillverkare": "Cale", "Modell": "CWT-C Touch", "Installerad": "11.10.2022", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Tilläg": "16 € / 26 h", "Ägare": "Åbo stad", "Zon": "Hamn", "Taxa/t": 1.3, "Maksuvyöhyke": "Satama", "Address": "3. linja", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Installed": "11.10.2022", "Power": "Mains", "Payment method": "Card, contactless", "Screen": "9\", touch screen", "Additional info": "16 € / 26 h", "Owner": "City of Turku", "Zone": "Harbour", "Tariff/h": 1.3 }, "geometry": { "type": "Point", "coordinates": [ 22.221389745850257, 60.435173290652273 ] } }, + { "type": "Feature", "properties": { "id": 405, "Osoite": "Linnankatu 91", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "7.10.2022", "Virta": "Verkkovirta", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": "16 € / 26 h", "Omistaja": "Turun kaupunki", "Taksa/h": 1.3, "Max.aika": null, "Adress": "Slottsgatan 91", "Plats": "Gata", "Tillverkare": "Cale", "Modell": "CWT-C Touch", "Installerad": "7.10.2022", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Tilläg": "16 € / 26 h", "Ägare": "Åbo stad", "Zon": "Hamn", "Taxa/t": 1.3, "Maksuvyöhyke": "Satama", "Address": "Linnankatu 91", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Installed": "7.10.2022", "Power": "Mains", "Payment method": "Card, contactless", "Screen": "9\", touch screen", "Additional info": "16 € / 26 h", "Owner": "City of Turku", "Zone": "Harbour", "Tariff/h": 1.3 }, "geometry": { "type": "Point", "coordinates": [ 22.219860237204227, 60.435680281344297 ] } }, + { "type": "Feature", "properties": { "id": 406, "Osoite": "2. linja", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "7.10.2022", "Virta": "Verkkovirta", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": "16 € / 26 h", "Omistaja": "Turun kaupunki", "Taksa/h": 1.3, "Max.aika": null, "Adress": "2. linjen", "Plats": "Gata", "Tillverkare": "Cale", "Modell": "CWT-C Touch", "Installerad": "7.10.2022", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Tilläg": "16 € / 26 h", "Ägare": "Åbo stad", "Zon": "Hamn", "Taxa/t": 1.3, "Maksuvyöhyke": "Satama", "Address": "2. linja", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Installed": "7.10.2022", "Power": "Mains", "Payment method": "Coin, card, contactless", "Screen": "9\", touch screen", "Additional info": "16 € / 26 h", "Owner": "City of Turku", "Zone": "Harbour", "Tariff/h": 1.3, "Max.time": null }, "geometry": { "type": "Point", "coordinates": [ 22.224974204395551, 60.433923001505228 ] } }, + { "type": "Feature", "properties": { "id": 407, "Osoite": "2. linja", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "11.10.2022", "Virta": "Verkkovirta", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": "16 € / 26 h", "Omistaja": "Turun kaupunki", "Taksa/h": 1.3, "Max.aika": null, "Adress": "2. linjen", "Plats": "Gata", "Tillverkare": "Cale", "Modell": "CWT-C Touch", "Installerad": "11.10.2022", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Tilläg": "16 € / 26 h", "Ägare": "Åbo stad", "Zon": "Hamn", "Taxa/t": 1.3, "Maksuvyöhyke": "Satama", "Address": "2. linja", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Installed": "11.10.2022", "Power": "Mains", "Payment method": "Card, contactless", "Screen": "9\", touch screen", "Additional info": "16 € / 26 h", "Owner": "City of Turku", "Zone": "Harbour", "Tariff/h": 1.3 }, "geometry": { "type": "Point", "coordinates": [ 22.225946466932712, 60.434033761861251 ] } }, + { "type": "Feature", "properties": { "id": 408, "Osoite": "4. linja", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "17.10.2022", "Virta": "Verkkovirta", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": "16 € / 26 h", "Omistaja": "Turun kaupunki", "Taksa/h": 1.3, "Max.aika": null, "Adress": "4. linjen", "Plats": "Gata", "Tillverkare": "Cale", "Modell": "CWT-C Touch", "Installerad": "17.10.2022", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Tilläg": "16 € / 26 h", "Ägare": "Åbo stad", "Zon": "Hamn", "Taxa/t": 1.3, "Maksuvyöhyke": "Satama", "Address": "4. linja", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Installed": "17.10.2022", "Power": "Mains", "Payment method": "Coin, card, contactless", "Screen": "9\", touch screen", "Additional info": "16 € / 26 h", "Owner": "City of Turku", "Zone": "Harbour", "Tariff/h": 1.3 }, "geometry": { "type": "Point", "coordinates": [ 22.224755030627708, 60.434824489085884 ] } }, + { "type": "Feature", "properties": { "id": 409, "Osoite": "Linnankatu 87", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "7.10.2022", "Virta": "Verkkovirta", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": "16 € / 26 h", "Omistaja": "Turun kaupunki", "Taksa/h": 1.3, "Max.aika": null, "Adress": "Slottsgatan 87", "Plats": "Gata", "Tillverkare": "Cale", "Modell": "CWT-C Touch", "Installerad": "7.10.2022", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Tilläg": "16 € / 26 h", "Ägare": "Åbo stad", "Zon": "Hamn", "Taxa/t": 1.3, "Maksuvyöhyke": "Satama", "Address": "Linnankatu 87", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Installed": "7.10.2022", "Power": "Mains", "Payment method": "Coin, card, contactless", "Screen": "9\", touch screen", "Additional info": "16 € / 26 h", "Owner": "City of Turku", "Zone": "Harbour", "Tariff/h": 1.3 }, "geometry": { "type": "Point", "coordinates": [ 22.225127681727219, 60.435830090490398 ] } }, + { "type": "Feature", "properties": { "id": 413, "Osoite": "Satamakatu 18", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "14.10.2022", "Virta": "Verkkovirta", "Maksutapa": "Kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": "16 € / 26 h", "Omistaja": "Turun kaupunki", "Taksa/h": 1.3, "Max.aika": null, "Adress": "Hamngatan 18", "Plats": "Gata", "Tillverkare": "Cale", "Modell": "CWT-C Touch", "Installerad": "14.10.2022", "Ström": "Nät", "Betalningssätt": "Kort, kontaktlös", "Skärm": "9\", pekskärm", "Tilläg": "16 € / 26 h", "Ägare": "Åbo stad", "Zon": "Hamn", "Taxa/t": 1.3, "Maksuvyöhyke": "Satama", "Address": "Satamakatu 18", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Installed": "14.10.2022", "Power": "Mains", "Payment method": "Card, contactless", "Screen": "9\", touch screen", "Additional info": "16 € / 26 h", "Owner": "City of Turku", "Zone": "Harbour", "Tariff/h": 1.3 }, "geometry": { "type": "Point", "coordinates": [ 22.225972071802026, 60.436572492254285 ] } }, + { "type": "Feature", "properties": { "id": 415, "Osoite": "Satamakatu 18 vp", "Sijainti": "Katuosa", "Valmistaja": "Cale", "Malli": "CWT-C Touch", "Asennettu": "15.10.2022", "Virta": "Verkkovirta", "Maksutapa": "Kolikko, kortti, lähimaksu", "Näyttö": "9\", kosketus", "Muuta": "16 € / 26 h", "Omistaja": "Turun kaupunki", "Taksa/h": 1.3, "Max.aika": null, "Adress": "Hamngatan 18 me", "Plats": "Gata", "Tillverkare": "Cale", "Modell": "CWT-C Touch", "Installerad": "15.10.2022", "Ström": "Nät", "Betalningssätt": "Mynt, kort, kontaktlös", "Skärm": "9\", pekskärm", "Tilläg": "16 € / 26 h", "Ägare": "Åbo stad", "Zon": "Hamn", "Taxa/t": 1.3, "Maksuvyöhyke": "Satama", "Address": "Satamakatu 18 vp", "Location": "On-street", "Manufacturer": "Cale", "Model": "CWT-C Touch", "Installed": "15.10.2022", "Power": "Mains", "Payment method": "Coin, card, contactless", "Screen": "9\", touch screen", "Additional info": "16 € / 26 h", "Owner": "City of Turku", "Zone": "Harbour", "Tariff/h": 1.3 }, "geometry": { "type": "Point", "coordinates": [ 22.227764721514966, 60.436782262744913 ] } } + ] + } + \ No newline at end of file diff --git a/mobility_data/importers/bicycle_stands.py b/mobility_data/importers/bicycle_stands.py index 54afdca98..967721b49 100644 --- a/mobility_data/importers/bicycle_stands.py +++ b/mobility_data/importers/bicycle_stands.py @@ -9,7 +9,11 @@ from django.conf import settings from django.contrib.gis.gdal import DataSource from django.contrib.gis.geos import GEOSGeometry -from munigeo.models import AdministrativeDivision, AdministrativeDivisionGeometry +from munigeo.models import ( + AdministrativeDivision, + AdministrativeDivisionGeometry, + Municipality, +) from mobility_data.models import MobileUnit from services.models import Unit @@ -54,26 +58,27 @@ class BicyleStand: WFS_HULL_LOCKABLE_STR = "runkolukitusmahdollisuus" GEOJSON_HULL_LOCKABLE_STR = "runkolukittava" COVERED_IN_STR = "katettu" + EXTRA_FIELDS = [ + "maintained_by_turku", + "covered", + "hull_lockable", + "model", + "number_of_places", + "number_of_stands", + ] def __init__(self): self.geometry = None - self.model = None - self.number_of_stands = None - self.number_of_places = None # The total number of places for bicycles. - self.hull_lockable = None - self.covered = None - self.city = None - self.street_address = None - self.maintained_by_turku = None + self.municipality = None self.name = {} self.prefix_name = {} - self.street_address = {} + self.address = {} self.related_unit = None + self.extra = {f: None for f in self.EXTRA_FIELDS} def set_geojson_feature(self, feature): name = feature["kohde"].as_string().strip() unit_name = name.split(",")[0] - self.geometry = GEOSGeometry(feature.geom.wkt, srid=GEOJSON_SOURCE_DATA_SRID) self.geometry.transform(settings.DEFAULT_SRID) units_qs = Unit.objects.filter(name=unit_name) @@ -84,26 +89,33 @@ def set_geojson_feature(self, feature): self.related_unit = unit break - self.number_of_stands = feature["telineitä"].as_int() - self.number_of_places = feature["paikkoja"].as_int() + self.extra["number_of_stands"] = feature["telineitä"].as_int() + self.extra["number_of_places"] = feature["paikkoja"].as_int() model_elem = feature["pys.malli"].as_string() if model_elem: - self.model = model_elem + self.extra["model"] = model_elem + else: + self.extra["model"] = None quality_elem = feature["laatutaso"].as_string() if quality_elem: quality_text = quality_elem.lower() if self.GEOJSON_HULL_LOCKABLE_STR in quality_text: - self.hull_lockable = True + self.extra["hull_lockable"] = True else: - self.hull_lockable = False + self.extra["hull_lockable"] = False if self.COVERED_IN_STR in quality_text: - self.covered = True + self.extra["covered"] = True else: - self.covered = False + self.extra["covered"] = False + + municipality_name = get_municipality_name(self.geometry) + try: + self.municipality = Municipality.objects.get(name=municipality_name) + except Municipality.DoesNotExist: + self.municipality = None - self.city = get_municipality_name(self.geometry) self.name["fi"] = name # If related unit is known, use its translated names if self.related_unit: @@ -127,58 +139,64 @@ def set_geojson_feature(self, feature): else: # The last part is always the number address_number = address[-1] - translated_street_names = get_street_name_translations(street_name, self.city) - self.street_address["fi"] = f"{translated_street_names['fi']} {address_number}" - self.street_address["sv"] = f"{translated_street_names['sv']} {address_number}" - self.street_address["en"] = f"{translated_street_names['en']} {address_number}" + translated_street_names = get_street_name_translations( + street_name, municipality_name + ) + self.address["fi"] = f"{translated_street_names['fi']} {address_number}" + self.address["sv"] = f"{translated_street_names['sv']} {address_number}" + self.address["en"] = f"{translated_street_names['en']} {address_number}" def set_gml_feature(self, feature): object_id = feature["id"].as_string() # If ObjectId is set to "0", the bicycle stand is not maintained by Turku if object_id == "0": - self.maintained_by_turku = False + self.extra["maintained_by_turku"] = False else: - self.maintained_by_turku = True + self.extra["maintained_by_turku"] = True self.geometry = GEOSGeometry(feature.geom.wkt, srid=WFS_SOURCE_DATA_SRID) self.geometry.transform(settings.DEFAULT_SRID) model_elem = feature["Malli"] if model_elem is not None: - self.model = model_elem.as_string() + self.extra["model"] = model_elem.as_string() + else: + self.extra["model"] = None num_stands_elem = feature["Lukumaara"] if num_stands_elem is not None: num = num_stands_elem.as_int() # for bicycle stands that are Not maintained by Turku # the number of stands is set to 0 in the input data # but in reality there is no data so None is set. - if num == 0 and not self.maintained_by_turku: - self.number_of_stands = None + if num == 0 and not self.extra["maintained_by_turku"]: + self.extra["number_of_stands"] = None else: - self.number_of_stands = num + self.extra["number_of_stands"] = num num_places_elem = feature["Pyorapaikkojen_lukumaara"].as_string() - if num_places_elem: # Parse the numbers inside the string and finally sum them. # The input can contain string such as "8 runkolukittavaa ja 10 ei runkolukittavaa paikkaa" numbers = [int(s) for s in num_places_elem.split() if s.isdigit()] - self.number_of_places = sum(numbers) + self.extra["number_of_places"] = sum(numbers) quality_elem = feature["Pyorapaikkojen_laatutaso"].as_string() - if quality_elem: quality_text = quality_elem.lower() if self.WFS_HULL_LOCKABLE_STR in quality_text: - self.hull_lockable = True + self.extra["hull_lockable"] = True else: - self.hull_lockable = False - + self.extra["hull_lockable"] = False if self.COVERED_IN_STR in quality_text: - self.covered = True + self.extra["covered"] = True else: - self.covered = False - self.city = get_municipality_name(self.geometry) + self.extra["covered"] = False + try: + self.municipality = Municipality.objects.get( + name=get_municipality_name(self.geometry) + ) + except Municipality.DoesNotExist: + self.municipality = None full_names = get_closest_address_full_name(self.geometry) self.name[FI_KEY] = full_names[FI_KEY] self.name[SV_KEY] = full_names[SV_KEY] @@ -226,11 +244,11 @@ def get_bicycle_stand_objects(data_source=None): bicycle_stand.set_geojson_feature(feature) if ( bicycle_stand.name[FI_KEY] not in external_stands - and not bicycle_stand.maintained_by_turku + and not bicycle_stand.extra["maintained_by_turku"] ): external_stands[bicycle_stand.name[FI_KEY]] = True bicycle_stands.append(bicycle_stand) - elif bicycle_stand.maintained_by_turku: + elif bicycle_stand.extra["maintained_by_turku"]: bicycle_stands.append(bicycle_stand) logger.info(f"Retrieved {len(bicycle_stands)} bicycle stands.") @@ -257,18 +275,12 @@ def save_to_database(objects, delete_tables=True): content_type = create_bicycle_stand_content_type() for object in objects: mobile_unit = MobileUnit.objects.create( - content_type=content_type, + extra=object.extra, + municipality=object.municipality, ) - extra = {} - extra["model"] = object.model - extra["maintained_by_turku"] = object.maintained_by_turku - extra["number_of_stands"] = object.number_of_stands - extra["number_of_places"] = object.number_of_places - extra["hull_lockable"] = object.hull_lockable - extra["covered"] = object.covered - mobile_unit.extra = extra + mobile_unit.content_types.add(content_type) mobile_unit.geometry = object.geometry set_translated_field(mobile_unit, "name", object.name) - if object.street_address: - set_translated_field(mobile_unit, "address", object.street_address) + if object.address: + set_translated_field(mobile_unit, "address", object.address) mobile_unit.save() diff --git a/mobility_data/importers/bike_service_stations.py b/mobility_data/importers/bike_service_stations.py index b624def20..f7d00ad9a 100644 --- a/mobility_data/importers/bike_service_stations.py +++ b/mobility_data/importers/bike_service_stations.py @@ -29,8 +29,7 @@ def __init__(self, feature): self.address = {} self.description = {} self.extra = {} - self.address = {} - self.zip_code = None + self.address_zip = None self.municipality = None self.geometry = GEOSGeometry(feature.geom.wkt, srid=SOURCE_DATA_SRID) self.geometry.transform(settings.DEFAULT_SRID) @@ -41,7 +40,9 @@ def __init__(self, feature): # Addresses are in format: # Uudenmaankatu 18, 20700 Turku / Nylandsgatan 18, 20700 Turku addresses = feature["Osoite"].as_string().split("/") - self.zip_code, self.municipality = addresses[0].split(",")[1].strip().split(" ") + self.address_zip, self.municipality = ( + addresses[0].split(",")[1].strip().split(" ") + ) # remove zip code and municipality addresses = [address.split(",")[0].strip() for address in addresses] for i, language in enumerate(LANGUAGES): @@ -109,8 +110,11 @@ def save_to_database(objects, delete_tables=True): content_type = create_bike_service_station_content_type() for object in objects: mobile_unit = MobileUnit.objects.create( - content_type=content_type, extra=object.extra, geometry=object.geometry + extra=object.extra, + geometry=object.geometry, + address_zip=object.address_zip, ) + mobile_unit.content_types.add(content_type) set_translated_field(mobile_unit, "name", object.name) set_translated_field(mobile_unit, "description", object.description) set_translated_field(mobile_unit, "address", object.address) diff --git a/mobility_data/importers/charging_stations.py b/mobility_data/importers/charging_stations.py index 8d9e1708c..be6a5f36b 100644 --- a/mobility_data/importers/charging_stations.py +++ b/mobility_data/importers/charging_stations.py @@ -6,7 +6,6 @@ from django.contrib.gis.geos import Point from mobility_data.models import MobileUnit -from smbackend_turku.importers.constants import CHARGING_STATION_SERVICE_NAMES from .utils import ( delete_mobile_units, @@ -22,6 +21,11 @@ logger = logging.getLogger("mobility_data") +CHARGING_STATION_SERVICE_NAMES = { + "fi": "Autojen sähkölatauspiste", + "sv": "Elladdningsstation för bilar", + "en": "Car e-charging point", +} SOURCE_DATA_FILE_NAME = "LatauspisteetTurku.csv" SOURCE_DATA_SRID = 3877 CONTENT_TYPE_NAME = "ChargingStation" @@ -75,7 +79,7 @@ def __init__(self, values): self.extra["other"] = values["other"] self.extra["payment"] = values["payment"] self.municipality = get_municipality_name(self.geometry) - self.zip_code = get_postal_code(self.geometry) + self.address_zip = get_postal_code(self.geometry) tmp = values["address"].split(" ") address_number = None street_name = tmp[0] @@ -183,8 +187,9 @@ def save_to_database(objects, delete_tables=True): is_active=is_active, geometry=object.geometry, extra=object.extra, - content_type=content_type, + address_zip=object.address_zip, ) + mobile_unit.content_types.add(content_type) set_translated_field(mobile_unit, "name", object.name) set_translated_field(mobile_unit, "address", object.address) mobile_unit.save() diff --git a/mobility_data/importers/constants.py b/mobility_data/importers/constants.py index a501bfd59..12f05f266 100644 --- a/mobility_data/importers/constants.py +++ b/mobility_data/importers/constants.py @@ -1,3 +1,5 @@ +from django.contrib.gis.geos import Polygon + SOUTHWEST_FINLAND_BOUNDARY_SRID = 4236 SOUTHWEST_FINLAND_BOUNDARY = [ [20.377543, 60.876637], @@ -12764,3 +12766,7 @@ [20.437571, 60.901807], [20.377543, 60.876637], ] + +SOUTHWEST_FINLAND_GEOMETRY = Polygon( + SOUTHWEST_FINLAND_BOUNDARY, srid=SOUTHWEST_FINLAND_BOUNDARY_SRID +) diff --git a/mobility_data/importers/culture_routes.py b/mobility_data/importers/culture_routes.py index 6d37ae0dd..0829b9395 100644 --- a/mobility_data/importers/culture_routes.py +++ b/mobility_data/importers/culture_routes.py @@ -290,10 +290,10 @@ def save_to_database(routes, delete_tables=False): content_type = geometry_type mobile_unit, created = MobileUnit.objects.get_or_create( - content_type=content_type, mobile_unit_group=group, geometry=placemark.geometry, ) + mobile_unit.content_types.add(content_type) if created: mobile_unit.is_active = True set_translated_field(mobile_unit, "name", placemark.name) diff --git a/mobility_data/importers/data/lounaistieto_shapefiles_config.yml b/mobility_data/importers/data/lounaistieto_shapefiles_config.yml index 38c4f2cf9..022bbf198 100644 --- a/mobility_data/importers/data/lounaistieto_shapefiles_config.yml +++ b/mobility_data/importers/data/lounaistieto_shapefiles_config.yml @@ -1,4 +1,51 @@ data_sources: + - content_type_name: BusStopSouthwestFinland + content_type_description: "Bus stops in Southwest Finland." + data_url: "https://data.lounaistieto.fi/data/dataset/ee440090-7303-4453-8639-b5f711669acb/resource/14060749-5215-41af-9312-5393c966f987/download/tieverkkodata.zip/bussipysakit.shp" + fields: + name: + fi: pysnimi + sv: stopnamn + extra_fields: + piiri: piiri + tie: tie + tiety: tiety + puoli: puoli + bussity: bussity + pikavuo: pikavuo + katos: katos + korotettu: korotettu + pysid: pysid + pystunn196: pystunn196 + + - content_type_name: FerryDock + content_type_description: "Ferry docks in Southwest Finland." + data_url: "https://data.lounaistieto.fi/data/dataset/ea4dcae2-5832-403c-bf7e-b19783ee9a70/resource/faa02c52-2da8-4603-b8bf-4afca42d39a5/download/yhteysalusreitit_laiturit.zip/Laiturit.shp" + encoding: latin_1 + filter_by_southwest_finland: True + fields: + name: + fi: NIMI_ + municipality: KUNTA_1 + extra_fields: + nro: NRO + luokitus: LUOKITUS + alue: alue + reittialue: REITTIALUE + + - content_type_name: CommonFerryRoute + content_type_description: "Common ferry routes(yhteysalusreitti) in Southwest Finland." + data_url: "https://data.lounaistieto.fi/data/dataset/ea4dcae2-5832-403c-bf7e-b19783ee9a70/resource/faa02c52-2da8-4603-b8bf-4afca42d39a5/download/yhteysalusreitit_laiturit.zip/Yhteysalusreitit.shp" + encoding: latin_1 + filter_by_southwest_finland: True + fields: + name: + fi: REITTIALUE + sv: REITTIALUE + en: REITTIALUE + extra_fields: + yhteysalus: Yhteysalus + - content_type_name: FishingSpot content_type_description: "Fishing spots in Soutwest Finland." data_url: 'https://data.lounaistieto.fi/data/dataset/50451034-b760-4b39-8f88-701d9c968d88/resource/cd41b91f-f684-4cdc-bbf8-e2c4eaca3a70/download/kalapaikat.zip' diff --git a/mobility_data/importers/data/wfs_importer_config.yml b/mobility_data/importers/data/wfs_importer_config.yml index 345897fe6..f86db8084 100644 --- a/mobility_data/importers/data/wfs_importer_config.yml +++ b/mobility_data/importers/data/wfs_importer_config.yml @@ -1,4 +1,77 @@ features: + - content_type_name: PlayGround + content_type_description: Playgrounds in the city of Turku. + wfs_layer: GIS:Viheralueet + max_features: 50000 + include: + Kayttotyyppi: Leikkipaikka + fields: + name: + fi: Tunnus + extra_fields: + kayttotyyppi: + wfs_field: Kayttotyyppi + omistaja: + wfs_field: Omistaja + haltija: + wfs_field: Haltija + kunnossapitaja: + wfs_field: Kunnossapitaja + hoitaja: + wfs_field: Hoitaja + alueUrakkaAlue: + wfs_field: AlueUrakkaAlue + kunnossapitoluokka: + wfs_field: Kunnossapitoluokka + talvikunnossapito: + wfs_field: Talvikunnossapito + pintamateriaali: + wfs_field: Pintamateriaali + laskettuPintaAla: + wfs_field: LaskettuPintaAla + wfs_type: double + valmistusvuosi: + wfs_field: Valmistusvuosi + peruskorjausvuosi: + wfs_field: Peruskorjausvuosi + + - content_type_name: BarbecuePlace + content_type_description: Barbecue places in the city of Turku. + wfs_layer: GIS:Varusteet + max_features: 100000 + include: + Tyyppi: Grillipaikka + extra_fields: + valmistaja: + wfs_field: Valmistaja + valmistaja_koodi: + wfs_field: Valmistaja_koodi + wfs_type: int + malli: + wfs_field: Malli + malli_koodi: + wfs_field: Malli_koodi + wfs_type: int + hankintavuosi: + wfs_field: Hankintavuosi + wfs_type: int + kunto: + wfs_field: Kunto + kunto_koodi: + wfs_field: Kunto_koodi + wfs_type: int + lukumaara: + wfs_field: Lukumaara + wfs_type: int + pinta-ala: + wfs_field: Pinta-ala + wfs_type: double + pituus: + wfs_field: Pituus + wfs_type: double + asennus: + wfs_field: Asennus + - content_type_name: TicketMachineSign content_type_description: Ticket machine signs in the city of Turku. wfs_layer: GIS:Liikennemerkit diff --git a/mobility_data/importers/disabled_and_no_staff_parking.py b/mobility_data/importers/disabled_and_no_staff_parking.py index 4c68e89cf..ff9cfdb0e 100644 --- a/mobility_data/importers/disabled_and_no_staff_parking.py +++ b/mobility_data/importers/disabled_and_no_staff_parking.py @@ -98,8 +98,7 @@ def __init__(self, feature): feature["osoite"].as_string().split("/")[0].strip().split(" ")[-2:] ) try: - municipality = Municipality.objects.get(name=municipality) - self.municipality = municipality + self.municipality = Municipality.objects.get(name=municipality) except Municipality.DoesNotExist: self.municipality = None @@ -197,18 +196,14 @@ def save_to_database(objects, delete_tables=True): disabled_parking_content_type = get_and_create_disabled_parking_content_type() for object in objects: + mobile_unit = MobileUnit.objects.create( + extra=object.extra, + geometry=object.geometry, + ) if object.content_type == NO_STAFF_PARKING_CONTENT_TYPE_NAME: - mobile_unit = MobileUnit.objects.create( - content_type=no_staff_parking_content_type, - extra=object.extra, - geometry=object.geometry, - ) + mobile_unit.content_types.add(no_staff_parking_content_type) else: - mobile_unit = MobileUnit.objects.create( - content_type=disabled_parking_content_type, - extra=object.extra, - geometry=object.geometry, - ) + mobile_unit.content_types.add(disabled_parking_content_type) set_translated_field(mobile_unit, "name", object.name) set_translated_field(mobile_unit, "address", object.address) mobile_unit.address_zip = object.address_zip diff --git a/mobility_data/importers/foli_parkandride_stop.py b/mobility_data/importers/foli_parkandride_stop.py new file mode 100644 index 000000000..b1ff60df4 --- /dev/null +++ b/mobility_data/importers/foli_parkandride_stop.py @@ -0,0 +1,108 @@ +from django import db +from django.conf import settings +from django.contrib.gis.geos import Point +from munigeo.models import Municipality + +from mobility_data.models import MobileUnit + +from .utils import ( + delete_mobile_units, + fetch_json, + get_or_create_content_type, + set_translated_field, +) + +URL = "https://data.foli.fi/geojson/poi" +FOLI_PARKANDRIDE_CARS_STOP_CONTENT_TYPE_NAME = "FoliParkAndRideCarsStop" +FOLI_PARKANDRIDE_BIKES_STOP_CONTENT_TYPE_NAME = "FoliParkAndRideBikesStop" +PARKANDRIDE_CARS = "PARKANDRIDE_CARS" +PARKANDRIDE_BIKES = "PARKANDRIDE_BIKES" +SOURCE_DATA_SRID = 4326 + + +class ParkAndRideStop: + def __init__(self, feature): + properties = feature["properties"] + self.name = { + "fi": properties["name_fi"], + "sv": properties["name_sv"], + "en": properties["name_en"], + } + self.address = { + "fi": properties["address_fi"], + "sv": properties["address_sv"], + "en": properties["address_fi"], + } + self.address_zip = properties["text"].split(" ")[-1] + self.description = properties["text"] + try: + self.municipality = Municipality.objects.get(name=properties["city"]) + except Municipality.DoesNotExist: + self.municipality = None + geometry = feature["geometry"] + self.geometry = Point( + geometry["coordinates"][0], + geometry["coordinates"][1], + srid=SOURCE_DATA_SRID, + ) + self.geometry.transform(settings.DEFAULT_SRID) + + +def get_parkandride_stop_objects(): + json_data = fetch_json(URL) + car_stops = [] + bike_stops = [] + for feature in json_data["features"]: + if feature["properties"]["category"] == PARKANDRIDE_CARS: + car_stops.append(ParkAndRideStop(feature)) + elif feature["properties"]["category"] == PARKANDRIDE_BIKES: + bike_stops.append(ParkAndRideStop(feature)) + + return car_stops, bike_stops + + +@db.transaction.atomic +def get_and_create_foli_parkandride_bike_stop_content_type(): + description = "Föli park and ride bike stop." + content_type, _ = get_or_create_content_type( + FOLI_PARKANDRIDE_BIKES_STOP_CONTENT_TYPE_NAME, description + ) + return content_type + + +@db.transaction.atomic +def get_and_create_foli_parkandride_car_stop_content_type(): + description = "Föli park and ride car stop." + content_type, _ = get_or_create_content_type( + FOLI_PARKANDRIDE_CARS_STOP_CONTENT_TYPE_NAME, description + ) + return content_type + + +@db.transaction.atomic +def save_to_database(objects, content_type_name, delete_tables=True): + assert ( + content_type_name == FOLI_PARKANDRIDE_BIKES_STOP_CONTENT_TYPE_NAME + or content_type_name == FOLI_PARKANDRIDE_CARS_STOP_CONTENT_TYPE_NAME + ) + if delete_tables: + delete_mobile_units(content_type_name) + + if content_type_name == FOLI_PARKANDRIDE_BIKES_STOP_CONTENT_TYPE_NAME: + content_type = get_and_create_foli_parkandride_bike_stop_content_type() + elif content_type_name == FOLI_PARKANDRIDE_CARS_STOP_CONTENT_TYPE_NAME: + content_type = get_and_create_foli_parkandride_car_stop_content_type() + + for object in objects: + mobile_unit = MobileUnit.objects.create( + geometry=object.geometry, + address_zip=object.address_zip, + description=object.description, + municipality=object.municipality, + ) + mobile_unit.content_types.add(content_type) + set_translated_field(mobile_unit, "name", object.name) + set_translated_field(mobile_unit, "address", object.address) + mobile_unit.save() + + return len(objects) diff --git a/mobility_data/importers/foli_stops.py b/mobility_data/importers/foli_stops.py index d81639d13..a86a25cef 100644 --- a/mobility_data/importers/foli_stops.py +++ b/mobility_data/importers/foli_stops.py @@ -1,12 +1,12 @@ import logging -import requests from django import db +from django.conf import settings from django.contrib.gis.geos import Point from mobility_data.models import MobileUnit -from .utils import delete_mobile_units, get_or_create_content_type +from .utils import delete_mobile_units, fetch_json, get_or_create_content_type URL = "http://data.foli.fi/gtfs/stops" CONTENT_TYPE_NAME = "FoliStop" @@ -22,30 +22,18 @@ def __init__(self, stop_data): lon = stop_data["stop_lon"] lat = stop_data["stop_lat"] self.geometry = Point(lon, lat, srid=SOURCE_DATA_SRID) + self.geometry.transform(settings.DEFAULT_SRID) self.extra["stop_code"] = stop_data["stop_code"] self.extra["wheelchair_boarding"] = stop_data["wheelchair_boarding"] -def get_json_data(): - response = requests.get(URL) - assert ( - response.status_code == 200 - ), "Unable to fetch föli stops from url: {}, status code: {}".format( - URL, response.status_code - ) - return response.json() - - def get_foli_stops(): - json_data = get_json_data() - objects = [] - for stop_code in json_data: - objects.append(FoliStop(json_data[stop_code])) - return objects + json_data = fetch_json(URL) + return [FoliStop(json_data[stop_code]) for stop_code in json_data] @db.transaction.atomic -def create_foli_stop_content_type(): +def get_and_create_foli_stop_content_type(): description = "Föli stops." content_type, _ = get_or_create_content_type(CONTENT_TYPE_NAME, description) return content_type @@ -56,12 +44,12 @@ def save_to_database(objects, delete_tables=True): if delete_tables: delete_mobile_units(CONTENT_TYPE_NAME) - content_type = create_foli_stop_content_type() + content_type = get_and_create_foli_stop_content_type() for object in objects: - MobileUnit.objects.create( - content_type=content_type, + mobile_unit = MobileUnit.objects.create( name=object.name, geometry=object.geometry, extra=object.extra, ) + mobile_unit.content_types.add(content_type) logger.info(f"Saved {len(objects)} Föli stops to database.") diff --git a/mobility_data/importers/gas_filling_station.py b/mobility_data/importers/gas_filling_station.py index 18481916c..40430042b 100644 --- a/mobility_data/importers/gas_filling_station.py +++ b/mobility_data/importers/gas_filling_station.py @@ -3,6 +3,7 @@ from django import db from django.conf import settings from django.contrib.gis.geos import Point, Polygon +from munigeo.models import Municipality from mobility_data.models import MobileUnit @@ -30,35 +31,38 @@ class GasFillingStation: def __init__(self, elem, srid=settings.DEFAULT_SRID): # Contains the complete address with zip_code and city self.address = {} + self.extra = {} + self.name = {} # Contains Only steet_name and number self.street_address = {} self.is_active = True attributes = elem.get("attributes") x = attributes.get("LON", 0) y = attributes.get("LAT", 0) - self.point = Point(x, y, srid=srid) - self.name = attributes.get("STATION_NAME", "") + self.geometry = Point(x, y, srid=srid) + self.name["fi"] = attributes.get("STATION_NAME", "") address_field = attributes.get("ADDRESS", "") street_name, street_number = get_street_name_and_number(address_field) - self.zip_code = attributes.get("ZIP_CODE", "") - self.city = attributes.get("CITY", "") - translated_street_names = get_street_name_translations(street_name, self.city) + self.address_zip = attributes.get("ZIP_CODE", "") + municipality_name = attributes.get("CITY", "") + translated_street_names = get_street_name_translations( + street_name, municipality_name + ) + try: + self.municipality = Municipality.objects.get(name=municipality_name) + except Municipality.DoesNotExist: + self.municipality = None + for lang in LANGUAGES: if street_number: - self.address[ - lang - ] = f"{translated_street_names[lang]} {street_number}, " - self.address[lang] += f"{self.zip_code} {self.city}" - self.street_address[ - lang - ] = f"{translated_street_names[lang]} {street_number}" + self.address[lang] = f"{translated_street_names[lang]} {street_number}" else: - self.address[lang] = f"{translated_street_names[lang]}, " - self.address[lang] += f"{self.zip_code} {self.city}" - self.street_address[lang] = f"{translated_street_names[lang]}" + self.address[lang] = f"{translated_street_names[lang]}" - self.operator = attributes.get("OPERATOR", "") + self.operator = attributes.get("OPERATOR", "") self.lng_cng = attributes.get("LNG_CNG", "") + self.extra["operator"] = self.operator + self.extra["lng_cng"] = self.lng_cng def get_filtered_gas_filling_station_objects(json_data=None): @@ -78,7 +82,7 @@ def get_filtered_gas_filling_station_objects(json_data=None): # Filter objects by their location # Polygon used the detect if point intersects. i.e. is in the boundaries of SouthWest Finland. polygon = Polygon(SOUTHWEST_FINLAND_BOUNDARY, srid=SOUTHWEST_FINLAND_BOUNDARY_SRID) - filtered_objects = [o for o in objects if polygon.intersects(o.point)] + filtered_objects = [o for o in objects if polygon.intersects(o.geometry)] logger.info( "Filtered: {} gas filling stations by location to: {}.".format( len(json_data["features"]), len(filtered_objects) @@ -107,18 +111,15 @@ def save_to_database(objects, delete_tables=True): content_type = create_gas_filling_station_content_type() for object in objects: is_active = object.is_active - name = object.name - extra = {} - extra["operator"] = object.operator - extra["lng_cng"] = object.lng_cng - mobile_unit = MobileUnit.objects.create( is_active=is_active, - name=name, - geometry=object.point, - extra=extra, - content_type=content_type, + geometry=object.geometry, + extra=object.extra, + address_zip=object.address_zip, + municipality=object.municipality, ) + mobile_unit.content_types.add(content_type) + set_translated_field(mobile_unit, "name", object.name) set_translated_field(mobile_unit, "address", object.address) mobile_unit.save() logger.info(f"Saved {len(objects)} gas filling stations to database.") diff --git a/mobility_data/importers/loading_unloading_places.py b/mobility_data/importers/loading_unloading_places.py index 2af4e4b64..b45988ba0 100644 --- a/mobility_data/importers/loading_unloading_places.py +++ b/mobility_data/importers/loading_unloading_places.py @@ -151,10 +151,10 @@ def save_to_database(objects, delete_tables=True): content_type = get_and_create_loading_and_unloading_place_content_type() for object in objects: mobile_unit = MobileUnit.objects.create( - content_type=content_type, extra=object.extra, geometry=object.geometry, ) + mobile_unit.content_types.add(content_type) set_translated_field(mobile_unit, "name", object.name) set_translated_field(mobile_unit, "address", object.address) mobile_unit.address_zip = object.address_zip diff --git a/mobility_data/importers/lounaistieto_shapefiles.py b/mobility_data/importers/lounaistieto_shapefiles.py index ebcd5f6e1..010d7f349 100644 --- a/mobility_data/importers/lounaistieto_shapefiles.py +++ b/mobility_data/importers/lounaistieto_shapefiles.py @@ -13,8 +13,10 @@ ) from mobility_data.models import MobileUnit -logger = logging.getLogger("mobility_data") +from .constants import SOUTHWEST_FINLAND_GEOMETRY +logger = logging.getLogger("mobility_data") +SOUTHWEST_FINLAND_GEOMETRY.transform(settings.DEFAULT_SRID) DEFAULT_ENCODING = "utf-8" @@ -48,7 +50,7 @@ def add_feature(self, feature, config, srid): match feature.shape.shapeTypeName: case "POLYLINE": geometry = LineString(feature.shape.points, srid=srid) - case "POINT": + case "POINT" | "MULTIPOINTZ": points = feature.shape.points[0] assert len(points) == 2 geometry = Point(points[0], points[1], srid=srid) @@ -70,6 +72,11 @@ def add_feature(self, feature, config, srid): except Exception as e: logger.warning(f"Skipping feature {feature.geom}, invalid geom {e}") return False + + if config.get("filter_by_southwest_finland", False): + if not SOUTHWEST_FINLAND_GEOMETRY.covers(geometry): + return False + if "municipality" in config: municipality = feature.record[config["municipality"]] if municipality: @@ -78,11 +85,12 @@ def add_feature(self, feature, config, srid): id=municipality_id ).first() - for attr, field in config["fields"].items(): - for lang, field_name in field.items(): - # attr can have fallback definitons if None - if getattr(self, attr)[lang] is None: - getattr(self, attr)[lang] = feature.record[field_name] + if "fields" in config: + for attr, field in config["fields"].items(): + for lang, field_name in field.items(): + # attr can have fallback definitons if None + if getattr(self, attr)[lang] is None: + getattr(self, attr)[lang] = feature.record[field_name] if "extra_fields" in config: for attr, field in config["extra_fields"].items(): @@ -114,8 +122,9 @@ def save_to_database(objects, config): return for object in objects: mobile_unit = MobileUnit.objects.create( - content_type=content_type, extra=object.extra, geometry=object.geometry + extra=object.extra, geometry=object.geometry ) + mobile_unit.content_types.add(content_type) mobile_unit.municipality = object.municipality set_translated_field(mobile_unit, "name", object.name) set_translated_field(mobile_unit, "address", object.address) diff --git a/mobility_data/importers/marinas.py b/mobility_data/importers/marinas.py index 16d3a4f19..678e51567 100644 --- a/mobility_data/importers/marinas.py +++ b/mobility_data/importers/marinas.py @@ -99,12 +99,12 @@ def import_marinas(delete=True): marinas.append(Marina(feature)) content_type = create_marina_content_type() for marina in marinas: - MobileUnit.objects.create( - content_type=content_type, + mobile_unit = MobileUnit.objects.create( geometry=marina.geometry, name=marina.name, extra=marina.extra, ) + mobile_unit.content_types.add(content_type) return len(marinas) @@ -128,4 +128,5 @@ def import_guest_marina_and_boat_parking(delete=True): elif type_name == BOAT_PARKING: content_type = create_boat_parking_content_type() - MobileUnit.objects.create(content_type=content_type, geometry=geometry) + mobile_unit = MobileUnit.objects.create(geometry=geometry) + mobile_unit.content_types.add(content_type) diff --git a/mobility_data/importers/outdoor_gym_devices.py b/mobility_data/importers/outdoor_gym_devices.py index 6d17f64b3..13bc292aa 100644 --- a/mobility_data/importers/outdoor_gym_devices.py +++ b/mobility_data/importers/outdoor_gym_devices.py @@ -37,5 +37,7 @@ def save_outdoor_gym_devices(): content_type = create_content_type() units_qs = Unit.objects.filter(services=service) for unit in units_qs: - MobileUnit.objects.create(content_type=content_type, unit_id=unit.id) + mobile_unit = MobileUnit.objects.create(unit_id=unit.id) + mobile_unit.content_types.add(content_type) + mobile_unit.save() return units_qs.count() diff --git a/mobility_data/importers/parking_machines.py b/mobility_data/importers/parking_machines.py new file mode 100644 index 000000000..eaca1c259 --- /dev/null +++ b/mobility_data/importers/parking_machines.py @@ -0,0 +1,151 @@ +from django import db +from django.conf import settings +from django.contrib.gis.geos import Point + +from mobility_data.models import MobileUnit + +from .utils import ( + delete_mobile_units, + FieldTypes, + get_file_name_from_data_source, + get_or_create_content_type, + get_root_dir, + set_translated_field, +) + +SOURCE_DATA_SRID = 4326 +GEOJSON_FILENAME = "parking_machines.geojson" +CONTENT_TYPE_NAME = "ParkingMachine" +LANGUAGES = ["fi", "sv", "en"] + + +class ParkingMachine: + + extra_field_mappings = { + "Sijainti": { + "type": FieldTypes.MULTILANG_STRING, + "fi": "Sijainti", + "sv": "Plats", + "en": "Location", + }, + "Virta": { + "type": FieldTypes.MULTILANG_STRING, + "fi": "Virta", + "sv": "Ström", + "en": "Power", + }, + "Maksutapa": { + "type": FieldTypes.MULTILANG_STRING, + "fi": "Maksutapa", + "sv": "Betalningssätt", + # The source data contains Payment method with method starting with + # uppercase M and lowercase m. + "en": ["Payment method", "Payment Method"], + }, + "Näyttö": { + "type": FieldTypes.MULTILANG_STRING, + "fi": "Näyttö", + "sv": "Skärm", + "en": "Screen", + }, + "Omistaja": { + "type": FieldTypes.MULTILANG_STRING, + "fi": "Omistaja", + "sv": "Ägare", + "en": "Owner", + }, + "Maksuvyöhyke": { + "type": FieldTypes.MULTILANG_STRING, + "fi": "Maksuvyöhyke", + "sv": "Zon", + "en": "Zone", + }, + "Muuta": {"type": FieldTypes.STRING}, + "Taksa/h": {"type": FieldTypes.FLOAT}, + "Max.aika": {"type": FieldTypes.FLOAT}, + "Malli": {"type": FieldTypes.STRING}, + "Asennettu": {"type": FieldTypes.STRING}, + "Valmistaja": { + "type": FieldTypes.STRING, + }, + } + + def __init__(self, feature): + properties = feature["properties"] + geometry = feature["geometry"] + self.extra = {} + self.address = {"fi": properties["Osoite"]} + self.address["sv"] = properties["Adress"] + self.address["en"] = properties["Address"] + self.geometry = Point( + geometry["coordinates"][0], + geometry["coordinates"][1], + srid=SOURCE_DATA_SRID, + ) + self.geometry.transform(settings.DEFAULT_SRID) + + for field in properties.keys(): + if field in self.extra_field_mappings: + match self.extra_field_mappings[field]["type"]: + case FieldTypes.MULTILANG_STRING: + self.extra[field] = {} + for lang in LANGUAGES: + key = self.extra_field_mappings[field][lang] + # Support multiple keys for same field, e.g., + # 'Payment method' and 'Payment Method' + if type(key) == list: + for k in key: + val = properties.get(k, None) + if val: + self.extra[field][lang] = val + break + else: + self.extra[field][lang] = properties[key] + + case FieldTypes.STRING: + self.extra[field] = properties[field] + case FieldTypes.INTEGER: + val = properties[field] + self.extra[field] = int(val) if val else None + case FieldTypes.FLOAT: + val = properties[field] + self.extra[field] = float(val) if val else None + + +def get_json_data(): + file_name = get_file_name_from_data_source(CONTENT_TYPE_NAME) + if not file_name: + file_name = f"{get_root_dir()}/mobility_data/data/{GEOJSON_FILENAME}" + json_data = None + import json + + with open(file_name, "r") as json_file: + json_data = json.loads(json_file.read()) + return json_data + + +def get_parking_machine_objects(): + json_data = get_json_data()["features"] + return [ParkingMachine(feature) for feature in json_data] + + +@db.transaction.atomic +def get_and_create_parking_machine_content_type(): + description = "Parking machines in the City of Turku." + content_type, _ = get_or_create_content_type(CONTENT_TYPE_NAME, description) + return content_type + + +@db.transaction.atomic +def save_to_database(objects, delete_tables=True): + if delete_tables: + delete_mobile_units(CONTENT_TYPE_NAME) + content_type = get_and_create_parking_machine_content_type() + for object in objects: + mobile_unit = MobileUnit.objects.create( + geometry=object.geometry, + extra=object.extra, + ) + mobile_unit.content_types.add(content_type) + set_translated_field(mobile_unit, "address", object.address) + mobile_unit.save() diff --git a/mobility_data/importers/share_car_parking_places.py b/mobility_data/importers/share_car_parking_places.py index 6765a8cb3..87e25f9d0 100644 --- a/mobility_data/importers/share_car_parking_places.py +++ b/mobility_data/importers/share_car_parking_places.py @@ -95,9 +95,8 @@ def save_to_database(objects, delete_tables=True): delete_car_share_parking_places() content_type = create_car_share_parking_place_content_type() for object in objects: - mobile_unit = MobileUnit.objects.create( - content_type=content_type, extra=object.extra - ) + mobile_unit = MobileUnit.objects.create(extra=object.extra) + mobile_unit.content_types.add(content_type) set_translated_field(mobile_unit, "name", object.name) set_translated_field(mobile_unit, "address", object.address) mobile_unit.save() diff --git a/mobility_data/importers/utils.py b/mobility_data/importers/utils.py index 87411ffac..c49ba1dd4 100644 --- a/mobility_data/importers/utils.py +++ b/mobility_data/importers/utils.py @@ -68,7 +68,7 @@ def fetch_json(url): def delete_mobile_units(name): - ContentType.objects.filter(name=name).delete() + MobileUnit.objects.filter(content_types__name=name).delete() def create_mobile_unit_as_unit_reference(unit_id, content_type): @@ -78,10 +78,10 @@ def create_mobile_unit_as_unit_reference(unit_id, content_type): serialize the data from the services_unit table in the mobile_unit endpoint. """ - MobileUnit.objects.create( + mobile_unit = MobileUnit.objects.create( unit_id=unit_id, - content_type=content_type, ) + mobile_unit.content_types.add(content_type) def get_or_create_content_type(name, description): diff --git a/mobility_data/importers/wfs.py b/mobility_data/importers/wfs.py index bcfd2a6b6..bb15af06e 100644 --- a/mobility_data/importers/wfs.py +++ b/mobility_data/importers/wfs.py @@ -47,8 +47,9 @@ def save_to_database_using_yaml_config(objects, config): return for object in objects: mobile_unit = MobileUnit.objects.create( - content_type=content_type, extra=object.extra, geometry=object.geometry + extra=object.extra, geometry=object.geometry ) + mobile_unit.content_types.add(content_type) mobile_unit.municipality = object.municipality set_translated_field(mobile_unit, "name", object.name) set_translated_field(mobile_unit, "address", object.address) diff --git a/mobility_data/management/commands/import_foli_parkandride_stops.py b/mobility_data/management/commands/import_foli_parkandride_stops.py new file mode 100644 index 000000000..f237fd912 --- /dev/null +++ b/mobility_data/management/commands/import_foli_parkandride_stops.py @@ -0,0 +1,25 @@ +import logging + +from django.core.management import BaseCommand + +from mobility_data.importers.foli_parkandride_stop import ( + FOLI_PARKANDRIDE_BIKES_STOP_CONTENT_TYPE_NAME, + FOLI_PARKANDRIDE_CARS_STOP_CONTENT_TYPE_NAME, + get_parkandride_stop_objects, + save_to_database, +) + +logger = logging.getLogger("mobility_data") + + +class Command(BaseCommand): + def handle(self, *args, **options): + car_stops, bike_stops = get_parkandride_stop_objects() + logger.info( + f"Saved {save_to_database(car_stops, FOLI_PARKANDRIDE_CARS_STOP_CONTENT_TYPE_NAME)} " + "Föli park and ride car stops to database" + ) + logger.info( + f"Saved {save_to_database(bike_stops, FOLI_PARKANDRIDE_BIKES_STOP_CONTENT_TYPE_NAME)} " + "Föli park and ride bike stops to database" + ) diff --git a/mobility_data/management/commands/import_foli_stops.py b/mobility_data/management/commands/import_foli_stops.py index 21977c8d6..ebefee2d5 100644 --- a/mobility_data/management/commands/import_foli_stops.py +++ b/mobility_data/management/commands/import_foli_stops.py @@ -1,13 +1,13 @@ import logging -from mobility_data.importers.foli_stops import get_foli_stops, save_to_database +from django.core.management import BaseCommand -from ._base_import_command import BaseImportCommand +from mobility_data.importers.foli_stops import get_foli_stops, save_to_database logger = logging.getLogger("mobility_data") -class Command(BaseImportCommand): +class Command(BaseCommand): def handle(self, *args, **options): logger.info("Importing Föli stops") objects = get_foli_stops() diff --git a/mobility_data/management/commands/import_lounaistieto_shapefiles.py b/mobility_data/management/commands/import_lounaistieto_shapefiles.py index 3140af412..060b2b3f6 100644 --- a/mobility_data/management/commands/import_lounaistieto_shapefiles.py +++ b/mobility_data/management/commands/import_lounaistieto_shapefiles.py @@ -7,7 +7,6 @@ import_lounaistieto_data_source, ) from mobility_data.importers.utils import delete_mobile_units, get_root_dir -from mobility_data.models import ContentType from ._base_import_command import BaseImportCommand @@ -31,7 +30,8 @@ def handle(self, *args, **options): content_type = options["delete_data_source"] if len(content_type) == 0: logger.warning("Specify the content type to delete.") - delete_mobile_units(getattr(ContentType, content_type[0])) + delete_mobile_units(content_type[0]) + logger.info(f"Deleted MobileUnit and ContentType for {content_type[0]}") else: config_path = f"{get_root_dir()}/mobility_data/importers/data/" path = os.path.join(config_path, CONFIG_FILE) diff --git a/mobility_data/management/commands/import_mobility_data.py b/mobility_data/management/commands/import_mobility_data.py index 8515c554d..c514b3dc8 100644 --- a/mobility_data/management/commands/import_mobility_data.py +++ b/mobility_data/management/commands/import_mobility_data.py @@ -1,5 +1,5 @@ """ -Main importer for mobility data sources. +Imports all mobility data sources. """ import logging @@ -24,6 +24,7 @@ "lounaistieto_shapefiles", "foli_stops", "outdoor_gym_devices", + "foli_parkandride_stops", ] # Read the content type names to be imported wfs_content_type_names = get_configured_cotent_type_names() diff --git a/mobility_data/management/commands/import_parking_machines.py b/mobility_data/management/commands/import_parking_machines.py new file mode 100644 index 000000000..fdc52bda3 --- /dev/null +++ b/mobility_data/management/commands/import_parking_machines.py @@ -0,0 +1,17 @@ +import logging + +from django.core.management import BaseCommand + +from mobility_data.importers.parking_machines import ( + get_parking_machine_objects, + save_to_database, +) + +logger = logging.getLogger("mobility_data") + + +class Command(BaseCommand): + def handle(self, *args, **options): + objects = get_parking_machine_objects() + save_to_database(objects) + logger.info(f"Saved {len(objects)} parking machines to database.") diff --git a/mobility_data/management/commands/import_share_car_parking_places.py b/mobility_data/management/commands/import_share_car_parking_places.py index 68ade93f1..d0e003ffc 100644 --- a/mobility_data/management/commands/import_share_car_parking_places.py +++ b/mobility_data/management/commands/import_share_car_parking_places.py @@ -19,4 +19,4 @@ def handle(self, *args, **options): objects = get_car_share_parking_place_objects(geojson_file=geojson_file) save_to_database(objects) - logger.info(f"Imported {len(objects)} char share parking places.") + logger.info(f"Imported {len(objects)} car share parking places.") diff --git a/mobility_data/migrations/0035_add_many_to_many_field_content_types_to_mobile_unit.py b/mobility_data/migrations/0035_add_many_to_many_field_content_types_to_mobile_unit.py new file mode 100644 index 000000000..029d6b23f --- /dev/null +++ b/mobility_data/migrations/0035_add_many_to_many_field_content_types_to_mobile_unit.py @@ -0,0 +1,20 @@ +# Generated by Django 4.1.2 on 2023-02-08 07:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("mobility_data", "0034_remove_grouptype_type_name"), + ] + + operations = [ + migrations.AddField( + model_name="mobileunit", + name="content_types", + field=models.ManyToManyField( + related_name="mobile_units", to="mobility_data.contenttype" + ), + ), + ] diff --git a/mobility_data/migrations/0036_populate_mobile_type_content_types.py b/mobility_data/migrations/0036_populate_mobile_type_content_types.py new file mode 100644 index 000000000..cafd7c797 --- /dev/null +++ b/mobility_data/migrations/0036_populate_mobile_type_content_types.py @@ -0,0 +1,21 @@ +# Generated by Django 4.1.2 on 2023-02-08 07:12 + +from django.db import migrations + + +def make_many_to_many_content_types(apps, schema_editor): + MobileUnit = apps.get_model("mobility_data", "MobileUnit") + + for mobile_unit in MobileUnit.objects.all(): + mobile_unit.content_types.add(mobile_unit.content_type) + + +class Migration(migrations.Migration): + + dependencies = [ + ("mobility_data", "0035_add_many_to_many_field_content_types_to_mobile_unit"), + ] + + operations = [ + migrations.RunPython(make_many_to_many_content_types), + ] diff --git a/mobility_data/migrations/0037_remove_mobileunit_content_type.py b/mobility_data/migrations/0037_remove_mobileunit_content_type.py new file mode 100644 index 000000000..8d0626c0a --- /dev/null +++ b/mobility_data/migrations/0037_remove_mobileunit_content_type.py @@ -0,0 +1,17 @@ +# Generated by Django 4.1.2 on 2023-02-08 08:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("mobility_data", "0036_populate_mobile_type_content_types"), + ] + + operations = [ + migrations.RemoveField( + model_name="mobileunit", + name="content_type", + ), + ] diff --git a/mobility_data/migrations/0038_alter_contenttype_and_grouptype_ordering_to_field_name.py b/mobility_data/migrations/0038_alter_contenttype_and_grouptype_ordering_to_field_name.py new file mode 100644 index 000000000..2d450fe7f --- /dev/null +++ b/mobility_data/migrations/0038_alter_contenttype_and_grouptype_ordering_to_field_name.py @@ -0,0 +1,21 @@ +# Generated by Django 4.1.2 on 2023-02-08 14:04 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("mobility_data", "0037_remove_mobileunit_content_type"), + ] + + operations = [ + migrations.AlterModelOptions( + name="contenttype", + options={"ordering": ["name"]}, + ), + migrations.AlterModelOptions( + name="grouptype", + options={"ordering": ["name"]}, + ), + ] diff --git a/mobility_data/models/content_type.py b/mobility_data/models/content_type.py index 375166065..9dbec462e 100644 --- a/mobility_data/models/content_type.py +++ b/mobility_data/models/content_type.py @@ -12,7 +12,7 @@ class BaseType(models.Model): class Meta: abstract = True - ordering = ["id"] + ordering = ["name"] def __str__(self): return self.name diff --git a/mobility_data/models/mobile_unit.py b/mobility_data/models/mobile_unit.py index d5edbe44f..0054346f6 100644 --- a/mobility_data/models/mobile_unit.py +++ b/mobility_data/models/mobile_unit.py @@ -53,9 +53,7 @@ class MobileUnit(BaseUnit): ) address_zip = models.CharField(max_length=10, null=True) - content_type = models.ForeignKey( - ContentType, on_delete=models.CASCADE, related_name="units" - ) + content_types = models.ManyToManyField(ContentType, related_name="mobile_units") unit_id = models.IntegerField( null=True, verbose_name="optional id to a unit in the servicemap, if id exist data is serialized from services_unit table", diff --git a/mobility_data/specification.swagger2.0.yaml b/mobility_data/specification.swagger2.0.yaml index 832ad84da..3c46b7c78 100644 --- a/mobility_data/specification.swagger2.0.yaml +++ b/mobility_data/specification.swagger2.0.yaml @@ -60,7 +60,7 @@ definitions: type: string description_en: type: string - content_type: + content_types: $ref: "#/definitions/content_type" mobile_unit_group: $ref: "#/definitions/mobile_unit_group" @@ -134,6 +134,9 @@ paths: - $ref: "#/components/parameters/latlon_param" - $ref: "#/components/parameters/type_name_param" - $ref: "#/components/parameters/extra_param" + - $ref: "#/components/parameters/bbox_param" + - $ref: "#/components/parameters/bbox_srid_param" + responses: 200: description: "List of MobileUnits." @@ -286,4 +289,25 @@ components: required: false schema: type: string - example: extra__fieldname=value \ No newline at end of file + example: extra__fieldname=value + + bbox_param: + name: bbox + in: query + description: Search for mobile units that are within this bounding box. Decimal coordinates + are given in order west, south, east, north. Period is used as decimal + separator. Default srid is 4326. + schema: + type: array + items: + type: number + example: 24.9405559,60.1695096,24.9805559,60.1895096 + + bbox_srid_param: + name: bbox_srid + in: query + description: An SRID coordinate reference system identifier which specifies the + coordinate system used in the bbox parameter. + schema: + type: integer + example: 3046 \ No newline at end of file diff --git a/mobility_data/tasks.py b/mobility_data/tasks.py index 3e2ab1994..9ad42bb02 100644 --- a/mobility_data/tasks.py +++ b/mobility_data/tasks.py @@ -1,8 +1,9 @@ -from celery import shared_task from django.core import management +from smbackend.utils import shared_task_email -@shared_task + +@shared_task_email def import_culture_routes(args=None, name="import_culture_routes"): if args: management.call_command("import_culture_routes", args) @@ -10,17 +11,17 @@ def import_culture_routes(args=None, name="import_culture_routes"): management.call_command("import_culture_routes") -@shared_task +@shared_task_email def import_payments_zones(name="import_payment_zones"): management.call_command("import_wfs", "PaymentZone") -@shared_task +@shared_task_email def import_speed_limit_zones(name="import_speed_limit_zones"): management.call_command("import_wfs", "SpeedLimitZone") -@shared_task +@shared_task_email def import_scooter_restrictions(name="import_scooter_restrictions"): management.call_command( "import_wfs", @@ -28,12 +29,12 @@ def import_scooter_restrictions(name="import_scooter_restrictions"): ) -@shared_task +@shared_task_email def import_mobility_data(name="import_mobility_data"): management.call_command("import_mobility_data") -@shared_task +@shared_task_email def import_accessories(name="import_accessories"): management.call_command( "import_wfs", @@ -41,66 +42,81 @@ def import_accessories(name="import_accessories"): ) -@shared_task +@shared_task_email +def import_barbecue_places(name="import_barbecue_places"): + management.call_command("import_wfs", ["BarbecuePlace"]) + + +@shared_task_email +def import_playgrounds(name="import_playgrounds"): + management.call_command("import_wfs", ["PlayGround"]) + + +@shared_task_email def import_share_car_parking_places(name="impor_share_car_parking_places"): management.call_command("import_share_car_parking_places") -@shared_task +@shared_task_email def import_bicycle_networks(name="import_bicycle_networks"): management.call_command( "import_wfs", ["BrushSaltedBicycleNetwork", "BrushSandedBicycleNetwork"] ) -@shared_task +@shared_task_email def import_marinas(name="import_marinas"): management.call_command("import_marinas") -@shared_task +@shared_task_email def import_foli_stops(name="import_foli_stops"): management.call_command("import_foli_stops") -@shared_task +@shared_task_email +def import_foli_parkandride_stops(name="import_foli_parkandride_stops"): + management.call_command("import_foli_parkandride_stops") + + +@shared_task_email def import_outdoor_gym_devices(name="import_outdoor_gym_devices"): management.call_command("import_outdoor_gym_devices") -@shared_task +@shared_task_email def import_disabled_and_no_staff_parkings(name="import_disabled_and_no_staff_parkings"): management.call_command("import_disabled_and_no_staff_parkings") -@shared_task +@shared_task_email def import_loading_and_unloading_places(name="import_loading_and_unloading_places"): management.call_command("import_loading_and_unloading_places") -@shared_task +@shared_task_email def import_lounaistieto_shapefiles(name="import_lounaistieto_shapefiles"): management.call_command("import_lounaistieto_shapefiles") -@shared_task +@shared_task_email def import_paavonpolkus(name="import_paavonpolkus"): management.call_command("import_wfs", "PaavonPolku") -@shared_task +@shared_task_email def delete_mobility_data(args=None, name="delete_mobility_data"): management.call_command("delete_mobility_data", args) -@shared_task +@shared_task_email def import_outdoor_trails(name="import_outdoor_trails"): management.call_command( "import_wfs", ["PaddlingTrail", "HikingTrail", "NatureTrail", "FitnessTrail"] ) -@shared_task +@shared_task_email def import_traffic_signs(name="import_traffic_signs"): management.call_command( "import_wfs", @@ -124,11 +140,16 @@ def import_traffic_signs(name="import_traffic_signs"): ) -@shared_task +@shared_task_email def import_wfs(args=None, name="import_wfs"): management.call_command("import_wfs", args) -@shared_task +@shared_task_email +def import_parking_machines(name="import_parking_machines"): + management.call_command("import_parking_machines") + + +@shared_task_email def delete_deprecated_units(name="delete_deprecated_units"): management.call_command("delete_deprecated_units") diff --git a/mobility_data/tests/conftest.py b/mobility_data/tests/conftest.py index 7f91edc86..a344ab0de 100644 --- a/mobility_data/tests/conftest.py +++ b/mobility_data/tests/conftest.py @@ -1,6 +1,7 @@ import pytest from django.conf import settings from django.contrib.gis.geos import GEOSGeometry, Point +from django.utils import timezone from munigeo.models import ( Address, AdministrativeDivision, @@ -11,6 +12,8 @@ ) from rest_framework.test import APIClient +from services.models import Service, Unit, UnitServiceDetails + from ..models import ContentType, GroupType, MobileUnit, MobileUnitGroup # borders of Turku in well known text format. @@ -46,11 +49,29 @@ def api_client(): @pytest.mark.django_db @pytest.fixture -def content_type(): - content_type = ContentType.objects.create( - name="Test", description="test content type" +def content_types(): + content_types = [ + ContentType.objects.create( + id="aa6c2903-d36f-4c61-b828-19084fc7a64b", + name="Test", + description="test content type", + ) + ] + content_types.append( + ContentType.objects.create( + id="ba6c2903-d36f-4c61-b828-19084fc7a64b", + name="Test2", + description="test content type2", + ) + ) + content_types.append( + ContentType.objects.create( + id="ca6c2903-d36f-4c61-b828-19084fc7a64b", + name="Test unit", + description="test content type3", + ) ) - return content_type + return content_types @pytest.mark.django_db @@ -64,16 +85,68 @@ def group_type(): @pytest.mark.django_db @pytest.fixture -def mobile_unit(content_type): - extra = {"test_int": 4242, "test_float": 42.42, "test_string": "4242"} +def mobile_units(content_types): + mobile_units = [] + extra = { + "test_int": 4242, + "test_float": 42.42, + "test_string": "4242", + "test_bool": False, + } + geometry = Point(22.21, 60.3, srid=4326) + geometry.transform(settings.DEFAULT_SRID) mobile_unit = MobileUnit.objects.create( + id="aa6c2903-d36f-4c61-b828-19084fc7a64b", name="Test mobileunit", description="Test description", - content_type=content_type, - geometry=Point(42.42, 21.21, srid=settings.DEFAULT_SRID), + geometry=geometry, + extra=extra, + ) + mobile_unit.content_types.add(content_types[0]) + mobile_units.append(mobile_units) + extra = { + "test_int": 14, + "test_float": 2.4, + "test_string": "hello", + "test_bool": True, + } + mobile_unit = MobileUnit.objects.create( + id="ba6c2903-d36f-4c61-b828-19084fc7a64b", + name="Test2 mobileunit", + description="Test2 description", + geometry=Point(23.43, 62.22, srid=settings.DEFAULT_SRID), extra=extra, ) - return mobile_unit + mobile_unit.content_types.add(content_types[0]) + mobile_unit.content_types.add(content_types[1]) + mobile_units.append(mobile_units) + mobile_unit = MobileUnit.objects.create( + id="ca6c2903-d36f-4c61-b828-19084fc7a64b", unit_id=1 + ) + mobile_unit.content_types.add(content_types[2]) + mobile_units.append(mobile_units) + return mobile_units + + +@pytest.mark.django_db +@pytest.fixture +def service(): + return Service.objects.create(id=1, name="test", last_modified_time=timezone.now()) + + +@pytest.mark.django_db +@pytest.fixture +def unit(service): + unit = Unit.objects.create( + id=1, + name="Test unit", + description="desc", + last_modified_time=timezone.now(), + provider_type=1, + location=Point(24.24, 62.22, srid=settings.DEFAULT_SRID), + ) + UnitServiceDetails(unit=unit, service=service).save() + return unit @pytest.mark.django_db @@ -89,9 +162,12 @@ def mobile_unit_group(group_type): @pytest.mark.django_db @pytest.fixture -def municipality(): - muni = Municipality.objects.create(id="turku", name="Turku") - return muni +def municipalities(): + munis = [] + munis.append(Municipality.objects.create(id="turku", name="Turku")) + munis.append(Municipality.objects.create(id="lieto", name="Lieto")) + munis.append(Municipality.objects.create(id="raisio", name="Raisio")) + return munis @pytest.mark.django_db @@ -180,11 +256,12 @@ def streets(): @pytest.mark.django_db @pytest.fixture -def address(streets, municipality): +def address(streets, municipalities): + turku_muni = municipalities[0] addresses = [] location = Point(22.244, 60.4, srid=4326) address = Address.objects.create( - municipality_id=municipality.id, + municipality_id=turku_muni.id, id=100, location=location, street=streets[0], @@ -195,7 +272,7 @@ def address(streets, municipality): addresses.append(address) location = Point(22.227168, 60.4350612, srid=4326) address = Address.objects.create( - municipality_id=municipality.id, + municipality_id=turku_muni.id, id=101, location=location, street=streets[1], @@ -205,7 +282,7 @@ def address(streets, municipality): addresses.append(address) location = Point(22.264457, 60.448905, srid=4326) address = Address.objects.create( - municipality_id=municipality.id, + municipality_id=turku_muni.id, id=102, location=location, street=streets[2], @@ -216,7 +293,7 @@ def address(streets, municipality): addresses.append(address) location = Point(22.2383, 60.411726, srid=4326) address = Address.objects.create( - municipality_id=municipality.id, + municipality_id=turku_muni.id, id=103, location=location, street=streets[3], @@ -227,7 +304,7 @@ def address(streets, municipality): addresses.append(address) location = Point(22.2871092678621, 60.44677715747775, srid=4326) address = Address.objects.create( - municipality_id=municipality.id, + municipality_id=turku_muni.id, id=104, location=location, street=streets[4], @@ -238,7 +315,7 @@ def address(streets, municipality): addresses.append(address) location = Point(22.26097246971352, 60.45055294118857, srid=4326) address = Address.objects.create( - municipality_id=municipality.id, + municipality_id=turku_muni.id, id=105, location=location, street=streets[5], @@ -249,7 +326,7 @@ def address(streets, municipality): addresses.append(address) location = Point(22.247047171564706, 60.45159033848499, srid=4326) address = Address.objects.create( - municipality_id=municipality.id, + municipality_id=turku_muni.id, id=106, location=location, street=streets[6], diff --git a/mobility_data/tests/data/foli_parkandride_stops.json b/mobility_data/tests/data/foli_parkandride_stops.json new file mode 100644 index 000000000..0cf593528 --- /dev/null +++ b/mobility_data/tests/data/foli_parkandride_stops.json @@ -0,0 +1,123 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "poi_1054", + "geometry": { + "type": "Point", + "coordinates": [ + 22.4579, + 60.50413 + ] + }, + "properties": { + "category": "PARKANDRIDE_CARS", + "name": "Lieto Keskusta, K-Supermarket Lietorin piha", + "name_fi": "Lieto Keskusta, K-Supermarket Lietorin piha", + "name_sv": "Lundo centrum, K-Supermarket Lietori", + "name_en": "Lieto centre, K-Supermarket Lietori", + "popup": "