Monthly Archives: January 2019

OpenWeatherMap and OpenHab

With the end of the YahooWeather API, I signed up for some API keys from OpenWeatherMap’s free tier, but had real trouble getting the default weather binding to work. After many wasted hours puzzling over the following error message, I eventually found this thread.

[ERROR] [nal.provider.AbstractWeatherProvider] - OPENWEATHERMAP[home]: Can't retreive weather data: Invalid API key. Please see http://openweathermap.org/faq#error401 for more info.

The error is correct, but uninformative – the issue is that default binding is calling on the “paid for” API rather then the free one, so yes my free API key is invalid for the API call I’m making. Unfortunately that is less then informative when testing your API keys in a browser and receiving valid JSON!!

The solution for me was to add org.openhab.binding.weather-1.13.0-SNAPSHOT.jar to my addons directory, then using the following weather.items I was up and running:

Group gWeather

// atmosphere
Number   Humidity		  "Humidity [%d %%]"	 (gWeather) {weather="locationId=home, type=atmosphere, property=humidity"}
Number   Visibility		  "Visibility [%.2f km]" (gWeather) {weather="locationId=home, type=atmosphere, property=visibility"}
Number   Visibility_Mph   "Visibility [%.2f mi]" (gWeather) {weather="locationId=home, type=atmosphere, property=visibility, unit=mph"}
Number   Pressure		  "Pressure [%.2f mb]"   (gWeather) {weather="locationId=home, type=atmosphere, property=pressure"}
Number   Pressure_Inches  "Pressure [%.2f in]"   (gWeather) {weather="locationId=home, type=atmosphere, property=pressure, unit=inches"}
String   Pressure_Trend   "Pressuretrend [%s]"   (gWeather) {weather="locationId=home, type=atmosphere, property=pressureTrend"}
Number   Ozone            "Ozone [%d ppm]"		 (gWeather) {weather="locationId=home, type=atmosphere, property=ozone"}
Number   UV_Index         "UV Index"              (gWeather){weather="locationId=home, type=atmosphere, property=uvIndex, scale=0"}

// clouds
Number   Clouds   "Clouds [%.0f %%]"  (gWeather) {weather="locationId=home, type=clouds, property=percent"}

// condition
String   Condition        "Condition [%s]"     (gWeather) {weather="locationId=home, type=condition, property=text"}
String   Condition_ID     "Condition id [%s]"  (gWeather) {weather="locationId=home, type=condition, property=id"}
DateTime ObservationTime  "Observation time [%1$td.%1$tm.%1$tY %1$tH:%1$tM]"  (gWeather) {weather="locationId=home, type=condition, property=observationTime"}
DateTime LastUpdate       "Last update [%1$td.%1$tm.%1$tY %1$tH:%1$tM]"      (gWeather)  {weather="locationId=home, type=condition, property=lastUpdate"}
String   CommonId         "Common id [%s]"     (gWeather) {weather="locationId=home, type=condition, property=commonId"}
Image    LocalCurrentConditionIcon "Icon" (gWeather) { weather="locationId=home, type=condition, property=icon-id" }

// precipitation
Number   Rain          "Rain [%.2f mm/h]"  (gWeather) {weather="locationId=home, type=precipitation, property=rain"}
Number   Rain_Inches   "Rain [%.2f in/h]"  (gWeather) {weather="locationId=home, type=precipitation, property=rain, unit=inches"}
Number   Snow          "Snow [%.2f mm/h]"  (gWeather) {weather="locationId=home, type=precipitation, property=snow"}
Number   Snow_Inches   "Snow [%.2f in/h]"  (gWeather) {weather="locationId=home, type=precipitation, property=snow, unit=inches"}
Number   Precip_Probability   "Precip probability [%d %%]"  (gWeather) {weather="locationId=home, type=precipitation, property=probability"}
// new total property in 1.8, only Wunderground
Number   Precip_Total         "Precip total [%d mm]"  (gWeather) {weather="locationId=home, type=precipitation, property=total"}
Number   Precip_Total_Inches  "Precip total [%d in]"  (gWeather) {weather="locationId=home, type=precipitation, property=total, unit=inches"}

// temperature
Number   Temperature      "Temperature [%.2f °C]"      (gWeather) {weather="locationId=home, type=temperature, property=current"}
Number   Temperature_F    "Temperature [%.2f °F]"      (gWeather) {weather="locationId=home, type=temperature, property=current, unit=fahrenheit"}
Number   Temp_Feel        "Temperature feel [%.2f °C]" (gWeather) {weather="locationId=home, type=temperature, property=feel"}
Number   Temp_Feel_F      "Temperature feel [%.2f °F]" (gWeather) {weather="locationId=home, type=temperature, property=feel, unit=fahrenheit"}
Number   Temp_Dewpoint    "Dewpoint [%.2f °C]"         (gWeather) {weather="locationId=home, type=temperature, property=dewpoint"}
Number   Temp_Dewpoint_F  "Dewpoint [%.2f °F]"         (gWeather) {weather="locationId=home, type=temperature, 
property=dewpoint, unit=fahrenheit"}
// min and max values only available in forecasts
Number   Temp_Min         "Temperature min [%.2f °C]"  (gWeather) {weather="locationId=home, type=temperature, property=min"}
Number   Temp_Min_F       "Temperature min [%.2f °F]"  (gWeather) {weather="locationId=home, type=temperature, property=min, unit=fahrenheit"}
Number   Temp_Max         "Temperature max [%.2f °C]"  (gWeather) {weather="locationId=home, type=temperature, property=max"}
Number   Temp_Max_F       "Temperature max [%.2f °F]"  (gWeather) {weather="locationId=home, type=temperature, property=max, unit=fahrenheit"}
String   Temp_MinMax      "Min/Max [%s °C]"            (gWeather) {weather="locationId=home, type=temperature, property=minMax"}
String   Temp_MinMax_F    "Min/Max [%s °F]"            (gWeather) {weather="locationId=home, type=temperature, property=minMax, unit=fahrenheit"}

// wind
Number   Wind_Speed           "Windspeed [%.2f km/h]"   (gWeather) {weather="locationId=home, type=wind, property=speed"}
Number   Wind_Speed_Beaufort  "Windspeed Beaufort [%d]" (gWeather) {weather="locationId=home, type=wind, property=speed, unit=beaufort"}
Number   Wind_Speed_Knots     "Windspeed [%.2f kn]"     (gWeather) {weather="locationId=home, type=wind, property=speed, unit=knots"}
Number   Wind_Speed_Mps       "Windspeed [%.2f mps]"    (gWeather) {weather="locationId=home, type=wind, property=speed, unit=mps"}
Number   Wind_Speed_Mph       "Windspeed [%.2f mph]"    (gWeather) {weather="locationId=home, type=wind, property=speed, unit=mph"}
String	 Wind_Direction       "Wind direction [%s]"     (gWeather) {weather="locationId=home, type=wind, property=direction"}
Number   Wind_Degree          "Wind degree [%.0f °]"    (gWeather) {weather="locationId=home, type=wind, property=degree"}
Number   Wind_Gust            "Wind gust [%.2f km/h]"   (gWeather) {weather="locationId=home, type=wind, property=gust"}
Number   Wind_Gust_Beaufort   "Wind gust Beaufort [%d]" (gWeather) {weather="locationId=home, type=wind, property=gust, unit=beaufort"}
Number   Wind_Gust_Knots      "Wind gust [%.2f kn]"     (gWeather) {weather="locationId=home, type=wind, property=gust, unit=knots"}
Number   Wind_Gust_Mps        "Wind gust [%.2f mps]"    (gWeather) {weather="locationId=home, type=wind, property=gust, unit=mps"}
Number   Wind_Gust_Mph        "Wind gust [%.2f mph]"    (gWeather) {weather="locationId=home, type=wind, property=gust, unit=mph"}
Number   Wind_Chill           "Wind chill [%.2f °C]"    (gWeather) {weather="locationId=home, type=wind, property=chill"}
Number   Wind_Chill_F         "Wind chill [%.2f °F]"    (gWeather) {weather="locationId=home, type=wind, property=chill, unit=fahrenheit"}

OpenHab – Boost Button on the Basic UI

While I’ve been adding simple on/off controls and rules controlling timers for my heating, I noticed something that was missing was the idea of a 1+ hour boost button, so I decided to create one.

The standard pattern for building this type of thing is to create a “dummy” Switch – one not bound to any channel, and make use of that + timers in the rules to handle the off transition. In my sitemap however, I was aiming to have a push button type setup, rather then a toggle.

One pattern I found for this made use of an additional dummy Switch to store the state, and use the “visibility” options in the sitemap to show the “on” or “running” buttons depending on that state. While nice, I prefer not to have a second dummy variable, so I don’t 🙂

Define the item

First I define the “dummy” switch:

Group gVirtual

Switch HeaterTimer "1 Hour Boost" <temperature> (gHeating, gVirtual, gSwitches)

The rules

Then I define my rules for this switch:

var Timer boostTimer = null

rule "One Hour Heat On"
when
    Item HeaterTimer received command
then
    Heating.sendCommand(ON)
    postUpdate(HeaterTimer, ON)
    if(boostTimer === null || boostTimer.hasTerminated){
        boostTimer = createTimer(now.plusHours(1), [| 
            Heating.sendCommand(OFF)
            postUpdate(HeaterTimer, OFF)
            boostTimer = null
        ])
    }
    else{
        boostTimer.reschedule(now.plusHours(1)) // if pressed a second time keep it on for another hour from now
    }
end

So what I’m doing here is triggering on the HeaterTimer receiving a command, then I turn the heating on, and update the state of HeaterTimer to ‘On’.

If the timer is equal to null, or has ended, I create a timer set at 1 hour from now, and when the timer triggers I switch the heating off, update the state, and set the timer to null.

If we have an command, and the timer is already running e.g. I pushed the button again, then I reschedule to 1 hour from now.

Now for the sitemap

   Frame label="Heating" {
      Switch item=HeaterTimer mappings=[ON="Boost"] icon="fire-off" visibility=[HeaterTimer == OFF, HeaterTimer == "NULL"]
      Switch item=HeaterTimer mappings=[ON="Running"] icon="fire-on" visibility=[HeaterTimer == ON]

   }

This is where it gets a little interesting.

The first switch is showing an ON/Boost button, with the icon in the off state. This is only visible if the HeatingTimer is OFF, or equal to “NULL”.

Why the second/NULL check?

When the “dummy” switch is created, it is created with a null state – my persistence config will restore the state if we ever reload, but for the very first time, we need to handle the lack of ON/OFF state. You could update the sitemap after the first time you use it to remove the NULL comparison as it will only be used once. The other option is to only add the visibility options after you run for the first time.

The second switch should be obvious now – we have a “Running” button, that if you push it, will add 1 hour from now (remember the rules) to the timer.

Preparing for some Home Automation – Heating

Today I decided to start planning for the install of some home automation kit, specifically related to heating, but while planning on that I decided to take a closer look at a problem I’ve been having for some time – the thermostat hasn’t been doing very much.

This is a standard dial thermostat – and as you would expect, the numbers on the dial are a little off (~6°C) compared to the actual temperature. This isn’t the actual issue, since once you find the comfortable point, it doesn’t really matter what the reading on the dial is.

The issue I was having was that, regardless of the thermostat position, the radiators were always on (except in the rooms with thermostatic valves) – I had managed before the summer by running with the timer on the boiler, and reducing the boiler temperature.

This has the side effect of (1) the boiler operating less efficiently, and (2) I can’t use it for heating the hot water as the temperature isn’t high enough.

After some digging, I got to this simple diagram of the basic setup:

As you can see, the thermostat doesn’t directly influence the boiler at all – instead it controls the actuator, which in turn allows hot water to flow, or not, through the radiator loop.

Taking a multimeter to the two wires in the Thermostat, I could see that it was in fact switching – 240V between the two when turned off vs 0V between the two terminals when it was on.

So with the thermostat basically functional, I then moved on to the Actuator (SZ2301) – this is a basic 2 port actuator. When there is current applied it opens, and when the current is stopped a spring pushes it back closed – generally speaking these things either work or they don’t.

But… on closer inspection, I found that someone had set the manual lever to flushing – basically forcing the valve open at all times. I moved it back to the “normal” position, and bingo – the thermostat could now control the flow of hot water through the radiators.


Next Steps

Now that that little niggle is sorted, I’m looking for a HA type solution to allow me to manage it all a bit better.

I’m also starting to use OpenHab for some of my other devices, so integration into that setup is essential.

TBC…