Temperature Gauge Widget [3.1.0.0;5.0.0.0)

Temperature SS5

A temperature gauge that can optionally show felt temperature, a corresponding set point/thermostat value and humidity, with a “classic” style.

It has many configuration options and can be linked to up to 4 Items, although it wouldn’t make sense to use all 4 in the same widget. Most colors can be changed, and there are optional “extras” like an LCD, a relative humidity gauge and the set point value shown in “the frame”.

Screenshots

Temperature SS1
Temperature SS2
Temperature SS3
Temperature SS4

Changelog

Version 0.1

  • initial release

Resources

uid: temperature_gauge
tags:
  - gauge
  - temperature
props:
  parameters:
    - description: The title text
      label: Title
      name: title
      required: false
      type: TEXT
    - context: item
      description: The temperature Item
      label: Temperature Item
      name: item
      required: true
      type: TEXT
    - default: "15"
      description: The minimum temperature value to show
      label: Min Temperature
      name: min
      required: false
      type: TEXT
    - default: "30"
      description: The maximum temperature value to show
      label: Max Temperature
      name: max
      required: false
      type: TEXT
    - default: "5"
      description: The number of splits
      label: Splits
      name: splits
      required: false
      type: INTEGER
      min: 1
      max: 20
    - default: "3"
      description: The number of ticks between each split
      label: Ticks
      name: ticks
      required: false
      type: INTEGER
      min: 1
      max: 20
    - description: The threshold under which it is colored blue
      label: Cold Threshold
      name: coldThreshold
      required: false
      type: TEXT
    - description: The threshold over which it is colored red
      label: Warm Threshold
      name: warmThreshold
      required: false
      type: TEXT
    - default: "#e64a19"
      description: The needle color
      label: Needle Color
      name: needleColor
      required: false
      type: TEXT
    - default: "#ddd"
      description: The gauge frame color
      label: Frame Color
      name: frameColor
      required: false
      type: TEXT
    - default: transparent
      description: The dial color
      label: Dial Color
      name: dialColor
      required: false
      type: TEXT
    - default: "#464646"
      description: The dial print color
      label: Print Color
      name: printColor
      required: false
      type: TEXT
    - default: transparent
      description: The shadow color, e.g. "black" or "#0008"
      label: Shadow Color
      name: shadowColor
      required: false
      type: TEXT
      advanced: true
    - default: "10"
      description: The blur value for the dial shadow (no effect if the dial is transparent)
      label: Shadow Blur
      name: shadowBlur
      required: false
      type: INTEGER
      advanced: true
    - default: "3"
      description: The offset value for the dial shadow (no effect if the dial is
        transparent)
      label: Shadow Offset
      name: shadowOffset
      required: false
      type: INTEGER
      advanced: true
    - default: "15"
      description: The axis font size
      label: AxisFontSize
      name: axisFontSize
      required: false
      type: INTEGER
      min: 6
      max: 50
      advanced: true
    - context: item
      description: The felt temperature Item
      label: Felt Temperature Item
      name: feltItem
      required: true
      type: TEXT
    - default: "#e3c010"
      description: The felt temperature needle color
      label: Felt Temp Needle Color
      name: feltNeedleColor
      required: false
      type: TEXT
    - context: item
      description: The setpoint Item if applicable
      label: Setpoint Item
      name: setPointItem
      required: false
      type: TEXT
    - default: "#ff8800cc"
      description: The setpoint indicator color
      label: Setpoint Color
      name: setPointColor
      required: false
      type: TEXT
    - default: none
      label: Extras
      name: extras
      required: false
      type: TEXT
      limitToOptions: true
      options:
        - label: None
          value: none
        - label: LCD
          value: lcd
        - label: Humidity
          value: humidity
    - context: item
      description: The relative humidity Item
      label: Relative Humidity Item
      name: rhItem
      required: false
      type: TEXT
    - default: "%"
      description: The name to show for relative humidity
      label: Relative Humidity Name
      name: rhName
      required: false
      type: TEXT
    - description: The height of widget
      label: Height
      name: height
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Dec 29, 2024, 9:37:38 PM
component: oh-chart
config:
  height: =props.height
slots:
  series:
    - component: oh-data-series
      config:
        emptyCircleStyle:
          color: =props.dialColor
          shadowBlur: =props.shadowBlur
          shadowColor: =props.shadowColor
          shadowOffsetX: =props.shadowOffset
          shadowOffsetY: =props.shadowOffset
        radius: 85%
        type: pie
    - component: oh-data-series
      config:
        anchor:
          itemStyle:
            color: "#000"
          show: true
          size: 20
        axisLabel:
          show: false
        axisLine:
          lineStyle:
            color:
              - - 1
                - =props.frameColor
            shadowBlur: 6
            shadowColor: "#0008"
            width: 6
        axisTick:
          show: false
        detail:
          show: false
        endAngle: -270
        pointer:
          show: false
        radius: 85%
        splitLine:
          show: false
        startAngle: 90
        title:
          show: false
        type: gauge
    - component: oh-data-series
      config:
        anchor:
          itemStyle:
            color: "#333"
          show: true
          size: 20
        axisLabel:
          show: false
        axisLine:
          show: false
        axisTick:
          show: false
        data:
          - value: =Number.parseFloat(items[props.setPointItem].state)
            itemStyle:
              color: =props.setPointColor
        detail:
          show: false
        max: =Number.parseFloat(props.max)
        min: =Number.parseFloat(props.min)
        pointer:
          show: false
        progress:
          itemStyle:
            color: =props.setPointColor
            shadowBlur: 2
          roundCap: false
          show: true
          width: 8
        radius: 85%
        splitLine:
          show: false
        title:
          show: false
        tooltip:
          valueFormatter: "=v=>v.toFixed(1)+(items[props.setPointItem].state.split(' ').length > 1 ? items[props.setPointItem].state.split(' ')[1] : '')"
        type: gauge
    - component: oh-data-series
      config:
        anchor:
          show: false
        axisLabel:
          show: false
        axisLine:
          show: false
        axisTick:
          show: false
        data:
          - name: =props.title
            value: =Number.parseFloat(items[props.feltItem].state)
            itemStyle:
              color: =props.feltNeedleColor
        detail:
          show: false
        max: =Number.parseFloat(props.max)
        min: =Number.parseFloat(props.min)
        pointer:
          show: =props.feltItem
          icon: path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999
            2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929
            C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078
            C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014
            L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423
            2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314
            2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028
            2089.24407,615.30999 2090.36389,615.30999 Z
          itemStyle:
            color: =props.feltNeedleColor
            shadowBlur: 2
            shadowColor: "#000a"
            shadowOffsetX: 2
            shadowOffsetY: 2
          keepAspect: false
          length: 95%
          offsetCenter:
            - 0
            - 10%
        radius: 73%
        splitLine:
          show: false
        title:
          offsetCenter:
            - 0
            - -35%
          color: =props.printColor
        tooltip:
          formatter: "=p=>'<b>'+p.value.toFixed(1)+(items[props.feltItem].state.split(' ').length > 1 ? items[props.feltItem].state.split(' ')[1] : '')+'</b>'"
        type: gauge
    - component: oh-data-series
      config:
        anchor:
          itemStyle:
            color: =props.needleColor
            shadowBlur: 0
          show: true
          showAbove: true
          size: 16
        axisLabel:
          distance: 18
          fontSize: =props.axisFontSize
          color: =props.printColor
        axisLine:
          lineStyle:
            color:
              - - =(Number.parseFloat(props.coldThreshold) -
                  props.min)/(props.max - props.min)
                - "#58D9F933"
              - - =(Number.parseFloat(props.warmThreshold) -
                  props.min)/(props.max - props.min)
                - "#7CFF8200"
              - - 1
                - "#FF6E7633"
            width: 15
        axisTick:
          distance: -15
          length: 10
          splitNumber: =props.ticks
          lineStyle:
            color: =props.printColor
        data:
          - name: =props.title
            value: =Number.parseFloat(items[props.item].state)
            itemStyle:
              color: =props.needleColor
        detail:
          show: =props.extras=="lcd"?true:false
          backgroundColor: rgb(137,150,96)
          borderColor: "#000"
          borderWidth: 1
          color: "#000"
          fontFamily: Courier New
          fontSize: 1em
          fontWeight: 600
          formatter: "=v=>v.toFixed(1)+(items[props.item].state.split(' ').length > 1 ? items[props.item].state.split(' ')[1] : '')"
          offsetCenter:
            - 0
            - 40%
          padding:
            - 0
            - 2
            - 0
            - 2
          valueAnimation: true
          width: 50%
        max: =Number.parseFloat(props.max)
        min: =Number.parseFloat(props.min)
        pointer:
          icon: path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999
            2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929
            C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078
            C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014
            L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423
            2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314
            2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028
            2089.24407,615.30999 2090.36389,615.30999 Z
          itemStyle:
            color: =props.needleColor
            shadowBlur: 2
            shadowColor: "#000a"
            shadowOffsetX: 2
            shadowOffsetY: 2
          keepAspect: false
          length: 105%
          offsetCenter:
            - 0
            - 10%
        radius: 73%
        splitLine:
          distance: -15
          length: 20
          lineStyle:
            color: =props.printColor
        splitNumber: =props.splits
        title:
          show: false
        tooltip:
          formatter: "=props.title ? p=>props.title+':
            <b>'+p.value.toFixed(1)+(items[props.item].state.split(' ').length > 1 ? items[props.item].state.split(' ')[1] : '')+'</b>'
            : NULL"
          valueFormatter: "=v=>v.toFixed(1)+(items[props.item].state.split(' ').length > 1 ? items[props.item].state.split(' ')[1] : '')"
        type: gauge
    - component: oh-data-series
      config:
        anchor:
          show: =props.extras=="humidity"?true:false
          itemStyle:
            color: "#000"
          size: 11
        axisLabel:
          show: false
        axisLine:
          show: false
        axisTick:
          show: false
        detail:
          show: false
        pointer:
          show: false
        splitLine:
          show: false
        title:
          show: false
        radius: 30%
        center:
          - 50%
          - 68%
        type: gauge
    - component: oh-data-series
      config:
        startAngle: 215
        endAngle: 325
        clockwise: false
        center:
          - 50%
          - 68%
        radius: 30%
        anchor:
          itemStyle:
            color: =props.needleColor
            shadowBlur: 0
          show: =props.extras=="humidity"?true:false
          showAbove: true
          size: 9
        axisLabel:
          show: =props.extras=="humidity"?true:false
          distance: -12
          fontSize: 8
          color: =props.printColor
        axisLine:
          show: =props.extras=="humidity"?true:false
          lineStyle:
            color:
              - - 0.1
                - "#a1a6d633"
              - - 0.2
                - "#a1a6d644"
              - - 0.3
                - "#a1a6d655"
              - - 0.4
                - "#a1a6d666"
              - - 0.5
                - "#a1a6d677"
              - - 0.6
                - "#a1a6d688"
              - - 0.7
                - "#a1a6d699"
              - - 0.8
                - "#a1a6d6aa"
              - - 0.9
                - "#a1a6d6bb"
              - - 1
                - "#a1a6d6cc"
            width: 10
        axisTick:
          show: =props.extras=="humidity"?true:false
          distance: -10
          length: 6
          splitNumber: 4
          lineStyle:
            color: =props.printColor
        splitLine:
          show: =props.extras=="humidity"?true:false
          distance: -10
          length: 10
          lineStyle:
            color: =props.printColor
            width: 2
        data:
          - name: =props.rhName
            value: =Number.parseFloat(items[props.rhItem].state)
            itemStyle:
              color: "#a1a6d6"
        detail:
          show: false
        max: 100
        min: 20
        pointer:
          show: =props.extras=="humidity"?true:false
          icon: path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999
            2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929
            C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078
            C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014
            L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423
            2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314
            2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028
            2089.24407,615.30999 2090.36389,615.30999 Z
          itemStyle:
            color: =props.needleColor
            shadowBlur: 2
            shadowColor: "#000a"
            shadowOffsetX: 1
            shadowOffsetY: 1
          keepAspect: false
          length: 95%
          width: 8%
          offsetCenter:
            - 0
            - 20%
        splitNumber: 4
        title:
          show: =props.extras=="humidity"?true:false
          fontSize: 9
          offsetCenter:
            - 0
            - 45%
          color: =props.printColor
        tooltip:
          formatter: =p=>'<b>'+p.value.toFixed(0)+'%</b>'
        type: gauge
  tooltip:
    - component: oh-chart-tooltip
      config:
        show: true
6 Likes

Good widget.
Question:
If I add 300 to the widget height the widget disappears. It only works if the height is blank.
Also if I set LCD I get undefined instead of numbers. Does the LCD have to have units?

I just set it up as a test for my water tank instead of temperature.
Screenshot from 2024-12-30 09-03-34

Here is the LCD undefined:
Screenshot from 2024-12-30 09-04-44

I am sure I can use this for many other things.
Good work. I have been looking for something like this for ages.
I wish gauges like this were standard openHab widgets.

What I am looking for is something like this for water tank:

The behavior of the height field is a mystery to me as well. But, it doesn’t disappear for me if I put 300 there. Maybe it works better with a unit, e.g. 300px or 300%. I think it depends on the layout. The reason I include the “height” field is that these widgets don’t scale very well, so it can sometimes, depending on the layout in use, help to “force” it somewhat.

The LCD expects an Item with units, yes. It might be possible to make the logic smarter so that it will also handle Items without a unit, but hacking these “widget expressions” really isn’t my strong side - they never seem to behave like I think they will. It’s one big mix of YAML, Java and JavaScript syntax, which certainly is enough to confuse me. You can easily modify the widget to not use the unit if you make a copy of it and edit it though: Just find the “formatter” (the correct one, there are multiple) and remote the items[props.itemName].state.split(' ')[1] parts - as that’s what fetches the unit.

By copying the widget and editing the YAML, you can tweak it to do many things. Some things are easy, some are hard, but things like changing fonts size and position of labels generally isn’t too hard to figure out. You can see the changes as you make them in the widget editor, which helps.

That’s not hard to do with the ECharts components I’ve used. If you look at the wind gauge, you can see that it already has different colors defined for the “outer scale”. The colors are set as fractions, so you can define which color should be between 0 and 0.15, which should be between 0.15 and 0.25 and generally however you like. If you copy and customize the wind widget, you can basically delete most of the code and end up with something quite similar to what you want. But, getting it all the way (like making the needle like you want it) does require some knowledge of the ECharts.

Thanks. I will look at it later when I have some time to spend on it.
It is a good widget.
Keep putting them out there.

I’ve edited the widget so that it should now also handle Items without unit. It must probably be deleted and “installed” again to get the updated version.