Implement transaction handling

This commit is contained in:
Oliver Traber 2024-04-19 00:08:29 +02:00
parent 161c6aa027
commit a65dee8962
Signed by: Bluemedia
GPG key ID: C0674B105057136C
16 changed files with 331 additions and 94 deletions

View file

@ -1,5 +1,6 @@
import random
import string
from datetime import datetime, timedelta, UTC
from uuid import UUID
from fastapi import APIRouter, HTTPException, Security
from fastapi.params import Depends
@ -18,7 +19,9 @@ from app.schemas.chargepoint import (
ChargePointResetRequest,
ChargePointResetResponse
)
from app.schemas.id_token import IdTokenLearnRequest, IdTokenLearnResponse
from app.models.chargepoint import ChargePoint as DbChargePoint
from app.models.user import User as DbUser
from app.security import get_api_key
router = APIRouter(
@ -77,9 +80,10 @@ async def create_chargepoint(
db: Session = Depends(get_db)
):
chargepoint_db = DbChargePoint(
friendly_name=chargepoint.friendly_name,
identity=chargepoint.identity,
is_active=chargepoint.is_active,
password=''.join(random.choice(string.ascii_letters + string.digits) for i in range(24))
password=''.join(random.choice(string.ascii_letters + string.digits) for i in range(24)),
price=chargepoint.price
)
db.add(chargepoint_db)
db.commit()
@ -139,3 +143,73 @@ async def reset_chargepoint(
return ChargePointResetResponse(status=response.status)
except TimeoutError:
raise HTTPException(status_code=503, detail="Chargepoint didn't respond in time.")
@router.post(path="/{chargepoint_id}/token-learning", status_code=201, response_model=IdTokenLearnResponse)
async def create_id_token_learn_request(
chargepoint_id: UUID,
learn_request: IdTokenLearnRequest,
api_key: str = Security(get_api_key),
db: Session = Depends(get_db)
):
chargepoint = db.get(DbChargePoint, chargepoint_id)
if chargepoint is None:
raise HTTPException(status_code=404, detail="Chargepoint not found")
owner = db.get(DbUser, learn_request.user_id)
if owner == None:
raise HTTPException(status_code=422, detail=[{
"loc": ["body", "user_id"],
"msg": "Target user not found",
"type": "invalid_relation"
}])
chargepoint.learn_user_id = learn_request.user_id
if learn_request.until == None:
chargepoint.learn_until = datetime.now(UTC) + timedelta(minutes=5)
else:
chargepoint.learn_until = learn_request.until
db.commit()
return IdTokenLearnResponse(
user_id=chargepoint.learn_user_id,
until=chargepoint.learn_until
)
@router.get(path="/{chargepoint_id}/token-learning", response_model=IdTokenLearnResponse)
async def get_id_token_learn_request(
chargepoint_id: UUID,
api_key: str = Security(get_api_key),
db: Session = Depends(get_db)
):
chargepoint = db.get(DbChargePoint, chargepoint_id)
if chargepoint is None:
raise HTTPException(status_code=404, detail="Chargepoint not found")
if chargepoint.learn_user_id == None:
raise HTTPException(status_code=404, detail="No active learning request")
return IdTokenLearnResponse(
user_id=chargepoint.learn_user_id,
until=chargepoint.learn_until
)
@router.delete(path="/{chargepoint_id}/token-learning", response_model=[])
async def get_id_token_learn_request(
chargepoint_id: UUID,
api_key: str = Security(get_api_key),
db: Session = Depends(get_db)
):
chargepoint = db.get(DbChargePoint, chargepoint_id)
if chargepoint is None:
raise HTTPException(status_code=404, detail="Chargepoint not found")
if chargepoint.learn_user_id == None:
raise HTTPException(status_code=404, detail="No active learning request")
chargepoint.learn_user_id = None
chargepoint.learn_until = None
db.commit()
return []

View file

@ -0,0 +1,22 @@
from fastapi import APIRouter, Depends
from fastapi.params import Security
from sqlalchemy.orm import Session
from app.security import get_api_key
from app.database import get_db
from app.schemas.meter_value import MeterValue
from app.models.meter_value import MeterValue as DbMeterValue
router = APIRouter(
prefix="/meter-values",
tags=["MeterValue (v1)"]
)
@router.get(path="", response_model=list[MeterValue])
async def get_meter_values(
skip: int = 0,
limit: int = 20,
api_key: str = Security(get_api_key),
db: Session = Depends(get_db)
):
return db.query(DbMeterValue).offset(skip).limit(limit).all()

View file

@ -7,19 +7,19 @@ from app.util.websocket_wrapper import WebSocketWrapper
router = APIRouter()
@router.websocket("/{charging_station_friendly_name}")
@router.websocket("/{chargepoint_identity}")
async def websocket_endpoint(
*,
websocket: WebSocket,
charging_station_friendly_name: str,
chargepoint_identity: str,
):
""" For every new charging station that connects, create a ChargePoint
instance and start listening for messages.
"""
if (websocket.user.friendly_name != charging_station_friendly_name):
if (websocket.user.identity != chargepoint_identity):
raise WebSocketException(code=1008, reason="Username doesn't match chargepoint identifier")
logging.info("Charging station '%s' (%s) connected", charging_station_friendly_name, websocket.user.id)
logging.info("Charging station '%s' (%s) connected", chargepoint_identity, websocket.user.id)
# Check protocols
try:
@ -43,5 +43,5 @@ async def websocket_endpoint(
# Accept connection and begin communication
await websocket.accept(subprotocol="ocpp2.0.1")
cp = ChargePoint(charging_station_friendly_name, WebSocketWrapper(websocket))
cp = ChargePoint(chargepoint_identity, WebSocketWrapper(websocket))
await chargepoint_manager.start(websocket.user.id, cp)

View file

@ -0,0 +1,22 @@
from fastapi import APIRouter, Depends
from fastapi.params import Security
from sqlalchemy.orm import Session
from app.security import get_api_key
from app.database import get_db
from app.schemas.transaction import Transaction
from app.models.transaction import Transaction as DbTransaction
router = APIRouter(
prefix="/transactions",
tags=["Transaction (v1)"]
)
@router.get(path="", response_model=list[Transaction])
async def get_transactions(
skip: int = 0,
limit: int = 20,
api_key: str = Security(get_api_key),
db: Session = Depends(get_db)
):
return db.query(DbTransaction).offset(skip).limit(limit).all()