REST API to KNX groups - sx3 - 27.09.2022
Hello,
I'm working on a script to control my heatpump based on actual prices on the electrical market!
So far I have managed to fetch data to the LM but now I don't know how to continue
The result contains 24 values, each for every hour of the day.
The response is in EUR/MWh so to convert it to SEK öre/kWh take the price in EUR/MWh (e.g. 11.75) times the currency exchange rate for SEK/EUR (e.g. 10.36) and then we need to divide it with 1000 to get kWh from MWh and again take it times 100 to get öre insted of SEK. We can shorten the MWh->kWh and öre->SEK by instead divide the result by ten (as divided by 1000, times 100 equals out to divided by 10), so e.g. 11.75 EUR/MWh * 10.36 / 10 = 12.173 öre/kWh.
My groupadress 5/5/6 is intended to keep the currency exchange.
I would want every read hour to be sent to a separate KNX group adress.
position 1 = 1/1/1
position 2 = 1/1/2
position 3 = 1/1/3
....
...
Code: currency = grp.getvalue('5/5/6')
http = require('socket.http')
ltn12 = require('ltn12')
res, code = http.request({
url = 'https://web-api.tp.entsoe.eu/api?securityToken=XXXXXXXXXX&documentType=A44&in_Domain=10Y1001A1001A46L&out_Domain=10Y1001A1001A46L&periodStart=202209270000&periodEnd=202209272300',
method = 'GET',
})
log(res, code)
The output in the log is:
Code: * arg: 1
* string: <?xml version="1.0" encoding="UTF-8"?>
<Publication_MarketDocument xmlns="urn:iec62325.351:tc57wg16:451-3:publicationdocument:7:0">
<mRID>5fad2c86f6644f35bfdde1c325b766bf</mRID>
<revisionNumber>1</revisionNumber>
<type>A44</type>
<sender_MarketParticipant.mRID codingScheme="A01">10X1001A1001A450</sender_MarketParticipant.mRID>
<sender_MarketParticipant.marketRole.type>A32</sender_MarketParticipant.marketRole.type>
<receiver_MarketParticipant.mRID codingScheme="A01">10X1001A1001A450</receiver_MarketParticipant.mRID>
<receiver_MarketParticipant.marketRole.type>A33</receiver_MarketParticipant.marketRole.type>
<createdDateTime>2022-09-27T14:43:39Z</createdDateTime>
<period.timeInterval>
<start>2022-09-26T22:00Z</start>
<end>2022-09-28T22:00Z</end>
</period.timeInterval>
<TimeSeries>
<mRID>1</mRID>
<businessType>A62</businessType>
<in_Domain.mRID codingScheme="A01">10Y1001A1001A46L</in_Domain.mRID>
<out_Domain.mRID codingScheme="A01">10Y1001A1001A46L</out_Domain.mRID>
<currency_Unit.name>EUR</currency_Unit.name>
<price_Measure_Unit.name>MWH</price_Measure_Unit.name>
<curveType>A01</curveType>
<Period>
<timeInterval>
<start>2022-09-26T22:00Z</start>
<end>2022-09-27T22:00Z</end>
</timeInterval>
<resolution>PT60M</resolution>
<Point>
<position>1</position>
<price.amount>13.93</price.amount>
</Point>
<Point>
<position>2</position>
<price.amount>13.00</price.amount>
</Point>
<Point>
<position>3</position>
<price.amount>12.66</price.amount>
</Point>
<Point>
<position>4</position>
<price.amount>12.97</price.amount>
</Point>
<Point>
<position>5</position>
<price.amount>14.32</price.amount>
</Point>
<Point>
<position>6</position>
<price.amount>16.20</price.amount>
</Point>
<Point>
<position>7</position>
<price.amount>24.72</price.amount>
</Point>
<Point>
<position>8</position>
<price.amount>59.41</price.amount>
</Point>
<Point>
<position>9</position>
<price.amount>90.16</price.amount>
</Point>
<Point>
<position>10</position>
<price.amount>69.95</price.amount>
</Point>
<Point>
<position>11</position>
<price.amount>69.29</price.amount>
</Point>
<Point>
<position>12</position>
<price.amount>68.76</price.amount>
</Point>
<Point>
<position>13</position>
<price.amount>62.06</price.amount>
</Point>
<Point>
<position>14</position>
<price.amount>60.86</price.amount>
</Point>
<Point>
<position>15</position>
<price.amount>58.48</price.amount>
</Point>
<Point>
<position>16</position>
<price.amount>57.42</price.amount>
</Point>
<Point>
<position>17</position>
<price.amount>58.05</price.amount>
</Point>
<Point>
<position>18</position>
<price.amount>62.05</price.amount>
</Point>
<Point>
<position>19</position>
<price.amount>66.33</price.amount>
</Point>
<Point>
<position>20</position>
<price.amount>65.16</price.amount>
</Point>
<Point>
<position>21</position>
<price.amount>60.39</price.amount>
</Point>
<Point>
<position>22</position>
<price.amount>52.37</price.amount>
</Point>
<Point>
<position>23</position>
<price.amount>46.10</price.amount>
</Point>
<Point>
<position>24</position>
<price.amount>34.73</price.amount>
</Point>
</Period>
</TimeSeries>
<TimeSeries>
<mRID>2</mRID>
<businessType>A62</businessType>
<in_Domain.mRID codingScheme="A01">10Y1001A1001A46L</in_Domain.mRID>
<out_Domain.mRID codingScheme="A01">10Y1001A1001A46L</out_Domain.mRID>
<currency_Unit.name>EUR</currency_Unit.name>
<price_Measure_Unit.name>MWH</price_Measure_Unit.name>
<curveType>A01</curveType>
<Period>
<timeInterval>
<start>2022-09-27T22:00Z</start>
<end>2022-09-28T22:00Z</end>
</timeInterval>
<resolution>PT60M</resolution>
<Point>
<position>1</position>
<price.amount>45.57</price.amount>
</Point>
<Point>
<position>2</position>
<price.amount>45.17</price.amount>
</Point>
<Point>
<position>3</position>
<price.amount>45.81</price.amount>
</Point>
<Point>
<position>4</position>
<price.amount>46.70</price.amount>
</Point>
<Point>
<position>5</position>
<price.amount>47.04</price.amount>
</Point>
<Point>
<position>6</position>
<price.amount>50.63</price.amount>
</Point>
<Point>
<position>7</position>
<price.amount>56.48</price.amount>
</Point>
<Point>
<position>8</position>
<price.amount>69.02</price.amount>
</Point>
<Point>
<position>9</position>
<price.amount>76.26</price.amount>
</Point>
<Point>
<position>10</position>
<price.amount>77.24</price.amount>
</Point>
<Point>
<position>11</position>
<price.amount>76.49</price.amount>
</Point>
<Point>
<position>12</position>
<price.amount>76.34</price.amount>
</Point>
<Point>
<position>13</position>
<price.amount>76.09</price.amount>
</Point>
<Point>
<position>14</position>
<price.amount>76.43</price.amount>
</Point>
<Point>
<position>15</position>
<price.amount>76.81</price.amount>
</Point>
<Point>
<position>16</position>
<price.amount>76.88</price.amount>
</Point>
<Point>
<position>17</position>
<price.amount>72.22</price.amount>
</Point>
<Point>
<position>18</position>
<price.amount>75.92</price.amount>
</Point>
<Point>
<position>19</position>
<price.amount>75.72</price.amount>
</Point>
<Point>
<position>20</position>
<price.amount>75.61</price.amount>
</Point>
<Point>
<position>21</position>
<price.amount>76.76</price.amount>
</Point>
<Point>
<position>22</position>
<price.amount>70.25</price.amount>
</Point>
<Point>
<position>23</position>
<price.amount>70.00</price.amount>
</Point>
<Point>
<position>24</position>
<price.amount>60.17</price.amount>
</Point>
</Period>
</TimeSeries>
</Publication_MarketDocument>
* arg: 2
* number: 200
One other thing, I would want the following string in the adress to be dynamic and also always be the date of tomorrow, but the time should be static.
"periodStart=202209270000&periodEnd=202209272300"
RE: REST API to KNX groups - admin - 28.09.2022
Try this:
Code: date = os.date('%Y%m%d')
periodstart = date .. '0000'
periodend = date .. '2300'
url = 'https://web-api.tp.entsoe.eu/api?securityToken=XXXXXXXXXX&' ..
'documentType=A44&in_Domain=10Y1001A1001A46L&out_Domain=10Y1001A1001A46L&' ..
'periodStart=' .. periodstart .. '&periodEnd=' .. periodend
data, code = require('socket.http').request(url)
if not data or code ~= 200 then
log('request failed', data, code)
return
end
prices = {}
key = 0
callbacks = {
StartElement = function(p, tag)
if tag == 'TimeSeries' then
key = key + 1
prices[ key ] = {}
elseif tag == 'position' then
state = 'position'
elseif tag == 'price.amount' then
state = 'price'
end
end,
EndElement = function(p, tag)
state = nil
end,
CharacterData = function(p, value)
value = value:trim()
if #value > 0 then
if state == 'position' then
position = tonumber(value)
elseif state == 'price' then
prices[ key ][ position ] = tonumber(value)
end
end
end
}
parser = require('lxp').new(callbacks)
parser:parse(data)
parser:close()
if key > 0 then
rate = grp.getvalue('5/5/6')
for i, price in pairs(prices[ 1 ]) do
grp.checkupdate('1/1/' .. i, price * rate / 10)
end
end
RE: REST API to KNX groups - sx3 - 28.09.2022
Thanks!
If I would want to manipulate the "date = os.date('%Y%m%d')" to be tomorrows date, would be a simple adjustment?
In example, September is only 30 days, if plussing 1 it shouldn't be 31, instead October 1st.
Also I'm thinking maybe the REST API with all the currency exchanges would be a little bit advanced.
I've found a JSON API with currency and power units already correct.
https://www.vattenfall.se/api/price/spot/pricearea/2022-09-28/2022-09-28/SN3
RE: REST API to KNX groups - admin - 28.09.2022
Use this to calculate tomorrow's date:
Code: date = os.date('%Y%m%d', os.time() + 86400)
RE: REST API to KNX groups - sx3 - 29.09.2022
Thanks Admin,
I went with the JSON API from Vattenfall instead, I have made the code to work. However not the prettiest code
I would want that, if the Vattenfall homepage is not responding or something goes wrong fetching info, set all the group adresses to "0"
How should I think when writing that code!?
Also, the timestamp format is YYYY-MM--DD while the DTP 11 is DD-MM-YYYY, so the value in my groupadress is "00-00-2000" after writing.
Code: require('json')
https = require 'ssl.https'
date = os.date('%Y-%m-%d')
url = 'https://www.vattenfall.se/api/price/spot/pricearea/' .. date .. '/' .. date .. '/SN3'
status = ssl.https.request(url)
data = json.decode(status)
timestamp = data[1].TimeStampDay
grp.checkupdate('5/5/28', timestamp)
price1 = data[1].Value
grp.checkupdate('5/5/1', price1)
price2 = data[2].Value
grp.checkupdate('5/5/2', price2)
price3 = data[3].Value
grp.checkupdate('5/5/3', price3)
price4 = data[4].Value
grp.checkupdate('5/5/4', price4)
price5 = data[5].Value
grp.checkupdate('5/5/5', price5)
price6 = data[6].Value
grp.checkupdate('5/5/6', price6)
price7 = data[7].Value
grp.checkupdate('5/5/7', price7)
price8 = data[8].Value
grp.checkupdate('5/5/8', price8)
price9 = data[9].Value
grp.checkupdate('5/5/9', price9)
price10 = data[10].Value
grp.checkupdate('5/5/10', price10)
price11 = data[11].Value
grp.checkupdate('5/5/11', price11)
price12 = data[12].Value
grp.checkupdate('5/5/12', price12)
price13 = data[13].Value
grp.checkupdate('5/5/13', price13)
price14 = data[14].Value
grp.checkupdate('5/5/14', price14)
price15 = data[15].Value
grp.checkupdate('5/5/15', price15)
price16 = data[16].Value
grp.checkupdate('5/5/16', price16)
price17 = data[17].Value
grp.checkupdate('5/5/17', price17)
price18 = data[18].Value
grp.checkupdate('5/5/18', price18)
price19 = data[19].Value
grp.checkupdate('5/5/19', price19)
price20 = data[20].Value
grp.checkupdate('5/5/20', price20)
price21 = data[21].Value
grp.checkupdate('5/5/21', price21)
price22 = data[22].Value
grp.checkupdate('5/5/22', price22)
price23 = data[23].Value
grp.checkupdate('5/5/23', price23)
price24 = data[24].Value
grp.checkupdate('5/5/24', price24)
medelpris = price1+price2+price3+price4+price5+price6+price7+price8+price9+price10+price11+price12+price13+price14+price15+price16+price17+price18+price19+price20+price21+price22+price23+price24
medelpris = medelpris / 24
grp.checkupdate('5/5/25', medelpris)
maxpris = math.max(price1, price2, price3, price4, price5, price6, price7, price8, price9, price10, price11, price12, price13, price14, price15, price16, price17, price18, price19, price20, price21, price22, price23, price24)
grp.checkupdate('5/5/26', maxpris)
minpris = math.min(price1, price2, price3, price4, price5, price6, price7, price8, price9, price10, price11, price12, price13, price14, price15, price16, price17, price18, price19, price20, price21, price22, price23, price24)
grp.checkupdate('5/5/27', minpris)
log(price1,price2)
RE: REST API to KNX groups - admin - 30.09.2022
A for loop makes the code more compact and can't cause copy-paste errors. DPT 11 expects a table with year/month/day, not a string.
Code: require('json')
https = require 'ssl.https'
date = os.date('%Y-%m-%d')
url = 'https://www.vattenfall.se/api/price/spot/pricearea/' .. date .. '/' .. date .. '/SN3'
status = ssl.https.request(url)
data = json.decode(status)
if type(data) ~= 'table' then
return
end
ts = data[ 1 ].TimeStampDay
if type(ts) == 'string' then
ts = ts:split('-')
grp.checkupdate('5/5/28', {
year = tonumber(ts[1]),
month = tonumber(ts[2]),
day = tonumber(ts[3])
})
end
min = math.huge
max = -math.huge
cnt = 0
sum = 0
for i, item in ipairs(data) do
price = item.Value
min = math.min(min, price)
max = math.max(max, price)
sum = sum + price
cnt = cnt + 1
grp.checkupdate('5/5/' .. i, price)
end
grp.checkupdate('5/5/25', sum / cnt)
grp.checkupdate('5/5/26', max)
grp.checkupdate('5/5/27', min)
|