Raffstore / Blinds control with slat angle

A simple list-item widget (for use in location-pages) which enables control of a raffstore including slat-angle controls selectable via buttons.

Changelog

Version 1.0

  • initial release

Usage

To make this widget work, you will need the following item structure

  • X_Raffstore: Rollershutter item used as the main control; must accept UP, DOWN, STOP, and 0–100 percent commands and report a numeric position state.
  • X_Raffstore_Position: Number item providing position feedback in the 0–100 range; used only for displaying the percentage text (shows if missing or NULL).
  • X_Raffstore_TargetSlat: Number item that receives slat target commands 0, 25, 50, 75, and 100 (mapped to discrete slat angles from fully open to fully closed); must be handled by rules or a binding.
  • X_Raffstore_Slat: Number item reporting the current slat position in the 0–100 range; the widget rounds this to the nearest 25 to highlight the active angle button.
  • Naming constraint: props.item must end in _Raffstore; all other items are derived from this base name and must exist with exactly these suffixes for full functionality.

Resources

Version 1.0

YAML Code
uid: raffstore_controller_v7
tags: []
props:
  parameters:
    - label: Title
      name: title
      required: false
      type: TEXT
    - description: Proxy rollershutter item, e.g. <RoomName>_Raffstore
      label: Raffstore Proxy Item
      name: item
      required: true
      type: TEXT
      context: item
timestamp: Dec 22, 2025, 11:39:36 AM
component: f7-list-item
config:
  class: media-item
slots:
  default:
    - component: oh-rollershutter-item
      config:
        after: "=(items[props.item.replace('_Raffstore','') + '_Raffstore_Position'] &&
          items[props.item.replace('_Raffstore','') +
          '_Raffstore_Position'].state !== null) ? ('' +
          items[props.item.replace('_Raffstore','') +
          '_Raffstore_Position'].state + '%') : '—'"
        icon: blinds
        iconUseState: true
        item: =props.item
        stylesheet: |
          .item-after { float: right; }
        title: "=props.title ? props.title : props.item"
    - component: f7-block
      config:
        style:
          margin-top: 10px
      slots:
        default:
          - component: f7-segmented
            slots:
              default:
                - component: oh-button
                  config:
                    action: command
                    actionCommand: "0"
                    actionItem: =props.item.replace('_Raffstore','') + '_Raffstore_TargetSlat'
                    class: "=(Math.round(Number(items[props.item.replace('_Raffstore','') +
                      '_Raffstore_Slat']?.state || 0)/25)*25 === 0) ?
                      'button-active' : ''"
                    outline: true
                    round: true
                    text: 0°
                - component: oh-button
                  config:
                    action: command
                    actionCommand: "25"
                    actionItem: =props.item.replace('_Raffstore','') + '_Raffstore_TargetSlat'
                    class: "=(Math.round(Number(items[props.item.replace('_Raffstore','') +
                      '_Raffstore_Slat']?.state || 0)/25)*25 === 25) ?
                      'button-active' : ''"
                    outline: true
                    round: true
                    text: 45°
                - component: oh-button
                  config:
                    action: command
                    actionCommand: "50"
                    actionItem: =props.item.replace('_Raffstore','') + '_Raffstore_TargetSlat'
                    class: "=(Math.round(Number(items[props.item.replace('_Raffstore','') +
                      '_Raffstore_Slat']?.state || 0)/25)*25 === 50) ?
                      'button-active' : ''"
                    outline: true
                    round: true
                    text: 90°
                - component: oh-button
                  config:
                    action: command
                    actionCommand: "75"
                    actionItem: =props.item.replace('_Raffstore','') + '_Raffstore_TargetSlat'
                    class: "=(Math.round(Number(items[props.item.replace('_Raffstore','') +
                      '_Raffstore_Slat']?.state || 0)/25)*25 === 75) ?
                      'button-active' : ''"
                    outline: true
                    round: true
                    text: 135°
                - component: oh-button
                  config:
                    action: command
                    actionCommand: "100"
                    actionItem: =props.item.replace('_Raffstore','') + '_Raffstore_TargetSlat'
                    class: "=(Math.round(Number(items[props.item.replace('_Raffstore','') +
                      '_Raffstore_Slat']?.state || 0)/25)*25 === 100) ?
                      'button-active' : ''"
                    outline: true
                    round: true
                    text: 180°