diff --git a/backend/alembic/versions/20250323_00edfb13e611-add_firmware_update_table.py b/backend/alembic/versions/20250323_00edfb13e611-add_firmware_update_table.py deleted file mode 100644 index 39c447b..0000000 --- a/backend/alembic/versions/20250323_00edfb13e611-add_firmware_update_table.py +++ /dev/null @@ -1,50 +0,0 @@ -"""Add firmware_update table - -Revision ID: 00edfb13e611 -Revises: c7f72154c90b -Create Date: 2025-03-23 14:01:14.029527+00:00 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '00edfb13e611' -down_revision: Union[str, None] = 'c7f72154c90b' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('firmware_updates', - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('request_id', sa.Integer(), nullable=True), - sa.Column('status', sa.Enum('CREATED', 'SUBMITTED', 'DOWNLOADED', 'DOWNLOAD_FAILED', 'DOWNLOADING', 'DOWNLOAD_SCHEDULED', 'DOWNLOAD_PAUSED', 'IDLE', 'INSTALLATION_FAILED', 'INSTALLING', 'INSTALLED', 'INSTALL_REBOOTING', 'INSTALL_SCHEDULED', 'INSTALL_VERIFICATION_FAILED', 'INVALID_SIGNATURE', 'SIGNATURE_VERIFIED', name='firmwareupdatestatus'), nullable=True), - sa.Column('retries', sa.Integer(), nullable=True), - sa.Column('retry_interval', sa.Integer(), nullable=True), - sa.Column('location', sa.String(), nullable=True), - sa.Column('retrieve_date_time', sa.DateTime(), nullable=True), - sa.Column('install_date_time', sa.DateTime(), nullable=True), - sa.Column('chargepoint_id', sa.Uuid(), nullable=True), - sa.ForeignKeyConstraint(['chargepoint_id'], ['chargepoints.id'], ), - sa.PrimaryKeyConstraint('id') - ) - op.create_index(op.f('ix_firmware_updates_chargepoint_id'), 'firmware_updates', ['chargepoint_id'], unique=False) - op.alter_column('users', 'is_active', - existing_type=sa.BOOLEAN(), - nullable=False) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.alter_column('users', 'is_active', - existing_type=sa.BOOLEAN(), - nullable=True) - op.drop_index(op.f('ix_firmware_updates_chargepoint_id'), table_name='firmware_updates') - op.drop_table('firmware_updates') - # ### end Alembic commands ### diff --git a/backend/alembic/versions/20250323_506cc8d086c9-add_signature_fields_to_firmware_update_.py b/backend/alembic/versions/20250323_506cc8d086c9-add_signature_fields_to_firmware_update_.py deleted file mode 100644 index 01ae624..0000000 --- a/backend/alembic/versions/20250323_506cc8d086c9-add_signature_fields_to_firmware_update_.py +++ /dev/null @@ -1,32 +0,0 @@ -"""Add signature fields to firmware_update table - -Revision ID: 506cc8d086c9 -Revises: 00edfb13e611 -Create Date: 2025-03-23 14:49:42.662564+00:00 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '506cc8d086c9' -down_revision: Union[str, None] = '00edfb13e611' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('firmware_updates', sa.Column('signing_certificate', sa.Text(), nullable=True)) - op.add_column('firmware_updates', sa.Column('signature', sa.String(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('firmware_updates', 'signature') - op.drop_column('firmware_updates', 'signing_certificate') - # ### end Alembic commands ### diff --git a/backend/app/models/__init__.py b/backend/app/models/__init__.py index f7b338d..26e5c03 100644 --- a/backend/app/models/__init__.py +++ b/backend/app/models/__init__.py @@ -2,7 +2,6 @@ __all__ = [ "chargepoint_variable", "chargepoint", "connector", - "firmware_update", "id_token", "meter_value", "session", diff --git a/backend/app/models/firmware_update.py b/backend/app/models/firmware_update.py deleted file mode 100644 index 9e4fc4b..0000000 --- a/backend/app/models/firmware_update.py +++ /dev/null @@ -1,22 +0,0 @@ -import uuid -from sqlalchemy import Column, DateTime, Enum, ForeignKey, Integer, String, Text, Uuid - -from app.database import Base -from app.schemas.firmware_update import FirmwareUpdateStatus - -class FirmwareUpdate(Base): - __tablename__ = "firmware_updates" - - id = Column(Uuid, primary_key=True, default=uuid.uuid4) - request_id = Column(Integer) - status = Column(Enum(FirmwareUpdateStatus)) - - retries = Column(Integer) - retry_interval = Column(Integer) - location = Column(String) - retrieve_date_time = Column(DateTime) - install_date_time = Column(DateTime, nullable=True) - signing_certificate = Column(Text, nullable=True) - signature = Column(String, nullable=True) - - chargepoint_id = Column(Uuid, ForeignKey("chargepoints.id"), index=True) diff --git a/backend/app/models/session.py b/backend/app/models/session.py index cd0c5ba..b1c2213 100644 --- a/backend/app/models/session.py +++ b/backend/app/models/session.py @@ -8,7 +8,7 @@ class Session(Base): id = Column(Uuid, primary_key=True, default=uuid.uuid4) name = Column(String) - refresh_token = Column(String, nullable=False, unique=True, index=True) + refresh_token = Column(String, unique=True, index=True) last_used = Column(DateTime(timezone=True)) - user_id = Column(Uuid, ForeignKey("users.id"), nullable=False, index=True) \ No newline at end of file + user_id = Column(Uuid, ForeignKey("users.id"), index=True) \ No newline at end of file diff --git a/backend/app/ocpp_proto/chargepoint.py b/backend/app/ocpp_proto/chargepoint.py index f9b8b48..88550a0 100644 --- a/backend/app/ocpp_proto/chargepoint.py +++ b/backend/app/ocpp_proto/chargepoint.py @@ -8,7 +8,6 @@ from ocpp.v201.enums import Action, RegistrationStatusEnumType, TransactionEvent from ocpp.v201.call import GetBaseReport from app.services import ( - firmware_service, variable_service, id_token_service, chargepoint_service, @@ -109,11 +108,6 @@ class ChargePoint(cp): return call_result.TransactionEvent() else: return call_result.TransactionEvent(id_token_info=id_token_info) - - @on(Action.firmware_status_notification) - async def on_firmware_status_notification(self, status, request_id, **kwargs): - await firmware_service.update_firmware_status(self.id, request_id, status) - return call_result.FirmwareStatusNotification() @on(Action.meter_values) async def on_meter_values(self, **kwargs): diff --git a/backend/app/routers/chargepoint_v1.py b/backend/app/routers/chargepoint_v1.py index 86b6df3..ff22bfd 100644 --- a/backend/app/routers/chargepoint_v1.py +++ b/backend/app/routers/chargepoint_v1.py @@ -28,13 +28,10 @@ from app.schemas.chargepoint_variable import ( MutabilityType, SetVariableStatusType ) -from app.schemas.firmware_update import FirmwareUpdate, FirmwareUpdateCreate, FirmwareUpdateSubmissionResponse from app.models.chargepoint import ChargePoint as DbChargePoint from app.models.user import User as DbUser from app.models.chargepoint_variable import ChargepointVariable as DbChargepointVariable -from app.models.firmware_update import FirmwareUpdate as DbFirmwareUpdate from app.security.jwt_bearer import JWTBearer -from app.services import firmware_service router = APIRouter( prefix="/chargepoints", @@ -296,67 +293,3 @@ async def update_chargepoint_variable( return ChargepointVariableResponse(status=status) except TimeoutError: raise HTTPException(status_code=503, detail="Chargepoint didn't respond in time.") - -@router.get(path="/{chargepoint_id}/firmware-updates", response_model=list[FirmwareUpdate]) -async def get_firmware_updates( - chargepoint_id: UUID, - db: Session = Depends(get_db), - token: AccessToken = Depends(JWTBearer(required_roles=["administrator"])), -): - chargepoint = db.get(DbChargePoint, chargepoint_id) - if chargepoint is None: - raise HTTPException(status_code=404, detail="Chargepoint not found") - - firmware_updates = db.query(DbFirmwareUpdate).filter( - DbFirmwareUpdate.chargepoint_id == chargepoint_id - ).all() - - return firmware_updates - -@router.get(path="/{chargepoint_id}/firmware-updates/{firmware_update_id}", response_model=FirmwareUpdate) -async def get_firmware_update( - chargepoint_id: UUID, - firmware_update_id: UUID, - db: Session = Depends(get_db), - token: AccessToken = Depends(JWTBearer(required_roles=["administrator"])), -): - chargepoint = db.get(DbChargePoint, chargepoint_id) - if chargepoint is None: - raise HTTPException(status_code=404, detail="Chargepoint not found") - - firmware_update = db.query(DbFirmwareUpdate).filter( - DbFirmwareUpdate.chargepoint_id == chargepoint_id, - DbFirmwareUpdate.id == firmware_update_id - ).first() - if firmware_update is None: - raise HTTPException(status_code=404, detail="FirmwareUpdate not found") - - return firmware_update - -@router.post(path="/{chargepoint_id}/firmware-updates", response_model=FirmwareUpdate) -async def create_firmware_update( - chargepoint_id: UUID, - firmware_update: FirmwareUpdateCreate, - db: Session = Depends(get_db), - token: AccessToken = Depends(JWTBearer(required_roles=["administrator"])), -): - chargepoint = db.get(DbChargePoint, chargepoint_id) - if chargepoint is None: - raise HTTPException(status_code=404, detail="Chargepoint not found") - - firmware_update = await firmware_service.create_firmware_update(chargepoint_id, firmware_update) - return firmware_update - -@router.post(path="/{chargepoint_id}/firmware-updates/{firmware_update_id}/submit", response_model=ChargePointResetResponse) -async def submit_firmware_update( - chargepoint_id: UUID, - firmware_update_id: UUID, - token: AccessToken = Depends(JWTBearer(required_roles=["administrator"])), -): - if chargepoint_manager.is_connected(chargepoint_id) == False: - raise HTTPException(status_code=503, detail="Chargepoint not connected.") - try: - _, status = await firmware_service.submit_firmware_update(firmware_update_id) - return FirmwareUpdateSubmissionResponse(status=status) - except TimeoutError: - raise HTTPException(status_code=503, detail="Chargepoint didn't respond in time.") diff --git a/backend/app/schemas/firmware_update.py b/backend/app/schemas/firmware_update.py deleted file mode 100644 index a0f232d..0000000 --- a/backend/app/schemas/firmware_update.py +++ /dev/null @@ -1,43 +0,0 @@ -from datetime import datetime -import enum -from typing import Optional -from uuid import UUID -from pydantic import BaseModel - -class FirmwareUpdateStatus(enum.Enum): - CREATED = "xCreated" - SUBMITTED = "xSubmitted" - DOWNLOADED = "Downloaded" - DOWNLOAD_FAILED = "DownloadFailed" - DOWNLOADING = "Downloading" - DOWNLOAD_SCHEDULED = "DownloadScheduled" - DOWNLOAD_PAUSED = "DownloadPaused" - IDLE = "Idle" - INSTALLATION_FAILED = "InstallationFailed" - INSTALLING = "Installing" - INSTALLED = "Installed" - INSTALL_REBOOTING = "InstallRebooting" - INSTALL_SCHEDULED = "InstallScheduled" - INSTALL_VERIFICATION_FAILED = "InstallVerificationFailed" - INVALID_SIGNATURE = "InvalidSignature" - SIGNATURE_VERIFIED = "SignatureVerified" - -class FirmwareUpdateBase(BaseModel): - retries: int - retry_interval: int - location: str - retrieve_date_time: datetime - install_date_time: Optional[datetime] - signing_certificate: Optional[str] - signature: Optional[str] - -class FirmwareUpdate(FirmwareUpdateBase): - id: UUID - request_id: int - status: FirmwareUpdateStatus - -class FirmwareUpdateCreate(FirmwareUpdateBase): - pass - -class FirmwareUpdateSubmissionResponse(BaseModel): - status: str diff --git a/backend/app/services/firmware_service.py b/backend/app/services/firmware_service.py deleted file mode 100644 index 5cef3a4..0000000 --- a/backend/app/services/firmware_service.py +++ /dev/null @@ -1,66 +0,0 @@ -from uuid import UUID - -from ocpp.v201.call import UpdateFirmware -from ocpp.v201.call_result import UpdateFirmware as UpdateFirmwareResult -from ocpp.v201.datatypes import FirmwareType - -from app.database import SessionLocal -from app.models.chargepoint import ChargePoint -from app.models.firmware_update import FirmwareUpdate -from app.ocpp_proto import chargepoint_manager -from app.schemas.firmware_update import FirmwareUpdateCreate, FirmwareUpdateStatus - -async def create_firmware_update(chargepoint_id: UUID, firmware_update: FirmwareUpdateCreate) -> FirmwareUpdate: - with SessionLocal() as db: - db_chargepoint = db.get(ChargePoint, chargepoint_id) - latest_firmware_update = db.query(FirmwareUpdate).filter(FirmwareUpdate.chargepoint_id == db_chargepoint.id).order_by(FirmwareUpdate.request_id.desc()).first() - new_request_id = latest_firmware_update.request_id + 1 if latest_firmware_update else 1 - db_firmware_update = FirmwareUpdate( - request_id=new_request_id, - status=FirmwareUpdateStatus.CREATED, - retries=firmware_update.retries, - retry_interval=firmware_update.retry_interval, - location=firmware_update.location, - retrieve_date_time=firmware_update.retrieve_date_time, - install_date_time=firmware_update.install_date_time, - chargepoint_id=db_chargepoint.id, - signing_certificate=firmware_update.signing_certificate, - signature=firmware_update.signature - ) - db.add(db_firmware_update) - db.commit() - db.refresh(db_firmware_update) - return db_firmware_update - -async def submit_firmware_update(firmware_update_id: UUID) -> tuple[FirmwareUpdate, str]: - with SessionLocal() as db: - db_firmware_update = db.get(FirmwareUpdate, firmware_update_id) - try: - result: UpdateFirmwareResult = await chargepoint_manager.call( - db_firmware_update.chargepoint_id, - payload=UpdateFirmware( - request_id=db_firmware_update.request_id, - retries=db_firmware_update.retries, - retry_interval=db_firmware_update.retry_interval, - firmware=FirmwareType( - location=db_firmware_update.location, - retrieve_date_time=db_firmware_update.retrieve_date_time.isoformat(), - install_date_time=db_firmware_update.install_date_time.isoformat(), - signing_certificate=db_firmware_update.signing_certificate, - signature=db_firmware_update.signature - ) - )) - if result.status == "Accepted" or result.status == "AcceptedCanceled": - db_firmware_update.status = FirmwareUpdateStatus.SUBMITTED - db.commit() - - return db_firmware_update, result.status - except TimeoutError as e: - raise e - -async def update_firmware_status(chargepoint_identity: str, request_id: int, status: FirmwareUpdateStatus): - with SessionLocal() as db: - db_chargepoint = db.query(ChargePoint).filter(ChargePoint.identity == chargepoint_identity).first() - db_firmware_update = db.query(FirmwareUpdate).filter(FirmwareUpdate.chargepoint_id == db_chargepoint.id).filter(FirmwareUpdate.request_id == request_id).first() - db_firmware_update.status = FirmwareUpdateStatus(status) - db.commit()