示例#1
0
    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