Who we are

Contacts

1815 W 14th St, Houston, TX 77008

281-817-6190

Development Python Uncategorized

The Evolution of Demand Response with OpenADR 2.0b

Introduction:

The rising demand for energy, fueled by factors such as the adoption of electric vehicles, the constant construction of new data centers, and the increased use of electric devices, is presenting significant challenges to the modern energy grid in terms of capacity, reliability, and adaptability.

OpenADR (Open Automated Demand Response) is a protocol developed specifically to address these issues. It enhances the grid’s ability to effectively manage and respond to peak demand periods. In reaction to California’s energy crisis in the early 2000s, OpenADR was developed, establishing a common standard that allows utilities to communicate with customer devices. This communication facilitates automated demand response (ADR) events, which temporarily reduce energy consumption or increase production during critical times, helping to stabilize the grid and prevent outages.

How it works:

Example of an OpenADR implementationThere are two main actors in OpenADR communications the Virtual Top Node (VTN) and the Virtual End Node (VEN). VTN: – Manages Resources (VEN, Registration etc) – Creates/ transmits events – Can request reports from the VENs – Can be attached to one or multiple VENs

VEN: – Receives events and responds to them – Can control demand side resources – Can also act like a VTN (see aggregator in the diagram) and reach out to other downstream VENs – Can send reports to the VTN

OpenAdr provides a protocol for demand response message exchange. Applications are free however to translate the messages to downstream applications/ devices as needed. In practice, as seen in the diagram above VENs send control messages to their devices and can use OpenADR but most use other protocols like BACnet and Sep 2.0.

Breakdown of services offered by OpenADR 2.0b:

There are 4 main services offered by the OpenADR protocol;

  • Event
  • Report
  • Opt
  • Registration.

Event Service:

Main function: To send and acknowledge DR events. It enables the VTN to send event signals to the VEN requesting adjustments in energy consumption. These signals can trigger actions like load shedding, curtailment or price-based adjustments.

Signal Types: OpenADR 2.0b supports varise messages in this articleous signal types, including Emergency Events (signal for critical situations requiring immediate load reduction), Price Signals (informs devices of dynamic electricity prices, allowing them to optimize consumption based on cost) and Manual Events (allows utilities to send custom signals for specific purposes).

Targeting: Allows the VTN to target events to specific VENs/ devices (VEN ID), groups of VENs/ devices (group ID), or specific resources within a VEN (resource ID).

Example of the “EiEvent” Data structure. Note: OpenADR 2.0 protocols utilize SOAP based APIs and are therefore XML messages. OpenADR 3.0 does allow Restful apis but since most real-world implementation is still 2.0b we will be using those messages in this article.


<eiEvent>
  <!-- eventDescriptor: Describes the event's metadata including IDs, priority, market context, and timestamps. -->
  <eventDescriptor>
    <eventID>unique-event-id</eventID>
    <modificationNumber>0</modificationNumber>
    <priority>0</priority>
    <marketContext>market-context</marketContext>
    <createdDateTime>2024-05-05T00:00:00Z</createdDateTime>
    <eventStatus>far</eventStatus>
    <testEvent>false</testEvent>
    <vtnComment>A comment</vtnComment>
  </eventDescriptor>
  <!-- eiActivePeriod: Defines the active period of the event including start time, duration, and any specific instructions such as ramp-up and recovery times. -->
  <eiActivePeriod>
    <properties>
      <dtstart>
        <date-time>2024-05-06T00:00:00Z</date-time>
      </dtstart>
      <duration>
        <duration>PT1H</duration>
      </duration>
      <tolerance>
        <tolerate>
          <startafter>PT5M</startafter>
        </tolerate>
      </tolerance>
      <notification>
        <duration>PT15M</duration>
      </notification>
      <rampUp>
        <duration>PT5M</duration>
      </rampUp>
      <recovery>
        <duration>PT5M</duration>
      </recovery>
    </properties>
    <components>
      <!-- Components define specific intervals for changes during the event -->
    </components>
  </eiActivePeriod>
  <!-- eiEventSignals: Lists the signals associated with the event. -->
  <eiEventSignals>
    <eiEventSignal>
      <signalID>signal-id-1</signalID>
      <signalName>SIMPLE</signalName>
      <signalType>level</signalType>
      <signalInterval>
        <interval>
          <dtstart>
            <date-time>2024-05-06T00:00:00Z</date-time>
          </dtstart>
          <duration>
            <duration>PT1H</duration>
          </duration>
          <uid>
            <text>1</text>
          </uid>
          <payload>
            <payloadFloat>
              <value>1.0</value>
            </payloadFloat>
          </payload>
        </interval>
        <!-- More intervals can be added here -->
      </signalInterval>
    </eiEventSignal>
    <!-- More event signals can be added here -->
  </eiEventSignals>
  <eventResponse>
    <responseDescription>Response Description</responseDescription>
    <requestID>request-id</requestID>
    <responseCode>200</responseCode>
  <!-- eventResponse: Contains information about the VEN's response to the event. -->
  </eventResponse>
</eiEvent>


Report Service:

Main Function: Request and deliver reports. It allows VENs to report data back to the VTN. It supports a wide range of report specifications, from simple telemetry and energy usage reporting to complex performance tracking across a distributed energy resource network. The VTN also has the ability to either request these reports at specified intervals, have event-driven reports or ad hoc reports. This flexibility of the report specification allows the VTN to tailor the reporting to the precise needs of the Utility.

Example of an “oadrRegisterReport” data structure which is the initial step where the VEN informs the VTN of its reporting capabilities:


<oadr:oadrPayload>
    <oadr:oadrSignedObject>
        <oadr:oadrRegisterReport>
            <ei:reportRequestID>12345</ei:reportRequestID>
            <oadr:report>
                <reportSpecifierID>report1</reportSpecifierID>
                <reportName>TELEMETRY_USAGE</reportName>
                <createdDateTime>2024-05-05T00:00:00Z</createdDateTime>
                <!-- More details about the report -->
            </oadr:report>
            <!-- Additional reports can be included here -->
        </oadr:oadrRegisterReport>
    </oadr:oadrSignedObject>
</oadr:oadrPayload>

Opt Service:

Main Function: Define temporary availability schedules. It allows the VTN to send optimization-related instructions or signals to the VENs, and the VENs can then adjust their energy consumption or production accordingly. Allows VENs to Opt-in or Opt-out optimization programs, giving them control over their participation based on factors such as preferences, constraints, and operational requirements. The VTN can also send Price Signals to influence energy consumption or production decisions. These signals may include dynamic pricing information, such as real-time or day-ahead prices, to incentivize load shifting or other demand response actions.

A simplified example of an “OptService” data structure:


<oadrPayload>
    <oadrSignedObject>
        <oadrDistributeEvent>
            <!-- Event details, signals, and instructions -->
        </oadrDistributeEvent>
    </oadrSignedObject>
</oadrPayload>

Registration Service:

Main Function: VEN registration with the VTN, device information exchange. It serves as the entry point for VENs into the OpenADR ecosystem, enabling them to establish connections with the VTN.

Example of an “oadrCreatePartyRegistration” Data structure:


<oadrPayload>
    <oadrSignedObject>
        <oadrCreatePartyRegistration>
            <!-- Registration details such as VEN profile, transport parameters, etc. -->
        </oadrCreatePartyRegistration>
    </oadrSignedObject>
</oadrPayload>

Security:

TLS: OpenADR 2.0b uses TLS to encrypt it’s HTTPS messages between the VTN and VEN. Authentication: Mutual authentication between VTNs and VENs is achieved using digital certificates. This ensures that only trusted parties can participate in the communication. Message-Level Security: Messages can be digitally signed to ensure their integrity and authenticity using XML digital signatures. Signed messages provide assurance that the message content has not been altered in transit and that it originates from the expected sender.

Getting Started with OpenLEADR:

OpenLEADR is an open-source implementation of OpenADR under the Apache 2.0 license. It is Python based compatible with Python 3.7 or higher and provides all the basic logic and infrastructure to create your very own VTN or VEN.

GitHub: https://github.com/OpenLEADR Website: https://openleadr.org/docs/

An example VEN:

The example code below creates a VEN using the OpenLEADR application code. It establishes a connection with a VTN that is TLS encrypted and ensures messages are digitally signed by the VTN. It creates an event handler that upon receiving an event from the VTN will make an example api call and optIn if successful or optOut if the request fails. It also creates an example voltage report that the VTN can request.

import asyncio
from datetime import timedelta
from openleadr import OpenADRClient, enable_default_logging
from Metering import MyMeter
import requests

enable_default_logging()

my_meter = MyMeter(...)
async def read_voltage():
    # This callback is called when you need to collect a value for your Report
    # In this case we're getting the voltage. 
    value = my_meter.read('voltage')
    return value

async def handle_event(event):
    try:
        # Parse through event recieved. 
        payload = {
        'event_id': event['event_id'],
        'active_period': event['active_period'],
        'event_signal': event['event_signal'],
        'targets': event['targets']
        }
        #Make a call to the target devices. In this example a simple api call. 
        url = 'https://example.com/api/control_devices'
        response = requests.post(url, json=payload)
        #OptIn if devices were successfully reached
        if response.status_code == 200:
            print('Reached Devices Successfully')
            return 'optIn'
        else:
            #OptOut if there were errors.
            print('Could not reach devices')
            return 'optOut'
    except:
        #Error OptOut
        print('Error with the event payload')
        return 'optOut'

          
# Create the client object. 
client = OpenADRClient(ven_name='MyVEN',
                           vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b',
                           #Your x.509 Keypair for identifying your VEN 
                           #and signing messages during the TLS handshake
                           cert='/path/to/cert.pem',
                           key='/path/to/key.pem',
                           passphrase='my-key-password',
                           #Will validate that the incoming message is signed by
                           #the private key that corresponds to the public certificate 
                           vtn_fingerprint='AA:BB:CC:DD:EE:FF:11:22:33:44')

# Adding reporting capability to the VEN
# The VTN can pick which reports it wants. Callback is called automatically
client.add_report(callback=read_voltage,
                  resource_id='device001',
                  measurement='voltage',
                  sampling_rate=timedelta(seconds=30))

# Add event handling capability to the client. 
# Calls handle_event function on every event recieved. 
client.add_handler('on_event', handle_event)

# Run the client in the Python AsyncIO Event Loop
loop = asyncio.get_event_loop()
loop.create_task(client.run())
loop.run_forever()

Example of what an event dictionary may look like:


event = {
    'event_id': '123786-129831',
    'active_period': {'dtstart': datetime.datetime(2020, 1, 1, 12, 0, 0, tzinfo=timezone.utc),
                      'duration': datetime.timedelta(minutes=30)},
    'event_signals': [{'signal_name': 'simple',
                       'signal_type': 'level',
                       'intervals': [{'dtstart': datetime.datetime(2020, 1, 1, 12, 0, 0, tzinfo=timezone.utc),
                                      'duration': datetime.timedelta(minutes=10),
                                      'signal_payload': 1},
                                      {'dtstart': datetime.datetime(2020, 1, 1, 12, 10, 0, tzinfo=timezone.utc),
                                      'duration': datetime.timedelta(minutes=10),
                                      'signal_payload': 0},
                                      {'dtstart': datetime.datetime(2020, 1, 1, 12, 20, 0, tzinfo=timezone.utc),
                                      'duration': datetime.timedelta(minutes=10),
                                      'signal_payload': 1}]}],
   'targets': [{'resource_id': 'Device001'}]
}

Conclusion:

As society and technology continue to advance, the demand for energy grows, placing increased strain on our power grids. To meet these challenges, the grid must also evolve. The adoption of technologies like OpenADR encourages a promising future – ushering in an era of cleaner, more sustainable, and efficient energy management. With such innovations, we are well on our way to a brighter energy future for both utilities and consumers.

References: