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) await self._send(response.to_json()) try: handler = handlers['_after_action'] # Create task to avoid blocking when making a call inside the # after handler response = handler(**snake_case_payload) if inspect.isawaitable(response): asyncio.ensure_future(response) except KeyError: # '_on_after' hooks are not required. Therefore ignore exception # when no '_on_after' hook is installed. pass
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