diff --git a/ocpi.bookinglocation.v23.ts b/ocpi.bookinglocation.v23.ts new file mode 100644 index 0000000..5f6124d --- /dev/null +++ b/ocpi.bookinglocation.v23.ts @@ -0,0 +1,141 @@ +import { z } from "zod"; +import { ConnectorFormat, EvsePosition, VehicleType } from "./ocpi.location.v23"; +import { OcpiInterfaceRole } from "./ocpi.versions.v23"; +import { TokenType } from "./ocpi.common.v23"; + +export const BookableParkingOptions = z.object({ + evse_position: EvsePosition.nullish(), + vehicle_types: z.array(VehicleType).nonempty(), + format: ConnectorFormat, + max_vehicle_weight: z.number().nonnegative().nullish(), + max_vehicle_height: z.number().nonnegative().nullish(), + max_vehicle_length: z.number().nonnegative().nullish(), + max_vehicle_width: z.number().nonnegative().nullish(), + parking_space_length: z.number().nonnegative().nullish(), + parking_space_width: z.number().nonnegative().nullish(), + dangerous_goods_allowed: z.boolean().nullish(), + drive_through: z.boolean().nullish(), + restricted_to_type: z.boolean().nullish(), + refrigeration_outlet: z.boolean().nullish(), +}); + +export const CanceledReason = z.enum([ + "POWER_OUTAGE", + "BROKEN_CHARGER", + "FULL", + "BLOCKED", + "TRAFFIC", + "BROKEN_VEHICLE", + "NO_CANCELED", + "UNKNOWN", +]); + +export const Cancellation = z.object({ + cancellation_reason: CanceledReason, + who_canceled: OcpiInterfaceRole, +}); + +export const LocationAccess = z.enum([ + "OPEN", + "TOKEN", + "LICENSE_PLATE", + "ACCESS_CODE", + "INTERCOM", + "PARKING_TICKET", +]); + +export const AccessMethod = z.object({ + location_access: LocationAccess, + value: z.string().nullish(), +}); + +export const ReservationRequestStatus = z.enum([ + "PENDING", + "ACCEPTED", + "DECLINED", + "FAILED", +]); + +export const BookingToken = z.object({ + country_code: z.string().max(2), + party_id: z.string().max(3), + uid: z.string().max(36).nullish(), + type: TokenType, + contract_id: z.string().max(36).nullish(), +}); + +export const Timeslot = z.object({ + start_from: z.date(), + end_from: z.date(), + min_power: z.number().nonnegative().nullish(), + max_power: z.number().nonnegative().nullish(), + green_energy_support: z.boolean().nullish(), +}); + +export const BookingRequest = z.object({ + country_code: z.string().max(2), + party_id: z.string().max(3), + request_id: z.string().max(36), + bookable_parking_option: BookableParkingOptions.nullish(), + location_id: z.string().max(36), + evse_uid: z.string().max(36).nullish(), + connector_id: z.string().max(36).nullish(), + tokens: z.array(BookingToken).nullish(), + period: Timeslot, + authorization_reference: z.string().max(36), + power_required: z.number().int().nullish(), + cancelled: Cancellation.nullish(), +}); + +export const BookingRequestStatus = z.object({ + request_status: ReservationRequestStatus, + booking_request: BookingRequest, + request_received: z.date(), +}); + +export const Bookable = z.object({ + reservation_required: z.boolean(), + ad_hoc: z.number().nonnegative().nullish(), +}); + +export const BookingTerms = z.object({ + RFID_auth_required: z.boolean().nullish(), + token_groups_supported: z.boolean().nullish(), + remote_auth_supported: z.array(LocationAccess).nonempty(), + supported_access_methods: z.number().nonnegative().nullish(), + change_until_minutes: z.number().nonnegative(), + cancel_until_minutes: z.number().nonnegative(), + change_not_allowed: z.boolean().nullish(), + early_start_allowed: z.boolean().nullish(), + early_start_time: z.number().nonnegative().nullish(), + noshow_timeout: z.number().nonnegative().nullish(), + noshow_fee: z.boolean().nullish(), + late_stop_allowed: z.boolean().nullish(), + late_stop_time: z.number().nonnegative().nullish(), + overlapping_bookings_allowed: z.boolean().nullish(), + booking_terms: z.string().url().nullish(), +}); + +export const Calendar = z.object({ + id: z.string().max(36), + begin_from: z.date(), + end_before: z.date(), + step_size: z.number().int().nullish(), + available_timeslots: z.array(Timeslot).nonempty(), + last_updated: z.date(), +}); + +export const BookingLocation = z.object({ + country_code: z.string().max(2), + party_id: z.string().max(3), + id: z.string().max(36), + location_id: z.string().max(36), + evse_uid: z.string().max(36).nullish(), + connector_id: z.string().max(36).nullish(), + bookable_parking_options: z.array(BookableParkingOptions).nullish(), + bookable: Bookable.nullish(), + tariff_id: z.string().max(36).nullish(), + booking_terms: z.array(BookingTerms).nullish(), + calendars: z.array(Calendar).nullish(), + last_updated: z.date(), +}); \ No newline at end of file diff --git a/ocpi.cdrs.v23.ts b/ocpi.cdrs.v23.ts new file mode 100644 index 0000000..b4df584 --- /dev/null +++ b/ocpi.cdrs.v23.ts @@ -0,0 +1,105 @@ +import { z } from "zod"; + +import { Price } from "./ocpi.common.v23"; +import { TokenType } from "./ocpi.common.v23"; +import { ConnectorFormat, ConnectorType, GeoLocation, PowerType } from "./ocpi.location.v23"; +import { Tariff } from "./ocpi.tariff.v221"; + +export const AuthMethod = z.enum(["AUTH_REQUEST", "COMMAND", "WHITELIST"]); + +const CdrDimensionType = z.enum([ + "ENERGY", + "MAX_CURRENT", + "MIN_CURRENT", + "MAX_POWER", + "MIN_POWER", + "PARKING_TIME", + "RESERVATION_TIME", + "TIME", +]); + +export const CdrDimension = z.object({ + type: CdrDimensionType, + volume: z.number(), +}); + +export const CdrToken = z.object({ + uid: z.string().max(36), + type: TokenType.nullish(), + contract_id: z.string().max(36), + country_code: z.string().max(2), + party_id: z.string().max(3), +}) + +export const CdrLocation = z.object({ + id: z.string().max(36), + name: z.string().max(255).nullish(), + address: z.string().max(45), + city: z.string().max(45), + postal_code: z.string().max(10).nullish(), + state: z.string().max(20).nullish(), + country: z.string().length(3), + coordinates: GeoLocation, + evse_uid: z.string().max(36), + evse_id: z.string().max(48).regex(/^(([A-Z]{2}\*?[A-Z0-9]{3}\*?E[A-Z0-9\*]{1,30})|(\+?[0-9]{1,3}\*[0-9]{3}\*[0-9\*]{1,32}))$/), + connector_id: z.string().max(36), + connector_standard: ConnectorType, + connector_format: ConnectorFormat, + connector_power_type: PowerType, +}) + +export const ChargingPeriod = z.object({ + start_date_time: z.date(), + dimensions: z.array(CdrDimension).nonempty(), + tariff_id: z.string().max(36).nullish(), +}) + +export const SignedValue = z.object({ + nature: z.string().max(32), + plain_data: z.string().max(512), + signed_data: z.string().max(5000) +}); + +export const SignedData = z.object({ + encoding_method: z.string().max(36), + encoding_method_version: z.number().int().nullish(), + public_key: z.string().max(512).nullish(), + signed_values: z.array(SignedValue).nonempty(), + url: z.string().max(512).nullish() +}); + +export const Cdr = z.object({ + country_code: z.string().length(2), + party_id: z.string().max(3), + id: z.string().max(39), + start_date_time: z.date(), + end_date_time: z.date(), + booking_id: z.string().max(36).nullish(), + session_id: z.string().max(36).nullish(), + cdr_token: CdrToken, + auth_method: AuthMethod, + authorization_reference: z.string().max(36).nullish(), + cdr_location: CdrLocation, + meter_id: z.string().max(255).nullish(), + currency: z.string().length(3), + tariffs: z.array(Tariff).nullish(), + charging_periods: z.array(ChargingPeriod).nonempty(), + signed_data: SignedData.nullish(), + total_cost: Price, + total_fixed_cost: Price.nullish(), + total_energy: z.number().nonnegative(), + total_energy_cost: Price.nullish(), + total_time: z.number().nonnegative(), + total_time_cost: Price.nullish(), + total_parking_time: z.number().nonnegative().nullish(), + total_parking_cost: Price.nullish(), + total_reservation_cost: Price.nullish(), + remark: z.string().max(255).nullish(), + invoice_reference_id: z.string().max(39).nullish(), + credit: z.boolean().nullish(), + credit_reference_id: z.string().max(39).nullish(), + home_charging_compensation: z.boolean().nullish(), + last_updated: z.date(), +}); + +export const Cdrs = z.array(Cdr); diff --git a/ocpi.chargingprofiles.v23.ts b/ocpi.chargingprofiles.v23.ts new file mode 100644 index 0000000..aec3000 --- /dev/null +++ b/ocpi.chargingprofiles.v23.ts @@ -0,0 +1,64 @@ +import { z } from "zod"; + +const ChargingProfileResponseType = z.enum([ + "ACCEPTED", + "NOT_SUPPORTED", + "REJECTED", + "TOO_OFTEN", + "UNKNOWN_SESSION" +]); + +const ChargingRateUnit = z.enum([ + "W", + "A" +]); + +const ChargingProfilePeriod = z.object({ + start_period: z.number().int().nonnegative(), + limit: z.number().multipleOf(0.1).nonnegative(), +}); + +export const ChargingProfile = z.object({ + start_date_time: z.date().nullish(), + duration: z.number().int().nonnegative().nullish(), + charging_rate_unit: ChargingRateUnit, + min_charging_rate: z.number().multipleOf(0.1).nonnegative().nullish(), + charging_profile_period: z.array(ChargingProfilePeriod).nullish() +}); + +const ChargingProfileResultType = z.enum([ + "ACCEPTED", + "REJECTED", + "UNKNOWN" +]); + +export const ActiveChargingProfile = z.object({ + start_date_time: z.date(), + charging_profile: ChargingProfile +}); + +export const SetChargingProfile = z.object({ + charging_profile: ChargingProfile, + response_url: z.string().url(), +}); + +export const ChargingProfileResponse = z.object({ + result: ChargingProfileResponseType, + timeout: z.number().int().nonnegative(), +}); + +export const ActiveChargingProfileResult = z.object({ + result: ChargingProfileResultType, + profile: ActiveChargingProfile.nullish(), +}); + +export const ChargingProfileResult = z.object({ + result: ChargingProfileResultType, +}); + +export const ClearProfileResult = z.object({ + result: ChargingProfileResultType, +}); + + + diff --git a/ocpi.commands.v23.ts b/ocpi.commands.v23.ts new file mode 100644 index 0000000..b795cf9 --- /dev/null +++ b/ocpi.commands.v23.ts @@ -0,0 +1,86 @@ +import { z } from "zod"; +import { + DisplayText, +} from "./ocpi.common.v221"; +import { + Token, +} from "./ocpi.tokens.v221"; +import { createOpenEnum } from "./ocpi.common.v23"; + + +export const ReserveNowCommand = z.object({ + response_url: z.string().url(), + token: Token, + expiry_date: z.date(), + reservation_id: z.string().max(36), + location_id: z.string().max(36), + evse_uid: z.string().max(36).nullish(), + authorization_reference: z.string().max(36).nullish(), +}); + +export const CancelReservationCommand = z.object({ + response_url: z.string().url(), + reservation_id: z.string().max(36), +}); + +export const StartSessionCommand = z.object({ + response_url: z.string().url(), + token: Token, + location_id: z.string().max(36), + evse_uid: z.string().max(36).nullish(), + connector_id: z.string().max(36).nullish(), + authorization_reference: z.string().max(36).nullish(), +}); + +export const StopSessionCommand = z.object({ + response_url: z.string().url(), + session_id: z.string().max(36), +}); + +export const UnlockConnectorCommand = z.object({ + response_url: z.string().url(), + location_id: z.string().max(36), + evse_uid: z.string().max(36), + connector_id: z.string().max(36), +}); + +const CommandResponseType = z.enum([ + "NOT_SUPPORTED", + "REJECTED", + "ACCEPTED", + "UNKNOWN_SESSION", +]); + +export const CommandResponse = z.object({ + result: CommandResponseType, + timeout: z.number().int().nonnegative(), + message: z.array(DisplayText).nullish(), +}); + +const CommandResultType = z.enum([ + "ACCEPTED", + "CANCELED_RESERVATION", + "EVSE_OCCUPIED", + "EVSE_INOPERATIVE", + "FAILED", + "NOT_SUPPORTED", + "REJECTED", + "TIMEOUT", + "UNKNOWN_RESERVATION", +]); + +export const CommandResult = z.object({ + result: CommandResultType, + message: z.array(DisplayText).nullish(), +}); + +const CommandType = createOpenEnum([ + "CANCEL_RESERVATION", + "RESERVE_NOW", + "START_SESSION", + "STOP_SESSION", + "UNLOCK_CONNECTOR" +]); + + + diff --git a/ocpi.common.v23.ts b/ocpi.common.v23.ts new file mode 100644 index 0000000..3b6c883 --- /dev/null +++ b/ocpi.common.v23.ts @@ -0,0 +1,27 @@ +import { z } from "zod"; + +export const createOpenEnum = (knownValues: readonly T[]) => { + return z.union([ + z.enum(knownValues as [T, ...T[]]), + z.string().trim().min(1), + ]); +}; + +export const TaxAmount = z.object({ + name: z.string(), + account_number: z.string().nullish(), + percentage: z.number().nonnegative().nullish(), + amount: z.number(), +}); + +export const Price = z.object({ + before_taxes: z.number().nonnegative(), + taxes: z.array(TaxAmount).nullish(), +}); + +export const TokenType = createOpenEnum(["AD_HOC_USER", "APP_USER", "EMAID", "LICENSE_PLATE", "OTHER", "RFID"]); + +export const DisplayText = z.object({ + language: z.string().length(2), + text: z.string().max(512), +}); \ No newline at end of file diff --git a/ocpi.credentials.v23.ts b/ocpi.credentials.v23.ts new file mode 100644 index 0000000..3be0e22 --- /dev/null +++ b/ocpi.credentials.v23.ts @@ -0,0 +1,26 @@ +import { z } from "zod"; +import { BusinessDetails } from "./ocpi.common"; + +export const Role = z.enum([ + "CPO", + "EMSP", + "HUB", + "NAP", + "NSP", + "OTHER", + "SCSP" +]) + +export const CredentialsRole = z.object({ + role: Role, + business_details: BusinessDetails, + party_id: z.string().length(3), + country_code: z.string().length(2), +}) + +export const OcpiCredentials = z.object({ + token: z.string().max(64), + url: z.string().url(), + hub_party_id: z.string().max(5).nullish(), + roles: z.array(CredentialsRole).nonempty(), +}); diff --git a/ocpi.financialadviceconfirmation.v23.ts b/ocpi.financialadviceconfirmation.v23.ts new file mode 100644 index 0000000..c0223d9 --- /dev/null +++ b/ocpi.financialadviceconfirmation.v23.ts @@ -0,0 +1,19 @@ +import { z } from "zod"; +import { Price } from "./ocpi.common.v23"; + +export const InvoiceCreator = z.enum(["CPO", "PTP"]); + +export const CaptureStatusCode = z.enum(["SUCCESS", "PARTIAL_SUCCESS", "FAILED"]); + +export const FinancialAdviceConfirmation = z.object({ + id: z.string().max(36), + authorization_reference: z.string().max(36), + total_costs: Price, + currency: z.string().max(3), + eft_data: z.array(z.string().min(1).max(255)).nonempty(), + capture_status_code: CaptureStatusCode, + capture_status_message: z.string().min(1).max(255).nullish(), + last_updated: z.date(), +}); + +export const FinancialAdviceConfirmations = z.array(FinancialAdviceConfirmation); \ No newline at end of file diff --git a/ocpi.generate.ts b/ocpi.generate.ts index 1c13c31..84a7f81 100644 --- a/ocpi.generate.ts +++ b/ocpi.generate.ts @@ -9,6 +9,10 @@ import { Token as TokenV221, Tokens as TokensV221 } from "./ocpi.tokens.v221"; +import { + Token as TokenV23, + Tokens as TokensV23 +} from "./ocpi.tokens.v23"; import { Connector as ConnectorV22, Evse as EvseV22, @@ -21,6 +25,12 @@ import { Location as LocationV221, Locations as LocationsV221 } from "./ocpi.location.v221"; +import { + Connector as ConnectorV23, + Evse as EvseV23, + Location as LocationV23, + Locations as LocationsV23 +} from "./ocpi.location.v23"; import { Session as SessionV22, Sessions as SessionsV22, @@ -29,6 +39,10 @@ import { Session as SessionV221, Sessions as SessionsV221, } from "./ocpi.sessions.v221" +import { + Session as SessionV23, + Sessions as SessionsV23, +} from "./ocpi.sessions.v23" import { Cdr as CdrV22, Cdrs as CdrsV22, @@ -37,6 +51,10 @@ import { Cdr as CdrV221, Cdrs as CdrsV221, } from "./ocpi.cdrs.v221"; +import { + Cdr as CdrV23, + Cdrs as CdrsV23, +} from "./ocpi.cdrs.v23"; import { Tariff as TariffV22, Tariffs as TariffsV22, @@ -45,6 +63,10 @@ import { Tariff as TariffV221, Tariffs as TariffsV221, } from "./ocpi.tariff.v221"; +import { + Tariff as TariffV23, + Tariffs as TariffsV23, +} from "./ocpi.tariff.v23"; import { OcpiEmpty, OcpiErrorResponse, @@ -55,9 +77,11 @@ import { ZodTypeAny } from "zod"; import { OcpiVersionDetails, OcpiVersions } from "./ocpi.version"; import { OcpiVersionDetails as OcpiVersionDetailsV22, OcpiVersions as OcpiVersionsV22 } from "./ocpi.versions.v22"; import { OcpiVersionDetails as OcpiVersionDetailsV221, OcpiVersions as OcpiVersionsV221 } from "./ocpi.versions.v221"; +import { OcpiVersionDetails as OcpiVersionDetailsV23, OcpiVersions as OcpiVersionsV23 } from "./ocpi.versions.v23"; import { OcpiCredentials } from "./ocpi.credentials"; import { OcpiCredentials as OcpiCredentialsV22 } from "./ocpi.credentials.v22"; import { OcpiCredentials as OcpiCredentialsV221 } from "./ocpi.credentials.v221"; +import { OcpiCredentials as OcpiCredentialsV23 } from "./ocpi.credentials.v23"; import { Cdr, Cdrs } from "./ocpi.cdr"; import { Tariff, Tariffs } from "./ocpi.tariff"; import { Token, Tokens } from "./ocpi.tokens"; @@ -86,6 +110,15 @@ import { StopSessionCommand as StopSessionCommandV221, UnlockConnectorCommand as UnlockConnectorCommandV221 } from "./ocpi.commands.v221"; +import { + CommandResponse as CommandResponseV23, + CommandResult as CommandResultV23, + ReserveNowCommand as ReserveNowCommandV23, + CancelReservationCommand as CancelReservationCommandV23, + StartSessionCommand as StartSessionCommandV23, + StopSessionCommand as StopSessionCommandV23, + UnlockConnectorCommand as UnlockConnectorCommandV23 +} from "./ocpi.commands.v23"; import { ocpiDeepPartial } from "./ocpi.utils"; @@ -104,12 +137,35 @@ import { ClearProfileResult as ClearProfileResultV221, SetChargingProfile as SetChargingProfileV221 } from "./ocpi.chargingprofiles.v221"; +import { + ActiveChargingProfile as ActiveChargingProfileV23, + ActiveChargingProfileResult as ActiveChargingProfileResultV23, + ChargingProfileResponse as ChargingProfileResponseV23, + ChargingProfileResult as ChargingProfileResultV23, + ClearProfileResult as ClearProfileResultV23, + SetChargingProfile as SetChargingProfileV23 +} from "./ocpi.chargingprofiles.v23"; import {ClientInfo, ClientInfos} from "./ocpi.hubclientinfo.v22"; import { ClientInfo as ClientInfoV221, ClientInfos as ClientInfosV221 } from "./ocpi.hubclientinfo.v221"; +import { + ClientInfo as ClientInfoV23, + ClientInfos as ClientInfosV23 +} from "./ocpi.hubclientinfo.v23"; + +import { + Terminal as TerminalV23, + Terminals as TerminalsV23, + TerminalWithOptionalId as TerminalWithOptionalIdV23, +} from "./ocpi.terminal.v23"; +import { + FinancialAdviceConfirmation as FinancialAdviceConfirmationV23 , + FinancialAdviceConfirmations as FinancialAdviceConfirmationsV23 +} from "./ocpi.financialadviceconfirmation.v23"; + const OCPI_SCHEMA_DIR = ".ocpi-schema"; @@ -158,6 +214,17 @@ saveSchema( ocpiSuccessResponse(OcpiVersionDetailsV221), ); +/* Versions 2.3 */ +saveSchema("ocpi.2_3.versions", OcpiVersionsV23); +saveSchema("ocpi.2_3.versions.response", ocpiSuccessResponse(OcpiVersionsV23)); + +/* Version details 2.3 */ +saveSchema("ocpi.2_3.version_details", OcpiVersionDetailsV23); +saveSchema( + "ocpi.2_3.version_details.response", + ocpiSuccessResponse(OcpiVersionDetailsV23), +); + /* Credentials */ saveSchema("ocpi.2_1_1.credentials", OcpiCredentials); saveSchema( @@ -179,6 +246,13 @@ saveSchema( ocpiSuccessResponse(OcpiCredentialsV221), ); +/* Credentials 2.3 */ +saveSchema("ocpi.2_3.credentials", OcpiCredentialsV23); +saveSchema( + "ocpi.2_3.credentials.response", + ocpiSuccessResponse(OcpiCredentialsV23), +); + /* Locations */ saveSchema("ocpi.2_1_1.locations", Locations); saveSchema("ocpi.2_1_1.locations.response", ocpiSuccessResponse(Locations)); @@ -218,6 +292,19 @@ saveSchema("ocpi.2_2_1.connector", ConnectorV221); saveSchema("ocpi.2_2_1.connector.partial", ocpiDeepPartial(ConnectorV221)); saveSchema("ocpi.2_2_1.connector.response", ocpiSuccessResponse(ConnectorV221)); +/* Locations 2.3 */ +saveSchema("ocpi.2_3.locations", LocationsV23); +saveSchema("ocpi.2_3.locations.response", ocpiSuccessResponse(LocationsV23)); +saveSchema("ocpi.2_3.location", LocationV23); +saveSchema("ocpi.2_3.location.partial", ocpiDeepPartial(LocationV23)); +saveSchema("ocpi.2_3.location.response", ocpiSuccessResponse(LocationV23)); +saveSchema("ocpi.2_3.evse", EvseV23); +saveSchema("ocpi.2_3.evse.partial", ocpiDeepPartial(EvseV23)); +saveSchema("ocpi.2_3.evse.response", ocpiSuccessResponse(EvseV23)); +saveSchema("ocpi.2_3.connector", ConnectorV23); +saveSchema("ocpi.2_3.connector.partial", ocpiDeepPartial(ConnectorV23)); +saveSchema("ocpi.2_3.connector.response", ocpiSuccessResponse(ConnectorV23)); + /* Sessions */ saveSchema("ocpi.2_1_1.sessions", Sessions); saveSchema("ocpi.2_1_1.sessions.response", ocpiSuccessResponse(Sessions)); @@ -239,6 +326,13 @@ saveSchema("ocpi.2_2_1.session", SessionV221); saveSchema("ocpi.2_2_1.session.partial", ocpiDeepPartial(SessionV221)); saveSchema("ocpi.2_2_1.session.response", ocpiSuccessResponse(SessionV221)); +/* Sessions 2.3 */ +saveSchema("ocpi.2_3.sessions", SessionsV23); +saveSchema("ocpi.2_3.sessions.response", ocpiSuccessResponse(SessionsV23)); +saveSchema("ocpi.2_3.session", SessionV23); +saveSchema("ocpi.2_3.session.partial", ocpiDeepPartial(SessionV23)); +saveSchema("ocpi.2_3.session.response", ocpiSuccessResponse(SessionV23)); + /* CDRs */ saveSchema("ocpi.2_1_1.cdrs", Cdrs); saveSchema("ocpi.2_1_1.cdrs.response", ocpiSuccessResponse(Cdrs)); @@ -260,6 +354,13 @@ saveSchema("ocpi.2_2_1.cdr", CdrV221); saveSchema("ocpi.2_2_1.cdr.partial", ocpiDeepPartial(CdrV221)); saveSchema("ocpi.2_2_1.cdr.response", ocpiSuccessResponse(CdrV221)); +/* CDRs 2.3 */ +saveSchema("ocpi.2_3.cdrs", CdrsV23); +saveSchema("ocpi.2_3.cdrs.response", ocpiSuccessResponse(CdrsV23)); +saveSchema("ocpi.2_3.cdr", CdrV23); +saveSchema("ocpi.2_3.cdr.partial", ocpiDeepPartial(CdrV23)); +saveSchema("ocpi.2_3.cdr.response", ocpiSuccessResponse(CdrV23)); + /* Charging Profiles 2.2 */ saveSchema("ocpi.2_2.chargingprofiles", SetChargingProfile); saveSchema("ocpi.2_2.chargingprofiles.active", ActiveChargingProfile); @@ -276,6 +377,14 @@ saveSchema("ocpi.2_2_1.chargingprofiles.active_charging_profile.result", ActiveC saveSchema("ocpi.2_2_1.chargingprofiles.charging_profile.result", ChargingProfileResultV221); saveSchema("ocpi.2_2_1.chargingprofiles.clear_profile.result", ClearProfileResultV221); +/* Charging Profiles 2.3 */ +saveSchema("ocpi.2_3.chargingprofiles", SetChargingProfileV23); +saveSchema("ocpi.2_3.chargingprofiles.active", ActiveChargingProfileV23); +saveSchema("ocpi.2_3.chargingprofiles.response", ocpiSuccessResponse(ChargingProfileResponseV23)); +saveSchema("ocpi.2_3.chargingprofiles.active_charging_profile.result", ActiveChargingProfileResultV23); +saveSchema("ocpi.2_3.chargingprofiles.charging_profile.result", ChargingProfileResultV23); +saveSchema("ocpi.2_3.chargingprofiles.clear_profile.result", ClearProfileResultV23); + /* Hub Client Info 2.2 */ saveSchema("ocpi.2_2.hubclientinfo", ClientInfo); saveSchema("ocpi.2_2.hubclientinfo.response", ocpiSuccessResponse(ClientInfo)); @@ -286,6 +395,11 @@ saveSchema("ocpi.2_2_1.hubclientinfo", ClientInfoV221); saveSchema("ocpi.2_2_1.hubclientinfo.response", ocpiSuccessResponse(ClientInfoV221)); saveSchema("ocpi.2_2_1.hubclientinfos", ocpiSuccessResponse(ClientInfosV221)); +/* Hub Client Info 2.3 */ +saveSchema("ocpi.2_3.hubclientinfo", ClientInfoV23); +saveSchema("ocpi.2_3.hubclientinfo.response", ocpiSuccessResponse(ClientInfoV23)); +saveSchema("ocpi.2_3.hubclientinfos", ocpiSuccessResponse(ClientInfosV23)); + /* Tariffs */ saveSchema("ocpi.2_1_1.tariffs", Tariffs); saveSchema("ocpi.2_1_1.tariffs.response", ocpiSuccessResponse(Tariffs)); @@ -307,6 +421,13 @@ saveSchema("ocpi.2_2_1.tariff", TariffV221); saveSchema("ocpi.2_2_1.tariff.partial", ocpiDeepPartial(TariffV221)); saveSchema("ocpi.2_2_1.tariff.response", ocpiSuccessResponse(TariffV221)); +/* Tariffs 2.3 */ +saveSchema("ocpi.2_3.tariffs", TariffsV23); +saveSchema("ocpi.2_3.tariffs.response", ocpiSuccessResponse(TariffsV23)); +saveSchema("ocpi.2_3.tariff", TariffV23); +saveSchema("ocpi.2_3.tariff.partial", ocpiDeepPartial(TariffV23)); +saveSchema("ocpi.2_3.tariff.response", ocpiSuccessResponse(TariffV23)); + /* Tokens */ saveSchema("ocpi.2_1_1.tokens", Tokens); saveSchema("ocpi.2_1_1.tokens.response", ocpiSuccessResponse(Tokens)); @@ -321,13 +442,21 @@ saveSchema("ocpi.2_2.token", TokenV22); saveSchema("ocpi.2_2.token.partial", ocpiDeepPartial(TokenV22)); saveSchema("ocpi.2_2.token.response", ocpiSuccessResponse(TokenV22)); -/* Tokens 2.2 */ +/* Tokens 2.2.1 */ saveSchema("ocpi.2_2_1.tokens", TokensV221); saveSchema("ocpi.2_2_1.tokens.response", ocpiSuccessResponse(TokensV221)); saveSchema("ocpi.2_2_1.token", TokenV221); saveSchema("ocpi.2_2_1.token.partial", ocpiDeepPartial(TokenV221)); saveSchema("ocpi.2_2_1.token.response", ocpiSuccessResponse(TokenV221)); + +/* Tokens 2.3 */ +saveSchema("ocpi.2_3.tokens", TokensV23); +saveSchema("ocpi.2_3.tokens.response", ocpiSuccessResponse(TokensV23)); +saveSchema("ocpi.2_3.token", TokenV23); +saveSchema("ocpi.2_3.token.partial", ocpiDeepPartial(TokenV23)); +saveSchema("ocpi.2_3.token.response", ocpiSuccessResponse(TokenV23)); + /* Commands */ saveSchema("ocpi.2_1_1.commands.reserve_now.request", ReserveNowCommand); saveSchema("ocpi.2_1_1.commands.start_session.request", StartSessionCommand); @@ -359,5 +488,30 @@ saveSchema("ocpi.2_2_1.commands.unlock_connector.request", UnlockConnectorComman saveSchema("ocpi.2_2_1.commands.response", ocpiSuccessResponse(CommandResponseV221)); saveSchema("ocpi.2_2_1.commands.result", CommandResultV221); +/* Commands 2.3 */ +saveSchema("ocpi.2_3.commands.reserve_now.request", ReserveNowCommandV23); +saveSchema("ocpi.2_3.commands.cancel_reservation.request", CancelReservationCommandV23); +saveSchema("ocpi.2_3.commands.start_session.request", StartSessionCommandV23); +saveSchema("ocpi.2_3.commands.stop_session.request", StopSessionCommandV23); +saveSchema("ocpi.2_3.commands.unlock_connector.request", UnlockConnectorCommandV23); +saveSchema("ocpi.2_3.commands.response", ocpiSuccessResponse(CommandResponseV23)); +saveSchema("ocpi.2_3.commands.result", CommandResultV23); + +/* Payments 2.3 */ +saveSchema("ocpi.2_3.payments.terminals", TerminalsV23); +saveSchema("ocpi.2_3.payments.terminals.response", ocpiSuccessResponse(TerminalsV23)); +saveSchema("ocpi.2_3.payments.terminal", TerminalV23); +saveSchema("ocpi.2_3.payments.terminal_with_optional_id", TerminalWithOptionalIdV23); +saveSchema("ocpi.2_3.payments.terminal.partial", ocpiDeepPartial(TerminalV23)); +saveSchema("ocpi.2_3.payments.terminal.response", ocpiSuccessResponse(TerminalV23)); + +saveSchema("ocpi.2_3.payments.financial_advice_confirmations", FinancialAdviceConfirmationsV23); +saveSchema("ocpi.2_3.payments.financial_advice_confirmations.response", ocpiSuccessResponse(FinancialAdviceConfirmationsV23)); +saveSchema("ocpi.2_3.payments.financial_advice_confirmation", FinancialAdviceConfirmationV23); +saveSchema("ocpi.2_3.payments.financial_advice_confirmation.partial", ocpiDeepPartial(FinancialAdviceConfirmationV23)); +saveSchema("ocpi.2_3.payments.financial_advice_confirmation.response", ocpiSuccessResponse(FinancialAdviceConfirmationV23)); + + + /* Errors */ saveSchema("ocpi.error", OcpiErrorResponse); diff --git a/ocpi.hubclientinfo.v23.ts b/ocpi.hubclientinfo.v23.ts new file mode 100644 index 0000000..b477d02 --- /dev/null +++ b/ocpi.hubclientinfo.v23.ts @@ -0,0 +1,19 @@ +import {z} from "zod"; +import {Role} from "./ocpi.credentials.v23"; + +const ConnectionStatus = z.enum([ + "CONNECTED", + "OFFLINE", + "PLANNED", + "SUSPENDED" +]); + +export const ClientInfo = z.object({ + party_id: z.string().max(3), + country_code: z.string().length(2), + role: Role, + status: ConnectionStatus, + last_updated: z.date(), +}); + +export const ClientInfos = z.array(ClientInfo).nullish(); diff --git a/ocpi.location.v23.ts b/ocpi.location.v23.ts new file mode 100644 index 0000000..c48717a --- /dev/null +++ b/ocpi.location.v23.ts @@ -0,0 +1,344 @@ +import { z } from "zod"; +import { + BusinessDetails, + DisplayText, + Image, +} from "./ocpi.common"; +import { TokenType } from "./ocpi.common.v221"; +import { createOpenEnum } from "./ocpi.common.v23"; + +export const GeoLocation = z.object({ + latitude: z + .string() + .max(10) + .regex(/-?[0-9]{1,2}\.[0-9]{5,7}/), + longitude: z + .string() + .max(11) + .regex(/-?[0-9]{1,3}\.[0-9]{5,7}/), +}); + +export const ConnectorFormat = z.enum(["SOCKET", "CABLE"]); +export const PowerType = z.enum([ + "AC_1_PHASE", + "AC_2_PHASE", + "AC_2_PHASE_SPLIT", + "AC_3_PHASE", + "DC" +]); +export const ConnectorType = createOpenEnum([ + "CHADEMO", + "CHAOJI", + "DOMESTIC_A", + "DOMESTIC_B", + "DOMESTIC_C", + "DOMESTIC_D", + "DOMESTIC_E", + "DOMESTIC_F", + "DOMESTIC_G", + "DOMESTIC_H", + "DOMESTIC_I", + "DOMESTIC_J", + "DOMESTIC_K", + "DOMESTIC_L", + "DOMESTIC_M", + "DOMESTIC_N", + "DOMESTIC_O", + "GBT_AC", + "GBT_DC", + "IEC_60309_2_single_16", + "IEC_60309_2_three_16", + "IEC_60309_2_three_32", + "IEC_60309_2_three_64", + "IEC_62196_T1", + "IEC_62196_T1_COMBO", + "IEC_62196_T2", + "IEC_62196_T2_COMBO", + "IEC_62196_T3A", + "IEC_62196_T3C", + "MCS", + "NEMA_5_20", + "NEMA_6_30", + "NEMA_6_50", + "NEMA_10_30", + "NEMA_10_50", + "NEMA_14_30", + "NEMA_14_50", + "PANTOGRAPH_BOTTOM_UP", + "PANTOGRAPH_TOP_DOWN", + "SAE_J3400", + "TESLA_R", +]); +export const ConnectorCapability = createOpenEnum([ + "ISO_15118_2_PLUG_AND_CHARGE", + "ISO_15118_20_PLUG_AND_CHARGE", +]); + +export const Connector = z.object({ + id: z.string().max(36), + standard: ConnectorType, + format: ConnectorFormat, + power_type: PowerType, + max_voltage: z.number().int(), + max_amperage: z.number().int(), + max_electric_power: z.number().int().nullish(), + tariff_ids: z.array(z.string().max(36).nullish()).nullish(), + terms_and_conditions: z.string().url().nullish(), + capabilities: z.array(ConnectorCapability).nullish(), + last_updated: z.date(), +}); + +const EvseStatus = z.enum([ + "AVAILABLE", + "BLOCKED", + "CHARGING", + "INOPERATIVE", + "OUTOFORDER", + "PLANNED", + "REMOVED", + "RESERVED", + "UNKNOWN", +]); + +const StatusSchedule = z.object({ + period_begin: z.date(), + period_end: z.date().nullable(), + status: EvseStatus, +}); + +const Capability = createOpenEnum([ + "CHARGING_PROFILE_CAPABLE", + "CHARGING_PREFERENCES_CAPABLE", + "CHIP_CARD_SUPPORT", + "CONTACTLESS_CARD_SUPPORT", + "CREDIT_CARD_PAYABLE", + "DEBIT_CARD_PAYABLE", + "PED_TERMINAL", + "REMOTE_START_STOP_CAPABLE", + "RESERVABLE", + "RFID_READER", + "START_SESSION_CONNECTOR_REQUIRED", + "TOKEN_GROUP_CAPABLE", + "UNLOCK_CAPABLE", +]); + +const ParkingRestriction = createOpenEnum([ + "CUSTOMERS", + "DISABLED", + "EMPLOYEES", + "EV_ONLY", + "MOTORCYCLES", + "PLUGGED", + "TAXIS", +]); + +export const EvsePosition = z.enum([ + "LEFT", + "RIGHT", + "CENTER", +]); + +const EvseParking = z.object({ + parking_id: z.string().max(36), + evse_position: EvsePosition.nullish(), +}); + +export const Evse = z.object({ + uid: z.string().max(36), + evse_id: z.string().max(48).regex(/^(([A-Z]{2}\*?[A-Z0-9]{3}\*?E[A-Z0-9\*]{1,30})|(\+?[0-9]{1,3}\*[0-9]{3}\*[0-9\*]{1,32}))$/).nullish(), + status: EvseStatus, + status_schedule: z.array(StatusSchedule).nullish(), + capabilities: z.array(Capability).nullish(), + connectors: z.array(Connector).nonempty(), + floor_level: z.string().max(4).nullish(), + coordinates: GeoLocation.nullish(), + physical_reference: z.string().max(16).nullish(), + directions: z.array(DisplayText).nullish(), + parking_restrictions: z.array(ParkingRestriction).nullish(), + parking: z.array(EvseParking).nullish(), + images: z.array(Image).nullish(), + accepted_service_providers: z.array(z.string().max(50).nullish()).nullish(), + last_updated: z.date(), +}); + +const ParkingType = createOpenEnum([ + "ALONG_MOTORWAY", + "ON_STREET", + "ON_DRIVEWAY", + "PARKING_GARAGE", + "UNDERGROUND_GARAGE", + "PARKING_LOT", +]); + +const AdditionalGeoLocation = z.object({ + latitude: z + .string() + .max(10) + .regex(/-?[0-9]{1,2}\.[0-9]{5,7}/), + longitude: z + .string() + .max(11) + .regex(/-?[0-9]{1,3}\.[0-9]{5,7}/), + name: DisplayText.nullish(), +}); + +const Facility = createOpenEnum([ + "HOTEL", + "RESTAURANT", + "CAFE", + "MALL", + "SUPERMARKET", + "SPORT", + "RECREATION_AREA", + "NATURE", + "MUSEUM", + "BIKE_SHARING", + "BUS_STOP", + "TAXI_STAND", + "TRAM_STOP", + "METRO_STATION", + "TRAIN_STATION", + "AIRPORT", + "PARKING_LOT", + "CARPOOL_PARKING", + "FUEL_STATION", + "WIFI", +]); + +const ExceptionalPeriod = z.object({ + period_begin: z.date(), + period_end: z.date(), +}); + +const RegularHours = z.object({ + weekday: z.number().int().min(1).max(7), + period_begin: z + .string() + .length(5) + .regex(/([0-1][0-9]|2[0-3]):[0-5][0-9]/), + period_end: z + .string() + .length(5) + .regex(/([0-1][0-9]|2[0-3]):[0-5][0-9]/), +}); + +const Hours = z.object({ + regular_hours: z.array(RegularHours).nullish(), + twentyfourseven: z.boolean(), + exceptional_openings: z.array(ExceptionalPeriod).nullish(), + exceptional_closings: z.array(ExceptionalPeriod).nullish(), +}); + +const EnergySourceCategory = z.enum([ + "NUCLEAR", + "GENERAL_FOSSIL", + "COAL", + "GAS", + "GENERAL_GREEN", + "SOLAR", + "WIND", + "WATER", +]); + +const EnergySource = z.object({ + source: EnergySourceCategory, + percentage: z.number().min(0).max(100), +}); + +const EnvironmentalImpactCategory = createOpenEnum(["NUCLEAR_WASTE", "CARBON_DIOXIDE"]); + +const EnvironmentalImpact = z.object({ + category: EnvironmentalImpactCategory, + amount: z.number(), +}); + +export const EnergyMix = z.object({ + is_green_energy: z.boolean(), + energy_sources: z.array(EnergySource).nullish(), + environ_impact: z.array(EnvironmentalImpact).nullish(), + supplier_name: z.string().max(64).nullish(), + energy_product_name: z.string().max(64).nullish(), +}); + +export const PublishTokenType = z.object({ + uid: z.string().max(36).nullish(), + type: TokenType.nullish(), + visual_number: z.string().max(64).nullish(), + issuer: z.string().max(64).nullish(), + group_id: z.string().max(36).nullish(), +}); + +export const VehicleType = createOpenEnum([ + "MOTORCYCLE", + "PERSONAL_VEHICLE", + "PERSONAL_VEHICLE_WITH_TRAILER", + "VAN", + "SEMI_TRACTOR", + "RIGID", + "TRUCK_WITH_TRAILER", + "BUS", + "DISABLED", +]); + +export const ParkingDirection = z.enum([ + "PARALLEL", + "PERPENDICULAR", + "ANGLE", +]); + +export const Parking = z.object({ + id: z.string().max(36), + physical_reference: z.string().max(12).nullish(), + vehicle_types: z.array(VehicleType), + max_vehicle_weight: z.number().nonnegative().nullish(), + max_vehicle_height: z.number().nonnegative().nullish(), + max_vehicle_length: z.number().nonnegative().nullish(), + max_vehicle_width: z.number().nonnegative().nullish(), + parking_space_length: z.number().nonnegative().nullish(), + parking_space_width: z.number().nonnegative().nullish(), + dangerous_goods_allowed: z.boolean().nullish(), + direction: ParkingDirection.nullish(), + drive_through: z.boolean().nullish(), + restricted_to_type: z.boolean(), + reservation_required: z.boolean().nullish(), + time_limit: z.number().nonnegative().nullish(), + roofed: z.boolean().nullish(), + images: z.array(Image).nullish(), + lighting: z.boolean().nullish(), + refrigeration_outlet: z.boolean().nullish(), + standards: z.array(z.string().max(36).nullish()).nullish(), + apds_reference: z.string().nullish(), +}) + +export const Location = z.object({ + country_code: z.string().length(2), + party_id: z.string().max(3), + id: z.string().max(36), + publish: z.boolean(), + publish_allowed_to: z.array(PublishTokenType).nullish(), + name: z.string().max(255).nullish(), + address: z.string().max(45), + city: z.string().max(45), + postal_code: z.string().max(10).nullish(), + state: z.string().max(20).nullish(), + country: z.string().length(3), + coordinates: GeoLocation, + related_locations: z.array(AdditionalGeoLocation).nullish(), + parking_type: ParkingType.nullish(), + evses: z.array(Evse).nullish(), + parking_places: Parking.nullish(), + directions: z.array(DisplayText).nullish(), + operator: BusinessDetails.nullish(), + suboperator: BusinessDetails.nullish(), + owner: BusinessDetails.nullish(), + facilities: z.array(Facility).nullish(), + time_zone: z.string().max(255), + opening_times: Hours.nullish(), + charging_when_closed: z.boolean().nullish(), + images: z.array(Image).nullish(), + energy_mix: EnergyMix.nullish(), + help_phone: z.string().max(25).nullish(), + last_updated: z.date(), +}); + +export const Locations = z.array(Location); diff --git a/ocpi.sessions.v23.ts b/ocpi.sessions.v23.ts new file mode 100644 index 0000000..7d3151b --- /dev/null +++ b/ocpi.sessions.v23.ts @@ -0,0 +1,59 @@ +import {z} from "zod"; +import { AuthMethod, CdrToken } from "./ocpi.cdrs.v23"; +import { Price } from "./ocpi.common.v23"; + + +export const SessionStatus = z.enum(["ACTIVE", "COMPLETED", "INVALID", "PENDING", "RESERVATION"]); +export const ProfileType = z.enum(["CHEAP", "FAST", "GREEN", "REGULAR"]); + +const CdrDimensionType = z.enum([ + "CURRENT", + "ENERGY", + "ENERGY_EXPORT", + "ENERGY_IMPORT", + "MAX_CURRENT", + "MIN_CURRENT", + "MAX_POWER", + "MIN_POWER", + "PARKING_TIME", + "POWER", + "RESERVATION_TIME", + "RESERVATION_EXPIRES", + "RESERVATION_OVERTIME", + "STATE_OF_CHARGE", + "TIME", +]); + +export const CdrDimension = z.object({ + type: CdrDimensionType, + volume: z.number(), +}); + +export const ChargingPeriod = z.object({ + start_date_time: z.date(), + dimensions: z.array(CdrDimension).nonempty(), + tariff_id: z.string().max(36).nullish(), +}); + +export const Session = z.object({ + country_code: z.string().length(2), + party_id: z.string().max(3), + id: z.string().max(36), + start_date_time: z.date(), + end_date_time: z.date().nullish(), + kwh: z.number().nonnegative(), + cdr_token: CdrToken, + auth_method: AuthMethod, + authorization_reference: z.string().max(36).nullish(), + location_id: z.string().max(36), + evse_uid: z.string().max(36), + connector_id: z.string().max(36), + meter_id: z.string().max(255).nullish(), + currency: z.string().length(3), + charging_periods: z.array(ChargingPeriod).nullish(), + total_cost: Price.nullish(), + status: SessionStatus, + last_updated: z.date(), +}); + +export const Sessions = z.array(Session); diff --git a/ocpi.tariff.v23.ts b/ocpi.tariff.v23.ts new file mode 100644 index 0000000..63b3aba --- /dev/null +++ b/ocpi.tariff.v23.ts @@ -0,0 +1,83 @@ +import { z } from "zod"; +import { DisplayText } from "./ocpi.common"; +import { Price } from "./ocpi.common.v23"; +import { EnergyMix } from "./ocpi.location.v23"; + +const TariffDimensionType = z.enum(["ENERGY", "FLAT", "PARKING_TIME", "TIME"]); + +const PriceComponent = z.object({ + type: TariffDimensionType, + price: z.number().nonnegative(), + vat: z.number().nonnegative().nullish(), + step_size: z.number().int().nonnegative(), +}); + +const DayOfWeek = z.enum([ + "MONDAY", + "TUESDAY", + "WEDNESDAY", + "THURSDAY", + "FRIDAY", + "SATURDAY", + "SUNDAY", +]); + +const ReservationRestrictionType = z.enum([ + "RESERVATION", + "RESERVATION_EXPIRES", + "RESERVATION_CANCELLATION_FEES", + "RESERVATION_OVERTIME", +]); + +const TariffRestrictions = z.object({ + start_time: z.string().length(5).regex(/([0-1][0-9]|2[0-3]):[0-5][0-9]/).nullish(), + end_time: z.string().length(5).regex(/([0-1][0-9]|2[0-3]):[0-5][0-9]/).nullish(), + start_date: z.string().length(10).regex(/([12][0-9]{3})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])/).nullish(), + end_date: z.string().length(10).regex(/([12][0-9]{3})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])/).nullish(), + min_kwh: z.number().nonnegative().nullish(), + max_kwh: z.number().nonnegative().nullish(), + min_current: z.number().nonnegative().nullish(), + max_current: z.number().nonnegative().nullish(), + min_power: z.number().nonnegative().nullish(), + max_power: z.number().nonnegative().nullish(), + min_duration: z.number().int().nonnegative().nullish(), + max_duration: z.number().int().nonnegative().nullish(), + day_of_week: z.array(DayOfWeek).nullish(), + reservation: ReservationRestrictionType.nullish() +}); + +const TariffElement = z.object({ + price_components: z.array(PriceComponent).nonempty(), + restrictions: TariffRestrictions.nullish(), +}); + +const TariffType = z.enum([ + "AD_HOC_PAYMENT", + "PROFILE_CHEAP", + "PROFILE_FAST", + "PROFILE_GREEN", + "REGULAR" +]); + +const TaxIncluded = z.enum(["YES", "NO", "N/A"]); + +export const Tariff = z.object({ + id: z.string().max(36), + country_code: z.string().length(2), + party_id: z.string().max(3), + currency: z.string().length(3), + type: TariffType.nullish(), + tariff_alt_text: z.array(DisplayText).nullish(), + tariff_alt_url: z.string().url().nullish(), + min_price: Price.nullish(), + max_price: Price.nullish(), + preauthorize_amount: z.number().nullish(), + elements: z.array(TariffElement).nonempty(), + tax_included: TaxIncluded, + start_date_time: z.date().nullish(), + end_date_time: z.date().nullish(), + energy_mix: EnergyMix.nullish(), + last_updated: z.date(), +}); + +export const Tariffs = z.array(Tariff); diff --git a/ocpi.terminal.v23.ts b/ocpi.terminal.v23.ts new file mode 100644 index 0000000..21dd6de --- /dev/null +++ b/ocpi.terminal.v23.ts @@ -0,0 +1,30 @@ +import { z } from "zod"; +import { GeoLocation } from "./ocpi.location.v23"; + +export const InvoiceCreator = z.enum(["CPO", "PTP"]); + +export const Terminal = z.object({ + terminal_id: z.string().max(36), + customer_reference: z.string().max(36).nullish(), + party_id: z.string().max(3).nullish(), + country_code: z.string().max(2).nullish(), + address: z.string().max(45).nullish(), + city: z.string().max(45).nullish(), + postal_code: z.string().max(10).nullish(), + state: z.string().max(20).nullish(), + country: z.string().max(3).nullish(), + coordinates: GeoLocation.nullish(), + invoice_base_url: z.string().url().nullish(), + invoice_creator: InvoiceCreator.nullish(), + reference: z.string().max(36).nullish(), + location_ids: z.array(z.string().max(36).nullish()).nullish(), + evse_uids: z.array(z.string().max(36).nullish()).nullish(), + last_updated: z.date(), +}); + +// https://github.com/ocpi/ocpi/blob/release-2.3.0-bugfixes/mod_payments.asciidoc#request-body-1 +export const TerminalWithOptionalId = Terminal.extend({ + terminal_id: z.string().max(36).nullish(), +}); + +export const Terminals = z.array(Terminal); diff --git a/ocpi.tokens.v23.ts b/ocpi.tokens.v23.ts new file mode 100644 index 0000000..dba1e59 --- /dev/null +++ b/ocpi.tokens.v23.ts @@ -0,0 +1,34 @@ +import {z} from "zod"; +import { TokenType } from "./ocpi.common.v23"; +import { ProfileType } from "./ocpi.sessions.v23"; + +const WhitelistType = z.enum(["ALWAYS", "ALLOWED", "ALLOWED_OFFLINE", "NEVER"]); + +const EnergyContract = z.object({ + supplier_name: z.string().max(64), + contract_id: z.string().max(64).nullish(), +}); + +export const LocationReferences = z.object({ + location_id: z.string().max(36).nullish(), + evse_uids: z.array(z.string().max(36)).nullish(), +}); + +export const Token = z.object({ + country_code: z.string().length(2), + party_id: z.string().max(3), + uid: z.string().max(36), + type: TokenType, + contract_id: z.string().max(36), + visual_number: z.string().max(64).nullish(), + issuer: z.string().max(64), + group_id: z.string().max(36).nullish(), + valid: z.boolean(), + whitelist: WhitelistType, + language: z.string().length(2).nullish(), + default_profile_type: ProfileType.nullish(), + energy_contract: EnergyContract.nullish(), + last_updated: z.date(), +}); + +export const Tokens = z.array(Token); \ No newline at end of file diff --git a/ocpi.versions.v23.ts b/ocpi.versions.v23.ts new file mode 100644 index 0000000..14b543d --- /dev/null +++ b/ocpi.versions.v23.ts @@ -0,0 +1,40 @@ +import { z } from "zod"; +import { createOpenEnum } from "./ocpi.common.v23"; + +const OcpiVersionNumber = createOpenEnum(["2.0", "2.1", "2.1.1", "2.2", "2.2.1" ,"2.3"]); + +export const OcpiVersion = z.object({ + version: OcpiVersionNumber, + url: z.string().url(), +}); + +export const OcpiVersions = z.array(OcpiVersion); + +export const OcpiModuleId = createOpenEnum([ + "cdrs", + "chargingprofiles", + "commands", + "credentials", + "hubclientinfo", + "locations", + "sessions", + "tariffs", + "tokens", +]); + + +export const OcpiInterfaceRole= z.enum([ + "SENDER", + "RECEIVER", +]); + +const OcpiEndpoint = z.object({ + identifier: OcpiModuleId, + role: OcpiInterfaceRole, + url: z.string().url(), +}); + +export const OcpiVersionDetails = z.object({ + version: OcpiVersionNumber, + endpoints: z.array(OcpiEndpoint).nonempty(), +});