parent
be039e7376
commit
00dff24767
8 changed files with 1208 additions and 843 deletions
|
@ -4,8 +4,8 @@ import os
|
||||||
from ocpp.routing import on, after
|
from ocpp.routing import on, after
|
||||||
from ocpp.v201 import ChargePoint as cp
|
from ocpp.v201 import ChargePoint as cp
|
||||||
from ocpp.v201 import call_result
|
from ocpp.v201 import call_result
|
||||||
from ocpp.v201.enums import Action, RegistrationStatusType, TransactionEventType
|
from ocpp.v201.enums import Action, RegistrationStatusEnumType, TransactionEventEnumType
|
||||||
from ocpp.v201.call import GetBaseReportPayload
|
from ocpp.v201.call import GetBaseReport
|
||||||
|
|
||||||
from app.services import (
|
from app.services import (
|
||||||
variable_service,
|
variable_service,
|
||||||
|
@ -16,42 +16,42 @@ from app.services import (
|
||||||
|
|
||||||
class ChargePoint(cp):
|
class ChargePoint(cp):
|
||||||
|
|
||||||
@on(Action.BootNotification)
|
@on(Action.boot_notification)
|
||||||
async def on_boot_notification(self, charging_station, **kwargs):
|
async def on_boot_notification(self, charging_station, **kwargs):
|
||||||
await chargepoint_service.update_attributes(
|
await chargepoint_service.update_attributes(
|
||||||
chargepoint_identity=self.id,
|
chargepoint_identity=self.id,
|
||||||
charging_station=charging_station
|
charging_station=charging_station
|
||||||
)
|
)
|
||||||
return call_result.BootNotificationPayload(
|
return call_result.BootNotification(
|
||||||
current_time=datetime.now(UTC).isoformat(),
|
current_time=datetime.now(UTC).isoformat(),
|
||||||
interval=int(os.getenv("CS_HEARTBEAT_INTERVAL", "1800")),
|
interval=int(os.getenv("CS_HEARTBEAT_INTERVAL", "1800")),
|
||||||
status=RegistrationStatusType.accepted
|
status=RegistrationStatusEnumType.accepted
|
||||||
)
|
)
|
||||||
|
|
||||||
@after(Action.BootNotification)
|
@after(Action.boot_notification)
|
||||||
async def after_boot_notification(self, **kwargs):
|
async def after_boot_notification(self, **kwargs):
|
||||||
await self.call(payload=GetBaseReportPayload(request_id=0, report_base="FullInventory"))
|
await self.call(payload=GetBaseReport(request_id=0, report_base="FullInventory"))
|
||||||
|
|
||||||
@on(Action.NotifyReport)
|
@on(Action.notify_report)
|
||||||
async def on_notify_report(self, report_data, **kwargs):
|
async def on_notify_report(self, report_data, **kwargs):
|
||||||
for entry in report_data:
|
for entry in report_data:
|
||||||
await variable_service.create_or_update_variable(
|
await variable_service.create_or_update_variable(
|
||||||
chargepoint_identity=self.id,
|
chargepoint_identity=self.id,
|
||||||
report_entry=entry
|
report_entry=entry
|
||||||
)
|
)
|
||||||
return call_result.NotifyReportPayload()
|
return call_result.NotifyReport()
|
||||||
|
|
||||||
@on(Action.Heartbeat)
|
@on(Action.heartbeat)
|
||||||
async def on_heartbeat_request(self):
|
async def on_heartbeat_request(self):
|
||||||
return call_result.HeartbeatPayload(
|
return call_result.Heartbeat(
|
||||||
current_time=datetime.now(UTC).isoformat()
|
current_time=datetime.now(UTC).isoformat()
|
||||||
)
|
)
|
||||||
|
|
||||||
@after(Action.Heartbeat)
|
@after(Action.heartbeat)
|
||||||
async def after_heartbeat_request(self):
|
async def after_heartbeat_request(self):
|
||||||
await chargepoint_service.update_last_seen(chargepoint_identity=self.id)
|
await chargepoint_service.update_last_seen(chargepoint_identity=self.id)
|
||||||
|
|
||||||
@on(Action.StatusNotification)
|
@on(Action.status_notification)
|
||||||
async def on_status_notification(self, evse_id: int, connector_id: int, connector_status: str, **kwargs):
|
async def on_status_notification(self, evse_id: int, connector_id: int, connector_status: str, **kwargs):
|
||||||
await chargepoint_service.create_or_update_connector(
|
await chargepoint_service.create_or_update_connector(
|
||||||
chargepoint_identity=self.id,
|
chargepoint_identity=self.id,
|
||||||
|
@ -59,14 +59,14 @@ class ChargePoint(cp):
|
||||||
connector_id=connector_id,
|
connector_id=connector_id,
|
||||||
connector_status=connector_status
|
connector_status=connector_status
|
||||||
)
|
)
|
||||||
return call_result.StatusNotificationPayload()
|
return call_result.StatusNotification()
|
||||||
|
|
||||||
@on(Action.Authorize)
|
@on(Action.authorize)
|
||||||
async def on_authorize(self, id_token, **kwargs):
|
async def on_authorize(self, id_token, **kwargs):
|
||||||
id_token_info, _ = await id_token_service.get_id_token_info(chargepoint_id=self.id, id_token=id_token)
|
id_token_info, _ = await id_token_service.get_id_token_info(chargepoint_id=self.id, id_token=id_token)
|
||||||
return call_result.AuthorizePayload(id_token_info)
|
return call_result.Authorize(id_token_info)
|
||||||
|
|
||||||
@on(Action.TransactionEvent)
|
@on(Action.transaction_event)
|
||||||
async def on_transaction_event(
|
async def on_transaction_event(
|
||||||
self,
|
self,
|
||||||
event_type,
|
event_type,
|
||||||
|
@ -82,7 +82,7 @@ class ChargePoint(cp):
|
||||||
id_token_info = None
|
id_token_info = None
|
||||||
token_owner_id = None
|
token_owner_id = None
|
||||||
|
|
||||||
if event_type == str(TransactionEventType.started):
|
if event_type == str(TransactionEventEnumType.started):
|
||||||
await transaction_service.create_transaction(
|
await transaction_service.create_transaction(
|
||||||
chargepoint_identity=self.id,
|
chargepoint_identity=self.id,
|
||||||
user_id=token_owner_id,
|
user_id=token_owner_id,
|
||||||
|
@ -90,12 +90,12 @@ class ChargePoint(cp):
|
||||||
transaction_info=transaction_info,
|
transaction_info=transaction_info,
|
||||||
transaction_data=kwargs
|
transaction_data=kwargs
|
||||||
)
|
)
|
||||||
elif event_type == str(TransactionEventType.updated):
|
elif event_type == str(TransactionEventEnumType.updated):
|
||||||
await transaction_service.update_transaction(
|
await transaction_service.update_transaction(
|
||||||
transaction_id=transaction_info["transaction_id"],
|
transaction_id=transaction_info["transaction_id"],
|
||||||
transaction_data=kwargs
|
transaction_data=kwargs
|
||||||
)
|
)
|
||||||
elif event_type == str(TransactionEventType.ended):
|
elif event_type == str(TransactionEventEnumType.ended):
|
||||||
await transaction_service.end_transaction(
|
await transaction_service.end_transaction(
|
||||||
transaction_id=transaction_info["transaction_id"],
|
transaction_id=transaction_info["transaction_id"],
|
||||||
timestamp=datetime.fromisoformat(timestamp),
|
timestamp=datetime.fromisoformat(timestamp),
|
||||||
|
@ -105,14 +105,14 @@ class ChargePoint(cp):
|
||||||
)
|
)
|
||||||
|
|
||||||
if id_token_info == None:
|
if id_token_info == None:
|
||||||
return call_result.TransactionEventPayload()
|
return call_result.TransactionEvent()
|
||||||
else:
|
else:
|
||||||
return call_result.TransactionEventPayload(id_token_info=id_token_info)
|
return call_result.TransactionEvent(id_token_info=id_token_info)
|
||||||
|
|
||||||
@on(Action.MeterValues)
|
@on(Action.meter_values)
|
||||||
async def on_meter_values(self, **kwargs):
|
async def on_meter_values(self, **kwargs):
|
||||||
return call_result.MeterValuesPayload()
|
return call_result.MeterValues()
|
||||||
|
|
||||||
@on(Action.SecurityEventNotification)
|
@on(Action.security_event_notification)
|
||||||
async def on_security_event_notification(self, **kwargs):
|
async def on_security_event_notification(self, **kwargs):
|
||||||
return call_result.SecurityEventNotificationPayload()
|
return call_result.SecurityEventNotification()
|
||||||
|
|
|
@ -6,7 +6,7 @@ from fastapi import APIRouter, HTTPException, Security
|
||||||
from fastapi.params import Depends
|
from fastapi.params import Depends
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from ocpp.v201.call import ResetPayload, SetVariablesPayload
|
from ocpp.v201.call import Reset, SetVariables
|
||||||
|
|
||||||
from app.database import get_db
|
from app.database import get_db
|
||||||
from app.ocpp_proto import chargepoint_manager
|
from app.ocpp_proto import chargepoint_manager
|
||||||
|
@ -146,7 +146,7 @@ async def reset_chargepoint(
|
||||||
try:
|
try:
|
||||||
response = await chargepoint_manager.call(
|
response = await chargepoint_manager.call(
|
||||||
chargepoint_id,
|
chargepoint_id,
|
||||||
payload=ResetPayload(type=reset_request.type, evse_id=reset_request.evse_id)
|
payload=Reset(type=reset_request.type, evse_id=reset_request.evse_id)
|
||||||
)
|
)
|
||||||
return ChargePointResetResponse(status=response.status)
|
return ChargePointResetResponse(status=response.status)
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
|
@ -269,7 +269,7 @@ async def update_chargepoint_variable(
|
||||||
evse['connectorId'] = variable.connector_id
|
evse['connectorId'] = variable.connector_id
|
||||||
result = await chargepoint_manager.call(
|
result = await chargepoint_manager.call(
|
||||||
chargepoint_id,
|
chargepoint_id,
|
||||||
payload=SetVariablesPayload(set_variable_data=[
|
payload=SetVariables(set_variable_data=[
|
||||||
{
|
{
|
||||||
'attributeType': variable.type.value,
|
'attributeType': variable.type.value,
|
||||||
'attributeValue': variable_update.value,
|
'attributeValue': variable_update.value,
|
||||||
|
|
|
@ -2,7 +2,7 @@ from fastapi import APIRouter, Depends, HTTPException
|
||||||
from fastapi.params import Security
|
from fastapi.params import Security
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from ocpp.v201.call import RequestStopTransactionPayload
|
from ocpp.v201.call import RequestStopTransaction
|
||||||
|
|
||||||
from app.ocpp_proto import chargepoint_manager
|
from app.ocpp_proto import chargepoint_manager
|
||||||
from app.security import get_api_key
|
from app.security import get_api_key
|
||||||
|
@ -55,7 +55,7 @@ async def remote_stop_transaction(
|
||||||
try:
|
try:
|
||||||
result = await chargepoint_manager.call(
|
result = await chargepoint_manager.call(
|
||||||
transaction.chargepoint_id,
|
transaction.chargepoint_id,
|
||||||
payload=RequestStopTransactionPayload(
|
payload=RequestStopTransaction(
|
||||||
transaction_id=transaction.id
|
transaction_id=transaction.id
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,7 @@ from pydantic import BaseModel
|
||||||
|
|
||||||
from app.schemas.connector import Connector
|
from app.schemas.connector import Connector
|
||||||
|
|
||||||
from ocpp.v201.enums import ResetType, ResetStatusType
|
from ocpp.v201.enums import ResetEnumType, ResetStatusEnumType
|
||||||
|
|
||||||
class ChargePointBase(BaseModel):
|
class ChargePointBase(BaseModel):
|
||||||
identity: str
|
identity: str
|
||||||
|
@ -40,8 +40,8 @@ class ChargePointConnectionInfo(BaseModel):
|
||||||
connected: bool
|
connected: bool
|
||||||
|
|
||||||
class ChargePointResetRequest(BaseModel):
|
class ChargePointResetRequest(BaseModel):
|
||||||
type: ResetType
|
type: ResetEnumType
|
||||||
evse_id: Optional[int] = None
|
evse_id: Optional[int] = None
|
||||||
|
|
||||||
class ChargePointResetResponse(BaseModel):
|
class ChargePointResetResponse(BaseModel):
|
||||||
status: ResetStatusType
|
status: ResetStatusEnumType
|
||||||
|
|
|
@ -3,8 +3,6 @@ from typing import Optional
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from app.schemas.user import User
|
|
||||||
|
|
||||||
class IdTokenBase(BaseModel):
|
class IdTokenBase(BaseModel):
|
||||||
friendly_name: str
|
friendly_name: str
|
||||||
is_active: bool
|
is_active: bool
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from datetime import datetime, UTC
|
from datetime import datetime, UTC
|
||||||
|
|
||||||
from ocpp.v201.datatypes import IdTokenInfoType
|
from ocpp.v201.datatypes import IdTokenInfoType
|
||||||
from ocpp.v201.enums import AuthorizationStatusType
|
from ocpp.v201.enums import AuthorizationStatusEnumType
|
||||||
|
|
||||||
from app.database import SessionLocal
|
from app.database import SessionLocal
|
||||||
from app.models.id_token import IdToken
|
from app.models.id_token import IdToken
|
||||||
|
@ -11,14 +11,14 @@ async def get_id_token_info(chargepoint_id: str, id_token: str):
|
||||||
owner_id = None
|
owner_id = None
|
||||||
if id_token["type"] not in ["ISO14443", "ISO15693"]:
|
if id_token["type"] not in ["ISO14443", "ISO15693"]:
|
||||||
return IdTokenInfoType(
|
return IdTokenInfoType(
|
||||||
status=AuthorizationStatusType.invalid
|
status=AuthorizationStatusEnumType.invalid
|
||||||
), owner_id
|
), owner_id
|
||||||
|
|
||||||
with SessionLocal() as db:
|
with SessionLocal() as db:
|
||||||
db_id_token = db.query(IdToken).filter(IdToken.token == id_token["id_token"]).first()
|
db_id_token = db.query(IdToken).filter(IdToken.token == id_token["id_token"]).first()
|
||||||
if db_id_token == None:
|
if db_id_token == None:
|
||||||
id_token_info = IdTokenInfoType(
|
id_token_info = IdTokenInfoType(
|
||||||
status=AuthorizationStatusType.unknown
|
status=AuthorizationStatusEnumType.unknown
|
||||||
)
|
)
|
||||||
db_chargepoint = db.query(ChargePoint).filter(ChargePoint.identity == chargepoint_id).first()
|
db_chargepoint = db.query(ChargePoint).filter(ChargePoint.identity == chargepoint_id).first()
|
||||||
# Learn token if requested
|
# Learn token if requested
|
||||||
|
@ -32,7 +32,7 @@ async def get_id_token_info(chargepoint_id: str, id_token: str):
|
||||||
db.add(db_id_token)
|
db.add(db_id_token)
|
||||||
|
|
||||||
id_token_info=IdTokenInfoType(
|
id_token_info=IdTokenInfoType(
|
||||||
status=AuthorizationStatusType.accepted
|
status=AuthorizationStatusEnumType.accepted
|
||||||
)
|
)
|
||||||
owner_id = db_id_token.owner_id
|
owner_id = db_id_token.owner_id
|
||||||
db_chargepoint.learn_user_id = None
|
db_chargepoint.learn_user_id = None
|
||||||
|
@ -42,10 +42,10 @@ async def get_id_token_info(chargepoint_id: str, id_token: str):
|
||||||
owner_id = db_id_token.owner_id
|
owner_id = db_id_token.owner_id
|
||||||
if db_id_token.is_active == False:
|
if db_id_token.is_active == False:
|
||||||
id_token_info=IdTokenInfoType(
|
id_token_info=IdTokenInfoType(
|
||||||
status=AuthorizationStatusType.blocked
|
status=AuthorizationStatusEnumType.blocked
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
id_token_info=IdTokenInfoType(
|
id_token_info=IdTokenInfoType(
|
||||||
status=AuthorizationStatusType.accepted
|
status=AuthorizationStatusEnumType.accepted
|
||||||
)
|
)
|
||||||
return id_token_info, owner_id
|
return id_token_info, owner_id
|
1955
poetry.lock
generated
1955
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -7,15 +7,15 @@ readme = "README.md"
|
||||||
package-mode = false
|
package-mode = false
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.11"
|
python = "^3.12"
|
||||||
ocpp = "^0.26.0"
|
ocpp = "^2.0.0"
|
||||||
fastapi = "^0.110.0"
|
fastapi = {extras = ["standard"], version = "^0.115.11"}
|
||||||
uvicorn = {extras = ["standard"], version = "^0.28.0"}
|
uvicorn = {extras = ["standard"], version = "^0.34.0"}
|
||||||
websockets = "^12.0"
|
websockets = "^15.0"
|
||||||
sqlalchemy = "^2.0.28"
|
sqlalchemy = "^2.0.28"
|
||||||
alembic = "^1.13.1"
|
alembic = "^1.15.1"
|
||||||
gunicorn = "^22.0.0"
|
gunicorn = "^22.0.0"
|
||||||
psycopg2-binary = "^2.9.9"
|
psycopg2-binary = "^2.9.10"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core"]
|
requires = ["poetry-core"]
|
||||||
|
|
Loading…
Add table
Reference in a new issue