Animated Weather Condition Icons for OpenWeatherMap

Tags: #<Tag:0x00007f4335dc2628> #<Tag:0x00007f4335dc2538> #<Tag:0x00007f4335dc2470>

Hi,

Quite a while ago i saw the awesome Climacons from Adam Whitcroft and Noah Blon did very well with animation of these…
Then i saw that @ysc did a Iconset for openHAB aswell with some of the Icons in there (here)

Even if these icons are just a small feature in my own HABPanel… i wanted to have all of them, so i can easily put them in any location where i need them… so I forked the repo, included all animated climacons, fixed the chrome display bug, renamed them to have the _sun and _moon tag at the end of the filename…

Here is how it looks in my HABPanel:
(sun image will be used if Elevation is greater than 0, else moon)

Overview of a few Icons linked to OpenWeatherMap Conditions
(there are much more in the .jar iconset, a gif with imagepreview and filenames will be provided soon™)
OWM-Animated%20Climacons%20day OWM-Animated%20Climacons%20night

What do you need:

  • the iconset binding from here (just place it in your /conf/addons folder)
  • Astro Binding installed
  • OpenWeatherMap Binding
  • Map Transformation

/items/openweathermap.items (or similiar, add the following 2 items)

// see openweathermap.rules
String				    owmCurrentConditionFormated "[%s]"
Switch                  owmNightState               "Night State"

/transform/openweathermap_day.map

200=cloud_lightning_sun
201=cloud_lightning_sun
202=cloud_lightning_sun
210=cloud_lightning_sun
211=cloud_lightning_sun
212=cloud_lightning_sun
221=cloud_lightning_sun
230=cloud_lightning_sun
231=cloud_lightning_sun
232=cloud_lightning_sun
300=cloud_drizzle_sun
301=cloud_drizzle_sun
302=cloud_drizzle_sun
310=cloud_drizzle_sun
311=cloud_drizzle_sun
312=cloud_drizzle_sun
313=cloud_drizzle_sun
314=cloud_drizzle_sun
321=cloud_drizzle_sun
500=cloud_rain_sun
501=cloud_rain_sun
502=cloud_rain_sun
503=cloud_rain_sun
504=cloud_rain_sun
511=cloud_hail_sun
520=cloud_rain_alt_sun
521=cloud_rain_alt_sun
522=cloud_rain_alt_sun
531=cloud_rain_alt_sun
600=cloud_snow_sun
601=cloud_snow_alt_sun
602=cloud_snow_alt_sun
611=cloud_hail_alt_sun
612=cloud_hail_alt_sun
615=cloud_hail_alt_sun
616=cloud_hail_alt_sun
620=cloud_snow_sun
621=cloud_snow_sun
622=cloud_snow_alt_sun
701=cloud_fog_sun
711=cloud_fog_alt_sun
721=cloud_fog_sun
731=tornado
741=cloud_fog_sun
751=cloud_fog_alt_sun
761=cloud_fog_alt_sun
762=cloud_fog_alt_sun
771=cloud_fog_alt_sun
781=tornado
800=sun
801=cloud_sun
802=cloud_sun
803=cloud_sun
804=cloud_sun

/transform/openweathermap_night.map

200=cloud_lightning_moon
201=cloud_lightning_moon
202=cloud_lightning_moon
210=cloud_lightning_moon
211=cloud_lightning_moon
212=cloud_lightning_moon
221=cloud_lightning_moon
230=cloud_lightning_moon
231=cloud_lightning_moon
232=cloud_lightning_moon
300=cloud_drizzle_moon
301=cloud_drizzle_moon
302=cloud_drizzle_moon
310=cloud_drizzle_moon
311=cloud_drizzle_moon
312=cloud_drizzle_moon
313=cloud_drizzle_moon
314=cloud_drizzle_moon
321=cloud_drizzle_moon
500=cloud_rain_moon
501=cloud_rain_moon
502=cloud_rain_moon
503=cloud_rain_moon
504=cloud_rain_moon
511=cloud_hail_moon
520=cloud_rain_alt_moon
521=cloud_rain_alt_moon
522=cloud_rain_alt_moon
531=cloud_rain_alt_moon
600=cloud_snow_moon
601=cloud_snow_alt_moon
602=cloud_snow_alt_moon
611=cloud_hail_alt_moon
612=cloud_hail_alt_moon
615=cloud_hail_alt_moon
616=cloud_hail_alt_moon
620=cloud_snow_moon
621=cloud_snow_moon
622=cloud_snow_alt_moon
701=cloud_fog_moon
711=cloud_fog_alt_moon
721=cloud_fog_moon
731=tornado
741=cloud_fog_moon
751=cloud_fog_alt_moon
761=cloud_fog_alt_moon
762=cloud_fog_alt_moon
771=cloud_fog_alt_moon
781=tornado
800=moon
801=cloud_moon
802=cloud_moon
803=cloud_moon
804=cloud_moon

/rules/openweathermap.rules

rule "OpenHAB system started - astro"
when
    System started
then
    createTimer(now.plusSeconds(180)) [ |
        if (now.isAfter((Sunset_Time.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli) ||
            now.isBefore((Sunrise_Time.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)
        ) {
            postUpdate(owmNightState, ON)
        } else {
            postUpdate(owmNightState, OFF)
        }
    ]
end

rule "Update NightState"
when
    Item Elevation changed
then
    // UoM <value>|<unit> (e.g. 20|°C)
    if(Elevation.state >  0|°){
        if(owmNightState.state != OFF) {
            postUpdate(owmNightState, OFF)
            // if owmNightState was ON we need to update owmCurrentConditionFormated too
            owmCurrentConditionFormated.postUpdate(transform("MAP", "openweathermap_day.map", owmCurrentConditionId.state.toString()))
        }
    } else {
        if(owmNightState.state != ON) {
            postUpdate(owmNightState, ON)
            owmCurrentConditionFormated.postUpdate(transform("MAP", "openweathermap_night.map", owmCurrentConditionId.state.toString()))
        }
    }
end

rule "Update conditions for HABPanel icon selection"
when
    Item owmCurrentConditionId changed
then
    if (owmNightState.state == ON) {
        owmCurrentConditionFormated.postUpdate(transform("MAP", "openweathermap_night.map", owmCurrentConditionId.state.toString()))
    }
    else {
        owmCurrentConditionFormated.postUpdate(transform("MAP", "openweathermap_day.map", owmCurrentConditionId.state.toString()))
    }
end

in your HABPanel widget

  • to match the images with your CSS color, have a look here
  • you can convert your HEX color code to filter: attribute
<div class="section">
	<div class="sectionIconContainer"><div class="sectionIcon"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#thunderstorms"></use></svg></div></div>
	<div class="bigDash">
		<div class="description">Aussen - Jetzt</div>
    <div class="top">
			<div class="icon on"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#thermometer-3"></use></svg></div>
			<div class="value">
				<div class="main">{{'%.1f' | sprintf:itemValue('owmCurrentTemperature').split(' ')[0]}}</div>
				<div class="sub">&#176C</div>
			</div>
		</div>
		<div class="bottom">
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#direction-n"></use></svg></div>
      <div class="value">Luftd.</div>
      <div class="valueGroup"><div class="value">{{itemValue('owmCurrentPressure')}}</div></div>
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#drop"></use></svg></div>
      <div class="value">Luftf.</div>
      <div class="valueGroup"><div class="value">{{itemValue('owmCurrentHumidity')}}</div></div>
    </div>
		<div class="bottom">
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#drops"></use></svg></div>
      <div class="value">Regen</div>
      <div class="valueGroup"><div class="value">{{itemValue('owmCurrentRain')}}</div></div>
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#snowflake-3"></use></svg></div>
      <div class="value">Schnee</div>
      <div class="valueGroup"><div class="value">{{itemValue('owmCurrentSnow')}}</div></div>
    </div>
    <div class="graph">
			<img width="300" height="100" src="http://openhabianpi:3000/render/dashboard-solo/db/mini-graphs?orgId=1&panelId=2&from=now-24h&to=now&width=500&height=250&tz=UTC%2B02%3A00" />
			<div class="legend">Letzte 24h</div>
    </div>
	</div>

	<div class="bigDash">
		<div class="description">Aussen - in 24h um {{itemValue('owmForecastHour24Timestamp') | date:'HH:mm'}}</div>    
		<div class="top">
			<div class="icon on"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#thermometer-3"></use></svg></div>
			<div class="value">
				<div class="main">{{'%.1f' | sprintf:itemValue('owmForecastHour24Temperature').split(' ')[0]}}</div>
				<div class="sub">&#176C</div>
			</div>
		</div>
		<div class="bottom">
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#direction-n"></use></svg></div>
      <div class="value">Luftd.</div>
      <div class="valueGroup"><div class="value">{{itemValue('owmForecastHour24Pressure')}}</div></div>
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#drop"></use></svg></div>
      <div class="value">Luftf.</div>
      <div class="valueGroup"><div class="value">{{itemValue('owmForecastHour24Humidity')}}</div></div>
		</div>
		<div class="bottom">
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#drops"></use></svg></div>
      <div class="value">Regen</div>
      <div class="valueGroup"><div class="value">{{'%.1f' | sprintf:itemValue('owmForecastHour24Rain').split(' ')[0]}} mm</div></div>
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#snowflake-3"></use></svg></div>
      <div class="value">Schnee</div>
        <div class="valueGroup"><div class="value">{{'%.1f' | sprintf:itemValue('owmForecastHour24Snow').split(' ')[0]}} mm</div></div>
    </div>
    <div class="graph">
			<img width="300" height="100" src="http://openhabianpi:3000/render/dashboard-solo/db/mini-graphs?orgId=1&panelId=4&from=now-24h&to=now&width=500&height=250&tz=UTC%2B02%3A00" />
			<div class="legend">Letzte 24h</div>
    </div>
	</div>

	<div class="bigDash">
		<div class="description">Niederschlag</div>    
		<div class="top">
			<div class="icon on">
        <img style="filter: invert(72%) sepia(79%) saturate(447%) hue-rotate(29deg) brightness(94%) contrast(87%);
                    -webkit-filter: invert(72%) sepia(79%) saturate(447%) hue-rotate(29deg) brightness(94%) contrast(87%);"
          src="/icon/climacon?iconset=climacons&format=svg&state={{itemValue('owmCurrentConditionFormated')}}"></img>
			</div>
			<div class="value">
				<div class="main">{{'%.1f' | sprintf:itemValue('owmCurrentRain').split(' ')[0]}}</div>
				<div class="sub">mm</div>
			</div>
		</div>
		<div class="bottom">
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#wind"></use></svg></div>
      <div class="value">Wind</div>
      <div class="valueGroup"><div class="value">{{'%.0f' | sprintf:itemValue('owmCurrentWindSpeed').split(' ')[0]}} km/h</div></div>
      <div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#direction"></use></svg></div>
      <div class="value">Windr.</div>
      <div class="valueGroup"><div class="value">{{'%.1f' | sprintf:itemValue('owmCurrentWindDirection2').split(' ')[0]}} °</div></div>
		</div>
		<div class="bottom">
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/smarthome.svg#sunset"></use></svg></div>
      <div class="value">Bewölk.</div>
      <div class="valueGroup"><div class="value">{{'%.1f' | sprintf:itemValue('owmCurrentCloudiness').split(' ')[0]}} %</div></div>

      <div class="value"></div>
      <div class="valueGroup"><div class="value">{{itemValue('owmCurrentCondition')}}</div></div>
		</div>
    <div class="graph">
			<img width="300" height="100" src="http://openhabianpi:3000/render/dashboard-solo/db/mini-graphs?orgId=1&panelId=5&from=now-24h&to=now&width=500&height=250&tz=UTC%2B02%3A00" />
			<div class="legend">Letzte 24h</div>
    </div>
	</div>  
</div>

Hope that helps someone…

If you have suggestions for improvement, please let me know… Since i’m not a developer all stuff is made with posts/code from the forum and a bit of trial and error :slight_smile:

/Holger

32 Likes

Thanks for the tutorial, very nice.:+1:

I’m in the same boat,:laughing: but that’s what I love the most about this community, we build and learn from one another.:wink:

Thanks again.

1 Like

as promised, here is a overview of all images included in that binding…

3 Likes

.:+1:

Now I just need to convince myself to start using HABpanel.:smile:

Super cool project :+1:
I am trying to get it working on my habpanel.
Rules and Bindings in openhab are working but the widget is boggling my head since I am not so good at html and css :sweat_smile:

I see the graphs are beeing pulled via the grafana instance. How did you set up persistance and grafana to work with the template?
For a start I changed the URL from

http://openhabianpi:3000/render/dashboard-solo/db/mini-graphs

to

http://:3000/render/dashboard-solo/db/mini-graphs …

since I use a different hostname…

I’m running openhabian on a RasPi2 and in the openhabian config there is a entry for install… then follow the instructions for creating database etc. from this post InfluxDB+Grafana persistence and graphing

after that, install the Influx persitance in PaperUI and choose as persistance service…

my influxdb.persist file looks like this

Strategies {
    everyMinute : "0 * * * * ?"
    everyHour   : "0 0 * * * ?"
    everyDay    : "0 0 0 * * ?"
}

Items {
        // persist all items on every change and restore them from the db at startup
        * : strategy = everyChange, everyHour
}

Ok. It is mostly working now :smiley:

A little suggestion for the rule “Update conditions for HABPanel icon selection”:

I changed

    if (owmNightState.state == ON) {
        owmCurrentConditionFormated.postUpdate(transform("MAP", "openweathermap_night.map", owmCurrentConditionId.state.toString()))
    }
    else {
        owmCurrentConditionFormated.postUpdate(transform("MAP", "openweathermap_day.map", owmCurrentConditionId.state.toString()))
    }

to:

    if (owmNightState.state == ON) {
        owmCurrentConditionFormated.postUpdate(transform("MAP", "openweathermap_night.map", owmCurrentConditionId.state.toString()))
    }
    if (owmNightState.state == OFF) {
        owmCurrentConditionFormated.postUpdate(transform("MAP", "openweathermap_day.map", owmCurrentConditionId.state.toString()))
    }

in order to handle (owmNightState.state == NULL) before end of timer in system startup rule during nightly server restarts.

All the best,
g

Finally, it is getting somewhere …

I added an extra item:

String     owmCurrentWindrichtungFormated     "Windrichtung"

and the following rule:

rule "Format Windrichtung"
when
    Item LocalWeatherAndForecast_Current_Windrichtung changed
then
    // Update String owmCurrentWindrichtungFormated
    if (LocalWeatherAndForecast_Current_Windrichtung.state === null ||
        LocalWeatherAndForecast_Current_Windrichtung.state == "") {
        // catch uninitialized state
        owmCurrentWindrichtungFormated.postUpdate("unbekannt")
    } 
    if (LocalWeatherAndForecast_Current_Windrichtung.state >  315|° &&
        LocalWeatherAndForecast_Current_Windrichtung.state <=  45|°) {
        // Norden
        owmCurrentWindrichtungFormated.postUpdate("Norden")
    }
    if (LocalWeatherAndForecast_Current_Windrichtung.state >  45|° &&
        LocalWeatherAndForecast_Current_Windrichtung.state <=  135|°) {
        // Osten
        owmCurrentWindrichtungFormated.postUpdate("Osten")
    }
    if (LocalWeatherAndForecast_Current_Windrichtung.state >  135|° &&
        LocalWeatherAndForecast_Current_Windrichtung.state <=  225|°) {
        // Süden
        owmCurrentWindrichtungFormated.postUpdate("Süden")
    }
    if (LocalWeatherAndForecast_Current_Windrichtung.state >  225|° &&
        LocalWeatherAndForecast_Current_Windrichtung.state <=  315|°) {
        // Westen
        owmCurrentWindrichtungFormated.postUpdate("Westen")
    }
end

I was able to use the matrix-theme, but replaced the icons with free default icons.
So, I am happy now, thanks for the inspiration!

Cheers,
g

You can do it also with the SCALE transformation, like i do…

/transform/wind.scale

[0..11.25[ = N - Nord
[11.25..33.75[ = NNE - NordNordOst
[33.75..56.25[ = NE - NordOst
[56.25..78.75[ = ENE - OstNordOst
[78.75..101.25[ = E - Ost
[101.25..123.75[ = ESE - OstSüdOst
[123.75..146.25[ = SE - SüdOst
[146.25..168.75[ = SSE - SüdSüdOst
[168.75..191.25[ = S - Süd
[191.25..213.75[ = SSW - SüdSüdWest
[213.75..236.25[ = SW - SüdWest
[236.25..258.75[ = WSW - WestSüdWest
[258.75..281.25[ = W - West
[281.25..303.75[ = WNW - WestNordWest
[303.75..326.25[ = NW - NordWest
[326.25..348.75[ = NNW - NordNordWest
[348.75..360] = N - Nord

.items file

Number:Dimensionless	owmCurrentWindDirection     "Aktuelle Windrichtung [SCALE(wind.scale):%s]
1 Like

Way better! Thanks.
How would the corresponding rule look like?

you dont need one… you just need to install the Scale transformation service in PaperUI and you need to call the wind.scale within you item… see my example 1 post above

II am curious how the item owmCurrentWindDirection gets its input (ID from owm-binding)? … Sorry, I am such a noob :wink:

yeah… of course you need to add a channel like :slight_smile:
{channel="openweathermap:weather-and-forecast:api:local:current#wind-direction"}

So i changed the item definition like this:

Number:Dimensionless	owmCurrentWindDirection     "[SCALE(wind.scale):%s]"      { channel="openweathermap:weather-and-forecast:eb144552:local:current#wind-direction" }

after a restart the item gets a strange value:

openhab> smarthome:status owmCurrentWindDirection                                                    
4.188790204786390984616857844372669
openhab> smarthome:status LocalWeatherAndForecast_Current_Windrichtung
240.0 °

Sorry, but I think I am completely missing how to initialize owmCurrentWindDirection correctly and how to get the formated text (eg. “NordWest”) out of it…

Oh well… my fault… i have had this old item in my sitemaps file… and didn’t checked if its working… and indeed there is a problem with Units of Measurement (UoM) type of items… which i cant solve…

But if you change your item to this it will work… now i tested it :wink:
Number owmCurrentWindDirection "Aktuelle Windrichtung [SCALE(wind.scale):%s]" {channel="openweathermap:weather-and-forecast:api:local:current#wind-direction"}

sorry for the confusion

That was it! Thank you!

Just for reference, to access the formated state of owmCurrentWindDirection I used in the Habmin template:

<div class="value">{{itemState('owmCurrentWindDirection')}}</div>
1 Like

Thank you for this great tutorial.

But I still have a few questions.

What kind of item type is the item elevation? Because the rules are not executed correctly.

And where could I find smarthome.svg?

Best regards
tim

Info is here, In case you dont purchased the squidink icons, just create your own smarthome.svg. maybe someone is willing to share their used free alternative svg file

1 Like

Hi! I am very new to openhab, so maybe I missed the obvious.
After some work I reached the following status:


For “smarthome.svg” I get the http status “404 not found”.
Where do I get the missing file?

Thanks for your support
Christoph

you need to create that file… i use payed icons in there from squidink so i cant share thm here… @the_generator did some free icons… maybe he or someone else is willing to share their file