Skip to content

Commit

Permalink
Merge branch 'master' into handle_responder_url
Browse files Browse the repository at this point in the history
  • Loading branch information
proelke authored Nov 14, 2023
2 parents 9575291 + 7e14b16 commit 331c02d
Show file tree
Hide file tree
Showing 24 changed files with 570 additions and 192 deletions.
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# Change log


- [#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
- [#485](https://github.com/mobilityhouse/ocpp/issues/485) Update documents for 2.0.1 to lastest; removed 2.0 docs
- [#412](https://github.com/mobilityhouse/ocpp/issues/412) Add default value to 1.6 AuthorizationData datatype, id_tag_info
- [#141](https://github.com/mobilityhouse/ocpp/issues/141) Add to docs OCPP 1.6 Security White Paper Ed 2

## 0.20.0 (2023-10-10)

- [#471](https://github.com/mobilityhouse/ocpp/issues/471) Fix `ImportError` when using jsonschema 4.19.0 or higher.
- Fix import error in v201 example. Thanks [@Shiwei-Shen](https://github.com/Shiwei-Shen)!
- Update Poetry to 1.5.1 in CI.

## 0.19.0 (2023-04-26)

- [#438] feat: add optional param for passing an unique_id to call method. Thanks [@santiagosalamandri](https://github.com/santiagosalamandri)
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.18.0"
release = "0.22.0"


# -- General configuration ---------------------------------------------------
Expand Down
Binary file not shown.
Binary file not shown.
Binary file added docs/v201/OCPP-2.0.1_part2_errata_v20.pdf
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added docs/v201/OCPP-2.0.1_part6_test_cases.pdf
Binary file not shown.
Binary file removed docs/v201/OCPP-2.0_part1_errata.pdf
Binary file not shown.
Binary file removed docs/v201/OCPP-2.0_part2_errata.pdf
Binary file not shown.
Binary file removed docs/v201/OCPP-2.0_part4_errata.pdf
Binary file not shown.
47 changes: 39 additions & 8 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 @@ -85,6 +85,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 @@ -173,17 +206,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 NotImplemtendError 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 @@ -198,9 +231,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
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
12 changes: 6 additions & 6 deletions ocpp/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from typing import Callable, Dict, Union

from jsonschema import Draft4Validator
from jsonschema import _validators as SchemaValidators
from jsonschema.exceptions import ValidationError as SchemaValidationError

from ocpp.exceptions import (
Expand Down Expand Up @@ -226,16 +225,17 @@ def validate_payload(message: Union[Call, CallResult], ocpp_version: str) -> Non
try:
validator.validate(message.payload)
except SchemaValidationError as e:
if e.validator == SchemaValidators.type.__name__:
if e.validator == "type":
raise TypeConstraintViolationError(
details={"cause": e.message, "ocpp_message": message}
)
elif e.validator == SchemaValidators.additionalProperties.__name__:
elif e.validator == "additionalProperties":
raise FormatViolationError(
details={"cause": e.message, "ocpp_message": message}
)
elif e.validator == SchemaValidators.required.__name__:
elif e.validator == "required":
raise ProtocolError(details={"cause": e.message})

elif e.validator == "maxLength":
raise TypeConstraintViolationError(
details={"cause": e.message, "ocpp_message": message}
Expand Down Expand Up @@ -437,8 +437,8 @@ def to_exception(self):
)

raise UnknownCallErrorCodeError(
"Error code '%s' is not defined by the" " OCPP specification",
self.error_code,
f"Error code '{self.error_code}' is not defined by the"
" OCPP specification"
)

def __repr__(self):
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
2 changes: 1 addition & 1 deletion ocpp/v16/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class AuthorizationData:
"""

id_tag: str
id_tag_info: Optional[IdTagInfo]
id_tag_info: Optional[IdTagInfo] = None


@dataclass
Expand Down
1 change: 1 addition & 0 deletions ocpp/v201/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ class EventDataType:
variable: VariableType
cause: Optional[int] = None
tech_code: Optional[str] = None
tech_info: Optional[str] = None
cleared: Optional[bool] = None
transaction_id: Optional[str] = None
variable_monitoring_id: Optional[int] = None
Expand Down
3 changes: 2 additions & 1 deletion ocpp/v201/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -1244,7 +1244,8 @@ class UnitOfMeasureType(str, Enum):
"""
Allowable values of the optional "unit" field of a Value element, as used
in MeterValues.req and StopTransaction.req messages. Default value of
"unit" is always "Wh".
"unit" is always "Wh". Also used in component/variables -
specifically the unit in variableCharacteristics.
"""

asu = "ASU"
Expand Down
Loading

0 comments on commit 331c02d

Please sign in to comment.