Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def test_validate_set_charging_profile_payload():
"""" Test if payloads with floats are validated correctly.
This test uses the value of 21.4, which is internally represented as
21.39999999999999857891452847979962825775146484375.
You can verify this using `decimal.Decimal(21.4)`
"""
message = Call(
unique_id="1234",
action="SetChargingProfile",
payload={
'connectorId': 1,
'csChargingProfiles': {
'chargingProfileId': 1,
'stackLevel': 0,
'chargingProfilePurpose': 'TxProfile',
'chargingProfileKind': 'Relative',
'chargingSchedule': {
'chargingRateUnit': 'A',
'chargingSchedulePeriod': [{
'startPeriod': 0,
'limit': 21.4
}]
},
def validate_payload(message, ocpp_version):
""" Validate the payload of the message using JSON schemas. """
if type(message) not in [Call, CallResult]:
raise ValidationError("Payload can't be validated because message "
f"type. It's '{type(message)}', but it should "
"be either 'Call' or 'CallResult'.")
try:
# 3 OCPP 1.6 schedules have fields of type floats. The JSON schema
# defines a certain precision for these fields of 1 decimal. A value of
# 21.4 is valid, whereas a value if 4.11 is not.
#
# The problem is that Python's internal representation of 21.4 might
# have more than 1 decimal. It might be 21.399999999999995. This would
# make the validation fail, although the payload is correct. This is a
# known issue with jsonschemas, see:
# https://github.com/Julian/jsonschema/issues/247
#
# This issue can be fixed by using a different parser for floats than
The given payload is transformed into a Call object by looking at the
type of the payload. A payload of type BootNotificationPayload will
turn in a Call with Action BootNotification, a HeartbeatPayload will
result in a Call with Action Heartbeat etc.
A timeout is raised when no response has arrived before expiring of
the configured timeout.
When waiting for a response no other Call message can be send. So this
function will wait before response arrives or response timeout has
expired. This is in line the OCPP specification
"""
camel_case_payload = snake_to_camel_case(asdict(payload))
call = Call(
unique_id=str(self._unique_id_generator()),
action=payload.__class__.__name__[:-7],
payload=remove_nones(camel_case_payload)
)
# Use a lock to prevent make sure that only 1 message can be send at a
# a time.
async with self._call_lock:
await self._send(call.to_json())
response = \
await self._get_specific_response(call.unique_id,
self._response_timeout)
if response.message_type_id == MessageType.CallError:
LOGGER.warning("Received a CALLError: %s'", response)
return