OpenLEADR / openleadr-python

Python library for OpenADR
https://openleadr.org/docs
Apache License 2.0
134 stars 52 forks source link

Implement one-shot history reports #18

Open stan-janssen opened 3 years ago

stan-janssen commented 3 years ago

The design for this should be:

bbartling commented 3 years ago

@stan-janssen if I understand this correctly the VEN stores the report data and the VTN does not?

The VEN will receive this message on its next poll, will then call the function to retrieve the historic data, and package it up and send it off into a oadrUpdateReport message.

So the VEN should have some db running collecting telemetry data from the building, where upon request from VTN owner, the VEN (not VTN) will provide the historical telemetry data ...

For some reason I thought the VTN would have a db running collecting data (report values) from VEN's. Thanks for high level quick responses...

00javad00 commented 3 years ago

I made a report on VEN side for HISTORY_USAGE:

  client.add_report(callback=collect_Energy_value,
                    resource_id = 'resource1',
                    measurement = 'RealEnergy',
                    data_collection_mode = 'incremental',
                    report_specifier_id =None,
                    r_id = None,
                    report_name='HISTORY_USAGE')

and I use a handler for registering the report (which works okay with TELEMETRY_USAGE registration) on server side:

async def on_register_report(ven_id, resource_id, measurement, unit, scale, min_sampling_interval, max_sampling_interval):
  print(f"Called on register report {ven_id}, {resource_id}, {measurement}, {unit}, {scale}, {min_sampling_interval}, {max_sampling_interval}")
  callback = partial(on_update_report, ven_id=ven_id, resource_id=resource_id, measurement=measurement)
  sampling_interval = min_sampling_interval
  return callback, sampling_interval

and seems the server is not able to register HISTORY_USAGE and will respond with an empty report_requests:

Responding to oadrRegisterReport with a oadrRegisteredReport message: {'report_requests': [], 'vtn_id': 'TH_VTN', 'ven_id': 'DUT_VEN', 'response': {'request_id': '44dfb810-9bde-4a26-a663-71e58e88fb55', 'response_code': 200, 'response_description': 'OK'}, 'request_id': '54697425-8d6a-4f98-a809-0697e4fb1e0d'}.

Could you please elaborate more on how should I make a on_register_report handler that supports both TELEMETRY_USAGE and HISTORY_USAGE?

stan-janssen commented 3 years ago

HISTORY_USAGE reports are not yet supported in OpenLEADR, as mentioned in the documentation for historic reports.

Only the reports with TELEMETRY_USAGE are propagated to your on_register_report handlers. The reason for this is that the on_register_report handler returns the reports which you want to receive at set intervals, which (to my mind) is usually not the case with the HISTORY_USAGE reports.

The HISTORY_USAGE report definitions that the VEN registers with the VTN are still available in the server.registered_reports[ven_id] property though, but you can't do anything automated with them at the moment.

This issue was intended to track the progess on me implementing a convenient way for you te request these historic reports from the VEN, but I haven't gotten to that yet.

00javad00 commented 3 years ago

Actually the VEN is the party that initiates reporting, and it would request registering the data_collection_mode = 'full' and report_name = HISTORY_USAGE. By this the VEN indicates how far it can go for HISTORY_USAGE considering its constraint. The easiest way (I think) of implementing HISTORY_USAGE is modifying lines 102-121 in report_service.py and include METADATA_HISTORY_USAGE in the accepted report names by VTN. Then VEN can reply back with a full report and includes a historical data for a period of time that was registered before. The suggesting modification could be:

            elif (report['report_name'] == 'METADATA_TELEMETRY_USAGE' or report['report_name'] == 'METADATA_HISTORY_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_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

Your thoughts?