Animated Weather Condition Icons for OpenWeatherMap

habpanel
openweathermap
dynamicicons
Tags: #<Tag:0x00007f51f0174e60> #<Tag:0x00007f51f0174cf8> #<Tag:0x00007f51f0174b68>

(Holger Eisold) #1

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


OpenWeatherMap widget for HABPanel
Weather Condition Icons for OpenWeatherMap Rule Problem
(CM6.5 H102) #2

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.


(Holger Eisold) #3

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


(CM6.5 H102) #4

.:+1:

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


(The Generator) #5

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…


(Holger Eisold) #6

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
}

(The Generator) #7

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


(The Generator) #8

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


(Holger Eisold) #9

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]

(The Generator) #10

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


(Holger Eisold) #11

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


(The Generator) #12

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


(Holger Eisold) #13

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


(The Generator) #14

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…


(Holger Eisold) #15

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


(The Generator) #16

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>

(Tim) #17

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


(Holger Eisold) #18

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


(Christoph) #19

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


(Holger Eisold) #20

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