### Usage Point XML Schema Example Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt An example of the Usage Point XML structure, detailing service category, delivery point, and physical service location including address and geographic coordinates. This structure is used to represent metering data points. ```xml 0 Main Building Electric Service COMMERCIAL-RATE-A AGR-789456 123 Main Street St Street San Francisco CA 94102 US 37.7749 -122.4194 ACCT-987654321 MTR-456789 ``` -------------------------------- ### Handle DST and Time Zones in ESPI Data (XML, Python) Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt Illustrates how to manage Daylight Saving Time (DST) rules and time zone offsets within ESPI data structures using XML examples. The Python code includes functions to decode DST rules and apply time zone and DST offsets to UTC timestamps for accurate local time representation. ```xml 0 B40E2000 B40B2000 3600 -28800 86400 1709445600 3600 1709445600 1250 ``` ```python from datetime import datetime, timezone, timedelta import struct def decode_dst_rule(hex_rule): """ Decode DST rule from hex format (B40E2000 format). Returns: dict with month, week, day_of_week, time """ rule_bytes = bytes.fromhex(hex_rule) # B4 = month (bits 8-11), week (bits 12-15) # 0E = day of week (bits 0-2), time in 15-min intervals month = (rule_bytes[0] & 0x0F) week = (rule_bytes[1] >> 4) day_of_week = (rule_bytes[1] & 0x07) time_intervals = rule_bytes[2] return { 'month': month, 'week': week, 'day_of_week': day_of_week, 'hour': (time_intervals * 15) // 60 } def apply_timezone_offset(unix_timestamp, tz_offset_seconds, dst_active=False, dst_offset_seconds=0): """ Convert UTC timestamp to local time with DST consideration. Args: unix_timestamp: Unix epoch timestamp tz_offset_seconds: Timezone offset from UTC in seconds (negative for west) dst_active: Whether DST is active dst_offset_seconds: DST offset in seconds (typically 3600) """ utc_time = datetime.fromtimestamp(unix_timestamp, tz=timezone.utc) total_offset = tz_offset_seconds if dst_active: total_offset += dst_offset_seconds local_time = utc_time + timedelta(seconds=total_offset) return local_time # Example usage timestamp = 1709445600 # 2025-03-03 00:00:00 UTC tz_offset = -28800 # PST: UTC-8 dst_offset = 3600 # 1 hour dst_active = False # Before DST transition local_time = apply_timezone_offset(timestamp, tz_offset, dst_active, dst_offset) print(f"Local time: {local_time.strftime('%Y-%m-%d %H:%M:%S %Z')}") # Output: Local time: 2025-03-02 16:00:00 UTC # Decode DST rules dst_start = decode_dst_rule("B40E2000") print(f"DST starts: Month {dst_start['month']}, Week {dst_start['week']}, Hour {dst_start['hour']}") # Output: DST starts: Month 3, Week 2, Hour 2 ``` -------------------------------- ### Validate Green Button DMD XML with Online Service Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt Demonstrates how to use a `curl` command to validate Green Button Download My Data (DMD) XML files against Atom and ESPI schemas using the Green Button Alliance validator. It shows example requests and expected response formats for both valid and invalid files. ```bash # Validate a Green Button XML file using the online validator curl -X POST https://validator.greenbuttonalliance.org/api/validate \ -H "Content-Type: multipart/form-data" \ -F "file=@usage_data.xml" \ -F "validation_type=dmd" \ -F "schema_version=espi_1_1" # Response format: # { # "valid": true, # "version": "1.1", # "errors": [], # "warnings": [ # { # "line": 45, # "message": "Optional element is missing", # "severity": "warning" # } # ], # "resources": { # "usage_points": 2, # "meter_readings": 4, # "interval_blocks": 8, # "reading_types": 2 # } # } # Example validation error response: # { # "valid": false, # "errors": [ # { # "line": 23, # "column": 15, # "message": "Invalid namespace: expected 'http://naesb.org/espi'", # "severity": "error" # }, # { # "line": 67, # "message": "Required element <kind> is missing in ServiceCategory", # "severity": "error" # } # ], # "warnings": [] ``` -------------------------------- ### Validate Green Button XML with Python Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt This Python script uses the 'requests' library to send an XML file to the Green Button Alliance validator API. It handles file uploads, schema version selection, and parses the JSON response to report validation success or failure with specific error messages. It requires the 'requests' library to be installed. ```python import requests import xml.etree.ElementTree as ET def validate_green_button_xml(file_path, schema_version='espi_1_1'): """ Validate Green Button XML file against ESPI schema. Args: file_path: Path to XML file schema_version: ESPI schema version (espi_1_1, espi_1_2) Returns: dict with validation results """ url = 'https://validator.greenbuttonalliance.org/api/validate' try: with open(file_path, 'rb') as f: files = {'file': f} data = { 'validation_type': 'dmd', 'schema_version': schema_version } response = requests.post(url, files=files, data=data) response.raise_for_status() result = response.json() if result['valid']: print(f"✓ Validation successful!") print(f" Resources: {result['resources']}") else: print(f"✗ Validation failed with {len(result['errors'])} error(s)") for error in result['errors']: print(f" Line {error.get('line', 'N/A')}: {error['message']}") if result.get('warnings'): print(f"⚠ {len(result['warnings'])} warning(s):") for warning in result['warnings']: print(f" Line {warning.get('line', 'N/A')}: {warning['message']}") return result except requests.exceptions.RequestException as e: return {'valid': False, 'errors': [{'message': f'Validation service error: {str(e)}'}]} # Example usage validation_result = validate_green_button_xml('usage_data.xml') if validation_result['valid']: print("Ready to process Green Button data") else: print("Fix errors before processing") ``` -------------------------------- ### Green Button REST API - Get Interval Data Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt Retrieve interval energy consumption data for a specific usage point within a date range. ```APIDOC ## GET /DataCustodian/espi/1_1/resource/Subscription/{subscriptionId}/UsagePoint/{usagePointId}/MeterReading/{meterReadingId}/IntervalBlock ### Description Retrieves detailed interval consumption data for a specific meter reading, filtered by publication date. This endpoint provides the granular energy usage readings. ### Method GET ### Endpoint `/DataCustodian/espi/1_1/resource/Subscription/{subscriptionId}/UsagePoint/{usagePointId}/MeterReading/{meterReadingId}/IntervalBlock` ### Parameters #### Path Parameters - **subscriptionId** (string) - Required - The unique identifier for the subscription. - **usagePointId** (string) - Required - The unique identifier for the usage point. - **meterReadingId** (string) - Required - The unique identifier for the meter reading. #### Query Parameters - **published-min** (string) - Optional - The minimum publication date for filtering interval data (ISO 8601 format, e.g., `2025-01-01T00:00:00Z`). - **published-max** (string) - Optional - The maximum publication date for filtering interval data (ISO 8601 format, e.g., `2025-01-31T23:59:59Z`). #### Request Body None ### Request Example ```bash curl -X GET "https://api.utility.com/DataCustodian/espi/1_1/resource/Subscription/5/UsagePoint/1/MeterReading/1/IntervalBlock?published-min=2025-01-01T00:00:00Z&published-max=2025-01-31T23:59:59Z" \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Accept: application/atom+xml" ``` ### Response #### Success Response (200 OK) - Returns an Atom feed (`application/atom+xml`) containing `IntervalBlock` resources with detailed consumption readings, timestamps, and quantities. #### Response Example (Atom feed XML structure containing IntervalBlock elements with readings) ``` -------------------------------- ### Map Utility Bill to ESPI Usage Summary (Python) Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt Maps a utility bill object to the ESPI (Energy Services Provider Interface) usage summary format. This involves converting dates to Unix timestamps, costs to cents, and structuring line items. Dependencies include datetime objects and custom mappers. ```python class BillToESPIMapper: def to_unix_timestamp(self, dt): # Placeholder for actual timestamp conversion return int(dt.timestamp()) def to_espi_cost(self, amount): # Placeholder for actual cost conversion to cents return int(amount * 100) def map_bill_to_usage_summary(self, bill): usage_summary = { 'billToDate': self.to_espi_cost(bill.current_bill_amount), 'overallConsumptionLastPeriod': { 'value': bill.energy_consumption_kwh, 'uom': 36, # kWh 'quality': [63], # Raw data 'readInterval': 1, 'readingType': ' ', # Placeholder 'registers': [], 'unit': 'kWh' }, 'lineItems': [] } # Add peak demand information usage_summary['peakDemandLastPeriod'] = { 'value': int(bill.peak_demand_kw), 'uom': 38, # kW 'quality': [63], # Raw data 'readInterval': 1, 'readingType': ' ', # Placeholder 'registers': [], 'unit': 'kW' } # Add line items for item in bill.line_items: usage_summary['lineItems'].append({ 'amount': self.to_espi_cost(item.amount), 'dateTime': self.to_unix_timestamp(item.date), 'note': item.description, 'rounding': 0 }) return usage_summary # Example usage from datetime import datetime class UtilityBill: def __init__(self, account_number, billing_period_start, billing_period_end, previous_bill_amount, current_bill_amount, energy_consumption_kwh, peak_demand_kw, taxes_and_fees, line_items): self.account_number = account_number self.billing_period_start = billing_period_start self.billing_period_end = billing_period_end self.previous_bill_amount = previous_bill_amount self.current_bill_amount = current_bill_amount self.energy_consumption_kwh = energy_consumption_kwh self.peak_demand_kw = peak_demand_kw self.taxes_and_fees = taxes_and_fees self.line_items = line_items class BillLineItem: def __init__(self, description, amount, date): self.description = description self.amount = amount self.date = date bill = UtilityBill( account_number='ACCT-987654321', billing_period_start=datetime(2025, 1, 1), billing_period_end=datetime(2025, 2, 1), previous_bill_amount=85.32, current_bill_amount=92.48, energy_consumption_kwh=543, peak_demand_kw=12.0, taxes_and_fees=14.28, line_items=[ BillLineItem('Energy Charges (543 kWh @ $0.10438/kWh)', 56.70, datetime(2025, 2, 1)), BillLineItem('Demand Charges (12 kW @ $1.79/kW)', 21.50, datetime(2025, 2, 1)), BillLineItem('Taxes and Regulatory Fees', 14.28, datetime(2025, 2, 1)) ] ) mapper = BillToESPIMapper() espi_data = mapper.map_bill_to_usage_summary(bill) print(f"Bill amount in ESPI format: {espi_data['billToDate']}") # 924800 print(f"Energy consumption: {espi_data['overallConsumptionLastPeriod']['value']} kWh") # 543 print(f"Number of line items: {len(espi_data['lineItems'])}") # 3 ``` -------------------------------- ### Python Utility Bill to ESPI Usage Summary Mapping Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt Provides a Python class `BillToESPIMapper` to convert custom `UtilityBill` objects into the ESPI Usage Summary dictionary format. It handles currency conversions, timestamp generation, and structuring of consumption and line item data. Dependencies include Python's `dataclasses` and `datetime` modules. ```python from dataclasses import dataclass from datetime import datetime from typing import List, Optional @dataclass class BillLineItem: description: str amount: float date: datetime @dataclass class UtilityBill: account_number: str billing_period_start: datetime billing_period_end: datetime previous_bill_amount: float current_bill_amount: float energy_consumption_kwh: float peak_demand_kw: Optional[float] line_items: List[BillLineItem] taxes_and_fees: float currency_code: int = 840 # USD class BillToESPIMapper: """Convert utility bill data to ESPI Usage Summary format""" COST_SCALE = 10000 # Scale factor for currency (10^-4) @staticmethod def to_espi_cost(amount: float) -> int: """Convert dollar amount to ESPI integer format""" return round(amount * BillToESPIMapper.COST_SCALE) @staticmethod def to_unix_timestamp(dt: datetime) -> int: """Convert datetime to Unix epoch""" return int(dt.timestamp()) @staticmethod def map_bill_to_usage_summary(bill: UtilityBill) -> dict: """Map utility bill to ESPI Usage Summary structure""" duration = int((bill.billing_period_end - bill.billing_period_start).total_seconds()) usage_summary = { 'billingPeriod': { 'duration': duration, 'start': BillToESPIMapper.to_unix_timestamp(bill.billing_period_start) }, 'billLastPeriod': BillToESPIMapper.to_espi_cost(bill.previous_bill_amount), 'billToDate': BillToESPIMapper.to_espi_cost(bill.current_bill_amount), 'costAdditionalLastPeriod': BillToESPIMapper.to_espi_cost(bill.taxes_and_fees), 'currency': bill.currency_code, 'qualityOfReading': 14, # Valid and verified 'statusTimeStamp': BillToESPIMapper.to_unix_timestamp(bill.billing_period_end), 'overallConsumptionLastPeriod': { 'powerOfTenMultiplier': 0, 'timeStamp': BillToESPIMapper.to_unix_timestamp(bill.billing_period_end), 'uom': 72, # kWh 'value': int(bill.energy_consumption_kwh) }, 'lineItems': [] } # Add peak demand if available if bill.peak_demand_kw: usage_summary['currentDayMaxDemand'] = { 'powerOfTenMultiplier': 0, ``` -------------------------------- ### Represent Cost and Currency in Green Button XML Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt Illustrates the XML structure for representing cost and currency using integer scaling for accuracy in energy billing data. It shows how values like billing amounts, fees, and consumption are encoded with appropriate units and multipliers. ```xml <UsageSummary xmlns="http://naesb.org/espi"> <billingPeriod> <duration>2678400</duration> <!-- 31 days in seconds --> <start>1704067200</start> <!-- 2025-01-01 --> </billingPeriod> <billLastPeriod>8532000</billLastPeriod> <!-- $85.32 --> <billToDate>12478900</billToDate> <!-- $124.789 (rounded to $124.79) --> <costAdditionalLastPeriod>250000</costAdditionalLastPeriod> <!-- $2.50 fees --> <currency>840</currency> <!-- ISO 4217: USD (840), EUR (978), GBP (826) --> <overallConsumptionLastPeriod> <powerOfTenMultiplier>0</powerOfTenMultiplier> <uom>72</uom> <!-- kWh --> <value>456</value> <!-- 456 kWh --> </overallConsumptionLastPeriod> </UsageSummary> ``` -------------------------------- ### Atom Elements in Green Button XML Files Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt Demonstrates the structure of Green Button energy data files using the Atom Syndication Format, which serves as a container for ESPI resource representations. This XML format is essential for organizing and presenting energy usage data. ```xml <?xml version="1.0" encoding="UTF-8"?> <feed xmlns="http://www.w3.org/2005/Atom" xmlns:espi="http://naesb.org/espi"> <id>urn:uuid:97EAEBAD-1214-4A58-A3D4-A16A6DE718E1</id> <title>Green Button Usage Feed 2025-01-15T14:30:00Z urn:uuid:DEB0A337-C1B5-4658-99BA-4688E253A99B Electric Meter - 123 Main St 2025-01-01T00:00:00Z 2025-01-15T14:30:00Z 0 ``` -------------------------------- ### Java Utilities for Green Button Cost Handling Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt Provides Java methods for converting between decimal currency values and the integer-scaled format used in Green Button data. It includes functions for converting to and from Green Button cost, and for formatting currency with appropriate symbols based on ISO codes. ```java import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Currency; public class GreenButtonCostHandler { private static final int CURRENCY_SCALE = 4; // Standard Green Button scale: 10^-4 /** * Convert decimal currency value to Green Button integer format */ public static long toGreenButtonCost(BigDecimal amount) { return amount.multiply(BigDecimal.valueOf(10000)) .setScale(0, RoundingMode.HALF_UP) .longValue(); } /** * Convert Green Button integer to decimal currency value */ public static BigDecimal fromGreenButtonCost(long greenButtonValue) { return BigDecimal.valueOf(greenButtonValue) .divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP); } /** * Format currency with proper symbol */ public static String formatCurrency(long greenButtonValue, int currencyCode) { BigDecimal amount = fromGreenButtonCost(greenButtonValue); Currency currency; switch (currencyCode) { case 840: currency = Currency.getInstance("USD"); break; case 978: currency = Currency.getInstance("EUR"); break; case 826: currency = Currency.getInstance("GBP"); break; default: currency = Currency.getInstance("USD"); } return currency.getSymbol() + amount.toPlainString(); } public static void main(String[] args) { // Example: Converting bill amount to Green Button format BigDecimal billAmount = new BigDecimal("85.32"); long greenButtonValue = toGreenButtonCost(billAmount); System.out.println("Bill amount: " + billAmount + " â2122 " + greenButtonValue); // Output: Bill amount: 85.32 â2122 853200 // Example: Reading from Green Button data long costFromXml = 12478900L; BigDecimal actualCost = fromGreenButtonCost(costFromXml); System.out.println("Green Button value: " + costFromXml + " â2122 $ " + actualCost); // Output: Green Button value: 12478900 â2122 $ 1247.89 // Example: Formatting with currency String formatted = formatCurrency(8532000L, 840); System.out.println("Formatted: " + formatted); // Output: Formatted: $853.20 } } ``` -------------------------------- ### Implement OAuth 2.0 for Green Button Authorization (JavaScript) Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt This snippet demonstrates the OAuth 2.0 authorization flow for Green Button. It includes steps for redirecting users, handling callbacks with authorization codes, exchanging codes for access tokens, and refreshing expired tokens. It relies on the `fetch` API and `URLSearchParams` for making HTTP requests. Ensure secure storage of tokens. ```javascript // Step 1: Redirect user to Data Custodian authorization endpoint const authorizationUrl = 'https://api.utility.com/DataCustodian/oauth/authorize?' + new URLSearchParams({ response_type: 'code', client_id: 'YOUR_CLIENT_ID', redirect_uri: 'https://thirdparty.com/callback', scope: 'FB=1_3_4_5_13_14_15_16_31_32_33_34_35_36_37_38_39_40_41_44;IntervalDuration=3600;BlockDuration=monthly;HistoryLength=13' }).toString(); // Redirect user: window.location.href = authorizationUrl; // Step 2: Handle callback with authorization code app.get('/callback', async (req, res) => { const { code, error } = req.query; if (error) { return res.status(400).json({ error: 'Authorization failed', details: error }); } try { // Exchange authorization code for access token const tokenResponse = await fetch('https://api.utility.com/DataCustodian/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic ' + Buffer.from('YOUR_CLIENT_ID:YOUR_CLIENT_SECRET').toString('base64') }, body: new URLSearchParams({ grant_type: 'authorization_code', code: code, redirect_uri: 'https://thirdparty.com/callback' }) }); const tokens = await tokenResponse.json(); // Store tokens.access_token, tokens.refresh_token securely res.json({ success: true, resource_uri: tokens.resourceURI }); } catch (err) { res.status(500).json({ error: 'Token exchange failed', details: err.message }); } }); // Step 3: Refresh expired access token async function refreshAccessToken(refreshToken) { const response = await fetch('https://api.utility.com/DataCustodian/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic ' + Buffer.from('YOUR_CLIENT_ID:YOUR_CLIENT_SECRET').toString('base64') }, body: new URLSearchParams({ grant_type: 'refresh_token', refresh_token: refreshToken }) }); return await response.json(); } ``` -------------------------------- ### XML Schema for ESPI Usage Summary Resource Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt Defines the structure for representing utility billing data in the ESPI Usage Summary format. It includes details on billing periods, costs, consumption, and line item charges. This schema is crucial for standardized data exchange in the Green Button ecosystem. ```xml 2678400 1704067200 8532000 9247500 1250000 840 14 1706745600 0 1706745600 72 543 0 1709424000 72 587 0 1705348800 38 12 5670000 1706745600 Energy Charges (543 kWh @ $0.10438/kWh) 0 2150000 1706745600 Demand Charges (12 kW @ $1.79/kW) 1427500 1706745600 Taxes and Regulatory Fees ``` -------------------------------- ### JavaScript Usage Point and Service Location Mapper Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt A JavaScript class `ServiceLocationMapper` with static methods to create Usage Point objects from account data and extract service location details from a Usage Point object. It facilitates the integration of service location data into the Usage Point structure. ```javascript // JavaScript mapping helper class ServiceLocationMapper { /** * Create Usage Point with service location mapping */ static createUsagePointWithLocation(accountData) { return { usagePoint: { serviceCategory: { kind: accountData.serviceType || 0 }, serviceDeliveryPoint: { name: accountData.serviceName, tariffProfile: accountData.rateSchedule, customerAgreement: accountData.agreementId }, serviceLocation: { mainAddress: { streetDetail: { number: accountData.address.streetNumber, name: accountData.address.streetName, suffix: accountData.address.streetSuffix, type: accountData.address.streetType }, townDetail: { name: accountData.address.city, stateOrProvince: accountData.address.state, code: accountData.address.zipCode, country: accountData.address.country || 'US' } }, geoInfoReference: accountData.coordinates ? { latitude: accountData.coordinates.lat, longitude: accountData.coordinates.lon } : null }, accountId: accountData.accountNumber, meterSerialNumber: accountData.meterSerial } }; } /** * Extract service location from Usage Point */ static extractServiceLocation(usagePointXml) { // Parse XML and extract location const location = { address: `${usagePointXml.serviceLocation.mainAddress.streetDetail.number} ` + `${usagePointXml.serviceLocation.mainAddress.streetDetail.name} ` + `${usagePointXml.serviceLocation.mainAddress.streetDetail.suffix}`, city: usagePointXml.serviceLocation.mainAddress.townDetail.name, state: usagePointXml.serviceLocation.mainAddress.townDetail.stateOrProvince, zip: usagePointXml.serviceLocation.mainAddress.townDetail.code, coordinates: usagePointXml.serviceLocation.geoInfoReference }; return location; } } // Example usage const accountData = { serviceName: 'Main Building Electric Service', serviceType: 0, rateSchedule: 'COMMERCIAL-RATE-A', agreementId: 'AGR-789456', accountNumber: 'ACCT-987654321', meterSerial: 'MTR-456789', address: { streetNumber: '123', streetName: 'Main', streetSuffix: 'St', streetType: 'Street', city: 'San Francisco', state: 'CA', zipCode: '94102', country: 'US' }, coordinates: { lat: 37.7749, lon: -122.4194 } }; const usagePoint = ServiceLocationMapper.createUsagePointWithLocation(accountData); console.log(JSON.stringify(usagePoint, null, 2)); ``` -------------------------------- ### Apply Power-of-Ten Multipliers in ESPI Data (XML, JavaScript) Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt Demonstrates how to represent and interpret scaled integer values in ESPI data using power-of-ten multipliers. The JavaScript code provides helper functions to apply and remove these multipliers, useful for both reading and preparing ESPI data for energy consumption and costs. ```xml 3600 1704067200 123456 -2 72 452300 840 -4 ``` ```javascript // JavaScript helper for applying multipliers function applyMultiplier(value, powerOfTen) { return value * Math.pow(10, powerOfTen); } function removeMultiplier(decimalValue, powerOfTen) { return Math.round(decimalValue * Math.pow(10, -powerOfTen)); } // Reading values from ESPI const intervalReading = { value: 123456, powerOfTenMultiplier: -2, uom: 72 // kWh }; const actualKwh = applyMultiplier(intervalReading.value, intervalReading.powerOfTenMultiplier); console.log(`Energy consumption: ${actualKwh} kWh`); // 1234.56 kWh // Preparing values for ESPI const costInDollars = 45.23; const powerOfTen = -4; const costInteger = removeMultiplier(costInDollars, powerOfTen); console.log(`ESPI cost value: ${costInteger}`); // 452300 ``` -------------------------------- ### Green Button REST API OAuth Authentication and Data Retrieval Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt Illustrates the process of interacting with Green Button Data Custodian REST APIs. It covers obtaining an OAuth access token, retrieving usage points for a subscription, and fetching interval data for a specific usage point and date range. Requires a valid client ID and secret for token exchange. ```bash # Step 1: Obtain OAuth access token curl -X POST https://api.utility.com/DataCustodian/oauth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -H "Authorization: Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=" \ -d "grant_type=authorization_code" \ -d "code=AUTH_CODE_FROM_USER_AUTHORIZATION" \ -d "redirect_uri=https://thirdparty.com/callback" # Response: # { # "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", # "token_type": "Bearer", # "expires_in": 3600, # "refresh_token": "8xLOxBtZp8", # "scope": "FB=1_3_4_5_13_14_15_16_31_32_33_34_35_36_37_38_39_40_41_44;IntervalDuration=3600" # } # Step 2: Retrieve usage data for a specific subscription curl -X GET https://api.utility.com/DataCustodian/espi/1_1/resource/Subscription/5/UsagePoint \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Accept: application/atom+xml" # Step 3: Get interval data for a specific usage point and date range curl -X GET "https://api.utility.com/DataCustodian/espi/1_1/resource/Subscription/5/UsagePoint/1/MeterReading/1/IntervalBlock?published-min=2025-01-01T00:00:00Z&published-max=2025-01-31T23:59:59Z" \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Accept: application/atom+xml" # Response includes interval readings with timestamps and consumption values ``` -------------------------------- ### Green Button XML Usage Point for Aggregated Data Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt This XML snippet demonstrates the structure for representing an aggregated Usage Point in Green Button data. It includes details about the service category, status, role flags indicating aggregated data, and a ServiceDeliveryPoint name. It also shows a MeterReading entry with aggregated Interval data, specifying daily aggregation and a total consumption value. ```xml urn:uuid:AFC97598-8DD8-43A1-A8E0-D6F8C3E5F2A1 Aggregated Usage Feed - Corporate Campus urn:uuid:B1C2D3E4-F5A6-4B7C-8D9E-0F1A2B3C4D5E Corporate Campus - Aggregated Electric Usage 0 1 12 Aggregated - Buildings 1-5 urn:uuid:C2D3E4F5-A6B7-4C8D-9E0F-1A2B3C4D5E6F 86400 1704067200 86400 1704067200 125000 -2 72 12 ``` -------------------------------- ### Green Button REST API - Retrieve Usage Data Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt Retrieve energy usage data for a specific subscription, including usage points. ```APIDOC ## GET /DataCustodian/espi/1_1/resource/Subscription/{id}/UsagePoint ### Description Retrieves a list of usage points associated with a given subscription ID. This is typically the first step in accessing detailed energy data for a customer. ### Method GET ### Endpoint `/DataCustodian/espi/1_1/resource/Subscription/{id}/UsagePoint` ### Parameters #### Path Parameters - **id** (string) - Required - The unique identifier for the subscription. #### Query Parameters None #### Request Body None ### Request Example ```bash curl -X GET https://api.utility.com/DataCustodian/espi/1_1/resource/Subscription/5/UsagePoint \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Accept: application/atom+xml" ``` ### Response #### Success Response (200 OK) - Returns an Atom feed (`application/atom+xml`) containing `UsagePoint` resources. #### Response Example (Atom feed XML structure containing UsagePoint elements) ``` -------------------------------- ### Generate Persistent UUIDs for Green Button Resources (Python) Source: https://context7.com/context7/greenbuttonalliance_developer-resources/llms.txt This Python function generates Version 5 UUIDs using SHA-1 hashing, ensuring that the same input parameters consistently produce the same UUID. This is useful for creating persistent and reproducible identifiers for Green Button resources. It requires the `uuid` and `hashlib` libraries. ```python import uuid import hashlib # Define namespace UUID for Green Button (example - use your organization's namespace) GREEN_BUTTON_NAMESPACE = uuid.UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8') def generate_persistent_uuid(resource_type, unique_identifier): """ Generate a Version 5 UUID for a Green Button resource. Args: resource_type: Type of resource (e.g., 'UsagePoint', 'MeterReading') unique_identifier: Unique identifier from source system (e.g., meter ID) Returns: UUID string in URN format """ # Combine resource type and identifier name = f"{resource_type}:{unique_identifier}" # Generate Version 5 UUID using SHA-1 resource_uuid = uuid.uuid5(GREEN_BUTTON_NAMESPACE, name) return f"urn:uuid:{resource_uuid}" # Example usage usage_point_id = generate_persistent_uuid('UsagePoint', 'MTR-12345-67890') print(f"UsagePoint UUID: {usage_point_id}") # Output: UsagePoint UUID: urn:uuid:a1b2c3d4-e5f6-5789-a1b2-c3d4e5f67890 meter_reading_id = generate_persistent_uuid('MeterReading', 'MTR-12345-67890-2025-01') print(f"MeterReading UUID: {meter_reading_id}") # Output: MeterReading UUID: urn:uuid:b2c3d4e5-f6a7-5890-b2c3-d4e5f6a78901 # Verify persistence - same input always produces same UUID duplicate_id = generate_persistent_uuid('UsagePoint', 'MTR-12345-67890') assert usage_point_id == duplicate_id # True ```