async def register_report(self, payload): """ Handle the VENs reporting capabilities. """ report_requests = [] args = inspect.signature(self.on_register_report).parameters if all(['measurement' in args, 'resource_id' in args, 'min_sampling_interval' in args, 'max_sampling_interval' in args, 'unit' in args, 'scale' in args]): for report in payload['reports']: result = [self.on_register_report(resource_id=rd['report_subject']['resource_id'], measurement=rd['measurement']['item_description'], unit=rd['measurement']['item_units'], scale=rd['measurement']['si_scale_code'], min_sampling_interval=rd['sampling_rate']['min_period'], max_sampling_interval=rd['sampling_rate']['max_period']) for rd in report['report_descriptions']] if iscoroutine(result[0]): result = await gather(*result) result = [(report['report_descriptions'][i]['r_id'], *result[i]) for i in range(len(report['report_descriptions']))] report_requests.append(result) else: # Use the 'full' mode for openADR reporting result = [self.on_register_report(report) for report in payload['reports']] if iscoroutine(result[0]): result = await gather(*result) # Now we have r_id, callback, sampling_rate report_requests = result for i, report_request in enumerate(report_requests): if report_request is not None: if not all(len(rrq) in (3, 4) for rrq in report_request): logger.error("Your on_register_report handler did not return a valid response") # Validate the report requests for i, report_request in enumerate(report_requests): if report_request is None: continue # Check if all sampling rates per report_request are the same sampling_interval = min(rrq[2] for rrq in report_request if rrq is not None) if not all(rrq is not None and report_request[0][2] == sampling_interval for rrq in report_request): logger.error("OpenADR does not support multiple different sampling rates per " "report. OpenLEADR will set all sampling rates to " f"{sampling_interval}") # Form the report request oadr_report_requests = [] for i, report_request in enumerate(report_requests): if report_request is None: continue orig_report = payload['reports'][i] report_specifier_id = orig_report['report_specifier_id'] report_request_id = generate_id() specifier_payloads = [] for rrq in report_request: if len(rrq) == 3: r_id, callback, sampling_interval = rrq report_interval = sampling_interval elif len(rrq) == 4: r_id, callback, sampling_interval, report_interval = rrq report_description = find_by(orig_report['report_descriptions'], 'r_id', r_id) reading_type = report_description['reading_type'] specifier_payloads.append(objects.SpecifierPayload(r_id=r_id, reading_type=reading_type)) # Append the callback to our list of known callbacks self.report_callbacks[(report_request_id, r_id)] = callback # Add the ReportSpecifier to the ReportRequest report_specifier = objects.ReportSpecifier(report_specifier_id=report_specifier_id, granularity=sampling_interval, report_back_duration=report_interval, specifier_payloads=specifier_payloads) # Add the ReportRequest to our outgoing message oadr_report_requests.append(objects.ReportRequest(report_request_id=report_request_id, report_specifier=report_specifier)) # Put the report requests back together response_type = 'oadrRegisteredReport' response_payload = {'report_requests': oadr_report_requests} return response_type, response_payload
async def register_report(self, payload): """ Handle the VENs reporting capabilities. """ report_requests = [] args = inspect.signature(self.on_register_report).parameters if all([ 'ven_id' in args, 'resource_id' in args, 'measurement' in args, 'min_sampling_interval' in args, 'max_sampling_interval' in args, 'unit' in args, 'scale' in args ]): mode = 'compact' else: mode = 'full' if payload['reports'] is None: return for report in payload['reports']: if report['report_name'] == 'METADATA_TELEMETRY_STATUS': if mode == 'compact': results = [ self.on_register_report( ven_id=payload['ven_id'], resource_id=rd.get('report_data_source', {}).get('resource_id'), measurement='Status', unit=None, scale=None, min_sampling_interval=rd['sampling_rate'] ['min_period'], max_sampling_interval=rd['sampling_rate'] ['max_period']) for rd in report['report_descriptions'] ] results = await utils.gather_if_required(results) elif mode == 'full': results = await utils.await_if_required( self.on_register_report(report)) elif report['report_name'] == 'METADATA_TELEMETRY_USAGE': if mode == 'compact': results = [ self.on_register_report( ven_id=payload['ven_id'], resource_id=rd.get('report_data_source', {}).get('resource_id'), measurement=rd['measurement']['description'], unit=rd['measurement']['unit'], scale=rd['measurement']['scale'], min_sampling_interval=rd['sampling_rate'] ['min_period'], max_sampling_interval=rd['sampling_rate'] ['max_period']) for rd in report['report_descriptions'] ] results = await utils.gather_if_required(results) elif mode == 'full': results = await utils.await_if_required( self.on_register_report(report)) elif report['report_name'] in ('METADATA_HISTORY_USAGE', 'METADATA_HISTORY_GREENBUTTON'): if payload['ven_id'] not in self.registered_reports: self.registered_reports[payload['ven_id']] = [] report['report_name'] = report['report_name'][9:] self.registered_reports[payload['ven_id']].append(report) report_requests.append(None) continue else: logger.warning( "Reports other than TELEMETRY_USAGE, TELEMETRY_STATUS, " "HISTORY_USAGE and HISTORY_GREENBUTTON are not yet supported. " f"Skipping report with name {report['report_name']}.") report_requests.append(None) continue # Perform some rudimentary checks on the returned type if results is not None: if not isinstance(results, list): logger.error( "Your on_register_report handler must return a list of tuples or None; " f"it returned '{results}' ({results.__class__.__name__})." ) results = None else: for i, r in enumerate(results): if r is None: continue if not isinstance(r, tuple): if mode == 'compact': logger.error( "Your on_register_report handler must return a tuple or None; " f"it returned '{r}' ({r.__class__.__name__})." ) elif mode == 'full': logger.error( "Your on_register_report handler must return a list of tuples or None; " f"The first item from the list was '{r}' ({r.__class__.__name__})." ) results[i] = None # If we used compact mode, prepend the r_id to each result # (this is already there when using the full mode) if mode == 'compact': results = [ (report['report_descriptions'][i]['r_id'], *results[i]) for i in range(len(report['report_descriptions'])) if isinstance(results[i], tuple) ] report_requests.append(results) utils.validate_report_request_tuples(report_requests, mode=mode) for i, report_request in enumerate(report_requests): if report_request is None or len(report_request) == 0 or all( rrq is None for rrq in report_request): continue # Check if all sampling rates per report_request are the same sampling_interval = min(rrq[2] for rrq in report_request if isinstance(rrq, tuple)) if not all(rrq is not None and report_request[0][2] == sampling_interval for rrq in report_request): logger.error( "OpenADR does not support multiple different sampling rates per " "report. OpenLEADR will set all sampling rates to " f"{sampling_interval}") # Form the report request oadr_report_requests = [] for i, report_request in enumerate(report_requests): if report_request is None or len(report_request) == 0 or all( rrq is None for rrq in report_request): continue orig_report = payload['reports'][i] report_specifier_id = orig_report['report_specifier_id'] report_request_id = utils.generate_id() specifier_payloads = [] for rrq in report_request: if len(rrq) == 3: r_id, callback, sampling_interval = rrq report_interval = sampling_interval elif len(rrq) == 4: r_id, callback, sampling_interval, report_interval = rrq report_description = utils.find_by( orig_report['report_descriptions'], 'r_id', r_id) reading_type = report_description['reading_type'] specifier_payloads.append( objects.SpecifierPayload(r_id=r_id, reading_type=reading_type)) # Append the callback to our list of known callbacks self.report_callbacks[(report_request_id, r_id)] = callback # Add the ReportSpecifier to the ReportRequest report_specifier = objects.ReportSpecifier( report_specifier_id=report_specifier_id, granularity=sampling_interval, report_back_duration=report_interval, specifier_payloads=specifier_payloads) # Add the ReportRequest to our outgoing message oadr_report_requests.append( objects.ReportRequest(report_request_id=report_request_id, report_specifier=report_specifier)) # Put the report requests back together response_type = 'oadrRegisteredReport' response_payload = {'report_requests': oadr_report_requests} # Store the requested reports self.requested_reports[payload['ven_id']] = oadr_report_requests return response_type, response_payload