Get local UV radiation -- prevent sunburn and skin cancer

Tags: #<Tag:0x00007fe058081700> #<Tag:0x00007fe058081598>

(Andrea Riela) #24

Hi folks, @rtvb

any update about this configuration? I’m trying to collect all the info via curl then, using sed, trying to take the values I need. But maybe you are doing a better job :slight_smile:

Please let us know :slight_smile:


(Robert) #25

I have been playing a lot with Home Assistant lately, so the migration has not yet been completed. Please find below a working (partial) update.


# Set up the http binding to fetch the data once every 15 minutes. updateInterval=15*60*1000=900.000

openuv_uv.url            ={x-access-token=redacted}
openuv_uv.updateInterval = 720000

openuv_forecast.url            ={x-access-token=redacted}
openuv_forecast.updateInterval = 720000

openuv_protection.url            ={x-access-token=redacted}
openuv_protection.updateInterval = 720000

openuv_exposure.url            ={x-access-token=redacted}
openuv_exposure.updateInterval = 720000


// =========================================================================================
// UV Index
// =========================================================================================


Group gUvi "UV Index" (gWeather)

// get raw json every 10 minutes
// use http caching to prevent hitting the API too much :-)
// String   Uvi_Raw     (gUvi) // { http="<[uvimateCache:600000:REGEX((.*))]" }

String   Uvi_Uv_Json         (gUvi) { http="<[openuv_uv:180000:REGEX((.*))]" } // every 3 minutes
String   Uvi_Forecast_Json         (gUvi) { http="<[openuv_uv:180000:REGEX((.*))]" } // every 3 minutes
String   Uvi_Protection_Json         (gUvi) { http="<[openuv_uv:180000:REGEX((.*))]" } // every 3 minutes
String   Uvi_Exposure_Json         (gUvi) { http="<[openuv_uv:180000:REGEX((.*))]" } // every 3 minutes

// these items are populated using a rule
Number   Uvi_Uv           "Huidige UV Index [%.2f]"                 <line>  (gUvi, gChart)
DateTime Uvi_Uv_Time      "Waarneming [%1$tH:%1$tM]"                <clock> (gUvi)
Number   Uvi_Uv_Max       "Max. UV-ndex vandaag verwacht [%.2f]"      <line>  (gUvi)
DateTime Uvi_Uv_Max_Time  "Tijdstip max. UV-index [%1$tH:%1$tM]"         <clock> (gUvi)
String   Uvi_Risk         "Risico UV-straling [MAP(]" <text>  (gUvi)

DateTime Uvi_Protection_From "Begin bescherming vandaag [%1$tH:%1$tM]" <clock> (gUvi)
DateTime Uvi_Protection_To   "Einde bescherming vandaag [%1$tH:%1$tM]" <clock> (gUvi)

DateTime Uvi_LastUpdate "Bijgewerkt [%1$tH:%1$tM]" <clock> (gUvi, gLastUpdated)


rule UvimateUpdated
	Item Uvi_Uv_Json received update or
	Item Uvi_Forecast_Json received update or
	Item Uvi_Protection_Json received update or
	Item Uvi_Exposure_Json received update or
	System started
	logDebug(logger, "Uvimate received update")

	// asap
	Uvi_LastUpdate.postUpdate(new DateTimeType)

	// get values
	val String raw_uv = Uvi_Uv_Json.state.toString
	val uv     = Float.parseFloat(transform("JSONPATH", "$.result.uv", raw_uv))
	val uv_max = Float.parseFloat(transform("JSONPATH", "$.result.uv_max", raw_uv))
	// directly converting to DateTimeType does not respect the timezone, DateTime does.
	val DateTime uv_time     = new DateTime(transform("JSONPATH", "$.result.uv_time", raw_uv))
	val DateTime uv_max_time = new DateTime(transform("JSONPATH", "$.result.uv_max_time", raw_uv))

	// debug
	logDebug(logger, "raw_uv        : " + raw_uv)
	logDebug(logger, "uvi           : " + uv)
	logDebug(logger, "uvi time      : " + uv_time)
	logDebug(logger, "uviMax        : " + uv_max)
	logDebug(logger, "uviMaxTime    : " + uv_max_time)

	logDebug(logger, "***")
	var risk = 'UNKNOWN'
	if (uv < 3.0) { 
		risk = "LOW" 
		logDebug(logger, risk)
	} else if (uv < 6.0) { 
		risk = 'MODERATE' 
	} else if (uv < 8.0) { 
		risk = 'HIGH'
	} else if (uv < 11.0) {
		risk = 'VERY_HIGH'
	} else { 
		risk = 'EXTREME' 
	logDebug(logger, "Risk          : " + risk)

	// post updates

	Uvi_Uv.postUpdate( uv.toString )	// uv
	Uvi_Uv_Max.postUpdate( uv_max.toString ) // uv_max

(Christoph) #26

Just because I saw it: You have to typos in your rule:

Item Uvi_Protection_Jason received update or
	Item Uvi_Exposure_Jason received update or

should be

Item Uvi_Protection_Json received update or
	Item Uvi_Exposure_Json received update or

don’t you think so?

(Robert) #27

You’re right. I’ve edited my code.

(Andrea Riela) #28

Are you sure this is working now? how can you send the API key via url?

In the meantime I’ve found another way to access their data, using a script to collect the data form their website, and using the http binding and jsonpath from internal openhab web server:

the script

/usr/bin/curl -s -XGET '' -H "x-access-token: MYAPIKEY" > /etc/openhab2/html/openuv.txt

the rule

rule openuv
		Time cron "* 0/15 * * * ?" // this one cycles every 15 minutes. 
			// executing the script and waiting for the JSON return
            var String cmd = "sh /etc/openhab2/myscripts/"
            executeCommandLine(cmd, 120000)


String Http_Openuv_UVIndex "UV Index (now): [%s]" (gOutdoor, gWeather) { http="<[http://localhost:8080/static/openuv.txt:60000:JSONPATH($.result.uv)]" }
String Http_Openuv_UVIndexMax "UV Index (max): [%s]" (gOutdoor, gWeather) { http="<[http://localhost:8080/static/openuv.txt:60000:JSONPATH($.result.uv_max)]" }

(Vincent Regaud) #29


Thank you for your workaround,

Could you change it a bit using

Thank you

(Andrea Riela) #30

Apologies :slight_smile:

Now it should be better

(Vincent Regaud) #31


(Robert) #32

I use the http binding; this is the config. That syntax is required to send headers.

This way you don’t need to executeCommandLine.

Please also read the OP. My last example isn’t a complete solution but a WIP update to it.

(Kurt S) #33


thanks for your input. I modified your rule to fit it to my needs, but for some reason it is causing havoc on my openhab installation (running on 2.3.0~20180324205302-1 (Build #1240)).

When loading this rule during startup, the boot process is stopped. :dizzy_face:

Any help on why and what to do to fix it? Never had this before :open_mouth:

rule "openuv"
		Time cron "0 0/15 * 1/1 * ? *" // this one cycles every 15 minutes. 
             executeCommandLine("sh /srv/openhab2-conf/scripts/", 10000)

rule "UV recalc"
    Item Openuv_sunburn received update or
    Time cron "0 0/16 * 1/1 * ? *" 
 	var int hours = ((Openuv_sunburn.state as DecimalType).intValue / 60) - (24 * days)
	var int minutes = ((Openuv_sunburn.state as DecimalType).intValue - 60 * (24 * days + hours))
	var String result = ""
	if (hours > 0) {
		result = result + hours + " Std. / "
	if (minutes > 0) {
		result = result + minutes + " Min."
	}	Openuv_sunburn_format.postUpdate(result)
	logInfo("UV recalc", "Sonnenbrandzeit upgedated auf: " + Openuv_sunburn_format.state)


The Shellscript is as below:

curl -X GET '' -H 'x-access-token: mytoken' > /srv/openhab2-conf/html/openuv.txt

The items are defined the following way:

String Openuv_UVIndex "UV Index (Jetzt): [%s]" <uvsun> (Wetter) { http="<[http://192.x.xx.x:8080/static/openuv.txt:60000:JSONPATH($.result.uv)]" }
String Openuv_UVIndexMax "UV Index (max): [%s]" <uvsun> (Wetter) { http="<[http://192.x.xx.x:8080/static/openuv.txt:60000:JSONPATH($.result.uv_max)]" }
String Openuv_Ozone "Ozone Index (Jetzt): [%s]" <ozon> (Wetter) { http="<[http://192.x.xx.x:8080/static/openuv.txt:60000:JSONPATH($.result.ozone)]" }
Number Openuv_sunburn "Sonnenbrand in Minuten:[%s] " <sunburn> (Wetter) { http="<[http://192.x.xx.x:8080/static/openuv.txt:60000:JSONPATH($.result.safe_exposure_time.st3)]" }
Number Openuv_sunburn_format "Sonnenbrand in: [%s] %unit%" <sunburn> (Wetter)  

Whenever I exclude the rule (rename the rules file, so it won’t get loaded) the OpenHAB service is starting up as normal.

thanks upfront for any help on this matter!


(Andrea Riela) #34

can you please check permissions of this file?


(Thomas Binder) #35

i find this very interesting - as my whole Family is outside quite often for biking, running or whatever! :wink:
I just did @rtvb already suggested an simple http binding with the additional header. With that you won’t need all that external script stuff… the API gets updated every 3-4 hours, as I read. you have something like 500 API-calls per day, so I figured and update every hour is enough. 1 hour in msec is 3600000.

insert a cached URL in http.cfg

# configuration of the cache item  

please replac LAT und LNG with your Location and replace the API-Key

with that cached item (it’s a string in JSON format), you can then easily update your items:

Number		openUV_UV		"aktueller UV-Wert [%d]"	 	{ http="<[openUV:60000:JSONPATH($.result.uv)]" }
DateTime	openUV_UV_Time		"UV-Wert Messung [%1$tH:%1$tM]"		{ http="<[openUV:60000:JSONPATH($.result.uv_time)]" }
Number 		openUV_UV_Max		"Maximaler UV-Wert [%d]"		{ http="<[openUV:60000:JSONPATH($.result.uv_max)]" }
DateTime	openUV_UV_MaxTime	"Max. UV-Wert Zeit [%1$tH:%1$tM]"	{ http="<[openUV:60000:JSONPATH($.result.uv_max_time)]" }
Number		openUV_Ozon		"Ozonwert [%d]"				{ http="<[openUV:60000:JSONPATH($.result.ozone)]" }
Number		openUV_st1		"maximale zeit Hauttyp 1 [%d min]"	{ http="<[openUV:60000:JSONPATH($.result.safe_exposure_time.st1)]" }
Number		openUV_st2		"maximale zeit Hauttyp 3 [%d min]"	{ http="<[openUV:60000:JSONPATH($.result.safe_exposure_time.st2)]" }
Number		openUV_st3		"maximale zeit Hauttyp 4 [%d min]"	{ http="<[openUV:60000:JSONPATH($.result.safe_exposure_time.st3)]" }
Number		openUV_st4		"maximale zeit Hauttyp 5 [%d min]"	{ http="<[openUV:60000:JSONPATH($.result.safe_exposure_time.st4)]" }
Number		openUV_st5		"maximale zeit Hauttyp 6 [%d min]"	{ http="<[openUV:60000:JSONPATH($.result.safe_exposure_time.st5)]" }
Number		openUV_st6		"maximale zeit Hauttyp 7 [%d min]"	{ http="<[openUV:60000:JSONPATH($.result.safe_exposure_time.st6)]" }

That’s it! of Course you can now add some additional items, which calculate the risk (e.g. for high Ozone-values or high UV-values!) and so on. But getting the raw items is easy as that! even DateTime works easily.

(Kurt S) #36


aha, interesting. It’s owned by openhabian:openhabian (obviously, this is what I’m running here :wink:). I’ve now made it openhab:openhabian. Thanks for the hint.
Any idea why openhab would completely freeze at startup due to it?


(Kurt S) #37

Very nice! Thanks for sharing!


(Andrea Riela) #38

Thank @binderth

just consider the sunburn items (st1, 2 …) are in minutes, not in seconds :slight_smile:

But thanks for your example, it works nicely.


(Thomas Binder) #39

you’re so right. I updated the code in my post above so it will be correctly displayed in UI.

(Mark Noe) #40


I am trying to get this to work, and I keep getting the error:
2018-04-05 23:03:33.412 [ERROR] [ ] - Fatal transport error:$
2018-04-05 23:03:33.416 [ERROR] [ab.binding.http.internal.HttpBinding] - No response received from ‘openUV’

I have the following lines in http.cfg:



What am I doing wrong?

Many thanks,


(Thomas Binder) #41

What’s your system specs? openHABian?
Try in the shell:

curl -s -XGET '' -H "x-access-token: <<APIKEY>>"

What’s the outcome?

(Mark Noe) #42


I am using openhab 2.2 on a Raspberry pi 3 - installed with apt-get. When I type the curl command noted above the system returns the expected data, so I think the api key is correct.

Many thanks,


(Christoph) #43

A little suggestion and caveat regarding the DateTime items (if look closely in @rtvb’s example, you can see, that he solved this also). The API gives back the time in UTC, so in order to match the Datetime items to your timezone, you could change the code like this:

String	    openUV_UV_Time		"UV-Wert Messung (UTC) [%s]"		        { http="<[openUV:60000:JSONPATH($.result.uv_time)]" }
DateTime	openUV_UV_Time_MEZ		"UV-Wert Messung [%1$tH:%1$tM]" (gUV)
String	    openUV_UV_MaxTime	"Max. UV-Wert Zeit (UTC) [%s]"	            { http="<[openUV:60000:JSONPATH($.result.uv_max_time)]" }
DateTime	openUV_UV_MaxTime_MEZ	"Max. UV-Wert Zeit [%1$tH:%1$tM]" (gUV) 

and add a rule:

rule "UV Index DateTimeItem"
    Item openUV_UV_Time changed or
    Item openUV_UV_MaxTime changed
    val DateTime uv_time = new DateTime(openUV_UV_Time.state.toString)
    val DateTime uv_time_max = new DateTime(openUV_UV_MaxTime.state.toString)