Comprehensive Wunderground using HTTP Binding Example

Thanks for the additional info. Wunderground can be a little opaque in this regard.

Your cautions about the stations is well founded. I live right up against the front range of the Rocky Mountains across from an airport. I can even see the building that has the weather station from the corner of my street. But we have such varied microclimates in this area that I couldn’t use that station to control my irrigation. They get a lot more rain then we do.

1 Like

microclimates indeed something to take into account, Fortunately I found a “goldstar” station maybe two hundred meters away, but it is right across from a pond… could be different microclimate, there is another goldstar, maybe 700 meters away, but I am in a leafier surrounding. I see an easy 1.5 degree difference between my well placed DS18B20 and the temp at the Goldstar station.
Hard to say if it is a different microclimate or just placement of sensors or maybe an inaccuracy. Nevertheless the general outcomes are pretty much in line. I have shied away from the majority of non-goldstar stations: Often incomplete data that sometimes hardly changes over time (is that wind really coming constantly from 270 degrees since yesterday???)

Certainly for something like irrigation you need a bit more accurate data. But… I am in the netherlands. If it doesnt rain now, it will rain in an hour

Ha! I’m in the high desert. If it’s raining now you probably should start building an arc. :grin:

:slight_smile: especially in the desert you want to get your irrigation right: not being wasteful but also not let yr plants dry.

Arc… well we have dikes and Hans Brinkers’ kids to stick their fingers in it if necessary

I didn’t see this mentioned, but another way to limit API calls is to combine multiple features into a single request. In the URL, instead of /<feature>/, you can use /<feature1>/<feature2>/, and modify the transforms as needed. Details for this are in the link you have under the Create the Query URLs section. In addition to the binding, I use /alerts/conditions/ to pull down and then parse out (with JSONPATH):

  • $.current_observation.solarradiation - last I looked this was missing from the binding, and it removed my need to calculate cloud cover. I mainly use it for adjusting dimmer levels based on outside brightness (lux).

  • $.alerts[0].message - for sending out notifications of severe weather alerts

2 Likes

Thanks! I never read the API closely enough to realize one could do that with the features. I just assumed it was one per call.

How do you install the transformations? I googled it, and all I can find is documentation on how the transformations work once they’re installed. Also, I don’t think I have services/exec.cfg (I’m using OH1). Can I safely ignore that step? Thanks.

These instructions are for OH 2. From this point forward I think you can assume that anything that is a new post, unless otherwise stated, will be for OH 2.

I believe all transformations come with 1.x and are not separately installable.

I never referred to exec.cfg as there isn’t one for OH 2 either and these instructions do not use the exec binding anyway. Instead they use the executeCommandLine action.

$.alerts[0].message - for sending out notifications of severe weather alerts

Since alerts may occur multiple times I wonder how your setting looks like, espacially for all the aler items: Currently I am using the following but not happy with it:

String vAlertWeather_Type1 			"Unwetterart [MAP(wu_alarms_code.map):%s]"  <weatherwarnung>		(gUnwetterH)    { http="<[weatherAlerts:420000:JSONPATH($.alerts[0].type)]" }
String vAlertWeather_Meteoalarm_Name1"Warnung [MAP(wu_alarms_code.map):%s]"		<weather>		(gUnwetterH)    { http="<[weatherAlerts:420000:JSONPATH($.alerts[0].wtype_meteoalarm_name)]" }
//Number vAlertWeather_Meteoalarm1 	"Warnart [%s]"								<temperature>	(gUnwetterH)    { http="<[weatherAlerts:420000:JSONPATH($.alerts[0].wtype_meteoalarm)]" }
String vAlertWeather_Type2 			"Unwetterart [MAP(wu_alarms_code.map):%s]"  <weatherwarnung>		(gUnwetterH)    { http="<[weatherAlerts:420000:JSONPATH($.alerts[1].type)]" }
String vAlertWeather_Meteoalarm_Name2"Warnung [MAP(wu_alarms_code.map):%s]"		<weather>		(gUnwetterH)    { http="<[weatherAlerts:420000:JSONPATH($.alerts[1].wtype_meteoalarm_name)]" }
//Number vAlertWeather_Meteoalarm2 	"Warnart [%s]"								<temperature>	(gUnwetterH)    { http="<[weatherAlerts:420000:JSONPATH($.alerts[1].wtype_meteoalarm)]" }

I would leave the JSON unparsed in a String Item and use a rule to parse out all the alerts and generate a single combined alerts String.

Creating separate items like you have will result in errors in the logs when there is fewer than two alerts and you will completely miss alerts when there is more than two.

If I understand your question correctly, I iterate through all of the alerts when there are multiples delivered in the API.

ITEMS:

String      Weather_Alert_Message_Raw      "Severe Weather Alert (Raw) [%s]"	    <text>  (gWeather,gNotification)
String      Weather_Alert_Message          "Severe Weather Alert [%s]"	            <text>  (gWeather,gNotification)    
String      Weather_Alert_NWS_VTEC         "Severe Weather Alert NWS VTEC [%s]"	    <text>  (gWeather,gNotification)
String      Weather_Alert_Type             "Severe Weather Alert Type [%s]"	        <text>  (gWeather,gNotification)
DateTime    Weather_Alert_Expiration       "Severe Weather Alert Expiration [%1$tA, %1$tB %1$te, %1$tY at %1$tl:%1$tM%1$tp]"	<calendar>  (gWeather,gNotification)

RULES:

rule "Alert: Check for weather alert"
when
	Time cron "0 1/5 * * * ?"
    //or
    //Item Virtual_Switch_1 changed
then
    //logDebug("Rules", "Alert: Check for weather alert: Starting")
    val String rawMessage = executeCommandLine("/bin/sh@@-c@@/usr/bin/curl -s -X GET https://api.wunderground.com/api/<api key>/alerts/conditions/q/pws:KOHHINCK2.json",60000)
    //logDebug("Rules", "Alert: Check for weather alert: Testing: rawMessage=[{}]",rawMessage)
    if (rawMessage.length > 0 && !rawMessage.contains("High Load")) {
        val String tempLux = transform("JSONPATH", "$.current_observation.solarradiation", rawMessage)
        //logDebug("Rules", "Alert: Check for weather alert: Testing: tempLux=[{}]",tempLux)
        if (tempLux != null && tempLux != "--") {
            Outside_Bloomsky_Lux_Raw.sendCommand(tempLux)
            //logDebug("Rules", "Alert: Check for weather alert: Testing: Outside_Bloomsky_Lux=[{}]",Outside_Bloomsky_Lux.state)
        }
        if (rawMessage.contains("message")) {
            Weather_Alert_Message_Raw.sendCommand(rawMessage)
            var i = 0
            while (i < Integer::parseInt(transform("JSONPATH", "$.response.features.alerts", rawMessage))) {
                logDebug("Rules", "Alert: Check for weather alert: Testing: starting loop. Alert=[{}]",i)
                val String parsedMessage = transform("JSONPATH", "$.alerts[" + i + "].message", rawMessage)
                //logDebug("Rules", "Alert: Check for weather alert: Testing: parsedMessage=[{}]",parsedMessage)
                if (!parsedMessage.contains("Small Craft")) {
                    val String weatherAlertDescription = transform("JSONPATH", "$.alerts[" + i + "].description", rawMessage)
                    Weather_Alert_Type.sendCommand(weatherAlertDescription)
                    val String weatherAlertType = transform("JSONPATH", "$.alerts[" + i + "].type", rawMessage)
                    Weather_Alert_NWS_VTEC.sendCommand(weatherAlertType)
                    val DateTime expirationTime = new DateTime(Long::parseLong(transform("JSONPATH", "$.alerts[" + i + "].expires_epoch", rawMessage)) * 1000L)
                    //logDebug("Rules", "Alert: Check for weather alert: Testing: rawExpirationTime=[{}]",rawExpirationTime)
                    Weather_Alert_Expiration.sendCommand(expirationTime.toString)
                    val String doubleParsedMessage = parsedMessage.replaceAll("(?s)\nLat...Lon.*","").replaceAll("\n\\.\\.\\.","").replaceAll("\\.\\.\\.",", ").replaceAll("\\*"," ").replaceAll("for,.*[Uu]ntil","until")
                    //logDebug("Rules", "Alert: Check for weather alert: Testing: doubleParsedMessage=[{}]",doubleParsedMessage)
                    Weather_Alert_Message.sendCommand(doubleParsedMessage)
                }
                i = i + 1
            }
        }
        else {
            logDebug("Rules", "Alert: Check for weather alert: No alert found")
        }
    }
    else {
        logInfo("Rules", "Alert: Check for weather alert: Communication with Weather Underground failed.")
    }

    /*
    example alert
    
    {
        "response": {
            "version":"0.1",
            "termsofService":"http://www.wunderground.com/weather/api/d/terms.html",
            "features": {
                "alerts": 1
                }
        },
        "query_zone": "020",
        "alerts": [
                {
                    "type": "FOG",
                    "description": "Dense Fog Advisory",
                    "date": "10:01 PM EDT on October 3, 2016",
                    "date_epoch": "1475546460",
                    "expires": "9:00 AM EDT on October 04, 2016",
                    "expires_epoch": "1475586000",
                    "tz_short":"EDT",
                    "tz_long":"America/New_York",
                    "message": "\u000A...Dense fog advisory in effect from 2 am to 9 am EDT Tuesday...\u000A\u000AThe National Weather Service in Cleveland has issued a dense fog\u000Aadvisory...which is in effect from 2 am to 9 am EDT Tuesday.\u000A\u000A* Visibilities...dropping below a quarter of a mile in low spots\u000A especially near rivers and ponds.\u000A\u000A* Timing...fog will develop and thicken through the night\u000A\u000A* impacts...expect dense fog to form especially in river valleys\u000A and other low lying locations. Visibility will drop below a\u000A quarter mile and remain low through about 830 am\u000A\u000APrecautionary/preparedness actions...\u000A\u000AA dense fog advisory is issued when visibilities will frequently\u000Abe reduced to less than one quarter mile. If driving...slow\u000Adown...use your headlights...and leave plenty of distance ahead\u000Aof you.\u000A\u000A\u000A\u000A\u000A",
                    "phenomena": "FG",
                    "significance": "Y"
                }
                "ZONES": []
        ]
    }
        
    https://espanol.wunderground.com/weather/api/d/docs?d=data/alerts
    typeTranslated

    HUR	Hurricane Local Statement
    TOR	Tornado Warning
    TOW	Tornado Watch
    WRN	Severe Thunderstorm Warning
    SEW	Severe Thunderstorm Watch
    WIN	Winter Weather Advisory
    FLO	Flood Warning
    WAT	Flood Watch / Statement
    WND	High Wind Advisory
    SVR	Severe Weather Statement
    HEA	Heat Advisory
    FOG	Dense Fog Advisory
    SPE	Special Weather Statement
    FIR	Fire Weather Advisory
    VOL	Volcanic Activity Statement
    HWW	Hurricane Wind Warning
    REC	Record Set
    REP	Public Reports
    PUB	Public Information Statement
    */
end

rule "Alert: Severe weather alert"
when
    Item Weather_Alert_Message changed
then		
    logDebug("Rules", "Alert: Weather_Alert_Message=[{}], Weather_Alert_NWS_VTEC=[{}]",Weather_Alert_Message.state.toString,Weather_Alert_NWS_VTEC.state.toString)
    SMS_Notification.sendCommand(Weather_Alert_Message.state.toString)
    if (Presence.state.toString != "Away" && (Mode.state.toString != "Night" || "HUR TOR WRN FLO SVR FIR VOL HWW REP PUB".contains(Weather_Alert_NWS_VTEC.state.toString))) {
        Audio_Notification.sendCommand(Weather_Alert_Message.state.toString)
    }
end

After trying to get alerts in GERMANY over weeks I can say, there is no alert delivered on the json stream. If I take any other city in Europe, does not matter which I take, I am able to receive alerts.
Someone can confirm this?
Looking at the current map https://www.wunderground.com/severe/europe.asp you will see all other countries arround GERMANY do have alerts … quite strange.

Similar topic (but no solution)… https://apicommunity.wunderground.com/weatherapi/topics/no-alert-messages-in-europe

Did you already try the relatively new Weather Underground Binding @rlkoshak? Because it is dedicated to WU I’d presume it should be more complete and less generic. I haven’t tried it myself yet. :blush:

When I wrote the above it was in response to several other users having a lot of problems with that binding, the old weather binding, and the yahoo binding. I’ve not kept up with it so have no idea if the kinks have been worked out. I’m happy with my implementation and have no plans to switch until perhaps there is a breaking change in the HTTP binding.

Even if one were to use the wunderground binding, the logic above that makes sure the right icon is used with the conditions data would still apply.

I have been using this setup ever since you posted it on august 15 and I can honestly say I have no problems at all anymore with obtaining weather data, as opposed to using the weather binding which gave me frequent problems, so thanks a bundle for that.

One thing that I did notice is that apparently… maybe weather station related or region related, there might be small differences in the name of the JSON items that are being sent. I for one couldnt get part of the precipitation data, until I checked the JSON for my station.
So if anyone using this set up (and you should) encounters some data to always stay blank, check what the json of the station you are using is actually sending.

Anyway, this setup has been a life saver for me

1 Like

Thanks @5iver using http://api.wunderground.com/api/xxxxxxx/conditions/forecast/q/pws:TOWNXX.json
gives me a perfect JSON with both the current conditions and the forecast
Updated that in my http.cfg and it seems that was all that was necessary. no need to alter my json parsing

some finetuning from my side (forgive me, if that already was mentioned someplace else…)
If using Wunderground with HTTP binding, you can also get some more tuned Information for your Special Location.

Localized Content

just put /lang:XX in the API-Call, e.g.

weatherForecast.url=http://api.wunderground.com/api/7cffc35ff04afd7c/forecast/lang:FR/q/France/Paris.json

in that case, the returning texts all come in french (no need to transform them into your language).
:exclamation:note: Wunderground doesn’t use the ISO for countries, so Germany is DL (see https://www.wunderground.com/weather/api/d/docs?d=resources/country-to-iso-matching)

Metric Information in localized Content

If you’re wondering, why you choose a non-imperial language as reference, but still get those funny imperial Units:

  1. Login to wunderground
  2. go to your Profile
  3. choose “Member Settings” - “Page Preferences”
  4. Change language and Units to your choosing

you should now get all texts in your chosen language and you should receive texts with units in it in two Attributes one in imperial units and one in the real measurement:

{
  "response": {
  "version":"0.1",
  "termsofService":"http://www.wunderground.com/weather/api/d/terms.html",
  "features": {
  "forecast": 1
  }
	}
		,
	"forecast":{
		"txt_forecast": {
		"date":"10:28 CET",
		"forecastday": [
		{
		"period":0,
		"icon":"cloudy",
		"icon_url":"http://icons.wxug.com/i/c/k/cloudy.gif",
		"title":"Dienstag",
		"fcttext":"Bedeckt. Höchsttemperatur 42F. Wind aus SSO und wechselhaft.",
		"fcttext_metric":"Bedeckt. Höchsttemperatur 6C. Wind aus SSO und wechselhaft.",
		"pop":"0"
...

here’s my example in german and metric units.

getting the Icons

goto https://www.wunderground.com/weather/api/d/docs?d=resources/icon-sets and you can just chose and download from 10 different sets

Imperial measurements are real too. :wink:

Thanks for posting, great information!

http://www.metric4us.com/

SCNR :wink:

3 Likes