EV

Using FastAPI to Bridge Mobile Apps with OCPP EV Charging Systems

June 8, 2025

As electric vehicles (EVs) become more mainstream, users expect seamless experiences when interacting with EV charging stations — especially from their mobile apps. This means building a backend that is not only robust but also real-time, scalable, and easy to extend.

That’s where FastAPI comes in.


⚡ What is FastAPI?

FastAPI is a modern, high-performance web framework for building APIs with Python 3.7+ based on standard Python type hints.

It’s built on top of:

  • Starlette – for the web parts (like routes and WebSockets)
  • Pydantic – for data validation
  • Uvicorn – for ASGI server execution

🚀 Why FastAPI is Ideal for EV Charging Systems

  • Async-ready: Handles many concurrent WebSocket connections — essential for OCPP-based charger networks.
  • WebSocket-native: Built-in support for protocols like OCPP 1.6 without needing additional libraries.
  • Auto-generated docs: Interactive Swagger UI and ReDoc out of the box — great for app devs.
  • Clean developer experience: Pythonic, strongly typed, and readable.
  • Blazing-fast: Comparable to Node.js and Go in performance — excellent for scalable, real-time systems.

✅ Why FastAPI Over Flask?

While Flask is widely used and flexible, FastAPI is purpose-built for modern, async, high-performance use cases like this one:

Feature Flask FastAPI
Async support ⚠️ Experimental ✅ Native
WebSocket support ❌ Needs plugin ✅ Built-in
Pydantic validation ❌ Manual ✅ Automatic
OpenAPI docs ❌ Extra setup ✅ Built-in
Performance 🐢 Sync WSGI ⚡ ASGI-native

If you need WebSocket + REST API + speed, FastAPI is the best choice.


🚦 What Are We Building?

We’ll build a backend that lets:

  • 🔌 EV chargers connect using OCPP 1.6 over WebSocket
  • 📲 Mobile apps connect using REST API over HTTP
  • 📡 Remote start commands be sent to chargers via API call

⚙️ Architecture Overview

graph TD
    Charger["EV Charger (OCPP 1.6)"] -->|WebSocket| FastAPI_WS["FastAPI WebSocket (OCPP)"]
    FastAPI_REST["FastAPI REST API (Mobile Access)"] -->|Internal call| Dispatcher
    Mobile["Mobile App (Flutter/React Native)"] -->|HTTP API| FastAPI_REST
    Dispatcher --> FastAPI_WS

🗂️ Project Structure

ev-system/
├── main.py              # FastAPI app (WebSocket + REST)
├── charge_point.py      # Custom ChargePoint logic (OCPP)
├── dispatcher.py        # RemoteStartTransaction logic
├── registry.py          # Connection tracking
└── requirements.txt

🔧 Step 1: Install Dependencies

pip install fastapi uvicorn ocpp

🧠 Step 2: OCPP Handler — charge_point.py

from ocpp.v16 import ChargePoint as CP
from ocpp.v16.enums import RegistrationStatus
from ocpp.v16 import call_result
from ocpp.routing import on

class ChargePoint(CP):
    @on('BootNotification')
    async def on_boot_notification(self, charge_point_model, charge_point_vendor, **kwargs):
        return call_result.BootNotificationPayload(
            current_time="2025-06-08T00:00:00Z",
            interval=10,
            status=RegistrationStatus.accepted
        )

🔌 Step 3: WebSocket Connection Registry — registry.py

class ConnectionRegistry:
    def __init__(self):
        self._registry = {}

    def add(self, cp_id, cp):
        self._registry[cp_id] = cp

    def get(self, cp_id):
        return self._registry.get(cp_id)

    def remove(self, cp_id):
        self._registry.pop(cp_id, None)

registry = ConnectionRegistry()

📡 Step 4: Send Remote Start — dispatcher.py

from ocpp.v16 import call

async def send_remote_start(cp, id_tag="MOBILE_USER"):
    request = call.RemoteStartTransaction(
        id_tag=id_tag,
        connector_id=1
    )
    response = await cp.call(request)
    return response.status

🚀 Step 5: Main App — main.py

from fastapi import FastAPI, WebSocket, WebSocketDisconnect, HTTPException
from charge_point import ChargePoint
from dispatcher import send_remote_start
from registry import registry

app = FastAPI()

@app.websocket("/ws/{cp_id}")
async def websocket_handler(websocket: WebSocket, cp_id: str):
    await websocket.accept(subprotocol="ocpp1.6")
    cp = ChargePoint(cp_id, websocket)
    registry.add(cp_id, cp)

    try:
        await cp.start()
    except WebSocketDisconnect:
        registry.remove(cp_id)

@app.post("/api/remote-start/{cp_id}")
async def remote_start(cp_id: str):
    cp = registry.get(cp_id)
    if not cp:
        raise HTTPException(404, "Charge point not connected")
    status = await send_remote_start(cp)
    return {"status": status}

📲 Step 6: Test API from Mobile App or Postman

Example Request:

POST /api/remote-start/CP001
Content-Type: application/json

{}

Your charger (connected via WebSocket to /ws/CP001) will receive a RemoteStartTransaction message.


🔐 Bonus: Securing the API

For production, add:

  • 🔑 JWT Authentication (fastapi-jwt-auth)
  • 📈 Rate limiting (e.g., slowapi)
  • 📦 Use Redis or MongoDB for persistent charger state
  • 🔒 HTTPS with Caddy or NGINX

🧱 Use Cases This Enables

  • ✅ Start/Stop charging from the mobile app
  • ✅ Display current charger status
  • ✅ Trigger firmware updates remotely
  • ✅ Support multiple chargers with real-time communication
  • ✅ Clean API docs for frontend/mobile teams

💬 Conclusion

FastAPI brings together everything you need to build a mobile-connected, OCPP-compliant, real-time backend:

  • 🔥 Async performance
  • 🌐 WebSocket + REST support
  • ⚙️ Type-safe development with Pydantic
  • 📲 Beautiful API docs for mobile clients

If you’re building an EV charging platform with mobile integration, FastAPI is the future-proof choice.


📦 Want More?

  • ✅ Docker Compose version with MongoDB or Redis?
  • ✅ Flutter mobile client example?
  • ✅ Admin dashboard with authentication?

Let me know — happy to help you build your smart EV platform!

Ready to talk about your project?

Share goals and constraints. We'll assemble architects and engineers to move fast with you.

Get in touch