Custom UI with Buttons - Fan Control

bits? If you mean buttons - you can use the inDialog param. It is true in more-info mode and false otherwise.

1 Like

Would you mind sharing your progress with the code ?
Thinking about quick-select buttons for my media_player,source

Sure - I attempted to follow @andrey format and my plan is to eventually add customization like has been done for the light/brightness slider. Some of the UI also isn’t as responsive as it should be… so it needs work. But I like it so far. Also of note, on a mobile device, when selecting a button the “more info” dialog still opens (doesn’t on a desktop) and the information in the dialog still needs limiting/adjusting.

here it is:

fan-model.html

<script>
(function () {
  window.FanEntity = function (hass, stateObj) {
    this.hass = hass;
    this.stateObj = stateObj;
  };

  function addGetter(name, getter) {
    Object.defineProperty(window.FanEntity.prototype, name,
                          { get: getter });
  }

  addGetter('isOff', function () {
      return this.stateObj.state === 'off';
    
  });
  
  addGetter('getSpeed', function () {
    if (this.stateObj.attributes.speed !== undefined && this.stateObj.state != 'off') {
      return this.stateObj.attributes.speed;
    }

    return 'off';
    
  });

  addGetter('isLowSpeed', function () {
    if (this.stateObj.attributes.speed !== undefined && this.stateObj.state != 'off') {
      return this.stateObj.attributes.speed === 'low';
    }
    
  });

  addGetter('isMedSpeed', function () {
    if (this.stateObj.attributes.speed !== undefined && this.stateObj.state != 'off') {
      return this.stateObj.attributes.speed === 'medium';
    }
    
  });

  addGetter('isHighSpeed', function () {
    if (this.stateObj.attributes.speed !== undefined && this.stateObj.state != 'off') {
      return this.stateObj.attributes.speed === 'high';
    }
    
  });


  /* eslint-enable no-bitwise */

    Object.assign(window.FanEntity.prototype, {
        setSpeed(speedVal, ev) {

            if (speedVal == 'off')
            {
                 this.callService('turn_off');
            }
            else
            {
                if (this.stateObj.state != 'on'){
                    this.callService('turn_on');
                }
                this.callService('set_speed', {speed: speedVal});
            }

            ev.stopPropagation();
        },


    // helper method

        callService(service, data) {
            var serviceData = data || {};
            serviceData.entity_id = this.stateObj.entity_id;
            this.hass.callService('fan', service, serviceData);
            
        },
  });
}());
</script>

state-card-with-speed.html


<link rel="import" href="fan-model.html">

<dom-module id="state-card-with-speed">
  <template>
    <style is="custom-style"></style>
    <style>
      
      .state {
        white-space: nowrap;
      }
      
      .speed {
        min-width: 0;
      }
    

      ha-entity-toggle {
        margin-left: 16px;
      }
    </style>

    <div class='state'>

        <paper-button-group 
          in-dialog='[[inDialog]]'
          selected='[[entityObj.getSpeed]]'>
            <!--<paper-button class='speed'
              toggles name="off" 
              on-tap='onOffTap'
              disabled='[[entityObj.isOff]]'>Off</paper-button>-->
            <paper-button 
              in-dialog='[[inDialog]]'
              class='speed'
              toggles name="low" 
              on-tap='onLowTap'
              disabled='[[entityObj.isLowSpeed]]'>Low</paper-button>
            <paper-button 
              in-dialog='[[inDialog]]'
              class='speed'
              toggles name="medium" 
              on-tap='onMedTap'
              disabled='[[entityObj.isMedSpeed]]'>Med</paper-button>
            <paper-button 
              in-dialog='[[inDialog]]'
              class='speed'
              toggles name="high" 
              on-tap='onHighTap'
              disabled='[[entityObj.isHighSpeed]]'>High</paper-button>
        </paper-button-group> 

    </div>

  </template>
</dom-module>

<script>
Polymer({
  is: 'state-card-with-speed',
  properties: {
    hass: {
      type: Object,
    },
    inDialog: {
      type: Boolean,
      value: false,
    },
    stateObj: {
      type: Object,
    },
    entityObj: {
      type: Object,
      computed: 'computeEntityObj(hass, stateObj)',
    },
  },
  computeEntityObj: function (hass, stateObj) {
    return new window.FanEntity(hass, stateObj);
  },
  onOffTap: function (ev) {
    this.entityObj.setSpeed('off', ev);
  },
  onLowTap: function (ev) {
    this.entityObj.setSpeed('low', ev);
  },
  onMedTap: function (ev) {
    this.entityObj.setSpeed('medium', ev);
  },
  onHighTap: function (ev) {
    this.entityObj.setSpeed('high', ev);
  },
});
</script>

state-card-custom_fan.html

<link rel="import" href="state-card-with-speed.html">

<dom-module id="state-card-custom_fan">
  <template>
    <style is="custom-style" include="iron-flex iron-flex-alignment"></style>
    <style>
      :host {
        line-height: 1.5;
      }
    </style>

    <div class='horizontal justified layout'>
      <state-info state-obj="[[stateObj]]" in-dialog='[[inDialog]]'></state-info>
      <state-card-with-speed hass="[[hass]]" state-obj="[[stateObj]]" in-dialog='[[inDialog]]'></state-card-with-speed>
      <ha-entity-toggle state-obj='[[stateObj]]' hass='[[hass]]' in-dialog='[[inDialog]]'></ha-entity-toggle>
    </div>
  </template>
</dom-module>

<script>
Polymer({
  is: 'state-card-custom_fan',

  properties: {
    hass: {
      type: Object,
    },

    inDialog: {
      type: Boolean,
      value: false,
    },

    stateObj: {
      type: Object,
    },
  },
});
</script>

and last, configuration.yaml

  homeassistant:
    customize:
 
      fan.master_bedroom_fan:
        custom_ui_state_card: custom_fan 

Which should give you:

5 Likes

thx, let me take a stab at this and see how it goes…

@kylerw, I sent a link to this thread to @balloob and he blessed the concept, so it would be great if you could make a PR agains the main repo with this UI.

@kylerw, With regards to your query on responsiveness , i don’t see any issues with the buttons here:

Here goes the code - i’ve put everything into one file.

state-card-custom_light.html

<dom-module id="state-card-custom_light">
  <template>
    <style is="custom-style" include="iron-flex iron-flex-alignment"></style>
    <style>
      :host {
        line-height: 1.5;
      }
      paper-button {
        min-width: 30px;
        height: 20px;
        margin: 10px 2px 10px 2px;
        padding: 0 0 0 0;
      }
    </style>

<div class='horizontal justified layout'>
  <state-info state-obj="[[stateObj]]"></state-info>
  <paper-button-group>
      <paper-button style="background-color:#74e7ff" on-tap="btntap1"></paper-button>
      <paper-button style="background-color:#74ffc2" on-tap="btntap2"></paper-button>
      <paper-button style="background-color:#ffd574" on-tap="btntap3"></paper-button>
      <paper-button style="background-color:#eaeae1" on-tap="btntap4"></paper-button>
  </paper-button-group>
  <ha-entity-toggle state-obj="[[stateObj]]" hass="[[hass]]"></ha-entity-toggle>
</div>
</template>
</dom-module>
<script>
        Polymer({
          is: 'state-card-custom_light',
          properties: {
            hass: {
              type: Object,
            },
            stateObj: {
              type: Object,
            },
          },

          btntap1: function (ev) {
            this.setColor(116, 231, 255, 200, ev);
          },
          btntap2: function (ev) {
            this.setColor(116, 255, 194, 200, ev);
          },
          btntap3: function (ev) {
            this.setColor(255, 213, 116, 200, ev);
          },
          btntap4: function (ev) {
            this.setColor(255, 225, 255, 255, ev);
          },
         
          setColor(r,g,b,br,ev) {
            var serviceData = {entity_id: this.stateObj.entity_id, rgb_color: [r, g, b], brightness: br, transition: 1} || {};
            this.hass.callService('light', 'turn_on', serviceData);
            ev.stopPropagation();
  },
  
});
</script>

configuration.yaml

 homeassistant:
   customize:
     light.entrance:
       custom_ui_state_card: custom_light
     light.bedroom:                
       custom_ui_state_card: custom_light
5 Likes

By responsive I meant adjustments with the UI. In certain states, the buttons push the toggle off the card. Are you seeing that here?

Not really, it has been stable with my usage so far.

How does the receivinig work. Awesome UI, but when you press ‘MED’ what exactly happens… I am very new with this and i want to use RF transmitter to send a signal to my RF box in my fan

what folder is the .html in?

@kylerw any plans to submit this to the main repo?

should be in a www folder in your root home assistant folder (where your configuration.yaml is located).

It is changing the fan speed to medium - if you can setup your RF fan and establish the low/med/high then it should work as expected.

1 Like

The custom ui html files are in <config_dir>/www/custom_ui/

thanks for the correction!

Thanks to both of you, I was trying to use a config ui in the wrong folder. I just needed to add the www. Thanks

Hey @andrey - My latest updates seemed to have broken it and my ability/availability to debug quickly is limited. If you or anyone else wants to take what I’ve got and submit to main repo, please feel free.

hi kyrlew, this configuration is only possible with a transmitter that transmitt 4 different signals?
i am using a broadlink rm pro that is seen as a switch, can i use your ui with the broadlink?
is it possible to link a command from a switch to the “low, med high” button?
thanks for your work.

It was something similar that I was looking for.

What fan do you use for this project?
Thank you.

I am using a GE Fan Switch with SmartThings - so HA is setup using the MQTT Fan Component.

1 Like