Lovelace Custom Fan Card Example

In case anyone wants this, I took @slipx06 code and customized it for my six speed fan.

class CustomFanCard extends Polymer.Element {

    static get template() {
        return Polymer.html`
            <style>
                .flex-container {
                    display: flex;
                    justify-content: center;
                    align-items: center;
                }
                @keyframes mdc-ripple-fg-radius-in{from{animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transform:translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1)}to{transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}}@keyframes mdc-ripple-fg-opacity-in{from{animation-timing-function:linear;opacity:0}to{opacity:var(--mdc-ripple-fg-opacity, 0)}}@keyframes mdc-ripple-fg-opacity-out{from{animation-timing-function:linear;opacity:var(--mdc-ripple-fg-opacity, 0)}to{opacity:0}}.mdc-ripple-surface--test-edge-var-bug{--mdc-ripple-surface-test-edge-var: 1px solid #000;visibility:hidden}.mdc-ripple-surface--test-edge-var-bug::before{border:var(--mdc-ripple-surface-test-edge-var)}.mdc-button{font-family:Roboto,sans-serif;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-size:.875rem;line-height:2.25rem;font-weight:500;letter-spacing:.0892857143em;text-decoration:none;text-transform:uppercase;--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity;padding:0 8px 0 8px;display:inline-flex;position:relative;align-items:center;justify-content:center;box-sizing:border-box;min-width:64px;height:36px;border:none;outline:none;line-height:inherit;user-select:none;-webkit-appearance:none;overflow:hidden;vertical-align:middle;border-radius:4px}.mdc-button::before,.mdc-button::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-button::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1}.mdc-button.mdc-ripple-upgraded::before{transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-button.mdc-ripple-upgraded::after{top:0;left:0;transform:scale(0);transform-origin:center center}.mdc-button.mdc-ripple-upgraded--unbounded::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-button.mdc-ripple-upgraded--foreground-activation::after{animation:225ms mdc-ripple-fg-radius-in forwards,75ms mdc-ripple-fg-opacity-in forwards}.mdc-button.mdc-ripple-upgraded--foreground-deactivation::after{animation:150ms mdc-ripple-fg-opacity-out;transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-button::before,.mdc-button::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-button.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-button::-moz-focus-inner{padding:0;border:0}.mdc-button:active{outline:none}.mdc-button:hover{cursor:pointer}.mdc-button:disabled{background-color:transparent;color:rgba(0,0,0,.37);cursor:default;pointer-events:none}.mdc-button.mdc-button--dense{border-radius:4px}.mdc-button:not(:disabled){background-color:transparent}.mdc-button:not(:disabled){color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-button::before,.mdc-button::after{background-color:#6200ee}@supports not (-ms-ime-align: auto){.mdc-button::before,.mdc-button::after{background-color:var(--mdc-theme-primary, #6200ee)}}.mdc-button:hover::before{opacity:.04}.mdc-button:not(.mdc-ripple-upgraded):focus::before,.mdc-button.mdc-ripple-upgraded--background-focused::before{transition-duration:75ms;opacity:.12}.mdc-button:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-button:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.16}.mdc-button.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.16}.mdc-button .mdc-button__icon{margin-left:0;margin-right:8px;display:inline-block;width:18px;height:18px;font-size:18px;vertical-align:top}[dir=rtl] .mdc-button .mdc-button__icon,.mdc-button .mdc-button__icon[dir=rtl]{margin-left:8px;margin-right:0}.mdc-button svg.mdc-button__icon{fill:currentColor}.mdc-button--raised .mdc-button__icon,.mdc-button--unelevated .mdc-button__icon,.mdc-button--outlined .mdc-button__icon{margin-left:-4px;margin-right:8px}[dir=rtl] .mdc-button--raised .mdc-button__icon,.mdc-button--raised .mdc-button__icon[dir=rtl],[dir=rtl] .mdc-button--unelevated .mdc-button__icon,.mdc-button--unelevated .mdc-button__icon[dir=rtl],[dir=rtl] .mdc-button--outlined .mdc-button__icon,.mdc-button--outlined .mdc-button__icon[dir=rtl]{margin-left:8px;margin-right:-4px}.mdc-button--raised,.mdc-button--unelevated{padding:0 16px 0 16px}.mdc-button--raised:disabled,.mdc-button--unelevated:disabled{background-color:rgba(0,0,0,.12);color:rgba(0,0,0,.37)}.mdc-button--raised:not(:disabled),.mdc-button--unelevated:not(:disabled){background-color:#6200ee}@supports not (-ms-ime-align: auto){.mdc-button--raised:not(:disabled),.mdc-button--unelevated:not(:disabled){background-color:var(--mdc-theme-primary, #6200ee)}}.mdc-button--raised:not(:disabled),.mdc-button--unelevated:not(:disabled){color:#fff;color:var(--mdc-theme-on-primary, #fff)}.mdc-button--raised::before,.mdc-button--raised::after,.mdc-button--unelevated::before,.mdc-button--unelevated::after{background-color:#fff}@supports not (-ms-ime-align: auto){.mdc-button--raised::before,.mdc-button--raised::after,.mdc-button--unelevated::before,.mdc-button--unelevated::after{background-color:var(--mdc-theme-on-primary, #fff)}}.mdc-button--raised:hover::before,.mdc-button--unelevated:hover::before{opacity:.08}.mdc-button--raised:not(.mdc-ripple-upgraded):focus::before,.mdc-button--raised.mdc-ripple-upgraded--background-focused::before,.mdc-button--unelevated:not(.mdc-ripple-upgraded):focus::before,.mdc-button--unelevated.mdc-ripple-upgraded--background-focused::before{transition-duration:75ms;opacity:.24}.mdc-button--raised:not(.mdc-ripple-upgraded)::after,.mdc-button--unelevated:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-button--raised:not(.mdc-ripple-upgraded):active::after,.mdc-button--unelevated:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:.32}.mdc-button--raised.mdc-ripple-upgraded,.mdc-button--unelevated.mdc-ripple-upgraded{--mdc-ripple-fg-opacity: 0.32}.mdc-button--raised{box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2),0px 2px 2px 0px rgba(0, 0, 0, 0.14),0px 1px 5px 0px rgba(0,0,0,.12);transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-button--raised:hover,.mdc-button--raised:focus{box-shadow:0px 2px 4px -1px rgba(0, 0, 0, 0.2),0px 4px 5px 0px rgba(0, 0, 0, 0.14),0px 1px 10px 0px rgba(0,0,0,.12)}.mdc-button--raised:active{box-shadow:0px 5px 5px -3px rgba(0, 0, 0, 0.2),0px 8px 10px 1px rgba(0, 0, 0, 0.14),0px 3px 14px 2px rgba(0,0,0,.12)}.mdc-button--raised:disabled{box-shadow:0px 0px 0px 0px rgba(0, 0, 0, 0.2),0px 0px 0px 0px rgba(0, 0, 0, 0.14),0px 0px 0px 0px rgba(0,0,0,.12)}.mdc-button--outlined{border-style:solid;padding:0 14px 0 14px;border-width:2px}.mdc-button--outlined:disabled{border-color:rgba(0,0,0,.37)}.mdc-button--outlined:not(:disabled){border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-button--dense{height:32px;font-size:.8125rem}.material-icons{font-family:var(--mdc-icon-font, "Material Icons");font-weight:normal;font-style:normal;font-size:var(--mdc-icon-size, 24px);line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:"liga";-webkit-font-smoothing:antialiased}:host{display:inline-flex;outline:none}.mdc-button{flex:1}
                :host {
                    display: inherit;
                }
                .speeds button:host {
                    display: inline-flex;
                    outline: none;
                }
                .speeds button {
                    min-width: 34px !important;
                    width: 34px;
                    font-size: 11px !important;
                }
            </style>
            
            <hui-generic-entity-row hass="[[hass]]" config="[[_config]]">
                <div class='flex-container' on-click="stopPropagation">
                    <div class='speeds'>
                        <button
                            class='mdc-button mdc-button--raised mdc-ripple-upgraded'
                            toggles name="off"
                            on-tap='setSpeed'
                            disabled='[[_isOff]]'>
                            <span class="mdc-button__label">O</span>
                        </button>
                        <button
                            class='mdc-button mdc-button--raised mdc-ripple-upgraded'
                            toggles name="1"
                            on-tap='setSpeed'
                            disabled='[[_isOneSpeed]]'>
                            <span class="mdc-button__label">1</span>
                        </button>
                        <button
                            class='mdc-button mdc-button--raised mdc-ripple-upgraded'
                            toggles name="2"
                            on-tap='setSpeed'
                            disabled='[[_isTwoSpeed]]'>
                            <span class="mdc-button__label">2</span>
                        </button>
                        <button
                            class='mdc-button mdc-button--raised mdc-ripple-upgraded'
                            toggles name="3"
                            on-tap='setSpeed'
                            disabled='[[_isThreeSpeed]]'>
                            <span class="mdc-button__label">3</span>
                        </button>
                        <button
                            class='mdc-button mdc-button--raised mdc-ripple-upgraded'
                            toggles name="4"
                            on-tap='setSpeed'
                            disabled='[[_isFourSpeed]]'>
                            <span class="mdc-button__label">4</span>
                        </button>
                        <button
                            class='mdc-button mdc-button--raised mdc-ripple-upgraded'
                            toggles name="5"
                            on-tap='setSpeed'
                            disabled='[[_isFiveSpeed]]'>
                            <span class="mdc-button__label">5</span>
                        </button>
                        <button
                            class='mdc-button mdc-button--raised mdc-ripple-upgraded'
                            toggles name="6"
                            on-tap='setSpeed'
                            disabled='[[_isSixSpeed]]'>
                            <span class="mdc-button__label">6</span>
                        </button>
                    </div>
                </div>
            </hui-generic-entity-row>
        `;
    }

    static get properties() {
        return {
            hass: {
                type: Object,
                observer: 'hassChanged'
            },
            _config: Object,
            _stateObj: Object,
            _isOff: Boolean,
            _isOneSpeed: Boolean,
            _isTwoSpeed: Boolean,
            _isThreeSpeed: Boolean,
            _isFourSpeed: Boolean,
            _isFiveSpeed: Boolean,
            _isSixSpeed: 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,
            _isOff: stateObj.state === 'off',
            _isOneSpeed: speed === '1' && stateObj.state === 'on',
            _isTwoSpeed: speed === '2' && stateObj.state === 'on',
            _isThreeSpeed: speed === '3' && stateObj.state === 'on',
            _isFourSpeed: speed === '4' && stateObj.state === 'on',
            _isFiveSpeed: speed === '5' && stateObj.state === 'on',
            _isSixSpeed: speed === '6' && stateObj.state === 'on',
        });
    }

    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);

Annotation 2019-12-29 182210

2 Likes

i have a fan (controlled by remote IR),
How can I edit this custom card to show 5 speed level and for each, on click, run a script where i set the IR code to send with a broadlink?
thanks

Hi all, I’ve seen it asked in some other posts but I’m not sure that if it ever was corrected. When using the custom-fan-card in my lovelace I keep getting this error that pops up at the bottom, everything seems to work with the exception of the Visual Editor, is everyone else getting this as well?

Error: Expected a value of type {entity,name,icon} | entity-id for entities.0.type but received "custom:custom-fan-card".

entities:
  - entity: fan.lroom_fan
    name: Living Room
    type: 'custom:custom-fan-card'
title: Fans
type: entities

Hi, can you share the code please I want to do just like you

Thanks

See here.

Hi Tom,
Firstly, thanks for creating a custom fan controller with 6 speed. I’m new to Home assistant and don’t have much idea. Can you please show me step by step who to implement your code from scratch. I have played a little with configuration.yaml.
Reading all these articles and threads are only adding confusion.
I’ve a purchased Atomberg Gorilla Renesa Smart Plus. Used Tuya-convert to push Tasmota and able to use it with HA having three speeds as that’s the speed limit. Having 6 speeds will be fantastic and need your guidance on it.
Thanks in advance!

which version of tuya-convert did you use?

Hi everyone and thanks for your help
I have the file ‘fan-control-entity-row-5-button.js’ with the following content:

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('fan-control-entity-row-5-button', CustomFanCard);

I added the following script to ‘configuration.yaml’ to make a stove work:

script:
  thermorossi_velocita_1:
    sequence:
      - service: remote.send_command
        data:
          entity_id: remote.telecomando_wifi_broadlink_remote
          delay_secs: 2
          command:
            - b64:ssA4AlCfBgAODQ4bRA4bNzYbDlIbDg0ODRxEDhs2NxsOURwNDg4NHEMPGjc2HA1SGw4ODQ4bRA4bNzYcDVIbDg4NDhtEDhs3NxsNUhsODQ4OG0QOGzc2Gw5SGw4NDg0cRA4bNjcbDVIcDQ4ODRxDDxo3NhwNUhsODg0OG0QOGzc2HA1SGw4ODQ4bRA4bNzYcDVIbDg0ODhtEDhs3NhsOUhsODQ4NHEQOGzY3Gw1TGw4NDg0cQw4bNzYcDVIbDg4ODRtEDhs3NhwNUhsODQ4OG0QOGzc2HA1SGw4NDg4bRA4bNzYcDVIbDg0ODRxEDhs3NhsOUhsODQ4NHEQNHDY2HA1SHA0ODg0cQw4bNzYcDVIbDg4NDhtEDhs4NRwNUg4PiA8NDg0cQw8aNzcbDVIcDQ4ODRxDDhs3NhwNUhsODg0OG0QOGzc2HA1SGw4NDg4bRA4bNzYcDVIbDg0ODhtEDhs2NxsOUhsODQ4NHEQOGjc2HA1SHA0ODg0cQw4bNzcbDVIbDg4NDhtEDhs3NhwNUhsODQ4OG0QOGzc2HA1SGw4NDg0cRA4bNzYbDlIbDg0ODRxEDho3NxsNUxsODQ4NHEMOGzc2HA1SGw4ODg0bRA4bNzYcDVIbDg4NDhtEDhs3NhsOUhsODQ4OG0QOGzc2Gw5SGw4NDg0cRA4aNzcbDlIbDg0ODRxEDho3NhwNUhwNDg4NG0QOGzc2HA1SGw4ODQ4bRA4bNzYcDVIbDg0ODhtEDhs3NhsOUg4ABdwAAAAAAAAAAAAAAAAAAA==
            - b64:scA4AvaeBgAODg4bRA4bNjcpGzYcDQ4ODRxEDho3NiobNxoODQ4OG0QOGzc2KRs3Gw4NDg4bRA4bNzYpGzcbDg0ODhtEDhs3NikbNxsODQ4NHEQOGjc3KRs2HA0ODg0cQw8aNzYqGzYbDg4ODRtEDhs3NikbNxsODQ4OG0QOGzc2KRs3Gw4ODQ4bRA4bNzYpGzcbDg0ODRxEDhs2NykbNxsODQ4NHEQNGzc2Kho3Gw4ODg0bRA4bNzYpGzcbDg4ODRtEDhs3NikbNxsODQ4OG0QOGzc2KRs3Gw4NDg0cRA4aNzcpGzcbDg0ODRxEDhs2NiobNxoODg4NHEMPGjc2KRs3Gw4NDg4bRA4bNzYpGzcbDg0ODhtEDhs3NikbNw4PiA8NDg0cQw8aNzYqGzYbDg0ODhtEDhs3NioaNxsODg0OG0QOGzc2KRs3Gw4NDg4bRA4bNzYpGzcbDg0ODRxEDhs2NykbNxsNDg4NHEMPGjc2KRw2Gw4ODQ4bRA4bNzYpGzcbDg0ODhtEDhs3NikbNxsODQ4OG0QOGzc2KRs3Gw4NDg4bRA4bNzUqGzcbDg0ODRxEDho3NiobNhsODg4NG0QOGzc2KRs3Gw4NDg4bRA4bNzYpGzcbDg0ODhtEDhs3NikbNxsODQ4NHEQOGzc2KRs3Gw0ODg0cRA4bNjYqGzcaDg4ODRxDDhs3NioaNxsODg0OG0QOGzc2KRs3Gw4NDg4bRA4bNzYpGzcbDg0ODRxEDhs3NikbNg8ABdwAAAAAAAAAAAAAAAAAAA== 
  thermorossi_velocita_2:
    sequence:
      - service: remote.send_command
        data:
          entity_id: remote.telecomando_wifi_broadlink_remote
          delay_secs: 2
          command:
            - b64:scA6AtieBgCHDQ4NDhtFDRs3Ng4bUhsODg0OG0QOGzc2DhtSGw4NDw0bRA4bNzYOG1IbDg0ODRxEDhs3Ng4bUhsODQ4NHEQOGjg2DhpSHA0ODg0cQw8aNzYOG1IbDg4ODRtEDhs3Ng4bUhsODg0OG0QOGzc2DhtSGw4NDg4bRA4bNzYOG1IbDg0ODRxEDhs3Ng4bUhsNDg4NHEMPGjc2DhtSGw4ODg0bRA8aNzYOG1IbDg0ODhtEDhs3Ng4bUhsODQ4OG0QOGzc2DhtSGw4NDg0cRA4bNjcOGlMbDg0ODRxDDxo3Ng8aUhsODg4NHEMPGjc2DhtSHA0NDg4bRA4bNzYOG1IbDg0ODRxEDhs3Ng4bUhsODQ4NHEQOGzY3DhtSDg+IDg0PDRxDDhs3Ng4bUhsODQ4OG0QOGzc2DhtSGw4NDg4bRA4bNjcOG1IbDg0ODRxEDho3Nw4aUhwNDg4NHEQOGjc2DhtSGw4ODg0bRA4bNzYOG1IbDg0ODhtEDhs3Ng4bUhsODQ4OG0QOGzc2DhtSGw4NDg0cRA4bNjYPGlMbDg0ODRxDDhs3Ng4bUhsODg4NG0QOGzc2DhtSGw4NDg4bRA4bNzYOG1IbDg0ODRxEDhs3Ng4bUhsODQ4NHEQOGjc3DhpTGw4NDg0cRA4aNzYPGlIbDg4ODRtEDhs3Ng4bUhsODQ4OG0QOGzc2DhtSGw4NDg4bRA4bNzYOG1IbDg0ODRxEDhs2Nw4bURwNDg4NHEMPGjc2DxpSDwAF3AAAAAAAAAAAAAAAAA==
            - b64:scCIAtieBgAODg0bRQ0cNjcNDg4aNxsODg0OG0QOGzc2Dg0OGzcbDg0ODRxEDhs3Ng4NDhs3Gw4NDg0cRA4bNzYODQ4bNxsODQ4NHEQOGjc2Dw0OGzcaDw0ODRxDDhs3Ng4ODho3Gw4ODg0bRA4bNzYODg0bNxsODQ4OG0QOGzc2Dg0OGzcbDg0ODRxEDhs3Ng4NDhs3Gw4NDg0cRA4aNzYPDQ4bNxsNDg4NHEMOGzc2Dg4OGjcbDg4ODRtEDhs3Ng4NDxo3Gw4NDg4bRA4bNzYODQ4bNxsODQ4NHEQOGzc2Dg0OGzcbDg0ODRxEDho4Ng4NDhs3Gw0ODg0cQw8aNzYPDQ4bNxoODg4NHEMOGzc2Dg0PGjcbDg4ODRtEDhs3Ng4NDhs3Gw4NDg4bRA4bNzYODQ4bNxsODQ4NHEQOGjg2Dg0OGzcOD4gPDA8NHEMOGzc2Dg0OGzcbDg0ODhtEDhs3Ng4NDhs3Gw4NDg0cRA4bNzYODQ4bNxsODQ4NHEQOGzY2Dw0OGzcbDQ4ODRxDDhs3Ng4ODhs2Gw4NDw0bRA4bNzYODQ4bNxsODQ4OG0QOGzc2Dg0OGzcbDg0ODRxEDhs3Ng4NDhs3Gw4NDg0cRA4aNzYPDQ4bNxsNDg4NG0QOGzc2Dg4OGjcbDg4ODRxDDhs3Ng4NDhs3Gw4NDg4bRA4bNzYODQ4bNxsODQ4NHEQOGzc2Dg0OGzcbDg0ODRxEDhs2Nw4NDhs3Gw0ODg0cQw8aNzYPDQ4bNhwNDg0OG0QOGzc2Dg0PGjcbDg0ODhtEDhs3Ng4NDhs3Gw4NDg0cRA4bNzYODQ4bNxsODQ4NHEQOGzY3Dg0OGzcbDg0ODRxDDxo3Ng4ODhs3DgAF3AAAAAAAAAAAAAAAAAAA 
  thermorossi_velocita_3:
    sequence:
      - service: remote.send_command
        data:
          entity_id: remote.telecomando_wifi_broadlink_remote
          delay_secs: 2
          command:
            - b64:scA6AvaeBgCHDQ4ODRxEDRw2NikORBwNDg4NG0QOGzc2KQ5EGw4NDg4bRA4bNzYpDkQbDg0ODRxEDhs3NikNRRsODQ4NHEQOGjc3KQ1FGw0ODg0cRA4aODUqDUQbDg4ODRtEDhs3NikORBsODg0OG0QOGzc2KQ5EGw4NDg4bRA4bNzYpDkQbDg0ODRxEDhs2NykNRRsNDg4NHEMPGjc2Kg1FGw0ODg0bRA4bNzYqDUQbDg4ODRtEDhs3NikORBsODg0OG0QOGzc2KQ1FGw4NDg0cRA4bNzYpDUUbDg0ODRxDDxo3NioNRBsODg0OG0QOGzc2Kg1EGw4ODQ4bRA4bNzYpDkQbDg0ODhtEDhs3NikNRRsODQ4NHEQOGzY3KQ1FDg+IDg0PDRxDDhs3NikORBsODQ4OG0QOGzc2KQ5EGw4NDg0cRA4bNzYpDUUbDg0ODRxEDho3NioNRBwNDg4NHEMOGzc2Kg1EGw4ODQ4bRA4bNzYpDkQbDg0ODhtEDhs3NikORBsODQ4NHEQOGzc3KA1FGw4NDg0cRA4bNzYpDUUbDQ4ODRxDDxo3NioNRBwNDg0OG0QOGzc2Kg1EGw4ODQ4bRA4bNzYpDkQbDg0ODhtEDhs3NikNRRsODQ4NHEQOGzY3KQ1FGw0ODg0cRA4aNzcpDUQcDQ4ODRtEDhs3NioNRBsODg0OG0QOGzc2KQ5EGw4NDg4bRA4bNzYpDUUbDg0ODhtEDhs2NykNRRsODQ4NHEQOGjc2Kg1EDwAF3AAAAAAAAAAAAAAAAA==
            - b64:scA4AtieBgANDg4bRA4bNjcbKTcbDg0ODRxEDho3NhwpNxoPDQ4NHEMPGjc2HCg3Gw4NDg4bRA4bNzYcKDcbDg0ODRxEDhs3NhwoNxsODQ4NHEQOGzc2Gyk3Gw4NDg0cQw4bNzYcKTcaDg4ODRxDDhs3NhwoNxsODQ8NG0QOGzc2HCg3Gw4NDg4bRA4bNzYbKTcbDg0ODRxEDho3NxspNxsODQ4NHEQOGjc2HCk3Gw4NDg0cQw4bNzYcKDcbDg0PDRtEDhs3NhwoNxsODQ4OG0QOGzc2HCg3Gw4NDg0cRA4bNzYbKTcbDg0ODRxDDxo3NxspNhwNDg4NG0QOGzc2HCk2Gw4ODQ4bRA4bNzYcKDcbDg4NDhtEDhs3NhwoNw4Qhw8NDg0cQw8aNzYcKDcbDg4ODRtEDhs3NhwoNxsODQ4OG0QOGzc2HCg3Gw4NDg0cRA4bNzYbKTcbDg0ODRxEDho4NhspNxsNDg4NHEMPGjc2HCg3Gw4ODg0bRA4bNzYcKDcbDg0ODhtEDhs3NhwoNxsODQ4NHEQOGzc2Gyk3Gw4NDg0cRA4aODYbKTcbDg0ODRxDDxo3NxspNhsODg4NG0QOGzc2HCg3Gw4ODQ4bRA4bNzYcKDcbDg0ODhtEDhs3NhwoNxsODQ4NHEQOGzY3Gyk3Gw0ODg0cQw8aNzYcKTYbDg4ODRtEDhs3NhwoNxsODg0OG0QOGzc2HCg3Gw4ODg0bRA4bNzYcKDcbDg0ODRxEDhs2NxspNw4ABdwAAAAAAAAAAAAAAAAAAA== 
  thermorossi_velocita_4:
    sequence:
      - service: remote.send_command
        data:
          entity_id: remote.telecomando_wifi_broadlink_remote
          delay_secs: 2
          command:
            - b64:scCKAradBgCHDg4NDhtEDhs2Nw4NDg5EGw4NDg0cRA4bNjcODQ4NRBwODQ4NHEMPGjc2Dw0ODUQbDg4ODRtEDhs3Ng4NDw1EGw4NDg4bRA4bNzYODQ4ORBsODQ4OG0QOGzc2Dg0ODUUbDg0ODRxEDhs2Nw4NDg1FGw0ODg0cQw8aNzcNDg4NRBsODg4NG0QOGzc2Dg4ODUQbDg4NDhtEDhs3Ng4NDg5EGw4NDg4bRA4bNzYODQ4ORBsODQ4OG0QOGzc2Dg0ODUUbDg0ODRxEDhs2Nw0ODg1FGg4ODg0cQw8aNzYODg4NRBsODg0OG0QOGzc2Dg0ODkQbDg4NDhtEDhs3Ng4NDg5EGw4NDg4bRA4bNjcODQ4NRRsODQ4NHEQOGzY3DQ4ODUQcDQ4ODRxDDxo3Ng4ODg1EGw4NDw0bRA4bNzYODg0ORA4QiA4NDg0cRA4aNzcODQ4NRRsODQ4NHEMPGjc2Dg4ODUQbDg4ODRtEDhs3Ng4NDw1EGw4ODQ4bRA4bNzYODQ4NRRsODQ4OG0QOGzc2Dg0ODUUbDg0ODRxEDhs2Nw4NDg1FGg8NDg0cQw8aNzcNDg4NRBsODg4NG0QOGzc2Dg4ODUUaDg0PDRtEDhs3Ng4NDg5EGw4NDg4bRA4bNzYODQ4NRRsODQ4NHEQOGzc2Dg0ODUUbDg0ODRxEDho3Ng4ODg1FGg4ODg0cQw4bNzYODg4NRBsODg0OG0QOGzc2Dg4ODUQbDg0ODhtEDhs3Ng4NDg1FGw4NDg0cRA4aODYODQ4NRRsODQ4NHEMPGjc2Dw0ODUUbDg0ODRxDDhs3Ng4ODg1FGg4NDw0cQw4bNzYODQ4ORBsODQ4NHEQOGzc2Dg0ODUUOAAXcAAAAAAAAAAAAAAAA
            - b64:scA4AtieBgANDg4bRA4bNjcbKTcbDg0ODRxEDho3NhwpNxoPDQ4NHEMPGjc2HCg3Gw4NDg4bRA4bNzYcKDcbDg0ODRxEDhs3NhwoNxsODQ4NHEQOGzc2Gyk3Gw4NDg0cQw4bNzYcKTcaDg4ODRxDDhs3NhwoNxsODQ8NG0QOGzc2HCg3Gw4NDg4bRA4bNzYbKTcbDg0ODRxEDho3NxspNxsODQ4NHEQOGjc2HCk3Gw4NDg0cQw4bNzYcKDcbDg0PDRtEDhs3NhwoNxsODQ4OG0QOGzc2HCg3Gw4NDg0cRA4bNzYbKTcbDg0ODRxDDxo3NxspNhwNDg4NG0QOGzc2HCk2Gw4ODQ4bRA4bNzYcKDcbDg4NDhtEDhs3NhwoNw4Qhw8NDg0cQw8aNzYcKDcbDg4ODRtEDhs3NhwoNxsODQ4OG0QOGzc2HCg3Gw4NDg0cRA4bNzYbKTcbDg0ODRxEDho4NhspNxsNDg4NHEMPGjc2HCg3Gw4ODg0bRA4bNzYcKDcbDg0ODhtEDhs3NhwoNxsODQ4NHEQOGzc2Gyk3Gw4NDg0cRA4aODYbKTcbDg0ODRxDDxo3NxspNhsODg4NG0QOGzc2HCg3Gw4ODQ4bRA4bNzYcKDcbDg0ODhtEDhs3NhwoNxsODQ4NHEQOGzY3Gyk3Gw0ODg0cQw8aNzYcKTYbDg4ODRtEDhs3NhwoNxsODg0OG0QOGzc2HCg3Gw4ODg0bRA4bNzYcKDcbDg0ODRxEDhs2NxspNw4ABdwAAAAAAAAAAAAAAAAAAA== 
  thermorossi_spegni:
    sequence:
      - service: remote.send_command
        data:
          entity_id: remote.telecomando_wifi_broadlink_remote
          command:
            - b64:scCwBOKeBgAaDg0ODhtEDhs3NjwINhwODQ4NHEQNGzc2Nw42Gw4ODg0bRA4bNzY3DTcbDg4NDhtEDhs3NjcNNxsODQ4OG0QOGzc2Nw03Gw4NDg0cRA4bNzY3DTcbDg0ODRxEDho3NjcONhwNDg4NHEMOGzc2Nw03Gw4NDg4bRA4bNzY3DTcbDg0ODhtEDhs3NjcNNxsODQ4NHEQOGzc2Nw03Gw0ODg0cQw8aNzY3DjcbDQ4ODRtEDhs3NjcONxoODg4NG0QOGzc2Nw03Gw4ODQ4bRA4bNzY3DTcOD4gODg4NHEMPGjc2Nw03Gw4ODg0bRA4bNzY3DTcbDg4NDhtEDhs3NjcNNxsODQ4NHEQOGzc2Nw03Gw0ODg0cQw8aNzc2DjcbDg0ODRtEDhs3NjcONhwNDg4NG0QOGzc2Nw03Gw4ODQ4bRA4bNzY3DTcbDg0ODhtEDhs3NjcNNxsODQ4NHEQOGjg2Ng43Gw0ODg0cQw8aNzY3DjcaDg4ODRtEDhs3NjcNNxsODg0OG0QOGzg1Nw03Gw4NDg0cRA4bNzY3DTcbDg0ODRxEDhs3NjYONxsNDg4NHEQOGjc2Nw42Gw4ODQ4bRA4bNzY3DjYbDg4NDhtEDhs3NjcNNxsODQ4OG0QOGzc2Nw03Gw4NDg0cRA4bNzY2DjcO84gODQ4NHEQOGzY3Nw03Gg8NDg0cRA4aNzc2DjYcDQ4NDhtEDhs3NjcONhsODg0OG0QOGzc2Nw03Gw4ODQ4bRA4bNzY3DTcbDg0ODhtEDhs2NzYONhwODQ4NHEQOGjc3Ng42HA0ODg0cQw8aNzY3DjYbDg4NDhtEDhs3NjcONhsODQ4OG0QOGzc2Nw03Gw4NDg4bRA4bNzY3DTcbDg0ODRxEDhs2NzYONhwNDg4NHEMPGjc2Nw42Gw4ODQ4bRA4bNzY3DjYbDg4ODRtEDhs3NjcNNxsODQ4OG0QOGzc2Nw03Gw4NDg0cRA4bNjc2DjcbDg0ODRxEDho3NzYONhsODg4NG0QPGjc2Nw42Gw4NDg4bRA4bNzY3DTcOD4gPDQ4NHEMPGjc3Ng42Gw4ODg0bRQ0bNzc2DjYbDg4NDhtEDhs3NjcNNxsODg0OG0QOGzc2Nw03Gw4NDg4bRA4bNjc3DTcbDg0ODRxEDho3NzYONhwNDg4NHEMOGzc2Nw42Gw4ODQ4bRA4bNzY3DTcbDg4NDhtEDhs3NjcNNxsODQ4OG0QOGzY3Nw03Gw4NDg0cRA4bNjc2DjYcDQ4ODRxDDxo3NjcONhsODg0OG0QOGzc2Nw42Gw4ODQ4bRA4bNzY3DTcbDg0ODhtEDhs3NjcNNxsODQ4OG0QOGzY3Ng43Gw0ODg0cQw4bNzY3DjYcDQ4ODRxDDhs4NTcONhsODg0OG0QOGzc2Nw03Gw4NDg4bRA4bNzY3DTcO84gODQ4OG0QOGzc2Nw03Gw4NDg0cRA4bNjc3DTcbDg0ODRxEDho3NjcONxsNDg4NG0QOGzc2Nw03Gw4ODQ4bRA4bNzY3DTcbDg0ODhtEDhs3NjcNNxsODQ4NHEQOGzc2Nw03Gw4NDg0cRA4aNzY3DjcbDg0ODRtEDhs3NjgNNxoODg0OG0QOGzc2NwAAAAAAAA==

Fans

I can’t figure out how I can link the various buttons to the script:

Low --> Thermorossi_velocita_1
Med --> Thermorossi_velocita_2
Hmi --> Thermorossi_velocita_3
High --> Thermorossi_velocita_4
Off --> Thermorossi_spegni

Can anyone help me?

hay bro

just wrote this

mite point you down the right path

Maybe it is a dumb question, maybe not… but can I use this card for a Central Ventilation Unit (Itho CVE) with 3 speeds (no off setting)?

It’s been awhile since I visited this thread put I recently noticed a sh#t ton of errors that are apparently emanating from this resource in my log file as follows:

http://192.168.1.126:8123/local/fan-control-entity-row.js:191:25 Uncaught TypeError: Cannot read property ‘state’ of undefined

Is anyone else experiencing this? Any idea how to fix it?

I get those occassionally for some other entities but never my fan controls.

I believe it’s only when you are restarting HA and not everything has completely initialized yet. Or I guess your devices could be dropping off HA and the entity will then be undefined.

If so it’s not really something that I can control.

Does the control still work as expected?

It does work as expected, it just seems weird that I see over 250+ errors? I’ll keep an eye on it. Thanks for the quick response! Appreciate it!

disregard, answered above.

Is there a need to setup input_boolean entities in Helpers for this to work? I’ve used the code posted by @tscibilia and modified it for my 5 speed tuya fan. I have a fan template to do the service calls to the fan, which works fine. But the card doesn’t do anything when I click on any of the speed buttons.

Did you manage to fix it somehow?
I am at the same point as you.

I’ve been using this card for a while but it seems 2023.5 breaks it. I tried the beta but rolled back when I saw the issue. Anyone having issues with this after the latest May update?

During the pre-2023.5 releases we got warned about the Polymer component that is listed for deprecation.

If you check your logs you may find:

Logger: frontend.js.latest.202305031
Source: components/system_log/__init__.py:257
First occurred: 10:11:54 AM (1 occurrences)
Last logged: 10:11:54 AM

https://hass.<domain>/local/custom-fan-card.js:1:29 Uncaught ReferenceError: Polymer is not defined

In the dashboard it shows:
image

I think we have to come up with another custom JS file to make the buttons work for the fans.

1 Like

Here is a HACS repo with a 6 speed button row for Modern Forms fans. I simplified the code quite a bit so it could be easily modified if need be. Let me know if this helps.

Hey BrianHumlicek,
thanks for the repo! I haven’t gone into depth on programming in Home Assistant, do you have any scripts written for this? Also, do you have to create any templates? I tried creating a fan template but i’m getting confused with interacting your code and the template. Any help would be greatly appreciated!