Lovelace Custom Fan Card Example

had the same problem.
i add a line to the code and now it works fine:

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: 20px;
                   max-width: 85px;
                   margin-left: 2px;
                   margin-right: 2px;
                   float: right !important;  
                }
               </style>
            <hui-generic-entity-row hass="[[hass]]" config="[[_config]]">
                <div class='horizontal justified layout' on-click="stopPropagation">
                    <mwc-button
                        class='speed'
						style='[[_lowOnColor]]'
                        toggles name="low"
                        on-click='setSpeed'
                        disabled='[[_isonLow]]'>LOW</mwc-button>
                    <mwc-button
                        class='speed'
						style='[[_medOnColor]]'
                        toggles name="medium"
                        on-click='setSpeed'
                        disabled='[[_isonMed]]'>MED</mwc-button>
                    <mwc-button
                        class='speed'
						style='[[_highOnColor]]'
                        toggles name="high"
                        on-click='setSpeed'
                        disabled='[[_isonHigh]]'>HIGH</mwc-button>
				    <mwc-button
                        class='speed'
						style='[[_offColor]]'
                        toggles name="off"
                        on-click='setSpeed'
                        disabled='[[_isOffState]]'>OFF</mwc-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: #43A047';
		} else {
			lowcolor = '';
		}
		
		if (med == 'on') {
			medcolor = 'background-color: #43A047';
		} else {
			medcolor = '';
		}
		
		if (high == 'on') {
			hicolor = 'background-color: #43A047';
		} else {
			hicolor = '';
		}
		
		if (offstate == 'on') {
			//offcolor = 'background-color: #43A047';
			offcolor = 'background-color: #f44c09';
		} 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', 'turn_on', {
            entity_id: this._config.entity
        });
        this.hass.callService('fan', 'set_speed', {
            entity_id: this._config.entity, speed: speed
        });
    }


}

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

does anyone know how to add oscillation button?

How does this play with Google assistant?

Works fine. Can turn the fan on/off, set the fan speed etc

slipx06 Im using your custom-fan-card, after 0.96 update, the high button stopped working. Everything else works fine but the Hi button. Can turn the high speed through service set_speed. Restarted many times and cleared the cache but not working. Nothing changed except the update to 0.96. Any idea how to fix it. Thanks!

Does anyone have a version of this card that works with HA Cast ?

Very nice work on this! I modified it to support the 4-speed Caseta Fan controller.

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: 30px;
                    max-width: 30px;
                    height: 30px;
                    margin-left: 2px;
                    margin-right: 2px;
                    background-color:#759aaa;
                        border: 1px solid lightgrey;
                    border-radius: 4px;
                        font-size: 10px !important;
                    color: inherit;
                    text-align: center;
                        float: right !important;
                    padding: 1px;
                    }

            </style>
            <hui-generic-entity-row hass="[[hass]]" config="[[_config]]">
                <div class='horizontal justified layout' on-click="stopPropagation">
                    <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='[[_medHighOnColor]]'
                            toggles name="medium_high"
                            on-click='setSpeed'
                            disabled='[[_isOnMedHigh]]'>MHI</button>
                    <button
                            class='speed'
                            style='[[_highOnColor]]'
                            toggles name="high"
                            on-click='setSpeed'
                            disabled='[[_isOnHigh]]'>HIGH</button>
                    <button
                            class='speed'
                            style='[[_offColor]]'
                            toggles name="off"
                            on-click='setSpeed'
                            disabled='[[_isOffState]]'>OFF</button>
                    </div>
            </hui-generic-entity-row>
        `;
    }

    static get properties() {
        return {
            hass: {
                type: Object,
                observer: 'hassChanged'
            },
            _config: Object,
            _stateObj: Object,
            _lowOnColor: String,
            _medOnColor: String,
            _medHighOnColor: String,
            _highOnColor: String,
            _offColor: String,
            _isOffState: Boolean,
            _isOnState: Boolean,
            _isOnLow: Boolean,
            _isOnMed: Boolean,
            _isOnMedHigh: 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 medHigh;
        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 == 'medium_high') {
                medHigh = 'on';
            } else if (stateObj.state == 'on' && stateObj.attributes.speed == 'high') {
                high = 'on';
            } else {
                offstate = 'on';
            }
        }

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

        if (low == 'on') {
            lowcolor = 'background-color: #43A047';
        } else {
            lowcolor = '';
        }

        if (med == 'on') {
            medcolor = 'background-color: #43A047';
        } else {
            medcolor = '';
        }

        if (medHigh == 'on') {
            medhighcolor = 'background-color: #43A047';
        } else {
            medhighcolor = '';
        }

        if (high == 'on') {
            hicolor = 'background-color: #43A047';
        } else {
            hicolor = '';
        }

        if (offstate == 'on') {
            //offcolor = 'background-color: #43A047';
            offcolor = 'background-color: #f44c09';
        } else {
            offcolor = '';
        }

        this.setProperties({
            _stateObj: stateObj,
            _isOffState: stateObj.state == 'off',
            _isOnLow: low === 'on',
            _isOnMed: med === 'on',
            _isOnMedHigh: medHigh === 'on',
            _isOnHigh: high === 'on',
            _lowOnColor: lowcolor,
            _medOnColor: medcolor,
            _medHighOnColor: medhighcolor,
            _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);
1 Like

Thanks for this, I modified it to match my fan controller, works great.

Thanks!

I’ve thought about making it configurable for more fan speeds but I’m not sure it’s worth the effort to combine it all into one card.

I could make a bunch of them for different speeds but I think it might get confusing for people to install the correct one.

And how many different speeds would we eventually have to settle on? 3, 4, 5, 6, 10? I really don’t know the answer to that. Then you would also need to take the sizing into account or you start getting text bleed over as you see ion the card above. And you could only fit so many buttons into the allotted space.

Then I’m sure people won’t like the naming convention for the buttons.

Those were all the dilemma’s I’ve tried to think thru but never could figure it out to my satisfaction. So I just left it at 3 speeds as those are probably the most common.

I’m glad you were able to modify it to your needs tho. Good Job!

Thanks. Yeah, I can understand the challenge. The nice thing about the Lutron Caseta fan controller is that they named the speeds and there are just 4. I’m just getting into HA, but it seems like this might be a good candidate for HACS. I’d be happy to give that a try if you think it would be worth it.

I posted up above somewhere that I had split my code off to it’s own thread so to minimize confusion for this thread I think we should continue this discussion on that thread found here:

I’ll tag you there next…

How hard would it be to convert this to a dimmer (brightness) control? The reason I ask is that I have a fan that is controlled by a GE/Jasco in wall Fan Control. It is basically a heavy duty dimmer switch, meant for use on fans. It has 3 ‘speed’ settings (brightness) that control the fans plus OFF.
I have tried several fan plugins but my fan devices show as lights, not fans, so those did not work. My zwave platform is Vera and those fan control devices show up as switches by default. I’m not sure I could change them to fan devices in the Vera, or after importing to HA, so that brings me to the idea of using this plugin as a ‘brightness’ controller.
I’ll take a stab at making the changes if someone could confirm that it actually might be possible. The end goal would be 3 levels plus an OFF state, so not really much different from the original concept.
Thanks, I look forward to your responses.

at the risk of confusing this thread with my other code but because it seems generic to any other fan control i’ll answer here…

My fan code (linked to in the post right above yours) should be able to control any three speed fan that reports it’s speeds as low, med, high (plus off).

If you can configure your fan as a template fan that exposes those three speeds to HA in the background then my code should be able to work to control it.

I can confirm that a GE fan control works as intended with @finity’s custom fan control.

You can check if it will work by using the Services tab under Developer Tools. If manually setting the fan speeds there works, @finity’s lovelace card should work.

image

@jazzyisj,

Thanks for the quick reply. As i mentioned in the original post, using a Vera Secure as my ZWave controller forces that Fan Controller to report as a Dimmable Switch. A quick check of the available device types showed that Vera does not support FAN device type. See here for the full list: http://wiki.micasaverde.com/index.php/Luup_Device_Categories

@finity suggested I configure that switch as a ‘template fan’ but I am unaware of how to do that. I will continue to research it though.

Since the fan comes up as a switch I do not get even one service for fans. See screenshot:


So I ether figure out if a Template Fan will work, or convert the existing plugin to control brightness, which of course was my original question.

Any examples of converting a device from a switch to a fan would be greatly appreciated.

Can you do a screen shot of how your fan shows up in the states developer tools screen?

eg

To do a fan template you’re going to have to figure out how to get the values from your entity and what services to use to control it.

1 Like

not without a lot of work inside the code of the plug in.

It would be easier to convert your switches to a template fan.

1 Like

OK I was waiting for that screenshot to verify your fan was showing up as a light entity in HA but I got impatient and am just going to assume it is a light because there is no such thing as a “dimmable switch” entity in HA.

Here is the YAML to turn my living room pot lights into a fan that can be controlled by @finity fan control. I tested it, it works. You’ll have to change the entity to match whatever your fan is showing up as and you might have to fiddle with the brightness values.

fan:
  - platform: template
    fans:
      livingroom_fan:
        friendly_name: "Livingroom Fan"
        value_template: "{{ states('light.living_room_pot_lights') }}"
        speed_template: >
           {% if state_attr('light.living_room_pot_lights','brightness') | int < 1 %}
             off
           {% elif state_attr('light.living_room_pot_lights','brightness') | int > 0
              and state_attr('light.living_room_pot_lights','brightness') | int < 85 %}
             low
           {% elif state_attr('light.living_room_pot_lights','brightness') | int  > 84
                and  state_attr('light.living_room_pot_lights','brightness') | int < 170 %}
             medium
           {% elif state_attr('light.living_room_pot_lights','brightness') | int > 169 %}
             high
           {% endif %}
        turn_on:
          service: script.living_room_fan_on
        turn_off:
          service: script.living_room_fan_off
        set_speed:
          service: script.living_room_fan_speed
          data_template:
            speed: "{{ speed }}"
        speeds:
          - 'off'
          - 'low'
          - 'medium'
          - 'high'

Then you need to add these three scripts.

living_room_fan_on:
  sequence:
    - service: light.turn_on
      entity_id: light.living_room_pot_lights

living_room_fan_off:
  sequence:
    - service: light.turn_off
      entity_id: light.living_room_pot_lights

living_room_fan_speed:
  sequence:
    - service: light.turn_on
      data_template:
        entity_id: light.living_room_pot_lights
        brightness: >
          {% if speed == 'off' %}
            0
          {% elif speed == 'low' %}
            80
          {% elif speed == 'medium' %}
            165
          {% elif speed == 'high' %}
            255
          {% else %}
            0
          {% endif %}

@finity I think the fan template docs are lacking here, they really don’t explain that you have to create your own scripts and how you might go about doing that. I’ve seen questions similar to this one more than once on here. Maybe I should make this example here a little more generic and submit a PR to add it as an example in the docs?

Sounds good to me.

1 Like

@jazzyisj, @finity,
Gentlemen, thank you for the great responses. Jazzisj, yes, you are correct - my fans are in fact lights in HA. I should have been more clear about the Dimmable Switch. In my Vera that GE switch is reported as a dimmable switch. When HA connects to Vera the device is created in HA as a light entity.
finity, Although I have done enough template sensors to feel pretty comfortable with it, I was unaware you could create a fan entity as you suggested. I will start working with all the code tonight.

Thank you both for a very complete and extremely helpful explanation. I hope other users can also benefit from your expertise. Gratefuly,
Art

I really like this card — but does anyone have a modified version that work via HA Cast ?
Would be great to get it working on my google hub!