Custom Widget: roller blinds & slats

Was looking for some widget supporting roller blinds & slats control (aka jalousie / raffstore). But as I wasn’t able to find one I just started writing my own widget.

The widget uses two items:

  • item for absolute position (up / down)
  • item for absolute position of slats (open / close)

To control your roller blinds & slats just use the slider (up/down), the knob (open/close slats) or the button group.

Works excellent for my KNX home.

As I didn’t managed to upload a JSON file just create a new widget and copy & paste the coding below.

Have fun!

Joergee

Screenshot
my_widget_example my_widget_example2

Json

<style>

  .myFill { position:absolute; left:0px; top:0px; height:100%; width:100%; }
  .myHeader { min-height:24px;}
  .myKnob { min-height:70px; min-width:70px; }
  .myCenter { display:flex; justify-content:center; align-items:center; }
  
  .my100Height { height:100%; }
  .my95Height { height:95%; }
  .my50Height { height:50%; }
  .my25Height { height:25%; }
  .my15Height { height:15%; }  
  .my5Height { height:5%; }
  
  .myButtons { min-height:165px; min-width:85px; }
  .myButton { background-color:rgb(1, 18, 48); border-color:rgb(85,102,119); color:rgb(85,102,119); }
  .myButton:hover { background-color:rgb(1, 37, 96); }
  .myButton:focus { background-color:rgb(12, 185, 240); }  

</style>

<div class="root myFill">
  <div class="row my100Height">

		<!-- HEADER -->    	
    <div class="col-sm-12 myHeader myCenter my5Height">
      {{ngModel.name}}
    </div>
    
    <!-- LEFT -->
    <div class="col-sm-5 my95Height">
      <div class="my100Height" ng-init="my_shutter_slider={ 
                                         item: config.shutter_height,
                                         floor: 0, 
                                         ceil: 100, 
                                         step: 10,
                                         hidelabel: true,
                                         unit: '%',
                                         vertical: true,
                                         inverted: true,
                                         hidelabel: true,
                                         hidelimits: true,
                                         hidepointer: true                                                    
                                         }">
        <widget-slider ng-model="my_shutter_slider"/>	
      </div>        
    </div>

    <!-- RIGHT -->
    <div class="col-sm-7 my95Height">
      <div class="row my100Height">
       
       <div class="col-sm-12 my5Height">
       </div>        
        
        <div class="col-sm-12 myButtons my50Height">
          <!-- BUTTON UP -->
          <button style="z-index:1; position:absolute; left:0px; top:0px; width:80px; height:80px; border-radius: 5px 5px 0px 0px;"
                  type="button" class="btn btn-primary btn-block myButton" title="UP" ng-click="sendCmd(config.shutter_height, 'UP')">
            <div style="top:-23px" class="glyphicon glyphicon-chevron-up"></div>
          </button>

          <!-- BUTTON OPEN -->
          <button style="z-index:3; position:absolute; left:6px; top:30px; width:68px; height:50px; border-radius: 5px 5px 0px 0px;"
                  type="button" class="btn btn-primary btn-lg myButton" title="OPEN" ng-click="sendCmd(config.shutter_height, 'STOP')">
            <div style="top:-6px" class="glyphicon glyphicon-resize-full"></div>
          </button>

          <!-- BUTTON STOP -->
          <button style="z-index:5; position:absolute; left:0px; top:62px; width:80px; height:36px; border-radius: 5px 5px 5px 5px;"
                  type="button" class="btn btn-primary btn-lg myButton myButtonStop" title="STOP" ng-click="sendCmd(config.shutter_height, 'STOP')">
            <div style="top:-3px" class="glyphicon glyphicon-stop"></div>
          </button>              

          <!-- BUTTON CLOSE -->
          <button style="z-index:4; position:absolute; left:6px; top:80px; width:68px; height:50px; border-radius: 0px 0px 5px 5px;"
                  type="button" class="btn btn-primary btn-lg myButton" title="MOVE" ng-click="sendCmd(config.shutter_height, 'MOVE')">
            <div style="top:+10px" class="glyphicon glyphicon-resize-small"></div>
          </button>             

          <!-- BUTTON DOWN -->
          <button style="z-index:2; position:absolute; left:0px; top:80px; width:80px; height:80px; border-radius: 0px 0px 5px 5px;"
                  type="button" class="btn btn-primary btn-lg myButton" title="DOWN" ng-click="sendCmd(config.shutter_height, 'DOWN')">
            <div style="top:+28px" class="glyphicon glyphicon-chevron-down"></div>
          </button>

        </div>



        <div class="col-sm-12 my25Height">
          <div class="myKnob" ng-init="my_shutter_knob={
                                        item: config.shutter_shadow,
                                        type: 'knob',
                                        floor: 0,
                                        ceil: 100,
                                        step: 10,
                                        startAngle: 90,
                                        endAngle: 180,
                                        barColor: '#00CCFF',
                                        prevBarColor: '#0066FF',
                                        trackColor: '#003399',
                                        scaleEnabled: true,
                                        scaleType: 'dots',
                                        scaleQuantity: 11,
                                        skinType: 'tron',
                                        skinColor: '#003399',
                                        displayInput: false
                                        }">
            <div style="width:175px; height:105px; position:relative; left:-99px; top:-81px">
              <div>
                <div>
                  <widget-knob ng-model="my_shutter_knob" />
                </div>
              </div>        
            </div>
          </div>
        </div>

        <div class="col-sm-12 my15Height">
        </div>

      </div>
    </div>

  </div>
</div>
3 Likes

Thx for this cool widget. Can you make a screenshot of what elements I have to create in the settings to send the correct values to your widget?

Greetings
Stefan

Hi Stefan,

sure, just check the attached screenshots. For the KNX bindings it’s important to map the “absolute position” (read/write e.g. 0/5/33+<0/5/41) for both the shutter and blade. To configure the things and items I’m using the PaperUI. As long no special features like value formatting is required the web UI works perfect.

I’ve you have some issues just contact me.

Also working on a “popup” version of my custom widget to reduce the overall screen area required (e.g. show buttons in small dialog).

PaperUI
Things

Items

HabPanel
Custom Widget

Dashboard settings

Have fun!

Joerg

Hi joerg,
thx for this information. Now it works. In openhab you combine the value and the status of the two groupadress in knx? This is how your widget just updates one value and in knx the value and status groupadress is updated? I use ioBroker and for the visualisation i use habpanel (because I don’t live VIS).
Greetings
Stefan

Resurrecting this old thread with a question: how can I add this wonderful combo control for position and angle of slats to OH3.3? Thanks in advance!

[edit] Duh I’m an idiot, didn’t realize this applies to HABPanel UI.

While it applies to HABPanel, I would love to have similar widget in the new UI. I was not able to find anything that would combine position of blinds and louvres…

I’m currently modifying another widget, so that it has a combination of manual controls (up/down/stop) + 2 sliders (0-100%), one for absolute position of slats and the other for angle of slats. Unfortunately there is no building block in Framework7 for a slider on an arc or circle to visually reflect the angle, so a vertical slider will have to do. Something like this:

image

That would be great! Happy to help (more like beta test or tuning, not being much of a developer) or support.

Looks nice. Did you manage to finish the widget. I would also be very interessted to test it.

Unfortunately I halted all further work on it due to other priorities. Then I ditched the PaperUI altogether and just used the built-in Sitemap together with the OpenHAB app for Android. Each jalousie gets 2 sliders, one for position and another for angle, with stops every 20%. It’s pretty decent, and most importantly was immediately available for remote control. A fancier-looking interface on a wall-mounted tablet can take a similar approach.

I have somehow modified available for “floor plan” tablet - see bellow. Still work in progress but can be easily adapted.

image

uid: vp_shutter_full
tags: []
props:
  parameters:
    - description: Title
      label: Title
      name: title
      required: false
      type: TEXT
    - context: item
      description: Rollershutter control & position (receives UP, DOWN, STOP, 0 to 100 commands)
      label: Rollershutter control
      name: item
      required: true
      type: TEXT
    - context: item
      description: Louvre control & position (receives UP, DOWN, 0 to 100 commands)
      label: Rollershutter louvre item
      name: louvre
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Jan 24, 2023, 7:17:59 PM
component: f7-card
config:
  title: =props.title
slots:
  default:
    - component: f7-row
      config:
        class:
          - display-flex
          - justify-content-space-evenly
          - align-items-center
        style:
          height: 100px
          width: 100%
      slots:
        default:
          - component: f7-col
            config:
              class:
                - display-flex
                - flex-direction-column
                - justify-content-space-evenly
                - align-items-flex-end
              style:
                height: calc(100% - 10px)
            slots:
              default:
                - component: oh-slider
                  config:
                    color: white
                    item: =props.item
                    label: true
                    releaseOnly: true
                    scale: true
                    scaleSteps: 5
                    scaleSubSteps: 2
                    step: 5
                    style:
                      --f7-range-bar-active-bg-color: linear-gradient(to top, rgba(246,158,81,0), rgba(246,158,81,0.8))
                      --f7-range-bar-bg-color: rgba(246, 158, 81, 0.2)
                      --f7-range-bar-border-radius: 10px
                      --f7-range-bar-size: 10px
                      --f7-range-knob-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3)
                      --f7-range-knob-size: 10px
                      --f7-range-label-text-color: black
                    unit: "%"
                    vertical: true
                    verticalReversed: true
          - component: f7-col
            config:
              class:
                - display-flex
                - flex-direction-column
                - justify-content-center
                - align-items-center
              style:
                height: calc(100% - 0px)
            slots:
              default:
                - component: oh-link
                  config:
                    action: command
                    actionCommand: UP
                    actionItem: =props.item
                    colorTheme: gray
                    iconF7: arrowtriangle_up
                    iconSize: 20
                    style:
                      background-color: rgba(246, 158, 81, 0.2)
                      border-radius: 15px 15px 0px 0px
                      padding: 7px
                - component: oh-link
                  config:
                    action: command
                    actionCommand: STOP
                    actionItem: =props.item
                    iconF7: stop
                    iconSize: 20
                    style:
                      background-color: rgba(246, 158, 81, 0.2)
                      padding: 7px
                - component: oh-link
                  config:
                    action: command
                    actionCommand: DOWN
                    actionItem: =props.item
                    colorTheme: gray
                    iconF7: arrowtriangle_down
                    iconSize: 20
                    style:
                      background-color: rgba(246, 158, 81, 0.2)
                      border-radius: 0px 0px 15px 15px
                      padding: 7px
          - component: f7-col
            config:
              class:
                - display-flex
                - flex-direction-column
                - justify-content-space-evenly
                - align-items-flex-end
              style:
                height: calc(100% - 10px)
            slots:
              default:
                - component: oh-slider
                  config:
                    color: white
                    item: =props.louvre
                    label: true
                    releaseOnly: true
                    scale: true
                    scaleSteps: 4
                    scaleSubSteps: 0
                    step: 25
                    style:
                      --f7-range-bar-active-bg-color: linear-gradient(to top, rgba(246,158,81,0), rgba(246,158,81,0.8))
                      --f7-range-bar-bg-color: rgba(246, 158, 81, 0.2)
                      --f7-range-bar-border-radius: 10px
                      --f7-range-bar-size: 10px
                      --f7-range-knob-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3)
                      --f7-range-knob-size: 10px
                      --f7-range-label-text-color: black
                    unit: "%"
                    vertical: true
                    verticalReversed: true
          - component: f7-col
            config:
              class:
                - display-flex
                - flex-direction-column
                - justify-content-center
                - align-items-center
              style:
                height: calc(100% - 0px)
            slots:
              default:
                - component: oh-link
                  config:
                    action: command
                    actionCommand: UP
                    actionItem: =props.louvre
                    colorTheme: gray
                    iconF7: arrowtriangle_up
                    iconSize: 20
                    style:
                      background-color: rgba(246, 158, 81, 0.2)
                      border-radius: 15px 15px 0px 0px
                      padding: 7px
                - component: oh-link
                  config:
                    action: command
                    actionCommand: DOWN
                    actionItem: =props.louvre
                    colorTheme: gray
                    iconF7: arrowtriangle_down
                    iconSize: 20
                    style:
                      background-color: rgba(246, 158, 81, 0.2)
                      border-radius: 0px 0px 15px 15px
                      padding: 7px

I’m however using more simple ones to fit the “image” …

image

resp

image

I found the sliders sometimes lag or do not update state properly and ended up with numbers.

I’m using similar one for “list item” that lists all louvres using on-repeat.

Can share code, though this is Work In Progress and heavily reused and dirty one so not much prod of it ;-)…