UI Widget: Weather

The name with prefix should be:
items[props.itemPrefix + StationName]
instead of
items[props.itemPrefix + localStationName]

This way you can have multiple widgets, one for local, another for some other location, etc.

Hey @JimT thanks for your feedback - you are right and this would be valid for all the used item names as they all have the ‘local’ part in front of it. (I initially used the item-names from the docs and haven’t thought about the ideal naming at this stage). Even if this is just a naming thing and shouldn’t influence the functionality at all.

I’ll correct that (and adding the pre-defined model informations) tonight, when the last christmas events are over

Hey,

I am having some trouble with the configuration of the widget.
I was wondering, if you could post your yaml for comparison.
The thing I am most interested in is how to actually set a new name for “Daily” or “hourly” and how to set the images. Both might be related because somehow it doesn’t set the new value.
Do I have to set the Boolean value from false to true or where to write the actual word?
PS: I am also German so it might be quite convenient for me to just copycat right away :smiley: I don’t do programming that often.

Welcome @2relativ

If you mean the above shown variant from @oh11 - he posted his YAML in the post below the image

You can set the localized namings for ‘daily’ and ‘hourly’ in the widget-configuration.

Thanks! That helped. I thought it must be hardcoded. Didn’t even think about the widget configuration. I am still testing the new OH3 version so cheers, mate!

The next iteration of the weather widget:

  • Optional Information Item (Example BME680 Temperature)
  • The background image can be changed with the “TimeOfDay” funktion

Backgroundfiles (example):

Imagefiles:  zug_sunrise_sw.jpg (without TimeOfDay change)
                    zug_sunrise_sw_MORNING.jpg
                    zug_sunrise_sw_DAY.jpg
                    zug_sunrise_sw_EVENING.jpg
                    …

widget.PNG
 

Widget YAML
uid: weather_card
tags: []
props:
  parameters:
    - description: <b>Optional prefix</b> for item names.
      label: Item prefix
      name: itemPrefix
      required: false
      type: TEXT
      groupName: general
    - description: The number of hours you want to forecast <b>(<u>default:</u> 11)</b>
      label: Number of hours to forecast
      name: forecastHours
      required: false
      type: TEXT
      groupName: general
    - description: The number of days you want to forecast <b>(<u>default:</u> 5)</b>
      label: Number of days to forecast
      name: forecastDays
      required: false
      type: TEXT
      groupName: general
    - label: Background image-url
      name: backgroundUrl
      required: false
      type: TEXT
      groupName: general
    - description: Background blur
      label: Intensity of the background-blur (0 - 10)
      name: backgroundBlur
      required: false
      type: TEXT
      groupName: general
    - description: Acitvate 24-hour clock-format <b>(<u>default:</u> 12-hour clock-format)</b>
      label: 24h clock-format
      name: dateFormat
      required: false
      type: BOOLEAN
      groupName: general
    - description: Acitvate Sun-Indicator <b>(<u>default:</u> no)</b>
      label: Sun-Indicator
      name: sunIndicator
      required: false
      type: BOOLEAN
      groupName: general
    - description: Item for extra Information eg. local Temperature Sensor
      label: Information Item (optional)
      name: itemInform
      required: false
      type: TEXT
      groupName: general
      advanced: true      
    - description: Alternative title for 'Hourly' within the segmented control <b>(<u>default:</u> Hourly)</b>
      label: Alternative text for 'Hourly'
      name: wordingForecastHours
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative title for 'Daily' within the segmented control <b>(<u>default:</u> Daily)</b>
      label: Alternative text for 'Daily'
      name: wordingForecastDays
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative title for 'Precipitation' within the segmented control <b>(<u>default:</u> Daily)</b>
      label: Alternative text for 'Precipitation'
      name: wordingForecastPrecib
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative text for 'Now' in the hourly-forecast & precipitation-forecast tab
      label: Translation 'Now'
      name: wordingNow
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative text for 'Today' in the daily-forecast tab
      label: Translation 'Today'
      name: wordingToday
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative text for 'Feel' in the feel-temperature display
      label: Translation 'Feel'
      name: wordingFeel
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative text for 'h' as Hour in the timeline (z.B. Uhr)
      label: Translation 'h'
      name: wordingHour
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Enable Times of Day feature for background image
      label: item 'Times of Day'
      name: itemTimesOfDay
      required: false
      type: TEXT
      groupName: wording
      advanced: true
  parameterGroups:
    - name: general
      label: General settings
    - name: wording
      label: Wording
timestamp: Dec 25, 2020, 8:57:06 PM
component: f7-card
config:
  class:
    - padding
  style:
    background-image: "='url(' + props.backgroundUrl.substring(0, (props.backgroundUrl.length -4)) + ((props.itemTimesOfDay === undefined || items[props.itemTimesOfDay].state === 'NULL') ? '' : '_' + items[props.itemTimesOfDay].state) + props.backgroundUrl.substr(-4) + ')'"
    background-size: cover
    background-repeat: no-repeat
    background-position: 100% 100%
    border-radius: 20px
    overflow: hidden
    -ms-user-select: none
    -moz-user-select: none
    -webkit-user-select: none
    user-select: none
    --weather-card-color: 255,255,255
    --weather-card-text-color: rgba(var(--weather-card-color),1)
slots:
  default:
    - component: f7-block
      config:
        class:
          - no-padding
          - no-margin
        style:
          background-color: rgba(255,255,255,.15)
          backdrop-filter: ='blur(' + props.backgroundBlur + 'px)'
          width: 100%
          height: 100%
          position: absolute
          top: 0
          left: 0
          border-radius: 20px

    - component: f7-row
      slots:
        default:
          - component: f7-col
            config:
              class: col-80
              style:
                z-index: 999
            slots:
              default:
                - component: Label
                  config:
                    text: "=items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'StationName'].state"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 26px
                      line-height: 32px
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                - component: Label
                  config:
                    text: =dayjs().format("DD. MMMM YYYY")
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 12px
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                - component: f7-icon
                  config:
                    f7: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '01d') ? 'sun_max_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '01n') ? 'moon_stars_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '02d') ? 'cloud_sun_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '02n') ? 'cloud_moon_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '03d') ? 'cloud_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '03n') ? 'cloud_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '04d') ? 'cloud_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '04n') ? 'cloud_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '09d') ? 'cloud_heavyrain_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '09n') ? 'cloud_heavyrain_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '10d') ? 'cloud_sun_rain_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '10n') ? 'cloud_moon_rain_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '11d') ? 'cloud_sun_bolt_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '11n') ? 'cloud_moon_bolt_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '13d') ? 'cloud_snow_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '13n') ? 'cloud_snow_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '50d') ? 'cloud_fog_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Iconid'].state === '50n') ? 'cloud_fog_fill' : '?'"
                    size: 60
                    class:
                      - align-content-center
                    style:
                      color: rgba(var(--weather-card-color),.9)
                      padding-top: 5px
                      padding-bottom: 5px
                - component: Label
                  config:
                    text: "=items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Condition'].state"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 16px
                      line-height: 21px
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
          - component: f7-col
            config:
              class: col-20
              style:
                z-index: 999
                text-align: center
                width: fit-content
                overflow: hidden
            slots:
              default:
                - component: Label
                  config:
                    text: "=(props.itemPrefix === undefined) ? Math.round(items.localCurrent_Temperature.state.split(' ')[0]) + '°' :  Math.round(items[props.itemPrefix + 'Current_Temperature'].state.split(' ')[0])+'°'"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 58px
                      line-height: 58px
                      font-weight: 100
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                - component: Label
                  config:
                    text: "=(props.itemPrefix === undefined) ? 'gefühlt: ' + Math.round(items.localCurrent_Apparenttemperature.state.split(' ')[0]) +'°' :  ((props.wordingFeel === undefined) ? 'Feel: ' : props.wordingFeel + ': ') + Math.round(items[props.itemPrefix + 'Current_Apparenttemperature'].state.split(' ')[0]) +'°'"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 21px
                      font-weight: 100
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                - component: Label
                  config:
                    text: "=(props.itemPrefix === undefined) ? Math.round(items.localCurrent_Humidity.state.split(' ')[0])+'% ' :  Math.round(items[props.itemPrefix + 'Current_Humidity'].state.split(' ')[0]) + '% ' + Math.round(items[props.itemPrefix + 'Current_Windspeed'].state.split(' ')[0]) + 'km/h'"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 21px
                      font-weight: 100
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                - component: Label
                  config:
                    text: "=(props.itemInform === undefined) ? '' :  items[props.itemInform].state "
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 16px
                      font-weight: 100
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
    - component: f7-segmented
      config:
        strong: true
        textColor: white
        class: margin-top
        style:
          --f7-segmented-strong-button-active-box-shadow: 0px 4px 0px -1px white
          --f7-segmented-strong-button-active-text-color: rgba(var(--weather-card-color),1)
          --f7-button-text-color: rgba(var(--weather-card-color),.5)
          --f7-segmented-strong-text-color: rgba(var(--weather-card-color),.5)
          --f7-segmented-strong-padding: 3px
          --f7-button-active-text-color: rgba(var(--weather-card-color),1)
          --f7-button-raised-box-shadow: none
          --f7-segmented-strong-button-active-bg-color: transparent
          --f7-button-border-radius: 0
          border-bottom: 3px solid rgba(var(--weather-card-color),.5)
          background: transparent
          z-index: 999
      slots:
        default:
          - component: oh-button
            config:
              text: "=(props.wordingForecastHours === undefined) ? 'Hourly' : props.wordingForecastHours"
              color: var(--weather-card-text-color)
              active: =vars.tab === 'hourly_forecast'
              action: variable
              actionVariable: tab
              actionVariableValue: hourly_forecast
          - component: oh-button
            config:
              text: "=(props.wordingForecastHours === undefined) ? 'Daily' : props.wordingForecastDays"
              color: var(--weather-card-text-color)
              active: =vars.tab === 'daily_forecast'
              action: variable
              actionVariable: tab
              actionVariableValue: daily_forecast
          - component: oh-button
            config:
              text: "=(props.wordingForecastPrecib === undefined) ? 'Precipitation' : props.wordingForecastPrecib"
              color: var(--weather-card-text-color)
              active: =vars.tab === 'precip_forecast'
              action: variable
              actionVariable: tab
              actionVariableValue: precip_forecast
    - component: f7-swiper
      config:
        visible: =!vars.tab || vars.tab === 'hourly_forecast'
        navigation: true
        class:
          - padding-top
        params:
          initalSlide: 0
          runCallbacksOnInit: true
          grabCursor: true
          observer: true
          observeSlideChildren: true
          updateOnWindowResize: true
          spaceBetween: 5
          mousewheel: true
          keyboard: true
          watchOverflow: true
          breakpoints:
            "0":
              slidesPerView: 1
            "240":
              slidesPerView: 2
            "320":
              slidesPerView: 3
            "480":
              slidesPerView: 4
            "640":
              slidesPerView: 5
        style:
          --swiper-navigation-size: 30px
          --swiper-navigation-color: var(--weather-card-text-color)
      slots:
        default:
          - component: oh-repeater
            config:
              sourceType: range
              for: hour
              rangeStart: 0
              rangeStop: "=(props.forecastHours === undefined) ? 11 : Number(props.forecastHours)"
              fragment: true
            slots:
              default:
                - component: f7-swiper-slide
                  config:
                    id: =loop.hour_idx
                    expandable: true
                    style:
                      background: "=(props.sunIndicator === true) ? ((dayjs().add(loop.hour,'hour').format() >= items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').format() ? 'Today' : (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').add(1,'day').format() ? 'Tomorrow' : 'Day2')) + '_Sunrise'].state && dayjs().add(loop.hour,'hour').format() <= items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').format() ? 'Today' : (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').add(1,'day').format() ? 'Tomorrow' : 'Day2')) + '_Sunset'].state) ? 'rgba(44,130,201,.15)' : 'rgba(190,144,212,.15)') : 'none'"
                      border-radius: 5px
                  slots:
                    default:
                      - component: f7-row
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                        slots:
                          default:
                            - component: Label
                              config:
                                text: "=(loop.hour === 0) ? ((props.wordingNow === undefined) ? 'Now' : props.wordingNow) : ((props.dateFormat === false) ? dayjs().add(loop.hour,'hour').startOf('hour').format('h A') : dayjs().add(loop.hour,'hour').startOf('hour').format('HH') + ((props.wordingHour === undefined) ? ' h' : ' ' + props.wordingHour))"
                                style:
                                  color: var(--weather-card-text-color)
                                  font-size: 18px
                                  font-weight: 600
                      - component: f7-col
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                            - text-align-center
                        slots:
                          default:
                            - component: f7-icon
                              config:
                                f7: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '01d') ? 'sun_max_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '01n') ? 'moon_stars_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '02d') ? 'cloud_sun_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '02n') ? 'cloud_moon_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '03d') ? 'cloud_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '03n') ? 'cloud_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '04d') ? 'cloud_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '04n') ? 'cloud_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '09d') ? 'cloud_heavyrain_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '09n') ? 'cloud_heavyrain_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '10d') ? 'cloud_sun_rain_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '10n') ? 'cloud_moon_rain_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '11d') ? 'cloud_sun_bolt_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '11n') ? 'cloud_moon_bolt_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '13d') ? 'cloud_snow_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '13n') ? 'cloud_snow_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '50d') ? 'cloud_fog_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Iconid'].state === '50n') ? 'cloud_fog_fill' : ''"
                                size: 40
                                style:
                                  padding-right: 5px
                                  color: var(--weather-card-text-color)
                            - component: Label
                              config:
                                text: "=Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Temperature'].state.split(' ')[0]) + '° ' + Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Windspeed'].state.split(' ')[0]) + 'km/h'"
                                style:
                                  font-size: 18px
                                  font-weight: 400
                                  color: var(--weather-card-text-color)
    - component: f7-swiper
      config:
        visible: =vars.tab === 'daily_forecast'
        navigation: true
        class:
          - padding-top
        params:
          initalSlide: 0
          grabCursor: true
          observer: true
          spaceBetween: 1
          observeSlideChildren: true
          updateOnWindowResize: true
          watchOverflow: true
          mousewheel: true
          keyboard: true
          breakpoints:
            "0":
              slidesPerView: 1
            "210":
              slidesPerView: "=(props.forecastDays === undefined) ? 2 : ((props.forecastDays < 2) ? Math.round(Number(props.forecastDays) + 1) : 2)"
            "320":
              slidesPerView: "=(props.forecastDays === undefined) ? 3 : ((props.forecastDays < 3) ? Math.round(Number(props.forecastDays) + 1) : 3)"
            "480":
              slidesPerView: "=(props.forecastDays === undefined) ? 4 : ((props.forecastDays < 4) ? Math.round(Number(props.forecastDays) + 1) : 4)"
            "640":
              slidesPerView: "=(props.forecastDays === undefined) ? 5 : ((props.forecastDays < 5) ? Math.round(Number(props.forecastDays) + 1) : 5)"
        style:
          --swiper-navigation-size: 30px
          --swiper-navigation-color: var(--weather-card-text-color)
      slots:
        default:
          - component: oh-repeater
            config:
              sourceType: range
              for: day
              rangeStart: 0
              rangeStop: "=(props.forecastDays === undefined) ? 5 : Number(props.forecastDays)"
              fragment: true
            slots:
              default:
                - component: f7-swiper-slide
                  config:
                    class:
                      - text-align-center
                  slots:
                    default:
                      - component: f7-row
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                        slots:
                          default:
                            - component: Label
                              config:
                                text: "=(loop.day === 0) ? ((props.wordingToday === undefined) ? 'Today' : props.wordingToday) : dayjs().add(loop.day,'day').startOf('day').format('dddd')"
                                style:
                                  color: var(--weather-card-text-color)
                                  font-size: 18px
                                  font-weight: 600
                      - component: f7-icon
                        config:
                          class:
                            - align-center
                          f7: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '01d') ? 'sun_max_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '01n') ? 'moon_stars_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '02d') ? 'cloud_sun_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '02n') ? 'cloud_moon_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '03d') ? 'cloud_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '03n') ? 'cloud_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '04d') ? 'cloud_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '04n') ? 'cloud_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '09d') ? 'cloud_heavyrain_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '09n') ? 'cloud_heavyrain_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '10d') ? 'cloud_sun_rain_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '10n') ? 'cloud_moon_rain_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '11d') ? 'cloud_sun_bolt_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '11n') ? 'cloud_moon_bolt_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '13d') ? 'cloud_snow_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '13n') ? 'cloud_snow_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '50d') ? 'cloud_fog_fill' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx))) + '_Iconid'].state === '50n') ? 'cloud_fog_fill' : '?'"
                          size: 40
                          style:
                            color: var(--weather-card-text-color)
                      - component: f7-row
                        config:
                          class:
                            - justify-content-center
                        slots:
                          default:
                            - component: Label
                              config:
                                text: "=Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + ((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + (loop.day_idx))) + '_Maxtemperature'].state.split(' ')[0]) +'°'"
                                style:
                                  font-size: 18px
                                  font-weight: 400
                                  color: var(--weather-card-text-color)
                            - component: Label
                              config:
                                text: /
                                style:
                                  color: rgba(var(--weather-card-color),.5)
                                  font-size: 18px
                            - component: Label
                              config:
                                text: "=Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + ((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + (loop.day_idx))) + '_Mintemperature'].state.split(' ')[0]) +'°'"
                                style:
                                  font-size: 18px
                                  font-weight: 400
                                  color: rgba(var(--weather-card-color),.75)
    - component: f7-swiper
      config:
        visible: =vars.tab === 'precip_forecast'
        navigation: true
        class:
          - padding-top
        params:
          initalSlide: 0
          runCallbacksOnInit: true
          grabCursor: true
          observer: true
          observeSlideChildren: true
          updateOnWindowResize: true
          spaceBetween: 5
          mousewheel: true
          keyboard: true
          watchOverflow: true
          breakpoints:
            "0":
              slidesPerView: 1
            "240":
              slidesPerView: 2
            "320":
              slidesPerView: 3
            "480":
              slidesPerView: 4
            "640":
              slidesPerView: 5
        style:
          --swiper-navigation-size: 30px
          --swiper-navigation-color: var(--weather-card-text-color)
      slots:
        default:
          - component: oh-repeater
            config:
              sourceType: range
              for: hour
              rangeStart: 0
              rangeStop: "=(props.forecastHours === undefined) ? 11 : Number(props.forecastHours)"
              fragment: true
            slots:
              default:
                - component: f7-swiper-slide
                  config:
                    id: =loop.hour_idx
                    expandable: true
                    style:
                      background: "=(props.sunIndicator === true) ? ((dayjs().add(loop.hour,'hour').format() >= items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').format() ? 'Today' : (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').add(1,'day').format() ? 'Tomorrow' : 'Day2')) + '_Sunrise'].state && dayjs().add(loop.hour,'hour').format() <= items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').format() ? 'Today' : (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').add(1,'day').format() ? 'Tomorrow' : 'Day2')) + '_Sunset'].state) ? 'rgba(44,130,201,.15)' : 'rgba(190,144,212,.15)') : 'none'"
                      border-radius: 5px
                  slots:
                    default:
                      - component: f7-row
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                        slots:
                          default:
                            - component: Label
                              config:
                                text: "=(loop.hour === 0) ? ((props.wordingNow === undefined) ? 'Now' : props.wordingNow) : ((props.dateFormat === false) ? dayjs().add(loop.hour,'hour').startOf('hour').format('h A') : dayjs().add(loop.hour,'hour').startOf('hour').format('HH') + ((props.wordingHour === undefined) ? ' h' : ' ' + props.wordingHour))"
                                style:
                                  color: var(--weather-card-text-color)
                                  font-size: 18px
                                  font-weight: 600
                      - component: f7-col
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                            - text-align-center
                        slots:
                          default:
                            - component: f7-icon
                              config:
                                f7: "=(Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0') + '_Precipprobability'].state.split(' ')[0] ) >= 50 ) ? 'umbrella_fill' : 'umbrella' "
                                size: 40
                                style:
                                  padding-right: 5px
                                  color: var(--weather-card-text-color)
                            - component: Label
                              config:
                                text: "=Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0') + '_Precipprobability'].state.split(' ')[0] ) +'%'"
                                style:
                                  font-size: 18px
                                  font-weight: 400
                                  color: var(--weather-card-text-color)

Widget configuration example:
component: widget:weather_card
config:
  backgroundUrl: http://10.5.0.90:8080/static/zug_sunrise_sw.jpg
  sunIndicator: true
  itemTimesOfDay: TimeOfDay
  dateFormat: true
  wordingToday: Heute
  wordingNow: Jetzt
  wordingForecastDays: Täglich
  wordingFeel: gefühlt
  backgroundBlur: "0"
  wordingForecastPrecib: Niederschlag
  wordingHour: Uhr
  itemPrefix: OneCallAPIweatherandforecast_
  wordingForecastHours: Stündlich
  item: OneCallAPIweatherandforecast
  itemInform: GenericMQTTThing_BME680Temperatur

3 Likes

The “Time of day” Funktion gabe me an idea. Is it possible to set backgrounds according to the weather? That would be really cool. Also: I hope your widget becomes an official feature! Looks really great and is promising.

Hey @2relativ

this is what I did here

It sets/changes the background image depending on the current weather (the conditionIconID to be explicit) - it isn’t a fotorealistic one in that case, as it’s another style there.

The expression is kinda long, but you could change it and reuse it in any other widget-style:

"=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '01d') ? '' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '01n') ? '' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '02d') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '02.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '02n') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '02.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '03d') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '03.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '03n') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '03.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '04d') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '04.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '04n') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '04.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '09d') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '09.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '09n') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '09.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '10d') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '10.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '10n') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '10.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '11d') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '11.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '11n') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '11.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '13d') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '13.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '13n') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '13.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '50d') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '50.svg)' : (items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localCurrentIconId'].state === '50n') ? 'no-repeat top center/750px url(' + ((props.imageFolder === undefined) ? '/static/files/weather_img/' : props.imageFolder) + '50.svg)' : '?'"

This already looks really great.

I really love the way the weawow android app is displaying weather info

IMG_20201228_060704_047

Just thought I’d share it here maybe we can take parts from its display style for this widget.

Take a look in the YAML (line 120):

Change

"items[props.itemTimesOfDay].state" 

to

items[props.itemPrefix) + 'CurrentIconId'].state

However, as @RGroll wrote, this is already implemented as an symbol.
@salexes: I think that the graphics can be implemented via a “widget action”. I’ll try it.

1 Like

Does this version also support sunrise & sunset popup? If yes, then I did simething wrong :smiley: Everything else is working! Thanks a lot for this/these widget(s)!

the tile backgrounds is using for sunrise/sunset (see post @RGroll )
grafik

If anyone is also using Darksky here a customized version of @oh11 's version. Due to Darksky does not provide the correct icon-id’s like set in the code but provide’s already the Base64 icon I modified it to use them instead.

Modified Darksky YAML
uid: weather_card
tags: []
props:
  parameters:
    - description: <b>Optional prefix</b> for item names.
      label: Item prefix
      name: itemPrefix
      required: false
      type: TEXT
      groupName: general
    - description: The number of hours you want to forecast <b>(<u>default:</u> 11)</b>
      label: Number of hours to forecast
      name: forecastHours
      required: false
      type: TEXT
      groupName: general
    - description: The number of days you want to forecast <b>(<u>default:</u> 5)</b>
      label: Number of days to forecast
      name: forecastDays
      required: false
      type: TEXT
      groupName: general
    - label: Background image-url
      name: backgroundUrl
      required: false
      type: TEXT
      groupName: general
    - description: Background blur
      label: Intensity of the background-blur (0 - 10)
      name: backgroundBlur
      required: false
      type: TEXT
      groupName: general
    - description: Acitvate 24-hour clock-format <b>(<u>default:</u> 12-hour clock-format)</b>
      label: 24h clock-format
      name: dateFormat
      required: false
      type: BOOLEAN
      groupName: general
    - description: Acitvate Sun-Indicator <b>(<u>default:</u> no)</b>
      label: Sun-Indicator
      name: sunIndicator
      required: false
      type: BOOLEAN
      groupName: general
    - description: Alternative title for 'Hourly' within the segmented control <b>(<u>default:</u> Hourly)</b>
      label: Alternative text for 'Hourly'
      name: wordingForecastHours
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative title for 'Daily' within the segmented control <b>(<u>default:</u> Daily)</b>
      label: Alternative text for 'Daily'
      name: wordingForecastDays
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative title for 'Precipitation' within the segmented control <b>(<u>default:</u> Daily)</b>
      label: Alternative text for 'Precipitation'
      name: wordingForecastPrecib
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative text for 'Now' in the hourly-forecast & precipitation-forecast tab
      label: Translation 'Now'
      name: wordingNow
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative text for 'Today' in the daily-forecast tab
      label: Translation 'Today'
      name: wordingToday
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative text for 'Feel' in the feel-temperature display
      label: Translation 'Feel'
      name: wordingFeel
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative text for 'h' as Hour in the timeline (z.B. Uhr)
      label: Translation 'h'
      name: wordingHour
      required: false
      type: TEXT
      groupName: wording
      advanced: true
  parameterGroups:
    - name: general
      label: General settings
    - name: wording
      label: Wording
timestamp: Jan 2, 2021, 11:43:54 AM
component: f7-card
config:
  class:
    - padding
  style:
    background-image: ='url(' + props.backgroundUrl + ')'
    background-size: cover
    background-repeat: no-repeat
    background-position: 100% 100%
    border-radius: 20px
    overflow: hidden
    -ms-user-select: none
    -moz-user-select: none
    -webkit-user-select: none
    user-select: none
    --weather-card-color: 255,255,255
    --weather-card-text-color: rgba(var(--weather-card-color),1)
slots:
  default:
    - component: f7-block
      config:
        class:
          - no-padding
          - no-margin
        style:
          background-color: rgba(255,255,255,.15)
          backdrop-filter: ='blur(' + props.backgroundBlur + 'px)'
          width: 100%
          height: 100%
          position: absolute
          top: 0
          left: 0
          border-radius: 20px
    - component: f7-row
      slots:
        default:
          - component: f7-col
            config:
              class: col-80
              style:
                z-index: 999
            slots:
              default:
                - component: Label
                  config:
                    text: "=items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localStationName'].state"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 26px
                      line-height: 32px
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                - component: Label
                  config:
                    text: =dayjs().format("DD. MMMM YYYY")
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 12px
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                - component: oh-image
                  config:
                    item: "=((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Icon'"
                    visible: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Icon'].state.toString() != 'NULL')"
                    class:
                      - align-content-center
                    style:
                      color: rgba(var(--weather-card-color),.9)
                      padding-top: 5px
                      padding-bottom: 5px
                      width: 100px
                      height: 100px
                - component: oh-image
                  config:
                    url: '/static/weather/unknown.png'
                    visible: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Icon'].state === 'NULL')"
                    class:
                      - align-content-center
                    style:
                      color: rgba(var(--weather-card-color),.9)
                      padding-top: 5px
                      padding-bottom: 5px
                      width: 100px
                      height: 100px
                - component: Label
                  config:
                    text: "=items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Condition'].state"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 16px
                      line-height: 21px
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
          - component: f7-col
            config:
              class: col-20
              style:
                z-index: 999
                text-align: center
                width: fit-content
                overflow: hidden
            slots:
              default:
                - component: Label
                  config:
                    text: "=(props.itemPrefix === undefined) ? Math.round(items.localCurrent_Temperature.state.split(' ')[0]*10)/10+'°' :  Math.round(items[props.itemPrefix + 'Current_Temperature'].state.split(' ')[0]*10)/10+'°'"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 58px
                      line-height: 58px
                      font-weight: 100
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                - component: Label
                  config:
                    text: "=(props.itemPrefix === undefined) ? 'gefühlt: ' + Math.round(items.localCurrent_Apparenttemperature.state.split(' ')[0]) +'°' :  ((props.wordingFeel === undefined) ? 'Feel: ' : props.wordingFeel + ': ') + Math.round(items[props.itemPrefix + 'Current_Apparenttemperature'].state.split(' ')[0]) +'°'"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 21px
                      font-weight: 100
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                - component: Label
                  config:
                    text: "=(props.itemPrefix === undefined) ? Math.round(items.localCurrent_Humidity.state.split(' ')[0])+'% ' :  Math.round(items[props.itemPrefix + 'Current_Humidity'].state.split(' ')[0]) + '% ' + Math.round(items[props.itemPrefix + 'Current_Windspeed'].state.split(' ')[0]) + 'km/h'"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 21px
                      font-weight: 100
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
    - component: f7-segmented
      config:
        strong: true
        textColor: white
        class: margin-top
        style:
          --f7-segmented-strong-button-active-box-shadow: 0px 4px 0px -1px white
          --f7-segmented-strong-button-active-text-color: rgba(var(--weather-card-color),1)
          --f7-button-text-color: rgba(var(--weather-card-color),.5)
          --f7-segmented-strong-text-color: rgba(var(--weather-card-color),.5)
          --f7-segmented-strong-padding: 3px
          --f7-button-active-text-color: rgba(var(--weather-card-color),1)
          --f7-button-raised-box-shadow: none
          --f7-segmented-strong-button-active-bg-color: transparent
          --f7-button-border-radius: 0
          border-bottom: 3px solid rgba(var(--weather-card-color),.5)
          background: transparent
          z-index: 999
      slots:
        default:
          - component: oh-button
            config:
              text: "=(props.wordingForecastHours === undefined) ? 'Hourly' : props.wordingForecastHours"
              color: var(--weather-card-text-color)
              active: =vars.tab === 'hourly_forecast'
              action: variable
              actionVariable: tab
              actionVariableValue: hourly_forecast
          - component: oh-button
            config:
              text: "=(props.wordingForecastHours === undefined) ? 'Daily' : props.wordingForecastDays"
              color: var(--weather-card-text-color)
              active: =vars.tab === 'daily_forecast'
              action: variable
              actionVariable: tab
              actionVariableValue: daily_forecast
          - component: oh-button
            config:
              text: "=(props.wordingForecastPrecib === undefined) ? 'Precipitation' : props.wordingForecastPrecib"
              color: var(--weather-card-text-color)
              active: =vars.tab === 'precip_forecast'
              action: variable
              actionVariable: tab
              actionVariableValue: precip_forecast
    - component: f7-swiper
      config:
        visible: =!vars.tab || vars.tab === 'hourly_forecast'
        navigation: true
        class:
          - padding-top
        params:
          initalSlide: 0
          runCallbacksOnInit: true
          grabCursor: true
          observer: true
          observeSlideChildren: true
          updateOnWindowResize: true
          spaceBetween: 5
          mousewheel: true
          keyboard: true
          watchOverflow: true
          breakpoints:
            "0":
              slidesPerView: 1
            "240":
              slidesPerView: 2
            "320":
              slidesPerView: 3
            "480":
              slidesPerView: 4
            "640":
              slidesPerView: 5
        style:
          --swiper-navigation-size: 30px
          --swiper-navigation-color: var(--weather-card-text-color)
      slots:
        default:
          - component: oh-repeater
            config:
              sourceType: range
              for: hour
              rangeStart: 0
              rangeStop: "=(props.forecastHours === undefined) ? 11 : Number(props.forecastHours)"
              fragment: true
            slots:
              default:
                - component: f7-swiper-slide
                  config:
                    id: =loop.hour_idx
                    expandable: true
                    style:
                      background: "=(props.sunIndicator === true) ? ((dayjs().add(loop.hour,'hour').format() >= items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').format() ? 'Today' : (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').add(1,'day').format() ? 'Tomorrow' : 'Day2')) + '_Sunrise'].state && dayjs().add(loop.hour,'hour').format() <= items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').format() ? 'Today' : (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').add(1,'day').format() ? 'Tomorrow' : 'Day2')) + '_Sunset'].state) ? 'rgba(44,130,201,.15)' : 'rgba(190,144,212,.15)') : 'none'"
                      border-radius: 5px
                  slots:
                    default:
                      - component: f7-row
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                        slots:
                          default:
                            - component: Label
                              config:
                                text: "=(loop.hour === 0) ? ((props.wordingNow === undefined) ? 'Now' : props.wordingNow) : ((props.dateFormat === false) ? dayjs().add(loop.hour,'hour').startOf('hour').format('h A') : dayjs().add(loop.hour,'hour').startOf('hour').format('HH') + ((props.wordingHour === undefined) ? ' h' : ' ' + props.wordingHour))"
                                style:
                                  color: var(--weather-card-text-color)
                                  font-size: 18px
                                  font-weight: 600
                      - component: f7-col
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                            - text-align-center
                        slots:
                          default:
                            - component: oh-image
                              config:
                                item: "=((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Icon'"
                                visible: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Icon'].state != 'NULL')"
                                style:
                                  padding-right: 5px
                                  color: var(--weather-card-text-color)
                                  width: 50px
                                  height: 50px
                            - component: oh-image
                              config:
                                url: '/static/weather/unknown.png'
                                visible: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Icon'].state === 'NULL')"
                                style:
                                  padding-right: 5px
                                  color: var(--weather-card-text-color)
                                  width: 50px
                                  height: 50px
                            - component: Label
                              config:
                                text: "=Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Temperature'].state.split(' ')[0]) + '° ' + Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Windspeed'].state.split(' ')[0]) + 'km/h'"
                                style:
                                  font-size: 18px
                                  font-weight: 400
                                  color: var(--weather-card-text-color)
    - component: f7-swiper
      config:
        visible: =vars.tab === 'daily_forecast'
        navigation: true
        class:
          - padding-top
        params:
          initalSlide: 0
          grabCursor: true
          observer: true
          spaceBetween: 1
          observeSlideChildren: true
          updateOnWindowResize: true
          watchOverflow: true
          mousewheel: true
          keyboard: true
          breakpoints:
            "0":
              slidesPerView: 1
            "210":
              slidesPerView: "=(props.forecastDays === undefined) ? 2 : ((props.forecastDays < 2) ? Math.round(Number(props.forecastDays) + 1) : 2)"
            "320":
              slidesPerView: "=(props.forecastDays === undefined) ? 3 : ((props.forecastDays < 3) ? Math.round(Number(props.forecastDays) + 1) : 3)"
            "480":
              slidesPerView: "=(props.forecastDays === undefined) ? 4 : ((props.forecastDays < 4) ? Math.round(Number(props.forecastDays) + 1) : 4)"
            "640":
              slidesPerView: "=(props.forecastDays === undefined) ? 5 : ((props.forecastDays < 5) ? Math.round(Number(props.forecastDays) + 1) : 5)"
        style:
          --swiper-navigation-size: 30px
          --swiper-navigation-color: var(--weather-card-text-color)
      slots:
        default:
          - component: oh-repeater
            config:
              sourceType: range
              for: day
              rangeStart: 0
              rangeStop: "=(props.forecastDays === undefined) ? 5 : Number(props.forecastDays)"
              fragment: true
            slots:
              default:
                - component: f7-swiper-slide
                  config:
                    class:
                      - text-align-center
                  slots:
                    default:
                      - component: f7-row
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                        slots:
                          default:
                            - component: Label
                              config:
                                text: "=(loop.day === 0) ? ((props.wordingToday === undefined) ? 'Today' : props.wordingToday) : dayjs().add(loop.day,'day').startOf('day').format('dddd')"
                                style:
                                  color: var(--weather-card-text-color)
                                  font-size: 18px
                                  font-weight: 600
                      - component: oh-image
                        config:
                          class:
                            - align-center
                          item: "=((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + ((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx)) + '_Icon'"
                          visible: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + ((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx)) + '_Icon'].state != 'NULL')"
                          style:
                            color: var(--weather-card-text-color)
                            width: 50px
                            height: 50px
                      - component: oh-image
                        config:
                          class:
                            - align-center
                          url: '/static/weather/unknown.png'
                          visible: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + ((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx)) + '_Icon'].state === 'NULL')"
                          style:
                            color: var(--weather-card-text-color)
                            width: 50px
                            height: 50px
                      - component: f7-row
                        config:
                          class:
                            - justify-content-center
                        slots:
                          default:
                            - component: Label
                              config:
                                text: "=Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + ((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + (loop.day_idx))) + '_Maxtemperature'].state.split(' ')[0]) +'°'"
                                style:
                                  font-size: 18px
                                  font-weight: 400
                                  color: var(--weather-card-text-color)
                            - component: Label
                              config:
                                text: /
                                style:
                                  color: rgba(var(--weather-card-color),.5)
                                  font-size: 18px
                            - component: Label
                              config:
                                text: "=Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + ((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + (loop.day_idx))) + '_Mintemperature'].state.split(' ')[0]) +'°'"
                                style:
                                  font-size: 18px
                                  font-weight: 400
                                  color: rgba(var(--weather-card-color),.75)
    - component: f7-swiper
      config:
        visible: =vars.tab === 'precip_forecast'
        navigation: true
        class:
          - padding-top
        params:
          initalSlide: 0
          runCallbacksOnInit: true
          grabCursor: true
          observer: true
          observeSlideChildren: true
          updateOnWindowResize: true
          spaceBetween: 5
          mousewheel: true
          keyboard: true
          watchOverflow: true
          breakpoints:
            "0":
              slidesPerView: 1
            "240":
              slidesPerView: 2
            "320":
              slidesPerView: 3
            "480":
              slidesPerView: 4
            "640":
              slidesPerView: 5
        style:
          --swiper-navigation-size: 30px
          --swiper-navigation-color: var(--weather-card-text-color)
      slots:
        default:
          - component: oh-repeater
            config:
              sourceType: range
              for: hour
              rangeStart: 0
              rangeStop: "=(props.forecastHours === undefined) ? 11 : Number(props.forecastHours)"
              fragment: true
            slots:
              default:
                - component: f7-swiper-slide
                  config:
                    id: =loop.hour_idx
                    expandable: true
                    style:
                      background: "=(props.sunIndicator === true) ? ((dayjs().add(loop.hour,'hour').format() >= items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').format() ? 'Today' : (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').add(1,'day').format() ? 'Tomorrow' : 'Day2')) + '_Sunrise'].state && dayjs().add(loop.hour,'hour').format() <= items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').format() ? 'Today' : (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').add(1,'day').format() ? 'Tomorrow' : 'Day2')) + '_Sunset'].state) ? 'rgba(44,130,201,.15)' : 'rgba(190,144,212,.15)') : 'none'"
                      border-radius: 5px
                  slots:
                    default:
                      - component: f7-row
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                        slots:
                          default:
                            - component: Label
                              config:
                                text: "=(loop.hour === 0) ? ((props.wordingNow === undefined) ? 'Now' : props.wordingNow) : ((props.dateFormat === false) ? dayjs().add(loop.hour,'hour').startOf('hour').format('h A') : dayjs().add(loop.hour,'hour').startOf('hour').format('HH') + ((props.wordingHour === undefined) ? ' h' : ' ' + props.wordingHour))"
                                style:
                                  color: var(--weather-card-text-color)
                                  font-size: 18px
                                  font-weight: 600
                      - component: f7-col
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                            - text-align-center
                        slots:
                          default:
                            - component: oh-image
                              config:
                                _f7: "=(Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0') + '_Precipprobability'].state.split(' ')[0] ) >= 50 ) ? 'umbrella_fill' : 'umbrella' "
                                url: "=(Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0') + '_Precipprobability'].state.split(' ')[0] ) >= 50 ) ? '/static/weather/rain.png' : '/static/weather/lightrain.png' "
                                style:
                                  padding-right: 5px
                                  color: var(--weather-card-text-color)
                                  width: 50px
                                  height: 50px
                            - component: Label
                              config:
                                text: "=Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0') + '_Precipprobability'].state.split(' ')[0] ) +'%'"
                                style:
                                  font-size: 18px
                                  font-weight: 400
                                  color: var(--weather-card-text-color)


For the “static” rain icon in the icon tab and for unknown weather icon i’ve created a folder “weather” inside the “html” folder where you can place a “rain.png, lightrain.png, unknown.png”

2 Likes

Here an enhanced version with settings tab to switch between local or internet data (only current temp and wind as my own station readings)

Enhanced Version
uid: weather_card
tags: []
props:
  parameters:
    - description: <b>Optional prefix</b> for item names.
      label: Item prefix
      name: itemPrefix
      required: false
      type: TEXT
      groupName: undefined
    - description: Optional Station name
      label: Station name
      name: station_name
      required: false
      type: TEXT
      groupName: location
      advanced: false
    - description: The number of hours you want to forecast <b>(<u>default:</u> 11)</b>
      label: Number of hours to forecast
      name: forecastHours
      required: false
      type: TEXT
      groupName: general
    - description: The number of days you want to forecast <b>(<u>default:</u> 5)</b>
      label: Number of days to forecast
      name: forecastDays
      required: false
      type: TEXT
      groupName: general
    - label: Background image-url
      name: backgroundUrl
      required: false
      type: TEXT
      groupName: general
    - description: Background blur
      label: Intensity of the background-blur (0 - 10)
      name: backgroundBlur
      required: false
      type: TEXT
      groupName: general
    - description: Acitvate 24-hour clock-format <b>(<u>default:</u> 12-hour clock-format)</b>
      label: 24h clock-format
      name: dateFormat
      required: false
      type: BOOLEAN
      groupName: general
    - description: Acitvate Sun-Indicator <b>(<u>default:</u> no)</b>
      label: Sun-Indicator
      name: sunIndicator
      required: false
      type: BOOLEAN
      groupName: general
    - description: Alternative title for 'Hourly' within the segmented control <b>(<u>default:</u> Hourly)</b>
      label: Alternative text for 'Hourly'
      name: wordingForecastHours
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative title for 'Daily' within the segmented control <b>(<u>default:</u> Daily)</b>
      label: Alternative text for 'Daily'
      name: wordingForecastDays
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative title for 'Precipitation' within the segmented control <b>(<u>default:</u> Daily)</b>
      label: Alternative text for 'Precipitation'
      name: wordingForecastPrecib
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative text for 'Now' in the hourly-forecast & precipitation-forecast tab
      label: Translation 'Now'
      name: wordingNow
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative text for 'Today' in the daily-forecast tab
      label: Translation 'Today'
      name: wordingToday
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative text for 'Feel' in the feel-temperature display
      label: Translation 'Feel'
      name: wordingFeel
      required: false
      type: TEXT
      groupName: wording
      advanced: true
    - description: Alternative text for 'h' as Hour in the timeline (z.B. Uhr)
      label: Translation 'h'
      name: wordingHour
      required: false
      type: TEXT
      groupName: wording
      advanced: true
  parameterGroups:
    - name: location
      label: Location
    - name: general
      label: General settings
    - name: wording
      label: Wording
timestamp: Jan 2, 2021, 4:35:38 PM
component: f7-card
config:
  class:
    - padding
  style:
    background-image: ='url(' + props.backgroundUrl + ')'
    background-size: cover
    background-repeat: no-repeat
    background-position: 100% 100%
    border-radius: 20px
    overflow: hidden
    -ms-user-select: none
    -moz-user-select: none
    -webkit-user-select: none
    user-select: none
    --weather-card-color: 255,255,255
    --weather-card-text-color: rgba(var(--weather-card-color),1)
slots:
  default:
    - component: f7-block
      config:
        class:
          - no-padding
          - no-margin
        style:
          background-color: rgba(255,255,255,.15)
          backdrop-filter: ='blur(' + props.backgroundBlur + 'px)'
          width: 100%
          height: 100%
          position: absolute
          top: 0
          left: 0
          border-radius: 20px
    - component: f7-row
      slots:
        default:
          - component: f7-col
            config:
              class: col-80
              style:
                z-index: 999
            slots:
              default:
                - component: Label
                  config:
                    text: "=(props.station_name === undefined) ? items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localStationName'].state : props.station_name"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 26px
                      line-height: 32px
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                - component: Label
                  config:
                    text: =dayjs().format("DD. MMMM YYYY")
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 12px
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                - component: oh-image
                  config:
                    item: "=((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Icon'"
                    visible: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Icon'].state.toString() != 'NULL')"
                    class:
                      - align-content-center
                    style:
                      color: rgba(var(--weather-card-color),.9)
                      padding-top: 5px
                      padding-bottom: 5px
                      width: 100px
                      height: 100px
                - component: oh-image
                  config:
                    url: /static/weather/unknown.png
                    visible: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Icon'].state === 'NULL')"
                    class:
                      - align-content-center
                    style:
                      color: rgba(var(--weather-card-color),.9)
                      padding-top: 5px
                      padding-bottom: 5px
                      width: 100px
                      height: 100px
                - component: Label
                  config:
                    text: "=items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Current_Condition'].state"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 16px
                      line-height: 21px
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
          - component: f7-col
            config:
              class: col-20
              style:
                z-index: 999
                text-align: center
                width: fit-content
                overflow: hidden
            slots:
              default:
                - component: Label
                  config:
                    text: "=(vars.loc_net === false || vars.loc_net === undefined) ? (Math.round(items.Wetterstation_Temp.state) + '°') :(props.itemPrefix === undefined) ? Math.round(items.localCurrent_Temperature.state.split(' ')[0]*10)/10+'°' :  Math.round(items[props.itemPrefix + 'Current_Temperature'].state.split(' ')[0]*10)/10+'°'"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 58px
                      line-height: 58px
                      font-weight: 100
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                - component: Label
                  config:
                    text: "=(vars.loc_net === false || vars.loc_net === undefined) ? (props.wordingFeel + ': ' + Math.round(13.12 + 0.6215 * items.Wetterstation_Temp.state + (0.3965 * items.Wetterstation_Temp.state - 11.37) * Math.pow(items.Wetterstation_Wind.state, 0.16)) + '°') : ((props.itemPrefix === undefined) ? 'gefühlt: ' + Math.round(items.localCurrent_Apparenttemperature.state.split(' ')[0]) +'°' :  ((props.wordingFeel === undefined) ? 'Feel: ' : props.wordingFeel + ': ') + Math.round(items[props.itemPrefix + 'Current_Apparenttemperature'].state.split(' ')[0]) +'°')"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 21px
                      font-weight: 100
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                - component: Label
                  config:
                    text: "=(vars.loc_net === false || vars.loc_net === undefined) ? ((props.itemPrefix === undefined) ? Math.round(items.localCurrent_Humidity.state.split(' ')[0])+'% ' :  Math.round(items[props.itemPrefix + 'Current_Humidity'].state.split(' ')[0]) + '% ' + Math.round(items.Wetterstation_Wind.state) + 'km/h') : (props.itemPrefix === undefined) ? Math.round(items.localCurrent_Humidity.state.split(' ')[0])+'% ' :  Math.round(items[props.itemPrefix + 'Current_Humidity'].state.split(' ')[0]) + '% ' + Math.round(items[props.itemPrefix + 'Current_Windspeed'].state.split(' ')[0]) + 'km/h'"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 21px
                      font-weight: 100
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
                - component: Label
                  config:
                    text: "=(vars.loc_net === false || vars.loc_net === undefined) ? 'Lokal' : 'Internet'"
                    style:
                      color: var(--weather-card-text-color)
                      font-size: 10px
                      font-weight: 100
                      text-shadow: -1px 1px 1px hsl(0,0%,66%)
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: ellipsis
    - component: f7-segmented
      config:
        strong: true
        textColor: white
        class: margin-top
        style:
          --f7-segmented-strong-button-active-box-shadow: 0px 4px 0px -1px white
          --f7-segmented-strong-button-active-text-color: rgba(var(--weather-card-color),1)
          --f7-button-text-color: rgba(var(--weather-card-color),.5)
          --f7-segmented-strong-text-color: rgba(var(--weather-card-color),.5)
          --f7-segmented-strong-padding: 3px
          --f7-button-active-text-color: rgba(var(--weather-card-color),1)
          --f7-button-raised-box-shadow: none
          --f7-segmented-strong-button-active-bg-color: transparent
          --f7-button-border-radius: 0
          border-bottom: 3px solid rgba(var(--weather-card-color),.5)
          background: transparent
          z-index: 999
      slots:
        default:
          - component: oh-button
            config:
              text: "=(props.wordingForecastHours === undefined) ? 'Hourly' : props.wordingForecastHours"
              color: var(--weather-card-text-color)
              active: =vars.tab === 'hourly_forecast'
              action: variable
              actionVariable: tab
              actionVariableValue: hourly_forecast
          - component: oh-button
            config:
              text: "=(props.wordingForecastHours === undefined) ? 'Daily' : props.wordingForecastDays"
              color: var(--weather-card-text-color)
              active: =vars.tab === 'daily_forecast'
              action: variable
              actionVariable: tab
              actionVariableValue: daily_forecast
          - component: oh-button
            config:
              text: "=(props.wordingForecastPrecib === undefined) ? 'Precipitation' : props.wordingForecastPrecib"
              color: var(--weather-card-text-color)
              active: =vars.tab === 'precip_forecast'
              action: variable
              actionVariable: tab
              actionVariableValue: precip_forecast
          - component: oh-button
            config:
              iconF7: gear_alt
              iconSize: 20px
              color: var(--weather-card-text-color)
              active: =vars.tab === 'settings'
              action: variable
              actionVariable: tab
              actionVariableValue: settings
    - component: f7-swiper
      config:
        visible: =!vars.tab || vars.tab === 'hourly_forecast'
        navigation: true
        class:
          - padding-top
        params:
          initalSlide: 0
          runCallbacksOnInit: true
          grabCursor: true
          observer: true
          observeSlideChildren: true
          updateOnWindowResize: true
          spaceBetween: 5
          mousewheel: true
          keyboard: true
          watchOverflow: true
          breakpoints:
            "0":
              slidesPerView: 1
            "240":
              slidesPerView: 2
            "320":
              slidesPerView: 3
            "480":
              slidesPerView: 4
            "640":
              slidesPerView: 5
        style:
          --swiper-navigation-size: 30px
          --swiper-navigation-color: var(--weather-card-text-color)
      slots:
        default:
          - component: oh-repeater
            config:
              sourceType: range
              for: hour
              rangeStart: 0
              rangeStop: "=(props.forecastHours === undefined) ? 11 : Number(props.forecastHours)"
              fragment: true
            slots:
              default:
                - component: f7-swiper-slide
                  config:
                    id: =loop.hour_idx
                    expandable: true
                    style:
                      background: "=(props.sunIndicator === true) ? ((dayjs().add(loop.hour,'hour').format() >= items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').format() ? 'Today' : (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').add(1,'day').format() ? 'Tomorrow' : 'Day2')) + '_Sunrise'].state && dayjs().add(loop.hour,'hour').format() <= items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').format() ? 'Today' : (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').add(1,'day').format() ? 'Tomorrow' : 'Day2')) + '_Sunset'].state) ? 'rgba(44,130,201,.15)' : 'rgba(190,144,212,.15)') : 'none'"
                      border-radius: 5px
                  slots:
                    default:
                      - component: f7-row
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                        slots:
                          default:
                            - component: Label
                              config:
                                text: "=(loop.hour === 0) ? ((props.wordingNow === undefined) ? 'Now' : props.wordingNow) : ((props.dateFormat === false) ? dayjs().add(loop.hour,'hour').startOf('hour').format('h A') : dayjs().add(loop.hour,'hour').startOf('hour').format('HH') + ((props.wordingHour === undefined) ? ' h' : ' ' + props.wordingHour))"
                                style:
                                  color: var(--weather-card-text-color)
                                  font-size: 18px
                                  font-weight: 600
                      - component: f7-col
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                            - text-align-center
                        slots:
                          default:
                            - component: oh-image
                              config:
                                item: "=((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Icon'"
                                visible: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Icon'].state != 'NULL')"
                                style:
                                  padding-right: 5px
                                  color: var(--weather-card-text-color)
                                  width: 50px
                                  height: 50px
                            - component: oh-image
                              config:
                                url: /static/weather/unknown.png
                                visible: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Icon'].state === 'NULL')"
                                style:
                                  padding-right: 5px
                                  color: var(--weather-card-text-color)
                                  width: 50px
                                  height: 50px
                            - component: Label
                              config:
                                text: "=Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Temperature'].state.split(' ')[0]) + '° ' + Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + '' + ((loop.hour === 0) ? 'Current' : 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0')) + '_Windspeed'].state.split(' ')[0]) + 'km/h'"
                                style:
                                  font-size: 18px
                                  font-weight: 400
                                  color: var(--weather-card-text-color)
    - component: f7-swiper
      config:
        visible: =vars.tab === 'daily_forecast'
        navigation: true
        class:
          - padding-top
        params:
          initalSlide: 0
          grabCursor: true
          observer: true
          spaceBetween: 1
          observeSlideChildren: true
          updateOnWindowResize: true
          watchOverflow: true
          mousewheel: true
          keyboard: true
          breakpoints:
            "0":
              slidesPerView: 1
            "210":
              slidesPerView: "=(props.forecastDays === undefined) ? 2 : ((props.forecastDays < 2) ? Math.round(Number(props.forecastDays) + 1) : 2)"
            "320":
              slidesPerView: "=(props.forecastDays === undefined) ? 3 : ((props.forecastDays < 3) ? Math.round(Number(props.forecastDays) + 1) : 3)"
            "480":
              slidesPerView: "=(props.forecastDays === undefined) ? 4 : ((props.forecastDays < 4) ? Math.round(Number(props.forecastDays) + 1) : 4)"
            "640":
              slidesPerView: "=(props.forecastDays === undefined) ? 5 : ((props.forecastDays < 5) ? Math.round(Number(props.forecastDays) + 1) : 5)"
        style:
          --swiper-navigation-size: 30px
          --swiper-navigation-color: var(--weather-card-text-color)
      slots:
        default:
          - component: oh-repeater
            config:
              sourceType: range
              for: day
              rangeStart: 0
              rangeStop: "=(props.forecastDays === undefined) ? 5 : Number(props.forecastDays)"
              fragment: true
            slots:
              default:
                - component: f7-swiper-slide
                  config:
                    class:
                      - text-align-center
                  slots:
                    default:
                      - component: f7-row
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                        slots:
                          default:
                            - component: Label
                              config:
                                text: "=(loop.day === 0) ? ((props.wordingToday === undefined) ? 'Today' : props.wordingToday) : dayjs().add(loop.day,'day').startOf('day').format('dddd')"
                                style:
                                  color: var(--weather-card-text-color)
                                  font-size: 18px
                                  font-weight: 600
                      - component: oh-image
                        config:
                          class:
                            - align-center
                          item: "=((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + ((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx)) + '_Icon'"
                          visible: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + ((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx)) + '_Icon'].state != 'NULL')"
                          style:
                            color: var(--weather-card-text-color)
                            width: 50px
                            height: 50px
                      - component: oh-image
                        config:
                          class:
                            - align-center
                          url: /static/weather/unknown.png
                          visible: "=(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + ((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + loop.day_idx)) + '_Icon'].state === 'NULL')"
                          style:
                            color: var(--weather-card-text-color)
                            width: 50px
                            height: 50px
                      - component: f7-row
                        config:
                          class:
                            - justify-content-center
                        slots:
                          default:
                            - component: Label
                              config:
                                text: "=Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + ((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + (loop.day_idx))) + '_Maxtemperature'].state.split(' ')[0]) +'°'"
                                style:
                                  font-size: 18px
                                  font-weight: 400
                                  color: var(--weather-card-text-color)
                            - component: Label
                              config:
                                text: /
                                style:
                                  color: rgba(var(--weather-card-color),.5)
                                  font-size: 18px
                            - component: Label
                              config:
                                text: "=Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + ((loop.day === 0) ? 'Today' : ((loop.day === 1) ? 'Tomorrow' : 'Day' + (loop.day_idx))) + '_Mintemperature'].state.split(' ')[0]) +'°'"
                                style:
                                  font-size: 18px
                                  font-weight: 400
                                  color: rgba(var(--weather-card-color),.75)
    - component: f7-swiper
      config:
        visible: =vars.tab === 'precip_forecast'
        navigation: true
        class:
          - padding-top
        params:
          initalSlide: 0
          runCallbacksOnInit: true
          grabCursor: true
          observer: true
          observeSlideChildren: true
          updateOnWindowResize: true
          spaceBetween: 5
          mousewheel: true
          keyboard: true
          watchOverflow: true
          breakpoints:
            "0":
              slidesPerView: 1
            "240":
              slidesPerView: 2
            "320":
              slidesPerView: 3
            "480":
              slidesPerView: 4
            "640":
              slidesPerView: 5
        style:
          --swiper-navigation-size: 30px
          --swiper-navigation-color: var(--weather-card-text-color)
      slots:
        default:
          - component: oh-repeater
            config:
              sourceType: range
              for: hour
              rangeStart: 0
              rangeStop: "=(props.forecastHours === undefined) ? 11 : Number(props.forecastHours)"
              fragment: true
            slots:
              default:
                - component: f7-swiper-slide
                  config:
                    id: =loop.hour_idx
                    expandable: true
                    style:
                      background: "=(props.sunIndicator === true) ? ((dayjs().add(loop.hour,'hour').format() >= items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').format() ? 'Today' : (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').add(1,'day').format() ? 'Tomorrow' : 'Day2')) + '_Sunrise'].state && dayjs().add(loop.hour,'hour').format() <= items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'Forecast' + (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').format() ? 'Today' : (dayjs().add(loop.hour,'hour').startOf('day').format() === dayjs().startOf('day').add(1,'day').format() ? 'Tomorrow' : 'Day2')) + '_Sunset'].state) ? 'rgba(44,130,201,.15)' : 'rgba(190,144,212,.15)') : 'none'"
                      border-radius: 5px
                  slots:
                    default:
                      - component: f7-row
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                        slots:
                          default:
                            - component: Label
                              config:
                                text: "=(loop.hour === 0) ? ((props.wordingNow === undefined) ? 'Now' : props.wordingNow) : ((props.dateFormat === false) ? dayjs().add(loop.hour,'hour').startOf('hour').format('h A') : dayjs().add(loop.hour,'hour').startOf('hour').format('HH') + ((props.wordingHour === undefined) ? ' h' : ' ' + props.wordingHour))"
                                style:
                                  color: var(--weather-card-text-color)
                                  font-size: 18px
                                  font-weight: 600
                      - component: f7-col
                        config:
                          class:
                            - justify-content-center
                            - align-items-center
                            - text-align-center
                        slots:
                          default:
                            - component: oh-image
                              config:
                                _f7: "=(Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0') + '_Precipprobability'].state.split(' ')[0] ) >= 50 ) ? 'umbrella_fill' : 'umbrella' "
                                url: "=(Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0') + '_Precipprobability'].state.split(' ')[0] ) >= 50 ) ? '/static/weather/rain.png' : '/static/weather/lightrain.png' "
                                style:
                                  padding-right: 5px
                                  color: var(--weather-card-text-color)
                                  width: 50px
                                  height: 50px
                            - component: Label
                              config:
                                text: "=Math.round(items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'ForecastHours' + (loop.hour_idx+1).toString().padStart(2,'0') + '_Precipprobability'].state.split(' ')[0] ) +'%'"
                                style:
                                  font-size: 18px
                                  font-weight: 400
                                  color: var(--weather-card-text-color)
    - component: f7-swiper
      config:
        visible: =vars.tab === 'settings'
        navigation: true
        class:
          - padding-top
        params:
          initalSlide: 0
          runCallbacksOnInit: true
          grabCursor: true
          observer: true
          observeSlideChildren: true
          updateOnWindowResize: true
          spaceBetween: 5
          mousewheel: true
          keyboard: true
          watchOverflow: true
          breakpoints:
            "0":
              slidesPerView: 1
            "240":
              slidesPerView: 2
            "320":
              slidesPerView: 3
            "480":
              slidesPerView: 4
            "640":
              slidesPerView: 5
        style:
          --swiper-navigation-size: 30px
          --swiper-navigation-color: var(--weather-card-text-color)
      slots:
        default:
          - component: f7-swiper-slide
            config:
              expandable: true
            slots:
              default:
                - component: f7-row
                  config:
                    class:
                      - justify-content-center
                      - align-items-center
                  slots:
                    default:
                      - component: Label
                        config:
                          text: Datenquelle
                          style:
                            color: var(--weather-card-text-color)
                            font-size: 18px
                            font-weight: 600
                - component: f7-col
                  config:
                    class:
                      - justify-content-center
                      - align-items-center
                      - text-align-center
                  slots:
                    default:
                      - component: f7-col
                        slots:
                          default:
                            - component: f7-row
                              slots:
                                default:
                                  - component: f7-col
                                    config:
                                      outline: true
                                      style:
                                        width: "50"
                                    slots:
                                      default:
                                        - component: oh-toggle
                                          config:
                                            variable: loc_net
                                            style:
                                              margin-top: 10px
                                          slots: {}
                                        - component: Label
                                          config:
                                            text: "=(vars.loc_net === true) ? 'Internet' : 'Lokal'"
                                            textColor: white
                                            style:
                                              margin-top: 10px
                                              font-size: 18px
                                              font-weight: 400
                                              color: var(--weather-card-text-color)

Maybe if someone is searching for Windchill calculation (in km/h and °C): Here you go:

Math.round(13.12 + 0.6215 * Temp + (0.3965 * Temp- 11.37) * Math.pow(Wind, 0.16))
1 Like

Amazing work!

Just try to use the OneCall version with the standard item imported exactly as posted (only adjusting the channel info); API is working I able to see the values for each item.

The Issue is with the Widget, most part of the information is shown correct, the only problem with precipitation items, see image:

Any clue why the precipitation appear as undefined?

Let me know if you need any additional information.

Thanks in advance.

BR

Hey @Joselh

thanks for giving the widget a try!

Could you please have a look into the UI item configuration of one of the ForecastHour-items http://YOURIP:8080/#!/settings/items/localForecastHour2PrecipProb and check if you get a valid item-state there? And if yes, which value is shown there?

I also recognized that your station name in the top-right is ‘NULL’ - is this for demo purposes? Normaly it should show the name of the city, where your weather-station is located. But this information isn’t available in the OneCall API.

Do you created all things that I mentioned above? Including this one:
Thing weather-and-forecast local "Local Weather And Forecast" [location="YOURLOCATION", forecastDays=4]

If yes, what is the item-state of localStationName

Many thanks Rainer!

Station Name works Perfect!

Regarding precipitation, here is the item requested:

As you can see, it’s defined with the current value to 0.0%

Thanks in advance for your support.

BR
Jose

No problemo and thanks for the hint. It seems, that something is messed up in my setup due to the frequent updates from earlier versions I did. As an easy fix you could do the following:

Search for the line:

text: "=items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localForecastHour' + Math.round(loop.hour_idx+1) + 'PrecipProb'].displayState + '%'"

and replace it with:

text: "=items[((props.itemPrefix === undefined) ? '' : props.itemPrefix) + 'localForecastHour' + Math.round(loop.hour_idx+1) + 'PrecipProb'].state"

It slightly changes the format of the output, which shouldn’t bother too much, I hope.

And if you’re willed to help me one more time, it would be awesome if you could create a custom widget with this content and making me a screenshot with the output?! Thanks in advance!

Further more it would nice to know, if you used the UI to create the items or if you used textfiles?

uid: test
component: f7-card
config:
  content: "='State: ' + items.localForecastHour2PrecipProb.state + ' | displayState: ' + items.localForecastHour2PrecipProb.displayState"

Thank you very much!

Many Thanks Raimer,

your proposed Fix is working without any issue, precipitation is showed correctly!!

Items were created from textual definition, too many items to do it by hand.

Here you have the requested Screenshot:

image

Many thanks for your support!! let me know if you need any additional test from my side.

Thanks for your great widget

Happy New Year

BR

Jose

1 Like

Hii folks

any ideas on how we can create a line chart with the forecast temperatures? I am not sure, but the chart pages in OH3 might not suppor this. What i am thinking about is a line chart plotting all the forecast temperatures at a given instant in time vs. plotting historical values of an item against a time series (which i know is possible).

something like the line graph in salexes’ post