Ejemplo n.º 1
0
    async def call(self, *, message: Any, context: RouterContext):
        ocpp_version = subprotocol_to_ocpp_version(self.subprotocol)

        camel_case_payload = snake_to_camel_case(asdict(message))

        call = Call(
            unique_id=str(self._unique_id_generator()),
            action=message.__class__.__name__[:-7],
            payload=remove_nones(camel_case_payload),
        )

        validate_payload(call, ocpp_version)

        await self._send(message=call.to_json(),
                         is_response=False,
                         context=context)
        self.subscriptions[call.unique_id] = context.queue
        try:
            response = await asyncio.wait_for(context.queue.get(),
                                              self._response_timeout)
        except asyncio.TimeoutError:
            del self.subscriptions[call.unique_id]
            raise

        if response.message_type_id == MessageType.CallError:
            log.warning("Received a CALLError: %s'", response)
            raise response.to_exception()
        else:
            response.action = call.action
            validate_payload(response, ocpp_version)

        snake_case_payload = camel_to_snake_case(response.payload)
        call_result = context.ocpp_adapter.call_result
        cls = getattr(call_result, message.__class__.__name__)
        return cls(**snake_case_payload)
Ejemplo n.º 2
0
def message_to_payload(message: str, action: str) -> Any:
    response = unpack(message)
    response.action = action
    validate_payload(response, "1.6")
    snake_case_payload = camel_to_snake_case(response.payload)
    cls = getattr(call_result, f"{action}Payload")
    payload = cls(**snake_case_payload)
    return payload
Ejemplo n.º 3
0
def test_camel_to_snake_case(test_input, expected):
    result = camel_to_snake_case(test_input)
    assert result == expected
Ejemplo n.º 4
0
    async def _handle_call(self, msg):
        """
        Execute all hooks installed for based on the Action of the message.

        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.

        Next the '_after_action' hook is executed.

        """
        try:
            handlers = self.route_map[msg.action]
        except KeyError:
            raise NotImplementedError(f"No handler for '{msg.action}' "
                                      "registered.")

        if not handlers.get("_skip_schema_validation", False):
            validate_payload(msg, self._ocpp_version)

        # OCPP uses camelCase for the keys in the payload. It's more pythonic
        # to use snake_case for keyword arguments. Therefore the keys must be
        # 'translated'. Some examples:
        #
        # * chargePointVendor becomes charge_point_vendor
        # * firmwareVersion becomes firmwareVersion
        snake_case_payload = camel_to_snake_case(msg.payload)

        try:
            handler = handlers["_on_action"]
        except KeyError:
            raise NotImplementedError(f"No handler for '{msg.action}' "
                                      "registered.")

        try:
            response = handler(**snake_case_payload)
            if inspect.isawaitable(response):
                response = await response
        except Exception as e:
            LOGGER.exception("Error while handling request '%s'", msg)
            response = msg.create_call_error(e).to_json()
            await self._send(response)

            return

        temp_response_payload = asdict(response)

        # Remove nones ensures that we strip out optional arguments
        # which were not set and have a default value of None
        response_payload = remove_nones(temp_response_payload)

        # The response payload must be 'translated' from snake_case to
        # camelCase. So:
        #
        # * charge_point_vendor becomes chargePointVendor
        # * firmware_version becomes firmwareVersion
        camel_case_payload = snake_to_camel_case(response_payload)

        response = msg.create_call_result(camel_case_payload)

        if not handlers.get("_skip_schema_validation", False):
            validate_payload(response, self._ocpp_version)

        response = await self._response_strategy.run(response.to_json())

        try:
            handler = handlers["_after_action"]
            await self._after_hook_strategy.run(handler, snake_case_payload)
        except KeyError:
            # '_on_after' hooks are not required. Therefore ignore exception
            # when no '_on_after' hook is installed.
            pass
        return response
Ejemplo n.º 5
0
    async def _handle_call(self, msg, *, context: RouterContext = None):
        """
        Execute all hooks installed for based on the Action of the message.

        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.

        Next the '_after_action' hook is executed.

        """
        ocpp_version = subprotocol_to_ocpp_version(self.subprotocol)

        try:
            handlers = self._route_map[msg.action]
        except KeyError:
            raise NotImplementedError(f"No handler for '{msg.action}' "
                                      "registered.")

        if not handlers.get("_skip_schema_validation", False):
            validate_payload(msg, ocpp_version)

        # OCPP uses camelCase for the keys in the payload. It's more pythonic
        # to use snake_case for keyword arguments. Therefore the keys must be
        # 'translated'. Some examples:
        #
        # * chargePointVendor becomes charge_point_vendor
        # * firmwareVersion becomes firmwareVersion
        snake_case_payload = camel_to_snake_case(msg.payload)

        try:
            handler = handlers["_on_action"]
        except KeyError:
            raise NotImplementedError(f"No handler for '{msg.action}' "
                                      "registered.")

        handler_context = HandlerContext(
            charging_station_id=context.charging_station_id,
            _router_context=context,
            _router=self,
        )
        # Convert message to correct Call instance
        class_ = getattr(context.ocpp_adapter.call, f"{msg.action}Payload")
        payload = class_(**snake_case_payload)
        try:
            response = handler(payload=payload, context=handler_context)
            if inspect.isawaitable(response):
                response = await response
        except Exception as e:
            log.exception("Error while handling request '%s'", msg)
            response = msg.create_call_error(e).to_json()
            await self._send(message=response,
                             is_response=True,
                             context=context)

        temp_response_payload = asdict(response)

        # Remove nones ensures that we strip out optional arguments
        # which were not set and have a default value of None
        response_payload = remove_nones(temp_response_payload)

        # The response payload must be 'translated' from snake_case to
        # camelCase. So:
        #
        # * charge_point_vendor becomes chargePointVendor
        # * firmware_version becomes firmwareVersion
        camel_case_payload = snake_to_camel_case(response_payload)

        response = msg.create_call_result(camel_case_payload)

        if not handlers.get("_skip_schema_validation", False):
            validate_payload(response, ocpp_version)

        await self._send(message=response.to_json(),
                         is_response=True,
                         context=context)

        try:
            handler = handlers["_after_action"]
            response = handler(payload=payload, context=handler_context)
            if inspect.isawaitable(response):
                if self._create_task:
                    # Create task to avoid blocking when making a call
                    # inside the after handler
                    asyncio.ensure_future(response)
                else:
                    await response
        except KeyError:
            # '_on_after' hooks are not required. Therefore ignore exception
            # when no '_on_after' hook is installed.
            pass