OH3 32-point wind direction list widget with dynamic custom windrose icon, renders wind direction name without rule

Hi all,

Here’s yet another experiment with a custom list widget to render the wind direction by name instead of by angle, and with support for a dynamic icon.

This widget requires no openHAB rules to run, the logic is contained in the widget code:

uid: wind_direction_list_32
tags:
  - list
  - wind
props:
  parameters:
    - description: Widget title
      label: Title
      name: title
      required: false
      type: TEXT
    - context: item
      description: Wind direction angle item to display
      label: Item
      name: item
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Jun 4, 2021, 8:45:38 PM
component: oh-list-item
config:
  ## Get the wind angle in degrees:
  #    wind_angle = Number.parseFloat(items[props.item].state
  ## Scale wind angle from 360° range to 64 step range:
  #    scaled_wind_angle = wind_angle / 360.0 * 2 * 32
  ## North goes from -1 to +1 hence we add an offset so the index starts at 0, 2, 4...
  #    scaled_wind_angle += 1
  # Convert index to 32-step index (use Math.floor) and reduce range to [0; 32[:
  #    wind_name_index = Math.floor(scaled_wind_angle / 2) % 32
  ## Use custom windrose icons named 'windrose-<state>.svg' (<state> represents a wind direction in lower case), e.g. from:
  ## https://community.openhab.org/t/solved-making-dynamic-icons-work-32-point-wind-rose-example/76326/7?u=shutterfreak
  icon: >-
    =(!Number.isFinite(Number.parseFloat(items[props.item].state))) ? "f7:question_circle" : "oh:windrose-" + 
        ([
        "N", "NbE", "NNE", "NEbN", "NE", "NEbE", "ENE", "EbN",
        "E", "EbS", "ESE", "SEbE", "SE", "SEbS", "SSE", "SbE",
        "S", "SbW", "SSW", "SWbS", "SW", "SWbW", "WSW", "WbS",
        "W", "WbN", "WNW", "NWbW", "NW", "NWbN", "NNW", "NbW",
    ])[ Math.floor( (1 + Number.parseFloat(items[props.item].state) / 360.0 * 2 * 32) / 2) % 32 ].toLowerCase() + ".svg"
  title: =props.title
  item: =props.item
  action: analyzer
  actionAnalyzerCoordSystem: time
  actionAnalyzerItems: =[props.item]
  after: >-
    =(!Number.isFinite(Number.parseFloat(items[props.item].state))) ? "-" :  
        ([
        "N", "NbE", "NNE", "NEbN", "NE", "NEbE", "ENE", "EbN",
        "E", "EbS", "ESE", "SEbE", "SE", "SEbS", "SSE", "SbE",
        "S", "SbW", "SSW", "SWbS", "SW", "SWbW", "WSW", "WbS",
        "W", "WbN", "WNW", "NWbW", "NW", "NWbN", "NNW", "NbW",
    ])[ Math.floor( (1 + Number.parseFloat(items[props.item].state) / 360.0 * 2 * 32) / 2) % 32 ]

I documented the transform logic in YAML comments, but unfortunately openHAB removes these comments when you save the widget. I posted the overall logic elsewhere in a Python rule:

Convert wind direction in degrees (0°-360°) into a named wind direction by means of an index.

Since we’re producing a 32-point wind rose, ‘pure’ wind direction names are centred across arcs spanning 1/32th of a full circle. Or, having equal arcs of 1/64th of a full circle at each side as mapping intervals. In this logic:

  1. north is centred at step 0
  2. scaled wind angles with values between steps -1 and +1 are mapped to north
  3. since wind directions span 2 steps, we must count the intervals at odd nonzero step values

Therefore the wind direction name index can be computed as follows:

  1. Convert a wind direction angle value into 2 * 32 = 64 steps
  2. Round down this value to the closest integer
  3. Map this value to [0…64[ using modulo (north may yield values ≥64)
  4. Convert this value to a 32-step index (use Math.floor as wind name changes at threshold)
  5. Look up the wind direction name by means of this index in the wind direction name array

You can retrieve custom wind rose icons from:

Have fun!

Olivier

4 Likes

And for those more familiar with the traditional 16-point wind rose, the code for the list widget is:

uid: wind_direction_list_16
tags:
  - list
  - wind
props:
  parameters:
    - description: Widget title
      label: Title
      name: title
      required: false
      type: TEXT
    - context: item
      description: Wind direction angle item to display
      label: Item
      name: item
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Jun 4, 2021, 8:45:38 PM
component: oh-list-item
config:
  ## Get the wind angle in degrees:
  #    wind_angle = Number.parseFloat(items[props.item].state
  ## Scale wind angle from 360° range to 32 step range:
  #    scaled_wind_angle = wind_angle / 360.0 * 2 * 16
  ## North goes from -1 to +1 hence we add an offset so the index starts at 0, 2, 4...
  #    scaled_wind_angle += 1
  # Convert index to 16-step index (use Math.floor) and reduce range to [0; 16[:
  #    wind_name_index = Math.floor(scaled_wind_angle / 2) % 16
  ## Use custom windrose icons named 'windrose-<state>.svg' (<state> represents a wind direction in lower case), e.g. from:
  ## https://community.openhab.org/t/solved-making-dynamic-icons-work-32-point-wind-rose-example/76326/7?u=shutterfreak
  icon: >-
    =(!Number.isFinite(Number.parseFloat(items[props.item].state))) ? "f7:question_circle" : "oh:windrose-" + 
        ([
        "N", "NNE", "NE", "ENE",
        "E", "ESE", "SE", "SSE",
        "S", "SSW", "SW", "WSW",
        "W", "WNW", "NW", "NNW",
    ])[ Math.floor( (1 + Number.parseFloat(items[props.item].state) / 360.0 * 2 * 16) / 2) % 16 ].toLowerCase() + ".svg"
  title: =props.title
  item: =props.item
  action: analyzer
  actionAnalyzerCoordSystem: time
  actionAnalyzerItems: =[props.item]
  after: >-
    =(!Number.isFinite(Number.parseFloat(items[props.item].state))) ? "-" :  
        ([
        "N", "NNE", "NE", "ENE",
        "E", "ESE", "SE", "SSE",
        "S", "SSW", "SW", "WSW",
        "W", "WNW", "NW", "NNW",
    ])[ Math.floor( (1 + Number.parseFloat(items[props.item].state) / 360.0 * 2 * 16) / 2) % 16 ]

I didn’t test this code but it should work.

3 Likes

I have this mostly up and running but can’t seem to get the icons to serve up. If I inspect the html, I can see the icon link is getting built correctly but it does not resolve. Do I need to find a way to get “format” to png?

src="/icon/windrose-nw.png?format=svg&anyFormat=true

The “after” text shows up correctly. If I place a ‘windrose.png’ in the icon directory, the page will show that. Can’t figure out what I’m missing. Seems like openhab ‘reserving’ the hyphen+suffix for true dynamic icon usage but if you got it to work…
I’m on 3.0.2.

I have both PNG and SVG formats of the windrose icons installed. Long story short: iOS openHAB app issues on openHAB2.5.

Which icon file formats did you install?

I just grabbed the png’s from your other post, modified the names to match what is in the array, and dropped them in ‘icons/’ and ‘icons/classic/’.

I saw the threads about “png only” for the iOS app. I guess I could convert these png’s to svg (have both). Do you think that’s causing it?

You don’t need to convert the icons from PNG to SVG. It’s done the other way around, SVG is a vector format and PNG is a raster format,

The PNG icons should have’png’ file extension and the SVG icons should have ‘.svg’ file extension.

With openHAB3 I no longer use the iOS app )for now) and I believe by default the SVG icons are chosen…

Right, but your post only had png icons. That’s all I have.
I think there’s some logic to: given that it’s working for you, you’re not using the app, and are on oh3, with both SVG and PNG - the issue is that I don’t have SVGs. Seems to be a missing piece.

Were you expecting that post to be SVGs? Wonder if the upload converted them? Did you create them yourself or could I find the SVGs somewhere?

I crafted the SVG files by hand. I’m pretty certain that I posted them in my other thread:

If you inspect the images on that post, they’re all PNGs.

https://community-openhab-org.s3.dualstack.eu-central-1.amazonaws.com/original/3X/c/d/cdf28cd2670b017791c3a5e61ffd9351b2498a60.png

Apparently the forum software automagically converted the SVG files to PNG.

See the following post with SVG icons:

Please let me know if this still doesn’t work.