Lovelace Custom Fan Card Example

Ok, so…

I made a few more modifications to the component. The theme is now pretty much fully customizable (within the parameters of a standard 3 speed fan).

See my other thread for details if you’re interested.

Fan Control Entity Row

I’ve set everything up as per @slipx06 last code, when I click “LOW” “MED” or “HIGH” the fan goes to that setting, but the “OFF” remains highlighted in blue, and I cannot click “OFF” to turn off the fan. I can still change between speeds. Any reason why the card isn’t coming off of “OFF” in HA?

switches

ui-lovelace.yaml:

  - type: entities
    title: Switches
    show_header_toggle: false
    entities:
      - entity: switch.living_room_spot_lights
        secondary_info: last-changed
        icon: mdi:lightbulb        
      - entity: switch.fireplace_spot_lights
        secondary_info: last-changed
        icon: mdi:lightbulb
      - entity: switch.dining_room_plug
        name: "Dining Room Lamps"
        secondary_info: last-changed
        icon: mdi:lightbulb
      - entity: switch.living_room_fan_light
        name: "Living Room Fan Light"
        secondary_info: last-changed
        icon: mdi:lightbulb
      - entity: fan.living_room_fan
        name: "Living Room Fan"
        type: custom:custom-fan-card
        secondary_info: last-changed
        icon: mdi:fan 

configuration.yaml:

fan:

  • platform: mqtt
    name: “Living Room Fan”
    command_topic: “cmnd/sonoff_ifan02_1/FanSpeed”
    speed_command_topic: “cmnd/sonoff_ifan02_1/FanSpeed”
    state_topic: “stat/sonoff_ifan02_1/RESULT”
    speed_state_topic: “stat/sonoff_ifan02_1/RESULT”
    state_value_template: >
    {% if value_json.FanSpeed is defined %}
    {% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}
    {% else %}
    {% if states.fan.living_room_fan.state == ‘off’ -%}0{%- elif states.fan.living_room_fan.state == ‘on’ -%}4{%- endif %}
    {% endif %}
    speed_value_template: “{{ value_json.FanSpeed }}”
    availability_topic: tele/sonoff_ifan02_1/LWT
    payload_off: “0”
    payload_on: “4”
    payload_low_speed: “1”
    payload_medium_speed: “2”
    payload_high_speed: “3”
    payload_available: Online
    payload_not_available: Offline
    speeds:
    • ‘off’
    • low
    • medium
    • high

custom-fan-card.js

class CustomFanCard extends Polymer.Element {

static get template() {
return Polymer.html`


:host {
line-height: inherit;
}
.speed {
min-width: 34px;
max-width: 34px;
height: 34px;
margin-left: 2px;
margin-right: 2px;
background-color:‘var(–dark-accent-color)’;
border: 1px var(–dark-theme-disabled-color);
border-radius: 4px;
font-size: 11px !important;
text-align: center;
float: right !important;
padding: 1px;
font-family : inherit;
}

      </style>
      <hui-generic-entity-row hass="[[hass]]" config="[[_config]]">
          <div class='horizontal justified layout' on-click="stopPropagation">
              <button
                      class='speed'
                      style='[[_offColor]]'
                      toggles name="off"
                      on-click='setSpeed'
                      disabled='[[_isOffState]]'>OFF</button>
              <button
                      class='speed'
                      style='[[_lowOnColor]]'
                      toggles name="low"
                      on-click='setSpeed'
                      disabled='[[_isOnLow]]'>LOW</button>
              <button
                      class='speed'
                      style='[[_medOnColor]]'
                      toggles name="medium"
                      on-click='setSpeed'
                      disabled='[[_isOnMed]]'>MED</button>
              <button
                      class='speed'
                      style='[[_highOnColor]]'
                      toggles name="high"
                      on-click='setSpeed'
                      disabled='[[_isOnHigh]]'>HIGH</button>

              </div>
      </hui-generic-entity-row>
  `;

}

static get properties() {
return {
hass: {
type: Object,
observer: ‘hassChanged’
},
_config: Object,
_stateObj: Object,
_lowOnColor: String,
_medOnColor: String,
_highOnColor: String,
_offColor: String,
_isOffState: Boolean,
_isOnState: Boolean,
_isOnLow: Boolean,
_isOnMed: Boolean,
_isOnHigh: Boolean
}
}

setConfig(config) {
this._config = config;
}

hassChanged(hass) {

  const config = this._config;
  const stateObj = hass.states[config.entity];

  let speed;
  if (stateObj && stateObj.attributes) {
      speed = stateObj.attributes.speed || 'off';
  }

  let low;
let med;
let high;
let offstate;

if (stateObj && stateObj.attributes) {
    if (stateObj.state == 'on' && stateObj.attributes.speed == 'low') {
      low = 'on';

} else if (stateObj.state == ‘on’ && stateObj.attributes.speed == ‘medium’) {
med = ‘on’;
} else if (stateObj.state == ‘on’ && stateObj.attributes.speed == ‘high’) {
high = ‘on’;
} else {
offstate = ‘on’;
}
}

  let lowcolor;
  let medcolor;
let hicolor;
let offcolor;

if (low == ‘on’) {
lowcolor = ‘background-color: var(–dark-primary-color); color: white;’;
} else {
lowcolor = ‘’;
}

if (med == ‘on’) {
medcolor = ‘background-color: var(–dark-primary-color); color: white;’;
} else {
medcolor = ‘’;
}

if (high == ‘on’) {
hicolor = ‘background-color: var(–dark-primary-color); color: white;’;
} else {
hicolor = ‘’;
}

if (offstate == ‘on’) {
offcolor = ‘background-color: var(–dark-primary-color); color: white;’;
} else {
offcolor = ‘’;
}

this.setProperties({
_stateObj: stateObj,
_isOffState: stateObj.state == ‘off’,
_isOnLow: low === ‘on’,
_isOnMed: med === ‘on’,
_isOnHigh: high === ‘on’,
_lowOnColor: lowcolor,
_medOnColor: medcolor,
_highOnColor: hicolor,
_offColor: offcolor
});
}

stopPropagation(e) {
e.stopPropagation();
}

setSpeed(e) {
const speed = e.currentTarget.getAttribute(‘name’);
this.hass.callService(‘fan’, ‘set_speed’, {
entity_id: this._config.entity, speed: speed
});
}

}

customElements.define(‘custom-fan-card’, CustomFanCard);

If I remember correctly I ran into some kind of issue using that code but I don’t know if that was it or not. But I’ve modified the code here and made it pretty customizable and it works really good.

If you’re interested see my post up above for a link to the thread about my control row which has the link to the code on github.

@finity Can you confirm whether your fan card works with 0.92. I’m fairly certain I have it set up correctly but I keep getting the dreaded Red Box of No Worky. Below is the code I have in my ui-lovelace.yaml. The card was RAW downloaded from github using wget and stored in the www/ folder.

resources
- url: /local/fan-control-entity-row.js
  type: js 

- type: entities
  title: Fans
  show_header_toggle: false
  entities:
  - entity: fan.master_bedroom_fan
    type: custom:fan-contol-entity-row
    name: Master Bedroom
    customTheme: false

i haven’t updated to v92 yet and likely won’t for a few days until the dust settles on the new release.

ill let you know what i find then.

did you have it working before on an older version and now its not or is this the first version you tried it on?

This is the first time. I hadn’t updated since 0.88 so I was still running old fan button code.

ok. i’ll try to remember to let you know what i find when i update.

Used your yaml code for the fan (with off in quotes and not in quotes [I noticed when not in quotes its blue instead of orange]) and the json code on your link https://community.home-assistant.io/t/lovelace-fan-control-entity-row-split-from-the-other-topics/102952/3. Still same issue, the OFF button stays highlighted and is not selectable in HA. The HI, MED, and LOW buttons all work correctly.

Funny thing, is I also have HomeKit installed and it works correctly on my iPhone and iPad (turns on and off). So just HA/Lovelace is the issue.

I’m going to answer you in my other thread to prevent from jumbling up this thread any more with off (this) topic posts…

And I’ll do the same for @daphatty as well…

thank you!

it’s usefull code!

i’m customize to Xiaomi Airpurifier
silent / auto / favorite & on/off toggle

%EC%9D%B4%EB%AF%B8%EC%A7%80%203

Looks nice ! Is that possible to have your code about this Air Purifier ? thanks!

For my Xiaomi Airpurifier 2S code here.
save file name : custom-fan-card-xiaomiair.js
pickpick_1

class CustomFanCard extends Polymer.Element {

static get template() {
    return Polymer.html`
        <style is="custom-style" include="iron-flex iron-flex-alignment"></style>
        <style>
            :host {
                line-height: inherit;
            }
            .speed {
                min-width: 34px;
                max-width: 34px;
                height: 34px;
                margin-left: 2px;
                margin-right: 2px;
                background-color:'var(--dark-accent-color)';
	                border: 1px var(--dark-theme-disabled-color);  
                border-radius: 4px;
	                font-size: 11px !important;
                text-align: center;
	                float: right !important;
                padding: 1px;
                font-family : inherit;
		    }
				
        </style>
        <hui-generic-entity-row hass="[[hass]]" config="[[_config]]">
            <div class='horizontal justified layout' on-click="stopPropagation">
				    <button
                        class='speed'
                        style='[[_silOnColor]]'
                        toggles name="silent"
                        on-click='setSpeed'
                        disabled='[[_isOnSil]]'><ha-icon icon="mdi:power-sleep"></ha-icon></button>
                <button
                        class='speed'
                        style='[[_autoOnColor]]'
                        toggles name="auto"
                        on-click='setSpeed'
                        disabled='[[_isOnAuto]]'><ha-icon icon="mdi:brightness-auto"></ha-icon></button>
                <button
                        class='speed'
                        style='[[_favoOnColor]]'
                        toggles name="favorite"
                        on-click='setSpeed'
                        disabled='[[_isOnFavo]]'><ha-icon icon="mdi:fan"></ha-icon></button>
                <ha-entity-toggle hass="[[hass]]" state-obj="[[_stateObj]]"></ha-entity-toggle>

                </div>
        </hui-generic-entity-row>
    `;
}

static get properties() {
    return {
        hass: {
            type: Object,
            observer: 'hassChanged'
        },
        _config: Object,
        _stateObj: Object,
        _silOnColor: String,
        _autoOnColor: String,
        _favoOnColor: String,
        _offColor: String,
        _isOffState: Boolean,
        _isOnState: Boolean,
        _isOnSil: Boolean,
        _isOnAuto: Boolean,
        _isOnFavo: Boolean
    }
}

setConfig(config) {
    this._config = config;
}

hassChanged(hass) {

    const config = this._config;
    const stateObj = hass.states[config.entity];

    let speed;
    if (stateObj && stateObj) {
        speed = stateObj.state || 'off';
    }
		
    let sil;
	    let auto;
	    let favo;
	    let offstate;
		
	    if (stateObj && stateObj.attributes) {
	        if (stateObj.state == 'on' && stateObj.attributes.speed == 'Silent') {
		        sil = 'on';
		} else if (stateObj.state == 'on' && stateObj.attributes.speed == 'Auto') {
		        auto = 'on';
		} else if (stateObj.state == 'on' && stateObj.attributes.speed == 'Favorite') {
		        favo = 'on';
		} else {
			offstate = 'on';
		}
	}
		
    let silcolor;
    let autocolor;
	    let favocolor;
	    let offcolor;
		
	   if (sil == 'on') {
    silcolor = 'background-color: var(--dark-primary-color); color: white;';
} else { 
    silcolor = '';
}

if (auto == 'on') {
    autocolor = 'background-color: var(--dark-primary-color); color: white;';
} else {
    autocolor = '';
}

if (favo == 'on') {
    favocolor = 'background-color: var(--dark-primary-color); color: white;';
} else {
    favocolor = '';
}
	
if (offstate == 'on') {
    offcolor = 'background-color: var(--dark-primary-color); color: white;';
} else {
    offcolor = '';
}
		
	this.setProperties({
    _stateObj: stateObj,
	    _isOffState: stateObj.state == 'off',
    _isOnSil: sil === 'on',
	    _isOnAuto: auto === 'on',
	    _isOnFavo: favo === 'on',
	    _silOnColor: silcolor,
	    _autoOnColor: autocolor,
	    _favoOnColor: favocolor,
	    _offColor: offcolor
});
}

stopPropagation(e) {
    e.stopPropagation();
}

setSpeed(e) {
    const speed = e.currentTarget.getAttribute('name');
    this.hass.callService('fan', 'set_speed', {
        entity_id: this._config.entity, speed: speed
    });
}

}

customElements.define('custom-fan-card-xiaomiair', CustomFanCard);
2 Likes

Thanks I will try!

do u mind sharing how u got it done? I have 6 speed on my fan too and would like to achieve the same result

I have this

class CustomFanCard extends Polymer.Element {

    static get template() {
        return Polymer.html`
            <style is="custom-style" include="iron-flex iron-flex-alignment"></style>
            <style>
                :host {
                    line-height: 1.5;
                }
                .speed {
                    min-width: 30px;
                    max-width: 30px;
                    margin-left: 0px;
                    margin-right: 0px;
                }
                ha-entity-toggle {
                    margin-left: 16px;
                }
            </style>
            <hui-generic-entity-row hass="[[hass]]" config="[[_config]]">
                <div class='horizontal justified layout' on-click="stopPropagation">
                    <mwc-button
                        class='speed'
                        toggles name="1"
                        on-click='setSpeed'
                        disabled='[[_is1Speed]]'>1</mwc-button>
                    <mwc-button
                        class='speed'
                        toggles name="2"
                        on-click='setSpeed'
                        disabled='[[_is2Speed]]'>2</mwc-button>
                    <mwc-button
                        class='speed'
                        toggles name="3"
                        on-click='setSpeed'
                        disabled='[[_is3Speed]]'>3</mwc-button>
                    <mwc-button
                        class='speed'
                        toggles name="4"
                        on-click='setSpeed'
                        disabled='[[_is4Speed]]'>4</mwc-button>
                    <mwc-button
                        class='speed'
                        toggles name="5"
                        on-click='setSpeed'
                        disabled='[[_is5Speed]]'>5</mwc-button>
                    <mwc-button
                        class='speed'
                        toggles name="6"
                        on-click='setSpeed'
                        disabled='[[_is6Speed]]'>6</mwc-button>
                    <ha-entity-toggle hass="[[hass]]" state-obj="[[_stateObj]]"></ha-entity-toggle>
                </div>
            </hui-generic-entity-row>
        `;
    }

    static get properties() {
        return {
            hass: {
                type: Object,
                observer: 'hassChanged'
            },
            _config: Object,
            _stateObj: Object,
            _is1Speed: Boolean,
            _is2Speed: Boolean,
            _is3Speed: Boolean,
            _is4Speed: Boolean,
            _is5Speed: Boolean,
            _is6Speed: Boolean
        }
    }

    setConfig(config) {
        this._config = config;
    }

    hassChanged(hass) {

        const config = this._config;
        const stateObj = hass.states[config.entity];

        let speed;
        if (stateObj && stateObj.attributes) {
            speed = stateObj.attributes.speed || 'off';
        }

        this.setProperties({
            _stateObj: stateObj,
            _is1Speed: speed === '1',
            _is2Speed: speed === '2',
            _is3Speed: speed == '3',
            _is4Speed: speed == '4',
            _is5Speed: speed == '5',
            _is6Speed: speed == '6'
        });
    }

    stopPropagation(e) {
        e.stopPropagation();
    }

    setSpeed(e) {
        const speed = e.currentTarget.getAttribute('name');
        this.hass.callService('fan', 'set_speed', {
            entity_id: this._config.entity, speed: speed
        });
    }

}

customElements.define('custom-fan-card', CustomFanCard);

awesome… if i have 2 fans with 2 diff speed (4 and 9), do I have to create 2 separate custom component?

I don’t know. Have a try see how it goes. I have 4 6-speed only.

Has anyone got this working on .96 ?
I can get it to display, but the toggles dont work. If i change the speed elsewhere, the changes ARE reflected by the button being selected.

Not working for me either, popped here hoping someone else already fixed it ;/

It’s now working for me, but I’m not sure what I did.

I started fiddling with the surveillance card, did a couple of restarts, and then actually turned on the fan by accident!

Not overly helpful I know, but it does work.