/** * Javascript module for reading day ahead spot prices from Ensto-E API. * * Copyright (c) 2022-2023 Markus Sipilä. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /** * Exports. */ module.exports = { getSpotPrices: getSpotPrices }; /** * Reads the spot prices from Entso-E API. * * @param string start * Start time for the Entso-E API call in format YYYYMMDDHHMM. * @param string end * End time for the Entso-E API call in format YYYYMMDDHHMM. * @param string zone * Bidding zone code * @param string token * Entso-E access token * @param float tax * VAT multiplier * * @return array * Array of point objects. */ function getSpotPrices(start, end, zone, token, tax) { const priceXml = makeApiCall(start, end, zone, token); const points = preparePoints(priceXml, tax); return points; } /** * Makes an API call to Entso-E API to fetch the spot prices. * * @param string start * Start time for the Entso-E API call. * @param string end * End time for the Entso-E API call. * @param string area * Entso-E area code. * @param string token * Entso-E API token. * * @return string * XML response from Ensto-E API. */ function makeApiCall(start, end, zone, token) { const http = Java.type("org.openhab.core.model.script.actions.HTTP"); console.log('entsoe.js: Making an API call to Entso-E API...'); const url = 'https://web-api.tp.entsoe.eu/api?' + 'securityToken=' + token + '&documentType=A44' + '&in_Domain=' + zone + '&out_Domain=' + zone + '&periodStart=' + start + '&periodEnd=' + end; let priceXml = ''; priceXml = http.sendHttpGetRequest(url, 10000); console.debug(priceXml); return priceXml; } /** * Parses the spot prices from the Entso-E XML response. * * @param string priceXml * Entso-E response in XML format. * @param float tax * Multiplier for VAT. * * @return array * Array of point objects. */ function preparePoints(priceXml, tax) { console.log('entose.js: transforming XML to JSON and parsing prices...'); console.debug(priceXml); const transformation = Java.type("org.openhab.core.transform.actions.Transformation"); let parsedPrices = []; try { const prices = JSON.parse(transformation.transform('XSLT', 'xml2json.xsl', priceXml)); const startUtc = prices['Publication_MarketDocument']['period.timeInterval']['start']; const points = prices['Publication_MarketDocument']['TimeSeries']['Period']['Point']; const n = Object.keys(points).length // Loop through spot prices. Convert EUR / MWh to c / kWh and add tax. for (let i = 0; i < n; i++) { let date = new Date(startUtc); date.setHours(date.getHours() + i); let price = points[i]['price.amount'] * tax / 10; price = price.toFixed(4); let point = { datetime: date.toISOString(), value: price }; parsedPrices.push(point); console.debug('entsoe.js: ' + date.toISOString() + ' ' + price + ' c/kWh'); } } catch (exception) { console.error('entsoe.js: Exception parsing spot prices: ' + exception.message); } return parsedPrices; }