Skip to content

Commit

Permalink
Merge branch 'master' into Type-of-v16.datatypes.SampledValue.context…
Browse files Browse the repository at this point in the history
…-is-incorrect-#421
  • Loading branch information
OrangeTux authored Jan 15, 2024
2 parents e327de8 + a9df8eb commit 342dd71
Show file tree
Hide file tree
Showing 20 changed files with 1,582 additions and 34 deletions.
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,36 @@

- [#421](https://github.com/mobilityhouse/ocpp/issues/421) Type of v16.datatypes.SampledValue.context is incorrect

## 0.25.0 (2024-01-08)

- [#366](https://github.com/mobilityhouse/ocpp/issues/366) Fix type hint of OCPP 1.6 ChangeConfiguration.value
- [#431](https://github.com/mobilityhouse/ocpp/issues/431) Attributes with 'v2x' are serialized as 'V2x', but should be serialized as 'V2X'
- [#554](https://github.com/mobilityhouse/ocpp/issues/554) OCPP 2.0.1 Edition 2 Errata 2023-12 document added
- [#548](https://github.com/mobilityhouse/ocpp/issues/548) OCPP 2.0.1 MessageInfoType attribute name correction
- [#300](https://github.com/mobilityhouse/ocpp/issues/300) OCPP 2.0.1 add reference components and variables
- [#518](https://github.com/mobilityhouse/ocpp/issues/518) OCPP 2.0.1 add additional reason codes from v1.3

## 0.24.0 (2023-12-07)

- [#539](https://github.com/mobilityhouse/ocpp/issues/539) feat: Add ChargePoint._handle_call return value. Thanks [@wafa-yah](https://github.com/wafa-yah)
- [#266](https://github.com/mobilityhouse/ocpp/issues/266) fix: Central System documentation link.
- [#516](https://github.com/mobilityhouse/ocpp/issues/516) OCPP 2.0.1 add additional security events from v1.3.
- [#537](https://github.com/mobilityhouse/ocpp/pull/537) Fix DataTransfer data types. Thanks [@mdwcrft](https://github.com/mdwcrft)

## 0.23.0 (2023-11-30)

- [#531] Feat: Add 1.6 security extension datatypes. Thanks [@proelke](https://github.com/proelke)
- [#528](https://github.com/mobilityhouse/ocpp/issues/528) v2.0.1 CertificateHashDataChainType childCertificateHashData requires the default of None.
- [#510](https://github.com/mobilityhouse/ocpp/issues/510) v2.0.1 UnitOfMeasureType - Enums missing and update docstring to allow use for variableCharacteristics.
- [#508](https://github.com/mobilityhouse/ocpp/issues/508) Exception - OccurrenceConstraintViolationError doc string correction.

## 0.22.0 (2023-11-03)

- [#493](https://github.com/mobilityhouse/ocpp/issues/493) Reduce use of NotSupportedError in favor of NotImplementedError. Thanks [drc38](@https://github.com/drc38).
- [#278](https://github.com/mobilityhouse/ocpp/pull/278) Fix types for attributes of OCPP 1.6's type `IdTagInfo`. Thanks [@chan-vince](https://github.com/chan-vince)
- [#504](https://github.com/mobilityhouse/ocpp/pull/504) Add missing tech_info attribute to v2.0.1 EventDataType. Thanks [@LokiHokie](https://github.com/LokiHokie)
- [#381](https://github.com/mobilityhouse/ocpp/issues/381) Add FormationError and OccurrenceConstraintViolationError.

## 0.21.0 (2023-10-19)

- [#492] Minor fixes _handle_call doc string - Thanks @drc38
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Central system

The code snippet below creates a simple OCPP 2.0 central system which is able
to handle BootNotification calls. You can find a detailed explanation of the
code in the `Central System documentation_`.
code in the `Central System documentation`_.


.. code-block:: python
Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
author = "Auke Willem Oosterhoff"

# The full version, including alpha/beta/rc tags
release = "0.21.0"
release = "0.25.0"


# -- General configuration ---------------------------------------------------
Expand Down
Binary file added docs/v201/OCPP-2.0.1_edition2_errata_2023-12.pdf
Binary file not shown.
2 changes: 0 additions & 2 deletions examples/v201/central_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ async def on_connect(websocket, path):
try:
requested_protocols = websocket.request_headers["Sec-WebSocket-Protocol"]
except KeyError:
logging.info("Client hasn't requested any Subprotocol. " "Closing Connection")
return await websocket.close()
logging.error("Client hasn't requested any Subprotocol. Closing Connection")
return await websocket.close()
if websocket.subprotocol:
Expand Down
51 changes: 42 additions & 9 deletions ocpp/charge_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from dataclasses import asdict
from typing import Dict, List, Union

from ocpp.exceptions import NotSupportedError, OCPPError
from ocpp.exceptions import NotImplementedError, NotSupportedError, OCPPError
from ocpp.messages import Call, MessageType, unpack, validate_payload
from ocpp.routing import create_route_map

Expand Down Expand Up @@ -44,7 +44,7 @@ def camel_to_snake_case(data):

def snake_to_camel_case(data):
"""
Convert all keys of a all dictionaries inside given argument from
Convert all keys of all dictionaries inside given argument from
snake_case to camelCase.
Inspired by: https://stackoverflow.com/a/19053800/1073222
Expand All @@ -53,6 +53,7 @@ def snake_to_camel_case(data):
camel_case_dict = {}
for key, value in data.items():
key = key.replace("soc", "SoC")
key = key.replace("_v2x", "V2X")
components = key.split("_")
key = components[0] + "".join(x[:1].upper() + x[1:] for x in components[1:])
camel_case_dict[key] = snake_to_camel_case(value)
Expand All @@ -79,6 +80,39 @@ def remove_nones(data: Union[List, Dict]) -> Union[List, Dict]:
return data


def _raise_key_error(action, version):
"""
Checks whether a keyerror returned by _handle_call
is supported by the OCPP version or is simply
not implemented by the server/client and raises
the appropriate error.
"""

from ocpp.v16.enums import Action as v16_Action
from ocpp.v201.enums import Action as v201_Action

if version == "1.6":
if hasattr(v16_Action, action):
raise NotImplementedError(
details={"cause": f"No handler for {action} registered."}
)
else:
raise NotSupportedError(
details={"cause": f"{action} not supported by OCPP{version}."}
)
elif version in ["2.0", "2.0.1"]:
if hasattr(v201_Action, action):
raise NotImplementedError(
details={"cause": f"No handler for {action} registered."}
)
else:
raise NotSupportedError(
details={"cause": f"{action} not supported by OCPP{version}."}
)

return


class ChargePoint:
"""
Base Element containing all the necessary OCPP1.6J messages for messages
Expand Down Expand Up @@ -165,17 +199,17 @@ async def _handle_call(self, msg):
First the '_on_action' hook is executed and its response is returned to
the client. If there is no '_on_action' hook for Action in the message
a CallError with a NotSupportedError is returned.
a CallError with a NotImplementedError is returned. If the Action is
not supported by the OCPP version a NotSupportedError is returned.
Next the '_after_action' hook is executed.
"""
try:
handlers = self.route_map[msg.action]
except KeyError:
raise NotSupportedError(
details={"cause": f"No handler for {msg.action} registered."}
)
_raise_key_error(msg.action, self._ocpp_version)
return

if not handlers.get("_skip_schema_validation", False):
validate_payload(msg, self._ocpp_version)
Expand All @@ -190,9 +224,7 @@ async def _handle_call(self, msg):
try:
handler = handlers["_on_action"]
except KeyError:
raise NotSupportedError(
details={"cause": f"No handler for {msg.action} registered."}
)
_raise_key_error(msg.action, self._ocpp_version)

try:
response = handler(**snake_case_payload)
Expand Down Expand Up @@ -236,6 +268,7 @@ async def _handle_call(self, msg):
# '_on_after' hooks are not required. Therefore ignore exception
# when no '_on_after' hook is installed.
pass
return response

async def call(self, payload, suppress=True, unique_id=None):
"""
Expand Down
51 changes: 47 additions & 4 deletions ocpp/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ def __str__(self):

class NotImplementedError(OCPPError):
code = "NotImplemented"
default_description = "Requested Action is not known by receiver"
default_description = (
"Request Action is recognized but not supported by the receiver"
)


class NotSupportedError(OCPPError):
code = "NotSupported"
default_description = (
"Request Action is recognized but not supported by " "the receiver"
)
default_description = "Requested Action is not known by receiver"


class InternalError(OCPPError):
Expand All @@ -68,12 +68,31 @@ class SecurityError(OCPPError):


class FormatViolationError(OCPPError):
"""
Not strict OCPP 1.6 - see FormationViolationError
Valid OCPP 2.0.1
"""

code = "FormatViolation"
default_description = (
"Payload for Action is syntactically incorrect or " "structure for Action"
)


class FormationViolationError(OCPPError):
"""
To allow for strict OCPP 1.6 compliance
5. Known issues that will not be fixed
5.2. Page 14, par 4.2.3. CallError: incorrect name in enum: FormationViolation
Incorrect name in enum: FormationViolation
"""

code = "FormationViolation"
default_description = (
"Payload for Action is syntactically incorrect or structure for Action"
)


class PropertyConstraintViolationError(OCPPError):
code = "PropertyConstraintViolation"
default_description = (
Expand All @@ -83,6 +102,15 @@ class PropertyConstraintViolationError(OCPPError):


class OccurenceConstraintViolationError(OCPPError):
"""
To allow for strict OCPP 1.6 compliance
ocpp-j-1.6-errata-sheet.pdf
5. Known issues that will not be fixed
5.1. Page 14, par 4.2.3: CallError: Typo in enum
Typo in enum: OccurenceConstraintViolation
Valid in 2.0.1
"""

code = "OccurenceConstraintViolation"
default_description = (
"Payload for Action is syntactically correct but "
Expand All @@ -91,6 +119,21 @@ class OccurenceConstraintViolationError(OCPPError):
)


class OccurrenceConstraintViolationError(OCPPError):
"""
Not strict OCPP 1.6 - see OccurenceConstraintViolationError
Not valid OCPP 2.0.1
Valid in OCPP 2.1
"""

code = "OccurrenceConstraintViolation"
default_description = (
"Payload for Action is syntactically correct but "
"at least one of the fields violates occurence "
"constraints"
)


class TypeConstraintViolationError(OCPPError):
code = "TypeConstraintViolation"
default_description = (
Expand Down
4 changes: 2 additions & 2 deletions ocpp/v16/call.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional
from typing import Dict, List, Optional

from ocpp.v16.enums import (
AvailabilityType,
Expand Down Expand Up @@ -55,7 +55,7 @@ class ChangeAvailabilityPayload:
@dataclass
class ChangeConfigurationPayload:
key: str
value: Any
value: str


@dataclass
Expand Down
7 changes: 4 additions & 3 deletions ocpp/v16/call_result.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from dataclasses import dataclass
from typing import Dict, List, Optional

from ocpp.v16.datatypes import IdTagInfo
from ocpp.v16.enums import (
AvailabilityStatus,
CancelReservationStatus,
Expand Down Expand Up @@ -46,7 +47,7 @@

@dataclass
class AuthorizePayload:
id_tag_info: Dict
id_tag_info: IdTagInfo


@dataclass
Expand Down Expand Up @@ -94,7 +95,7 @@ class MeterValuesPayload:
@dataclass
class StartTransactionPayload:
transaction_id: int
id_tag_info: Dict
id_tag_info: IdTagInfo


@dataclass
Expand All @@ -104,7 +105,7 @@ class StatusNotificationPayload:

@dataclass
class StopTransactionPayload:
id_tag_info: Optional[Dict] = None
id_tag_info: Optional[IdTagInfo] = None


# The CALLRESULT messages that flow from Charge Point to Central System are
Expand Down
43 changes: 43 additions & 0 deletions ocpp/v16/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
ChargingProfilePurposeType,
ChargingRateUnitType,
CiStringType,
HashAlgorithm,
Location,
Measurand,
Phase,
Expand Down Expand Up @@ -121,3 +122,45 @@ class MeterValue:

timestamp: str
sampled_value: List[SampledValue]


# Security Extension


@dataclass
class CertificateHashData:
"""
CertificateHashDataType is used by:
DeleteCertificate.req, GetInstalledCertificateIds.conf
"""

hash_algorithm: HashAlgorithm
issuer_name_hash: str
issuer_key_hash: str
serial_number: str


@dataclass
class Firmware:
"""
Represents a copy of the firmware that can be loaded/updated on the Charge Point.
FirmwareType is used by: SignedUpdateFirmware.req
"""

location: str
retrieve_date_time: str
signing_certificate: str
install_date_time: Optional[str] = None
signature: Optional[str] = None


@dataclass
class LogParameters:
"""
Class for detailed information the retrieval of logging entries.
LogParametersType is used by: GetLog.req
"""

remote_location: str
oldest_timestamp: Optional[str] = None
latest_timestamp: Optional[str] = None
2 changes: 1 addition & 1 deletion ocpp/v201/call.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class CustomerInformationPayload:
class DataTransferPayload:
vendor_id: str
message_id: Optional[str] = None
data: Optional[str] = None
data: Optional[Any] = None
custom_data: Optional[Dict[str, Any]] = None


Expand Down
2 changes: 1 addition & 1 deletion ocpp/v201/call_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class CustomerInformationPayload:
class DataTransferPayload:
status: str
status_info: Optional[Dict] = None
data: Optional[Dict] = None
data: Optional[Any] = None
custom_data: Optional[Dict[str, Any]] = None


Expand Down
Loading

0 comments on commit 342dd71

Please sign in to comment.