Nordpool integration

Is there a way to integrate Nordpool? As in hour-by-hour electricity price? This works in Nordic countries, but now I’m looking specially solution for/from Finland.

I don’t know much about coding, but I believe there is a free API (API | Nord Pool) and pricing can be found also from couple more websites.

Like this someone private user webpage: https://sahko.tk/

I have seen solutions in HA, but how about in HE?

I’d like to control heating and warm water when hours are cheap.

1 Like

It does not look like the most complicated API, but I am not sure how many people want to get involved with an API that could potentially cost users if there is a mistake (or bug). With this one's auction and intraday trading systems I would be very hesitant to work on it like many of the other API drivers I have written.

Great thanks for your comments! @snell

Do you have any other ideas for this pricing? I was thinking even if virtual switch would work, when price is under xxEUR switch is on and if over xxEUR it is off. Or something to start with, but I have no Idea how to continue. :face_with_hand_over_mouth:

Found also this site: Market data | Nord Pool

Well... they have a notice right on that site that automatic extraction of data (ie: scraping the website to get the values) is against their terms and conditions.

So it should still be possible to do via the API... but their API exposes so much other stuff that you would not need. They really did not make it with residential customers in mind.

Okay.

How about this website? Data view

They do offer pricing day-ahead through Europe.

This system seems like it would be better to use, although they ALSO require an account for using their API. But the data seems relatively simple to use if you understand their regions and such. Here is the spot about authentication and requesting an account:
Authentication and Authorization Section

From what I can read of it, something like this (with an authentication token as part of it, you would replace the <TOKEN> with what is provided) would work for Finland (the Domain value specified), and the periods are structured as YYYYMMDDhhmm:

https://transparency.entsoe.eu/api?securityToken=<TOKEN>&documentType=A44&in_Domain=10YFI-1--------U&out_Domain=10YFI-1--------U&periodStart=202207122200&periodEnd=202207122300

That could actually be something you do as an HTTP Get request in Rule Machine. Of course it would likely need to be narrowed down further with the specific field you want the result from, and have that result go into a variable so that you could compare it with other Rules.

Many thanks @snell for your answers.

Kind of still looking for solutions, in Home Assistant they figured it out. I saw even a code that set for eg. boiler ON for cheapest 3 hours. Would this help with hubitat?

I have created some sort of driver that fetches data from https://transparency.entsoe.eu/api

I new to developing to Hubitat and I'm not sure that the driver is coded using best codnig standards. If anyone is interested I can share it here.

Kari

1 Like

Here it is. If you improve or find bugs, please post it here or to Github. I think that the time based prizes could differ TimeZone to TimeZone.

I have Rule that refreshes this driver @14.30 Finnish time. And I poll the driver once an hour, one minute past. The polling sets a driver attribute CurrentPrice to prize on that hour.

Note!!! You have to register to the portal and ask for the api token from the service desk. For me they responded in a same day.

/*
 * Electricity price api 

 */
import java.text.SimpleDateFormat


metadata {
    definition(name: "Electricity price", namespace: "kapakauppinen", author: "Kari Kauppinen", importUrl: "") {
        capability "Sensor"
		capability "Polling"
		capability "Refresh"
		attribute "PriceListToday", "HashMap"     
        attribute "CurrentPrice", "NUMBER"
        
          command "clearStateVariables" 

    }
}

preferences {
    section("Security") {
        input "securityToken", "text", title: "entsoe Token", required: true
        input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true

    }
}

def clearStateVariables(){
    device.deleteCurrentState('PriceListToday')
     state.clear()   
}

def logsOff() {
    log.warn "debug logging disabled..."
    device.updateSetting("logEnable", [value: "false", type: "bool"])
}

def updated() {
    log.info "updated..."
    log.warn "debug logging is: ${logEnable == true}"
    if (logEnable) runIn(1800, logsOff)
}



def getParams() 
	{ 
        def date = new Date()
        def sdf = new SimpleDateFormat("yyyyMMdd")
        
        sdf.format(date)
	    def start = sdf.format(date).toString()
  	    def end = sdf.format(date.plus(1)).toString()

        //documentation can be found
        // https://transparency.entsoe.eu/content/static_content/Static%20content/web%20api/Guide.html
  
		"https://transparency.entsoe.eu/api?securityToken=${securityToken}&documentType=A44&in_Domain=10YFI-1--------U&out_Domain=10YFI-1--------U&periodStart=${start}0000&periodEnd=${end}2300" 
	}


def poll () {
	
    //refresh()
    
    def date = new Date()
    def sdf = new SimpleDateFormat("yyyyMMddHH00")
    def currenttime = sdf.format(date).toString()
    HashMap<String, String> today = new HashMap<String, String>()
    
    //remove {}
    def todayString =device.currentValue("PriceListToday").substring(1, device.currentValue("PriceListToday").length() - 1)
      
    //string to hasmap
    for(String keyValue : todayString.split(",")) {    
        
        String[] pairs = keyValue.split("=", 2)    
        today.put(pairs[0].trim(), pairs.length == 1 ? "" : pairs[1].trim());

    }
  
    today = today.sort { it.key }
     
    def x = today.find{ it.key == currenttime }

    if(x)
        sendEvent(name: "CurrentPrice", value: x.value)
        if (logEnable) 
            log.debug  x.value
}


def refresh() {
    if (logEnable) 
	 log.debug "Refresh"
	
	def responseBody

	try {
		
		httpGet([uri: getParams(),contentType: "text/xml"]) { resp -> 
			responseBody =  resp.getData() /*.TimeSeries[0].Period.Point[13].'price.amount'*/
		}
        //2022-10-13T22:00Z
        def pattern = "yyyy-MM-dd'T'HH:mm'Z'"
        def outputTZ = TimeZone.getTimeZone('GMT+5')
        def date =  Date.parse(pattern,responseBody.TimeSeries[0].Period.timeInterval.start.text().toString())
        def convertedDate = date.format("yyyyMMddHHmm", outputTZ)
        def timeserieDate
       
         
        //def hmap
        HashMap<String, String> today = new HashMap<String, String>()
    
        Calendar calendar = new GregorianCalendar();   
        def dateLabel
        
        //get the Timeseries from the Data
        responseBody.TimeSeries.each {
            
            try {
                
                timeserieDate = Date.parse(pattern,it.Period.timeInterval.start.text().toString())
                calendar.setTime (timeserieDate)
           
                //get the price (inc vat for each hour)
                it.Period.Point.each {
                    calendar.add(Calendar.HOUR, it.position.text().toString() as Integer); 
                    dateLabel = calendar.getTime().format("yyyyMMddHHmm", outputTZ)
                    calendar.setTime (timeserieDate)
                    today.put(dateLabel, (Float.parseFloat(it.'price.amount'.text().toString())*0.124).round(2));
                   
                }
                
                //log.debug     
                
            }
            catch (Exception ex) {
                  log.debug ex
            }
        }
        today = today.sort { it.key }
       
		sendEvent(name: "PriceListToday", value: today)
    
		
	} 
	catch(Exception e) {
		log.debug "error occured calling httpget ${e}"
	}
}



2 Likes

Thank you!

You have a github link?
I thought id make some countributions :slight_smile:

1 Like

I didn't have. Is this ok GitHub - kapakauppinen/hubitat

1 Like

Prefect !

I did some changes
(vat, currencyfactor and timezone as parameters)

Hi @karipk ,
Thank you for the script. I have an issue with the date that I cannot understand. Seems like it cannot get the date correctly. Most likely I have not fully understood how to use it. Right now I have added it as a driver and created a device. When I try to refresh I get the following in the log.

2022-10-24 11:04:17.929[error]java.lang.NullPointerException: Cannot invoke method length() on null object on line 73 (method poll)

2022-10-24 11:04:15.358[debug]error occured calling httpget java.text.ParseException: Unparseable date: ""

2022-10-24 11:04:14.840[debug]Refresh

Any ideas what I am doing wrong? Thanks again for your contribution :pray:

I think I miss some builtin functions:

def installed() {
log.info "installed() called"
sendEvent(name: "PriceListToday", value: "{}")
updated()
}

def initialize() {

log.info "initialize() called"
sendEvent(name: "PriceListToday", value: "{}")

}

I cannot test these ATM. I will try these this evening. You may try these too.

Thanks, I gave it a try but without success. If you have time to try it out it's great but no stress.

Latest version in github (I was missing capability initialize from the metadata). For me clicking initialize writes {} to PriceListToday-attribute

@karipk Thanks, I get the same result as you when clikcing initialize but when I try to get data I still get issues with the date:
error occured calling httpget java.text.ParseException: Unparseable date: ""
I guess the date somehow is blank/null

Could you send me the result (PM) that you get when you make request (using browser)
https://transparency.entsoe.eu/api?securityToken=replacetoken&documentType=A44&in_Domain=10YFI-1--------U&out_Domain=10YFI-1--------U&periodStart=202210240000&periodEnd=202210242300

replace replacetoken with your real token.

What is the time in your hubitat?
What is your entsoe region?

I can confirm the latest version from github works fine for me.
With RuleMachine it is easy to refresh and poll the device. Also I control my floor heating thermostats via RuleMachine based on Nordpool hour pricing.
Great Work Kari!