Mokabyte

Dal 1996, architetture, metodologie, sviluppo software

  • Argomenti
    • Programmazione & Linguaggi
      • Java
      • DataBase & elaborazione dei dati
      • Frameworks & Tools
      • Processi di sviluppo
    • Architetture dei sistemi
      • Sicurezza informatica
      • DevOps
    • Project Management
      • Organizzazione aziendale
      • HR
      • Soft skills
    • Lean/Agile
      • Scrum
      • Teoria della complessità
      • Apprendimento & Serious Gaming
    • Internet & Digital
      • Cultura & Società
      • Conferenze & Reportage
      • Marketing & eCommerce
    • Hardware & Tecnologia
      • Intelligenza artificiale
      • UX design & Grafica
  • Ultimo numero
  • Archivio
    • Archivio dal 2006 ad oggi
    • Il primo sito web – 1996-2005
  • Chi siamo
  • Ventennale
  • Libri
  • Contatti
  • Argomenti
    • Programmazione & Linguaggi
      • Java
      • DataBase & elaborazione dei dati
      • Frameworks & Tools
      • Processi di sviluppo
    • Architetture dei sistemi
      • Sicurezza informatica
      • DevOps
    • Project Management
      • Organizzazione aziendale
      • HR
      • Soft skills
    • Lean/Agile
      • Scrum
      • Teoria della complessità
      • Apprendimento & Serious Gaming
    • Internet & Digital
      • Cultura & Società
      • Conferenze & Reportage
      • Marketing & eCommerce
    • Hardware & Tecnologia
      • Intelligenza artificiale
      • UX design & Grafica
  • Ultimo numero
  • Archivio
    • Archivio dal 2006 ad oggi
    • Il primo sito web – 1996-2005
  • Chi siamo
  • Ventennale
  • Libri
  • Contatti

Nel numero:

315 aprile
, anno 2025

FIWARE: Open APIs for Open Minds

V parte: Implementazione del sistema di ricarica

Giovanni Puliti

Giovanni Puliti ha lavorato per oltre 20 anni come consulente nel settore dell’IT e attualmente svolge la professione di Agile Coach. Nel 1996, insieme ad altri collaboratori, crea MokaByte, la prima rivista italiana web dedicata a Java. Autore di numerosi articoli pubblicate sia su MokaByte.it che su riviste del settore, ha partecipato a diversi progetti editoriali e prende parte regolarmente a conference in qualità di speaker. Dopo aver a lungo lavorato all’interno di progetti di web enterprise, come esperto di tecnologie e architetture, è passato a erogare consulenze in ambito di project management. Da diversi anni ha abbracciato le metodologie agili offrendo ad aziende e organizzazioni il suo supporto sia come coach agile che come business coach. È cofondatore di AgileReloaded, l’azienda italiana per il coaching agile.

FIWARE

FIWARE: Open APIs for Open Minds

V parte: Implementazione del sistema di ricarica

Picture of Giovanni Puliti

Giovanni Puliti

  • Questo articolo parla di: Architetture dei sistemi, Frameworks & Tools, Processi di sviluppo

Architettura del sistema

Dopo aver visto nella parte precedente le caratteristiche generali di un sistema intelligente di ricarica delle auto elettriche, con I vari elementi in gioco, in questo ultimo articolo della serie illustreremo una possibile implementazione di tale sistema, basato su componenti FIWARE.

Componenti FIWARE

Il sistema si basa infatti su diversi Generic Enablers FIWARE:

  • Orion-LD Context Broker, per la gestione del contesto;
  • IoT Agent, per l’integrazione con le colonnine;
  • KeyRock, per identity management;
  • Quantum Leap, per la storicizzazione dei dati temporali.
Figura 1 – Schema dell’architettura del sistema.
Figura 1 – Schema dell’architettura del sistema.

 

Riportiamo di seguito l’implementazione dei componenti chiave.

 

Modelli di Dati NGSI-LD

```typescript
// Definizione delle interfacce TypeScript per i modelli NGSI-LD
interface EVChargingStation {
       id: string;
       type: ‘EVChargingStation’;
       location: GeoProperty;
       status: Property<‘available’ | ‘occupied’ | ‘outOfService’>;
       connectorType: Property<string[]>;
       maxPower: Property<number>;
       currentPower: Property<number>;
       pricePerKWh: Property<number>;
       operator: Relationship;
       reservations: Property<Reservation[]>;
}

interface EVCharger {
       id: string;
       type: ‘EVCharger’;
       location: GeoProperty;
       batteryLevel: Property<number>;
       estimatedRange: Property<number>;
       preferredStations: Relationship[];
       owner: Relationship;
       lastUpdate: Property<Date>;
}
```

 

Backend Services

I servizi di backend prevedono il servizio di pianificazione delle ricariche e quello di gestione delle prenotazioni.

Servizio di pianificazione ricariche

```python
from datetime import datetime, timedelta
from typing import List, Optional
import asyncio

class ChargingPlanner:
       def __init__(self, context_broker: ContextBroker):
              self.context_broker = context_broker
              self.optimization_service = OptimizationService()

       async def plan_daily_charging(self, user_id: str, date: datetime) -> ChargingPlan:
              # Recupera gli appuntamenti del giorno
              calendar_events = await self.get_calendar_events(user_id, date)
              
              # Recupera lo stato del veicolo
              vehicle = await self.get_vehicle_status(user_id)
              
              # Calcola il fabbisogno energetico
              energy_needs = self.calculate_energy_needs(
                     current_charge=vehicle.battery_level,
                     planned_routes=self.extract_routes(calendar_events)
              )
              
              if not energy_needs.requires_charging:
                     return ChargingPlan(needed=False)
              
              # Trova le finestre temporali disponibili
              charging_windows = self.find_charging_windows(calendar_events)
              
              # Ottimizza il piano di ricarica
              optimal_plan = await self.optimization_service.optimize_charging(
                     energy_needs=energy_needs,
                     charging_windows=charging_windows,
                     available_stations=await self.get_available_stations()
              )
              
              return optimal_plan

       def calculate_energy_needs(self, current_charge: float, planned_routes: List[Route]) -> EnergyNeeds:
              total_distance = sum(route.distance for route in planned_routes)
              estimated_consumption = self.estimate_consumption(
                     total_distance,
                     routes=planned_routes,
                     weather=self.get_weather_forecast()
              )
              
              return EnergyNeeds(
                     current_level=current_charge,
                     required_energy=estimated_consumption,
                     safety_margin=10.0    # percentuale
              )
```

 

Gestore delle prenotazioni

```python
class ReservationManager:
       def __init__(self, context_broker: ContextBroker):
              self.context_broker = context_broker

       async def create_reservation(self, request: ReservationRequest) -> Reservation:
              # Verifica disponibilità
              station = await self.context_broker.get_entity(request.station_id)
              if not self.is_slot_available(station, request.time_slot):
                     raise SlotNotAvailableError()
              
              # Crea la prenotazione
              reservation = Reservation(
                     id=generate_uuid(),
                     station_id=request.station_id,
                     user_id=request.user_id,
                     time_slot=request.time_slot,
                     status=‘confirmed’
              )
              
              # Aggiorna il Context Broker
              await self.context_broker.update_entity(
                     entity_id=request.station_id,
                     attrs={
                            ‘reservations’: {
                                   ‘type’: ‘Property’,
                                   ‘value’: [...station.reservations, reservation]
                            }
                     }
              )
              
              # Invia notifica all’utente
              await self.notify_user(request.user_id, reservation)
              
              return reservation
```

 

Implementazione iOS

Vediamo ora i passi necessari per una implementazione su sistemi iOS.

Gestione del calendario

```swift
class CalendarManager {
       private let eventStore = EKEventStore()
       
       func requestAccess() async throws -> Bool {
              return try await eventStore.requestAccess(to: .event)
       }
       
       func fetchEvents(for date: Date) async throws -> [EKEvent] {
              let calendar = Calendar.current
              let startDate = calendar.startOfDay(for: date)
              let endDate = calendar.date(byAdding: .day, value: 1, to: startDate)!
              
              let predicate = eventStore.predicateForEvents(
                     withStart: startDate,
                     end: endDate,
                     calendars: nil
              )
              
              return eventStore.events(matching: predicate)
       }
       
       func analyzeEvents(_ events: [EKEvent]) -> [TripPlan] {
              return events.map { event in
                     TripPlan(
                            startTime: event.startDate,
                            endTime: event.endDate,
                            location: event.location,
                            title: event.title
                     )
              }
       }
}
```

 

Integrazione con FIWARE

```swift
class FIWAREClient {
       private let baseURL: URL
       private let session: URLSession
       
       func subscribeToUpdates() async throws {
              let subscription = NGSISubscription(
                     entities: [EntityType.chargingStation],
                     watchedAttributes: ["status", "currentPower"],
                     notification: NotificationEndpoint(
                            uri: "my-app-scheme://charging-update",
                            accept: "application/json"
                     )
              )
              
              try await createSubscription(subscription)
       }
       
       func updateVehicleStatus(_ status: VehicleStatus) async throws {
              let entity = NGSIEntity(
                     id: "urn:ngsi-ld:Vehicle:\(status.vehicleId)",
                     type: "Vehicle",
                     attributes: [
                            "batteryLevel": .property(status.batteryLevel),
                            "location": .geoProperty(status.location),
                            "lastUpdate": .property(Date())
                     ]
              )
              
              try await updateEntity(entity)
       }
}
```

 

User Interface

```swift
class ChargingPlanViewController: UIViewController {
       private let mapView: MKMapView
       private let timelineView: TimelineView
       private let chargingManager: ChargingManager
       
       override func viewDidLoad() {
              super.viewDidLoad()
              setupViews()
              Task {
                     await loadChargingPlan()
              }
       }
       
       private func loadChargingPlan() async {
              do {
                     let plan = try await chargingManager.getDailyPlan()
                     await MainActor.run {
                            updateUI(with: plan)
                     }
              } catch {
                     await showError(error)
              }
       }
       
       private func updateUI(with plan: ChargingPlan) {
              // Aggiorna la mappa con le stazioni di ricarica
              mapView.showChargingStations(plan.stations)
              
              // Aggiorna la timeline con gli eventi e le ricariche pianificate
              timelineView.update(with: plan.schedule)
              
              // Aggiorna le informazioni di riepilogo
              updateSummaryView(plan.summary)
       }
}
```

 

Gestione della Privacy

Per la gestione dei dati riservati, sarà necessario creare una classe PrivacyManager nel modo che segue.

```swift
class PrivacyManager {
       func filterCalendarData(_ events: [EKEvent]) -> [LocationTimeSlot] {
              return events.map { event in
                     LocationTimeSlot(
                            timeSlot: TimeSlot(start: event.startDate, end: event.endDate),
                            location: anonymizeLocation(event.location),
                            type: classifyEventType(event)
                     )
              }
       }
       
       private func anonymizeLocation(_ location: EKStructuredLocation?) -> AnonymizedLocation {
              guard let location = location else { return .unknown }
              
              return AnonymizedLocation(
                     coordinates: roundCoordinates(location.geoLocation),
                     area: determineArea(location),
                     type: classifyLocationType(location)
              )
       }
}
```

 

Testing e monitoraggio

Vediamo infine i componenti che si occuperanno dei test di unità e del monitoraggio.

Unit Testing

```swift
class ChargingPlannerTests: XCTestCase {
       var planner: ChargingPlanner!
       var mockContextBroker: MockContextBroker!
       
       override func setUp() {
              mockContextBroker = MockContextBroker()
              planner = ChargingPlanner(contextBroker: mockContextBroker)
       }
       
       func testChargingPlanGeneration() async throws {
              // Setup test data
              let events = createTestCalendarEvents()
              let vehicleStatus = createTestVehicleStatus()
              
              // Execute
              let plan = try await planner.generatePlan(
                     forEvents: events,
                     vehicleStatus: vehicleStatus
              )
              
              // Verify
              XCTAssertNotNil(plan)
              XCTAssertTrue(plan.isValid)
              XCTAssertTrue(plan.meetsEnergyNeeds(vehicleStatus))
       }
}
```

 

Performance Monitoring

```python
@contextlib.contextmanager
def monitor_performance(operation_name: str):
       start_time = time.time()
       try:
              yield
       finally:
              duration = time.time() - start_time
              prometheus_client.OPERATION_DURATION.labels(
                     operation=operation_name
              ).observe(duration)
```

 

Conclusioni

L’implementazione dimostra come FIWARE possa essere utilizzato per creare un sistema complesso che integra dati da diverse fonti e coordina attività in tempo reale. L’architettura modulare permette di gestire le sfide tecniche mantenendo il sistema flessibile e scalabile.

La combinazione di un backend FIWARE robusto con un’applicazione mobile intuitiva crea un’esperienza utente fluida che nasconde la complessità sottostante del sistema. L’approccio adottato permette di estendere facilmente il sistema con nuove funzionalità e di adattarlo a diverse esigenze degli utenti.

 

 

Giovanni Puliti

Giovanni Puliti ha lavorato per oltre 20 anni come consulente nel settore dell’IT e attualmente svolge la professione di Agile Coach. Nel 1996, insieme ad altri collaboratori, crea MokaByte, la prima rivista italiana web dedicata a Java. Autore di numerosi articoli pubblicate sia su MokaByte.it che su riviste del settore, ha partecipato a diversi progetti editoriali e prende parte regolarmente a conference in qualità di speaker. Dopo aver a lungo lavorato all’interno di progetti di web enterprise, come esperto di tecnologie e architetture, è passato a erogare consulenze in ambito di project management. Da diversi anni ha abbracciato le metodologie agili offrendo ad aziende e organizzazioni il suo supporto sia come coach agile che come business coach. È cofondatore di AgileReloaded, l’azienda italiana per il coaching agile.

Facebook
Twitter
LinkedIn
Picture of Giovanni Puliti

Giovanni Puliti

Giovanni Puliti ha lavorato per oltre 20 anni come consulente nel settore dell’IT e attualmente svolge la professione di Agile Coach. Nel 1996, insieme ad altri collaboratori, crea MokaByte, la prima rivista italiana web dedicata a Java. Autore di numerosi articoli pubblicate sia su MokaByte.it che su riviste del settore, ha partecipato a diversi progetti editoriali e prende parte regolarmente a conference in qualità di speaker. Dopo aver a lungo lavorato all’interno di progetti di web enterprise, come esperto di tecnologie e architetture, è passato a erogare consulenze in ambito di project management. Da diversi anni ha abbracciato le metodologie agili offrendo ad aziende e organizzazioni il suo supporto sia come coach agile che come business coach. È cofondatore di AgileReloaded, l’azienda italiana per il coaching agile.
Tutti gli articoli
Nello stesso numero
Loading...

Accessibilità in team di prodotto: sfide, normative e best practice

I parte: Cosa è l’accessibilità e perché implementarla

Il web al tempo della GEO (Generative Engine Optimization)

II parte: Strategie per strutturare i contenuti

Un backlog non tanto buono

II parte: Caratteristiche e ruolo del backlog.

Nella stessa serie
Loading...

FIWARE: Open APIs for Open Minds

IV parte: Sistema di ricarica intelligente per veicoli elettrici

FIWARE: Open APIs for Open Minds

III parte: Tecnologie e implementazione

FIWARE: Open APIs for Open Minds

II parte: Generic Enablers per costruire ecosistemi smart

FIWARE: Open APIs for Open Minds

I parte: Fondamenti e architettura

Mokabyte

MokaByte è una rivista online nata nel 1996, dedicata alla comunità degli sviluppatori java.
La rivista tratta di vari argomenti, tra cui architetture enterprise e integrazione, metodologie di sviluppo lean/agile e aspetti sociali e culturali del web.

Imola Informatica

MokaByte è un marchio registrato da:
Imola Informatica S.P.A.
Via Selice 66/a 40026 Imola (BO)
C.F. e Iscriz. Registro imprese BO 03351570373
P.I. 00614381200
Cap. Soc. euro 100.000,00 i.v.

Privacy | Cookie Policy

Contatti

Contattaci tramite la nostra pagina contatti, oppure scrivendo a redazione@mokabyte.it

Seguici sui social

Facebook Linkedin Rss
Imola Informatica
Mokabyte