-
Notifications
You must be signed in to change notification settings - Fork 324
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow to provide JSON schemas manually
The OCA doesn't allow to share the JSON schemas for OCPP 2.1 outside it's members. Thus this library can't include these schemas. This commit introduces the `SchemaValidator`: a structure that loads schemas located at inprovide folder and validates payload against those schemas. The file names of the schema must follow the format '<action>Request' or '<action>Response'. E.g.: "HeartbeatRequest" or "BootNotificationResponse". The file names for the schemas of OCPP 1.6 and OCPP 2.0 have been adjusted to follow this pattern. Users relying on `ocpp.v16`, `ocpp.v20` or `ocpp.v201` shouldn't be affected by introduction of `SchemaValidator`. These modules create a default instance of `Validator` to include the right set of schemas. Users of `ocpp.v21` can create a custom validator and pass it to the construct of `ocpp.v21.ChargePoint`. See also the two examples in `examples/v21/`. Fixes: #453
- Loading branch information
Showing
194 changed files
with
3,719 additions
and
280 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import asyncio | ||
import logging | ||
import pathlib | ||
from datetime import datetime, timezone | ||
|
||
try: | ||
import websockets | ||
except ModuleNotFoundError: | ||
print("This example relies on the 'websockets' package.") | ||
print("Please install it by running: ") | ||
print() | ||
print(" $ pip install websockets") | ||
import sys | ||
|
||
sys.exit(1) | ||
|
||
from ocpp.messages import SchemaValidator | ||
from ocpp.routing import on | ||
from ocpp.v21 import ChargePoint as cp | ||
from ocpp.v21 import call_result | ||
from ocpp.v21.enums import RegistrationStatus | ||
|
||
logging.basicConfig(level=logging.INFO) | ||
|
||
# The ocpp package doesn't come with the JSON schemas for OCPP 2.1. | ||
# See https://github.com/mobilityhouse/ocpp/issues/458 for more details. | ||
schemas_dir = str(pathlib.Path(__file__).parent.joinpath("schemas").resolve()) | ||
validator = SchemaValidator(schemas_dir) | ||
|
||
|
||
class ChargePoint(cp): | ||
@on("BootNotification") | ||
def on_boot_notification(self, reason: str, charging_station: str, **kwargs): | ||
return call_result.BootNotification( | ||
current_time=datetime.now(timezone.utc).isoformat(), | ||
interval=10, | ||
status=RegistrationStatus.accepted, | ||
) | ||
|
||
|
||
async def on_connect(websocket, path): | ||
charge_point_id = path.strip("/") | ||
cp = ChargePoint(charge_point_id, websocket, validator) | ||
|
||
await cp.start() | ||
|
||
|
||
async def main(): | ||
server = await websockets.serve( | ||
on_connect, "0.0.0.0", 9000, subprotocols=["ocpp2.1"] | ||
) | ||
|
||
logging.info("Server Started listening to new connections...") | ||
await server.wait_closed() | ||
|
||
|
||
if __name__ == "__main__": | ||
asyncio.run(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import asyncio | ||
import logging | ||
import pathlib | ||
|
||
try: | ||
import websockets | ||
except ModuleNotFoundError: | ||
print("This example relies on the 'websockets' package.") | ||
print("Please install it by running: ") | ||
print() | ||
print(" $ pip install websockets") | ||
import sys | ||
|
||
sys.exit(1) | ||
|
||
from ocpp.messages import SchemaValidator | ||
from ocpp.v21 import ChargePoint as cp | ||
from ocpp.v21 import call, call_result | ||
from ocpp.v21.datatypes import ChargingStation | ||
from ocpp.v21.enums import BootReason, RegistrationStatus | ||
|
||
logging.basicConfig(level=logging.INFO) | ||
|
||
schemas_dir = pathlib.Path(__file__).parent.joinpath("schemas").resolve() | ||
validator = SchemaValidator(str(schemas_dir)) | ||
|
||
|
||
class ChargePoint(cp): | ||
async def send_boot_notification(self): | ||
request = call.BootNotification( | ||
reason=BootReason.power_up, | ||
charging_station=ChargingStation( | ||
model="Virtual Charge Point", | ||
vendor_name="y", | ||
), | ||
) | ||
|
||
response: call_result.BootNotification = await self.call(request) | ||
|
||
if response.status == RegistrationStatus.accepted: | ||
print("Connected to central system.") | ||
|
||
|
||
async def main(): | ||
async with websockets.connect( | ||
"ws://localhost:9000/CP_1", subprotocols=["ocpp2.1"] | ||
) as ws: | ||
cp = ChargePoint("CP_1", ws, validator) | ||
|
||
await asyncio.gather(cp.start(), cp.send_boot_notification()) | ||
|
||
|
||
if __name__ == "__main__": | ||
asyncio.run(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
{ | ||
"$schema": "http://json-schema.org/draft-06/schema#", | ||
"$id": "urn:OCPP:Cp:2:2023:5:BootNotificationRequest", | ||
"comment": "OCPP 2.1 Draft 1, Copyright Open Charge Alliance", | ||
"definitions": { | ||
"CustomDataType": { | ||
"description": "This class does not get 'AdditionalProperties = false' in the schema generation, so it can be extended with arbitrary JSON properties to allow adding custom data.", | ||
"javaType": "CustomData", | ||
"type": "object", | ||
"properties": { | ||
"vendorId": { | ||
"type": "string", | ||
"maxLength": 255 | ||
} | ||
}, | ||
"required": [ | ||
"vendorId" | ||
] | ||
}, | ||
"BootReasonEnumType": { | ||
"javaType": "BootReasonEnum", | ||
"type": "string", | ||
"additionalProperties": false, | ||
"enum": [ | ||
"ApplicationReset", | ||
"FirmwareUpdate", | ||
"LocalReset", | ||
"PowerUp", | ||
"RemoteReset", | ||
"ScheduledReset", | ||
"Triggered", | ||
"Unknown", | ||
"Watchdog" | ||
] | ||
}, | ||
"ChargingStationType": { | ||
"javaType": "ChargingStation", | ||
"type": "object", | ||
"additionalProperties": false, | ||
"properties": { | ||
"customData": { | ||
"$ref": "#/definitions/CustomDataType" | ||
}, | ||
"serialNumber": { | ||
"type": "string", | ||
"maxLength": 25 | ||
}, | ||
"model": { | ||
"type": "string", | ||
"maxLength": 20 | ||
}, | ||
"modem": { | ||
"$ref": "#/definitions/ModemType" | ||
}, | ||
"vendorName": { | ||
"type": "string", | ||
"maxLength": 50 | ||
}, | ||
"firmwareVersion": { | ||
"type": "string", | ||
"maxLength": 50 | ||
} | ||
}, | ||
"required": [ | ||
"model", | ||
"vendorName" | ||
] | ||
}, | ||
"ModemType": { | ||
"javaType": "Modem", | ||
"type": "object", | ||
"additionalProperties": false, | ||
"properties": { | ||
"customData": { | ||
"$ref": "#/definitions/CustomDataType" | ||
}, | ||
"iccid": { | ||
"type": "string", | ||
"maxLength": 20 | ||
}, | ||
"imsi": { | ||
"type": "string", | ||
"maxLength": 20 | ||
} | ||
} | ||
} | ||
}, | ||
"type": "object", | ||
"additionalProperties": false, | ||
"properties": { | ||
"customData": { | ||
"$ref": "#/definitions/CustomDataType" | ||
}, | ||
"chargingStation": { | ||
"$ref": "#/definitions/ChargingStationType" | ||
}, | ||
"reason": { | ||
"$ref": "#/definitions/BootReasonEnumType" | ||
} | ||
}, | ||
"required": [ | ||
"reason", | ||
"chargingStation" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
{ | ||
"$schema": "http://json-schema.org/draft-06/schema#", | ||
"$id": "urn:OCPP:Cp:2:2023:5:BootNotificationResponse", | ||
"comment": "OCPP 2.1 Draft 1, Copyright Open Charge Alliance", | ||
"definitions": { | ||
"CustomDataType": { | ||
"description": "This class does not get 'AdditionalProperties = false' in the schema generation, so it can be extended with arbitrary JSON properties to allow adding custom data.", | ||
"javaType": "CustomData", | ||
"type": "object", | ||
"properties": { | ||
"vendorId": { | ||
"type": "string", | ||
"maxLength": 255 | ||
} | ||
}, | ||
"required": [ | ||
"vendorId" | ||
] | ||
}, | ||
"RegistrationStatusEnumType": { | ||
"javaType": "RegistrationStatusEnum", | ||
"type": "string", | ||
"additionalProperties": false, | ||
"enum": [ | ||
"Accepted", | ||
"Pending", | ||
"Rejected" | ||
] | ||
}, | ||
"StatusInfoType": { | ||
"javaType": "StatusInfo", | ||
"type": "object", | ||
"additionalProperties": false, | ||
"properties": { | ||
"customData": { | ||
"$ref": "#/definitions/CustomDataType" | ||
}, | ||
"reasonCode": { | ||
"type": "string", | ||
"maxLength": 20 | ||
}, | ||
"additionalInfo": { | ||
"type": "string", | ||
"maxLength": 512 | ||
} | ||
}, | ||
"required": [ | ||
"reasonCode" | ||
] | ||
} | ||
}, | ||
"type": "object", | ||
"additionalProperties": false, | ||
"properties": { | ||
"customData": { | ||
"$ref": "#/definitions/CustomDataType" | ||
}, | ||
"currentTime": { | ||
"type": "string", | ||
"format": "date-time" | ||
}, | ||
"interval": { | ||
"type": "integer", | ||
"minimum": -2147483648.0, | ||
"maximum": 2147483647.0 | ||
}, | ||
"status": { | ||
"$ref": "#/definitions/RegistrationStatusEnumType" | ||
}, | ||
"statusInfo": { | ||
"$ref": "#/definitions/StatusInfoType" | ||
} | ||
}, | ||
"required": [ | ||
"currentTime", | ||
"interval", | ||
"status" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.