server.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. .. _server:
  2. ======
  3. Server
  4. ======
  5. If you are implementing an OpenADR Server ("Virtual Top Node") using OpenLEADR, read this page.
  6. .. _server_registration:
  7. Registration
  8. ============
  9. If a client (VEN) wants to register for the first time, it will go through a Registration procedure.
  10. .. admonition:: Implementation Checklist
  11. 1. Create a handler that decides what to do with new registrations, based on their ``venID``.
  12. The client will send a :ref:`oadrQueryRegistration` message. The server will respond with a :ref:`oadrCreatedPartyRegistration` message containing a list of its capabilities, notably the implemented OpenADR protocol versions and the available Transport Mechanisms (HTTP and/or XMPP).
  13. The client will then usually send a :ref:`oadrCreatePartyRegistration` message, in which it registers to a specific OpenADR version and Transport Method. The server must then decide what it wants to do with this registration.
  14. In the case that the registration is accepted, the VTN will generate a RegistrationID for this VEN and respond with a :ref:`oadrCreatedPartyRegistration` message.
  15. In your application, when a VEN sends a :ref:`oadrCreatePartyRegistration` request, it will call your ``on_register_party`` handler. This handler must somehow look up what to do with this request, and respond with a ``registration_id``.
  16. Example implementation:
  17. .. code-block:: python3
  18. from openleadr.utils import generate_id
  19. async def on_create_party_registration(payload):
  20. ven_id = payload['ven_id']
  21. # Check whether or not this VEN is allowed to register
  22. result = await database.query("""SELECT COUNT(*)
  23. FROM vens
  24. WHERE ven_id = ?""",
  25. (payload['ven_id'],))
  26. if result == 1:
  27. # Generate an ID for this registration
  28. registration_id = generate_id()
  29. # Store the registration in a database (pseudo-code)
  30. await database.query("""UPDATE vens
  31. SET registration_id = ?
  32. WHERE ven_id = ?""",
  33. (registration_id, ven_id))
  34. # Return the registration ID.
  35. # This will be put into the correct form by the OpenADRServer.
  36. return registration_id
  37. .. _server_events:
  38. Events
  39. ======
  40. The server (VTN) is expected to know when it needs to inform the clients (VENs) of certain events that they must respond to. This could be a predicted shortage or overage of available power in a certain electricity grid area, for example.
  41. The VTN must determine when VENs are relevant and which Events to send to them. The next time the VEN polls for new messages (using a :ref:`oadrPoll` or :ref:`oadrRequestEvent` message), it will send the Event in a :ref:`oadrDistributeEvent` message to the client. The client will then evaluate whether or not it indends to comply with the request, and respond with an :ref:`oadrCreatedEvent` message containing an optStatus of ``'optIn'`` or ``'optOut'``.
  42. .. admonition:: Implementation Checklist
  43. In your application, the creation of Events is completely up to you. PyOpenADR will only call your ``on_poll`` handler with a ``ven_id``. This handler must be able to either retrieve the next event for this VEN out of some storage or queue, or make up the Event in real time.
  44. - ``on_created_event(payload)`` handler is called whenever the VEN sends an :ref:`oadrCreatedEvent` message, probably informing you of what they intend to do with the event you gave them.
  45. - ``on_request_event(ven_id)``: this should return the next event (if any) that you have for the VEN. If you return ``None``, a blank :ref:`oadrResponse` will be returned to the VEN.
  46. - ``on_request_report(ven_id)``: this should return then next report (if any) that you have for the VEN. If you return None, a blank :ref:`oadrResponse` will be returned to the VEN.
  47. - ``on_poll(ven_id)``: this should return the next message in line, which is usually either a new :ref:`oadrUpdatedReport` or a :ref:`oadrDistributeEvent` message.
  48. The Event consists of three main sections:
  49. 1. A time period for when this event is supposed to be active
  50. 2. A list of Targets to which the Event applies. This can be the VEN as a whole, or specific groups, assets, geographic areas, et cetera that this VEN represents.
  51. 3. A list of Signals, which form the content of the Event. This can be price signals, load reduction signals, et cetera. Each signal has a name, a type, multiple Intervals that contain the relative start times, and some payload value for the client to interpret.
  52. .. _server_reports:
  53. Reports
  54. =======
  55. Reporting is probably the most complicated of interactions within OpenADR. It involves the following steps:
  56. 1. Party A makes its reporting capabilities known to party B using a :ref:`oadrRegisterReport` message.
  57. 2. Party B responds with an :ref:`oadrRegisteredReport` message, optionally including an :ref:`oadrReportRequest` section that tells party A which party B is interested in.
  58. 3. Party A reponds with an oadrCreatedReport message telling party B that it will periodically generate the reports.
  59. This ceremony is performed once with the VTN as party A and once with the VEN as party A.
  60. The VEN party can collect the reports it requested from the VTN using either the :ref:`oadrPoll` or :ref:`oadrRequestReport` messages. The VTN will respond with an :ref:`oadrUpdateReport` message containing the actual report. The VEN should then respond with a :ref:`oadrUpdatedReport` message.
  61. The VEN should actively supply the reports to the VTN using :ref:`oadrUpdateReport` messages, to which the VTN will respond with :ref:`oadrUpdatedReport` messages.
  62. .. admonition:: Implementation Checklist
  63. To benefit from the automatic reporting engine in OpenLEADR, you should implement the following items yourself:
  64. 1. Configure the OpenADRServer() instance with your reporting capabilities and requirements
  65. 2. Implement a handlers that can retrieve the reports from your backend system
  66. 3. Implement a handler that deal with reports that come in from the clients
  67. .. _server_implement:
  68. Things you should implement
  69. ===========================
  70. You should implement the following handlers:
  71. - ``on_poll(ven_id)``
  72. - ``on_request_event(ven_id)``
  73. - ``on_request_report(payload)``
  74. - ``on_create_party_registration(payload)``
  75. .. _server_meta:
  76. Non-OpenADR signals from the server
  77. ===================================
  78. The OpenLEADR Server can call the following handlers, which are not part of the regular openADR communication flow, but can help you develop a more robust event-driven system:
  79. - ``on_ven_online(ven_id)``: called when a VEN sends an :ref:`oadrPoll`, :ref:`oadrRequestEvent` or :ref:`oadrRequestReport` message after it had been offline before.
  80. - ``on_ven_offline(ven_id)``: called when a VEN misses 3 consecutive poll intervals (configurable).
  81. Example implementation:
  82. .. code-block:: python3
  83. from openleadr import OpenADRServer
  84. server = OpenADRServer(vtn_id='MyVTN')
  85. server.add_handler('on_ven_online', on_ven_online)
  86. server.add_handler('on_ven_offline', on_ven_offline)
  87. async def on_ven_online(ven_id):
  88. print(f"VEN {ven_id} is now online again!")
  89. async def on_ven_offline(ven_id):
  90. print(f"VEN {ven_id} has gone AWOL")
  91. .. _server_signing_messages:
  92. Signing Messages
  93. ================
  94. The OpenLEADR can sign your messages and validate incoming messages. For some background, see the :ref:`message_signing`.
  95. Example implementation:
  96. .. code-block:: python3
  97. from openleadr import OpenADRServr
  98. def fingerprint_lookup(ven_id):
  99. # Look up the certificate fingerprint that is associated with this VEN.
  100. fingerprint = database.lookup('certificate_fingerprint').where(ven_id=ven_id) # Pseudo code
  101. return fingerprint
  102. server = OpenADRServer(vtn_id='MyVTN',
  103. cert='/path/to/cert.pem',
  104. key='/path/to/private/key.pem',
  105. passphrase='mypassphrase',
  106. validation_handler=fingerprint_lookup)
  107. The VEN's fingerprint should be obtained from the VEN outside of OpenADR.
  108. .. _server_message_handlers:
  109. Message Handlers
  110. ================
  111. Your server has to deal with the different OpenADR messages. The way this works is that OpenLEADR will expose certain modules at the appropriate endpoints (like /oadrPoll and /EiRegister), and figure out what type of message is being sent. It will then call your handler with the contents of the message that are relevant for you to handle. This section provides an overview with examples for the different kinds of messages that you can expect and what should be returned.
  112. .. _server_on_created_event:
  113. on_created_event
  114. ----------------
  115. The VEN informs you that they created an Event that you sent to them. You don't have to return anything.
  116. Return: `None`
  117. .. _server_on_request_event:
  118. on_request_event
  119. ----------------
  120. The VEN is requesting the next Event that you have for it. You should return an Event. If you have no Events for this VEN, you should return `None`.
  121. .. _server_on_register_report:
  122. on_register_report
  123. ------------------
  124. The VEN informs you which reports it has available. If you want to periodically receive any of these reports, you should return a list of the r_ids that you want to receive.
  125. Signature:
  126. .. code-block:: python3
  127. async def on_register_report(ven_id, reports):
  128. .. _server_on_created_report:
  129. on_created_report
  130. -----------------
  131. The VEN informs you that it created the automatic reporting that you requested. You don't have to return anything.
  132. Return: `None`
  133. .. _server_on_update_report:
  134. on_update_report
  135. ----------------
  136. The VEN is sending you a fresh report with data. You don't have to return anything.
  137. Signature:
  138. .. code-block:: python3
  139. async def on_update_report(ven_id, report):
  140. ...
  141. return None
  142. .. _server_on_poll:
  143. on_poll
  144. -------
  145. The VEN is requesting the next message that you have for it. You should return a tuple of message_type and message_payload as a dict. If there is no message for the VEN, you should return `None`.
  146. Signature:
  147. .. code-block:: python3
  148. async def on_poll(ven_id):
  149. ...
  150. return message_type, message_payload
  151. .. _server_on_query_registration:
  152. on_query_registration
  153. ---------------------
  154. A prospective VEN is requesting information about your VTN, like the versions and transports you support. You should not implement this handler and let OpenLEADR handle this response.
  155. .. _server_on_create_party_registration:
  156. on_create_party_registration
  157. ----------------------------
  158. The VEN tries to register with you. You will probably have manually configured the VEN beforehand, so you should look them up by their ven_name. You should have a ven_id that you generated ready.
  159. If they are allowed to register, return the ven_id (str), otherwise return False.
  160. .. code-block:: python3
  161. async def on_create_party_registration(ven_name):
  162. if ven_is_known:
  163. return ven_id
  164. else
  165. return None
  166. .. _server_on_cancel_party_registration:
  167. on_cancel_party_registration
  168. ----------------------------
  169. The VEN informs you that they are cancelling their registration and no longer wish to be contacted by you.
  170. You should deregister the VEN internally, and return `None`.
  171. Return: `None`