Managing Locations¶
This tutorial demonstrates how to manage charging locations in an OCPI CPO application.
Overview¶
Locations represent charging stations where electric vehicles can be charged. Each location contains: - Basic information (name, address, coordinates) - EVSEs (Electric Vehicle Supply Equipment) - Connectors - Tariffs - Operating hours - And more
Setup¶
First, ensure your application includes the locations module:
from ocpi import get_application
from ocpi.core.enums import ModuleID, RoleEnum
from ocpi.modules.versions.enums import VersionNumber
app = get_application(
version_numbers=[VersionNumber.v_2_3_0],
roles=[RoleEnum.cpo],
modules=[ModuleID.locations],
authenticator=YourAuthenticator,
crud=YourCrud,
)
Creating a Location¶
Basic Location¶
location_data = {
"country_code": "DE",
"party_id": "ABC",
"id": "LOC001",
"publish": True,
"name": "Berlin Central Charging Station",
"address": "Unter den Linden 1",
"city": "Berlin",
"postal_code": "10117",
"country": "DEU",
"coordinates": {
"latitude": "52.5200",
"longitude": "13.4050"
},
"evses": [],
"last_updated": "2024-01-01T00:00:00Z"
}
Location with EVSEs and Connectors¶
location_data = {
"country_code": "ES",
"party_id": "ABC",
"id": "LOC001",
"publish": True,
"name": "Madrid Premium Charging Hub",
"address": "Gran Vía 1",
"city": "Madrid",
"postal_code": "28013",
"country": "ESP",
"coordinates": {
"latitude": "40.4168",
"longitude": "-3.7038"
},
"evses": [
{
"uid": "EVSE001",
"evse_id": "EVSE001",
"status": "AVAILABLE",
"capabilities": ["CREDIT_CARD_PAYABLE"],
"connectors": [
{
"id": "CONN001",
"standard": "IEC_62196_T2",
"format": "SOCKET",
"power_type": "AC_3_PHASE",
"max_voltage": 400,
"max_amperage": 32,
"max_electric_power": 22000,
"tariff_ids": ["TARIFF001"],
"last_updated": "2024-01-01T00:00:00Z"
}
],
"last_updated": "2024-01-01T00:00:00Z"
}
],
"last_updated": "2024-01-01T00:00:00Z"
}
CRUD Operations¶
Create/Update Location¶
class YourCrud(Crud):
@classmethod
async def create(
cls, module: ModuleID, role: RoleEnum, data: dict, *args, **kwargs
) -> dict:
"""Create a new location."""
location_id = data.get("id")
# Store in your database
# ...
return data
@classmethod
async def update(
cls, module: ModuleID, role: RoleEnum, data: dict, id: str, *args, **kwargs
) -> dict:
"""Update an existing location."""
# Update in your database
# ...
return updated_data
Get Location¶
@classmethod
async def get(
cls, module: ModuleID, role: RoleEnum, id: str, *args, **kwargs
) -> dict | None:
"""Get a location by ID."""
# Retrieve from your database
# ...
return location_data
List Locations¶
@classmethod
async def list(
cls, module: ModuleID, role: RoleEnum, filters: dict, *args, **kwargs
) -> tuple[list[dict], int, bool]:
"""Get paginated list of locations."""
# Implement pagination using filters
offset = filters.get("offset", 0)
limit = filters.get("limit", 100)
date_from = filters.get("date_from")
date_to = filters.get("date_to")
# Query your database
# ...
return locations, total_count, is_last_page
API Usage¶
Create/Update Location (PUT)¶
curl -X PUT 'http://127.0.0.1:8000/ocpi/cpo/2.3.0/locations/DE/ABC/LOC001' \
-H 'Authorization: Token your-token' \
-H 'Content-Type: application/json' \
-d @location.json
Get Location (GET)¶
curl 'http://127.0.0.1:8000/ocpi/cpo/2.3.0/locations/DE/ABC/LOC001' \
-H 'Authorization: Token your-token'
List Locations (GET)¶
curl 'http://127.0.0.1:8000/ocpi/cpo/2.3.0/locations/?offset=0&limit=100' \
-H 'Authorization: Token your-token'
Partial Update (PATCH)¶
curl -X PATCH 'http://127.0.0.1:8000/ocpi/cpo/2.3.0/locations/DE/ABC/LOC001' \
-H 'Authorization: Token your-token' \
-H 'Content-Type: application/json' \
-d '{
"name": "Updated Location Name"
}'
Advanced Features¶
Operating Hours¶
location_data["opening_times"] = {
"twentyfourseven": False,
"regular_hours": [
{
"weekday": 1, # Monday
"period_begin": "08:00",
"period_end": "22:00"
},
# ... other weekdays
],
"exceptional_openings": [],
"exceptional_closings": []
}
Energy Mix¶
location_data["energy_mix"] = {
"is_green_energy": True,
"energy_sources": [
{"source": "SOLAR", "percentage": 60},
{"source": "WIND", "percentage": 40}
],
"supplier_name": "Green Energy Co",
"energy_product_name": "100% Renewable"
}
Images¶
location_data["images"] = [
{
"url": "https://example.com/location.jpg",
"thumbnail": "https://example.com/location-thumb.jpg",
"category": "NETWORK",
"type": "jpeg",
"width": 1920,
"height": 1080
}
]
Best Practices¶
- Always set
last_updated- This timestamp is crucial for synchronization - Use proper coordinates - Ensure latitude/longitude are valid
- Publish status - Set
publish: truefor locations visible to EMSPs - EVSE status - Keep EVSE status updated (AVAILABLE, CHARGING, etc.)
- Tariff references - Link connectors to tariffs using
tariff_ids
Complete Example¶
See the Basic CPO Example for a complete working implementation.