Fan Control / Set speed - Working Quick setup

I have this working on my HASSIO system, but I can’t get the buttons to change colors as I’d prefer. I’m using the html code that undertoe posted in post 3 with the addition added by jonmayer in post 14.

No matter what state the fan is in the “off” is highlighted and no other button. While the fan is on low, medium, or high, the “off” button remains highlighted and no other button changes state. I’d prefer to have the button highlight for the state the fan is in. Can this be done?

fan

My Configuration.yaml has:

  customize_glob: 
    fan.*:
      custom_ui_state_card: state-card-custom-fanspeed

customizer:
  custom_ui: local

frontend:
  extra_html_url:
    - /local/custom_ui/state-card-custom-fanspeed.html
  extra_html_url_es5:
    - /local/custom_ui/state-card-custom-fanspeed.html

fan:
  - platform: mqtt  
    name: "Master Bedroom Fan"
    command_topic: "cmnd/BedRoomFan/FanSpeed"
    speed_command_topic: "cmnd/BedRoomFan/FanSpeed"    
    state_topic: "stat/BedRoomFan/RESULT"
    speed_state_topic: "stat/BedRoomFan/RESULT"
    #state_value_template: "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}"
    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.master_bedroom_fan.state == 'off' -%}0{%- elif states.fan.master_bedroom_fan.state == 'on' -%}4{%- endif %}
      {% endif %}
    speed_value_template: "{{ value_json.FanSpeed }}"
    #speed_value_template: "{% if value_json.FanSpeed == 0 -%}off{%- elif value_json.FanSpeed > 0 -%}{{ value_json.FanSpeed }}{%- endif %}"
    availability_topic: tele/BedRoomFan/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:
      - low
      - medium
      - high

It looks like yours is pretty close to mine but…

Read down a couple of posts past #14 for the discussion about what I ultimately did to the code.

And look at the post right above this and add a speed of “- off”.

Once that’s done i think it should work. At least mine does.

Thanks for the reply. Sorry for my delay, my wife and I had a new daughter on Monday so I’ve been a little busy! :smiley:

I added the -off to my config

fan:
  - platform: mqtt  
    name: "Master Bedroom Fan"
    command_topic: "cmnd/BedRoomFan/FanSpeed"
    speed_command_topic: "cmnd/BedRoomFan/FanSpeed"    
    state_topic: "stat/BedRoomFan/RESULT"
    speed_state_topic: "stat/BedRoomFan/RESULT"
    #state_value_template: "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}"
    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.master_bedroom_fan.state == 'off' -%}0{%- elif states.fan.master_bedroom_fan.state == 'on' -%}4{%- endif %}
      {% endif %}
    speed_value_template: "{{ value_json.FanSpeed }}"
    #speed_value_template: "{% if value_json.FanSpeed == 0 -%}off{%- elif value_json.FanSpeed > 0 -%}{{ value_json.FanSpeed }}{%- endif %}"
    availability_topic: tele/BedRoomFan/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

And made the newVal.state change to state-card-custom-fanspeed.html

 stateObjChanged: function (newVal) {
            if (newVal) {
              if (newVal.state == 'off') {
                this.statusValue = 'off';
                this.btnOffstyle = 'background-color: #42d9f4;';
                this.btnLowstyle = '';
                this.btnMedstyle = '';
                this.btnHighstyle = '';
                this.updateStyles({'--status-text-color': 'gray'});
              } else if (newVal.state == 'low') {
                this.statusValue = 'low';
                this.btnOffstyle = '';
                this.btnLowstyle = 'background-color: #42d9f4;';
                this.btnMedstyle = '';
                this.btnHighstyle = '';    
                this.updateStyles({'--status-text-color': 'blue'});       
              } else if (newVal.state == 'medium') {
                this.statusValue = 'medium';
                this.btnOffstyle = '';
                this.btnLowstyle = '';
                this.btnMedstyle = 'background-color: #42d9f4;';
                this.btnHighstyle = '';
                this.updateStyles({'--status-text-color': 'yellow'});
              } else if (newVal.state == 'high') {
                this.statusValue = 'high';
                this.btnOffstyle = '';
                this.btnLowstyle = '';
                this.btnMedstyle = '';
                this.btnHighstyle = 'background-color: #42d9f4;';
                this.updateStyles({'--status-text-color': 'red'});

I also removed the “ha-entity-toggle state-obj…” code from the HTML file that was posted in posted 14. Removing this line removed my toggle buttom, so now I just have buttons for the 3 speeds plus an off button. But the states/colors of the buttons still don’t change when I change the fan speed.

Any chance this is an issue with MQTT not reporting the fan mode/speed?

Before you read on look at the EDIT toward the end for what the real problem might be… if not then come back to the top…:smiley:

You can run an MQTT sniffer on your network to check to make sure that the messages are being sent.

Just in case it’s something in your code, here is my complete working html code:

<dom-module id="state-card-custom-fanspeed">
  <template>
    <style is="custom-style" include="iron-flex iron-flex-alignment"></style>
    <style>
      :host {
        line-height: 1.5;
      }
      paper-button {
		    min-width: 30px;
		    height: 30px;
		    margin: 2px;  
		    background-color:#f3f3f3;
		    border: 1px solid lightgrey; 
		    font-size: 10px !important;
		    float: right !important;   	
      }
    </style>
		<div class='horizontal justified layout'>
		  <state-info state-obj="[[stateObj]]"></state-info>
		  <paper-button-group>
		      <paper-button style="[[btnOffstyle]]" on-click='handleOffTap'>Off</paper-button>
		      <paper-button style="[[btnLowstyle]]" on-click='handleLowTap'>Low</paper-button>
		      <paper-button style="[[btnMedstyle]]" on-click='handleMedTap'>Med</paper-button>
		      <paper-button style="[[btnHighstyle]]" on-click='handleHighTap'>High</paper-button>
		  </paper-button-group>
		  <!--<ha-entity-toggle state-obj='[[stateObj]]' hass='[[hass]]' in-dialog='[[inDialog]]'></ha-entity-toggle>-->
		</div>
</template>
</dom-module>
<script>
        Polymer({
          is: 'state-card-custom-fanspeed',
          properties: {
            hass: {
              type: Object,
            },
            stateObj: {
              type: Object,
              observer: 'stateObjChanged',
            },
            statusValue: {
              type: String,
              value: 'Unset',
            },
            btnOffstyle: {
              type: String,
              value: '',
            },
            btnHighstyle: {
              type: String,
              value: '',
            },
            btnMedstyle: {
              type: String,
              value: '',
            },
            btnLowstyle: {
              type: String,
              value: '',
            },
          },
          stateObjChanged: function (newVal) {
            if (newVal) {
              if (newVal.state == 'off') {
                this.statusValue = 'off';
                this.btnOffstyle = 'background-color: #42d9f4;';
                this.btnLowstyle = '';
                this.btnMedstyle = '';
                this.btnHighstyle = '';
                this.updateStyles({'--status-text-color': 'gray'});
              } else if (newVal.attributes.speed == 'low') {
                this.statusValue = 'low';
                this.btnOffstyle = '';
                this.btnLowstyle = 'background-color: #42d9f4;';
                this.btnMedstyle = '';
                this.btnHighstyle = '';    
                this.updateStyles({'--status-text-color': 'blue'});       
              } else if (newVal.attributes.speed == 'medium') {
                this.statusValue = 'medium';
                this.btnOffstyle = '';
                this.btnLowstyle = '';
                this.btnMedstyle = 'background-color: #42d9f4;';
                this.btnHighstyle = '';
                this.updateStyles({'--status-text-color': 'yellow'});
              } else if (newVal.attributes.speed == 'high') {
                this.statusValue = 'high';
                this.btnOffstyle = '';
                this.btnLowstyle = '';
                this.btnMedstyle = '';
                this.btnHighstyle = 'background-color: #42d9f4;';
                this.updateStyles({'--status-text-color': 'red'});
              }              
            }
          },
        	handleHighTap: function (ev) {
						this.setSpeed(ev, 'high');
          },
        	handleMedTap: function (ev) {
						this.setSpeed(ev, 'medium');
          },
        	handleLowTap: function (ev) {
						this.setSpeed(ev, 'low');
          },
        	handleOffTap: function (ev) {
            this.setSpeed(ev, 'off');
          },
          setSpeed: function (ev, setspeed ) {
          	if( setspeed == 'off' ){
							var serviceData = {entity_id: this.stateObj.entity_id};
            	this.hass.callService('fan', 'turn_off', serviceData);          		
          		
          	} else {
          		if (this.stateObj.state != 'on'){
								var serviceData = {entity_id: this.stateObj.entity_id, speed: setspeed };
            		this.hass.callService('fan', 'turn_on', serviceData );          			
          		}else{
          			var serviceData = {entity_id: this.stateObj.entity_id, speed: setspeed };
          			this.hass.callService('fan', 'set_speed', serviceData );
          		}
          	}
          	 ev.stopPropagation();
          },
         
});
</script>

Try copying this code into your “state_card_custom_fanspeed.html” file (make a backup of your existing file first!) and see if it works.

And just to be sure it’s not something that’s missing from your yaml copy mine over exactly as I posted above and replace with your details.

EDIT----

And after I just typed all of this out I went back and reviewed your yaml code and noticed that it looks like you didn’t replace my “state_value_template:” section details with your own:

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.**master_bedroom_fan**.state == 'off' -%}0{%- elif states.fan**.master_bedroom_fan**.state == 'on' -%}4{%- endif %}
  {% endif %}

Look at the entity_id for the fan denoted by the ** in the ‘else’ section (there are two of them). Make sure that is actually the entity_id of your fan.

I’m not deleting all of the above in case it can still help you or someone else.

Thanks finity! It must have been something in the html. Copying your html into my file solved it.

My fan entity_id is fan.master_bedroom_fan, so the code in yaml was correct. But that was just by coincidence that I used the same entity_id as you. I wouldn’t have seen that section to replace the entity_id.

Thanks!

1 Like

I cannot seem to get the custom ui to work correctly. I don’t get the 4 buttons. I can change the states, so that is working.

  time_zone: America/New_York
  # Customization file
  customize: !include customize.yaml
  customize_glob: 
    fan.*:
     custom_ui_state_card: state-card-custom-fanspeed
http:
  api_password: !secret http_password
# Show links to resources in log and frontend
# introduction:
customizer:
  custom_ui: local

# Enables the frontend
frontend:

I have also tried the frontend code, but that does not work either. I read not to do both. I refresh CTRL- F5 and have cleared the cache each time I make a change.

fan:
  - platform: mqtt  
    name: "Sonos_Fan_1"
    command_topic: "cmnd/sonoff_fan1/FanSpeed"
    speed_command_topic: "cmnd/sonoff_fan1/FanSpeed"    
    state_topic: "stat/sonoff_fan1/RESULT"
    speed_state_topic: "stat/sonoff_fan1/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.Sonos_Fan_1.state == 'off' -%}0{%- elif states.fan.Sonos_Fan_1.state == 'on' -%}4{%- endif %}
      {% endif %}
    speed_value_template: "{{ value_json.FanSpeed }}"
    availability_topic: tele/sonoff_fan1/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
light:
  - platform: mqtt
    name: "Ceiling Light 1"
    command_topic: "cmnd/sonoff_fan1/power1"
    state_topic: "stat/sonoff_fan1/POWER1"
    availability_topic: tele/sonoff_fan1/LWT
    payload_available: Online
    payload_not_available: Offline
    qos: 1
    payload_off: "OFF"
    payload_on: "ON"
    retain: false 

I have copied the state-card-custom-fanspeed.html and have it in \www\custom_ui\

Any ideas? Thanks

Did you put the proper code into your configuration.yaml file under the “frontend:” section?

If so then try copying my html code from post #23 above into your file. It has a couple of modifications in it.

Also doing a Shift - Refresh (forced reload) is needed to reload the base HTML - CSS

I am learning…therefore, I make mistakes. My state-card-custom-fanspeed.html file had a space in front of the file name. I am not sure how, or why this happened, but I found a link to it that had the %20 in front of the file name. Removed that, and all is well. I appreciate your help, and for others, watch your space bar :slight_smile:

Hello
You have done great work. And thankx for that. I make this work in the hassio. And now i have a question. Is it posible do implement this buttons in to lovelance too.
By

I second this request for the same information!

Thanks! I have yet to run lovelace. But i am sure it can be done.

you might want to start getting ready for it. :smile: it’s going to be the default in the near future.

I love this interface for Tasmota iFan02. Has anyone done any modifications to better support frontend colour themes? eg, setting the UI to any of the night time themes with dark backgrounds makes the fan speed buttons hard to read.
Thanks

as a matter of fact I have! :wink:

I changed the following lines:

line 12: background-color:#546E7A;
line 65: this.btnOffstyle = ‘background-color: #42d9f4;’;
line 73: this.btnLowstyle = ‘background-color: #42d9f4;’;
line 81: this.btnMedstyle = ‘background-color: #42d9f4;’;
line 89: this.btnHighstyle = ‘background-color: #42d9f4;’;

I have “slate” as the theme and this is how mine looks now:

ex

I can’t remember if I changed the theme at all tho so it might be a bit different.

Hi, but this is under the old frontend or under Lovelace?

that is from the old frontend…

I don’t think anyone has figured out how to adapt this to Lovelace yet.

But if anyone has it would sure be appreciated! :slightly_smiling_face:

Just as an FYI I piggybacked onto the work by another member to get a working functionally equivalent custom card to this component to use in Lovelace.

You can find the info needed in this post:

1 Like

Updated this from custom-ui to lovelace

Modified code from finity

Add this to your www/ folder called fan-control-row.js

class FanControlRow 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;
									margin-left: 4px;
                  margin-right: 4px;
									background-color: #d1d4d5;
               	 	border: 1px solid lightgrey; 
                	font-size: 10px !important;
                	float: right !important;   
                }       
       			</style>
            <hui-generic-entity-row hass="[[hass]]" config="[[_config]]">
                <div class='horizontal justified layout' on-click="stopPropagation">
                    <paper-button
                        class='speed'
												style='[[_highOnColor]]'
                        toggles name="high"
                        on-tap='setSpeed'
                        disabled='[[_isOnHigh]]'>HIGH</paper-button>
                    <paper-button
                        class='speed'
												style='[[_medOnColor]]'
                        toggles name="medium"
                        on-tap='setSpeed'
                        disabled='[[_isOnMed]]'>MED</paper-button>
                        
                    <paper-button
                        class='speed'
												style='[[_lowOnColor]]'
                        toggles name="low"
                        on-tap='setSpeed'
                        disabled='[[_isOnLow]]'>LOW</paper-button>

								    <paper-button
				             		class='speed'
												style='[[_offColor]]'
				               	toggles name="off"
				               	on-tap='setSpeed'
				             		disabled='[[_isOffState]]'>OFF</paper-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: #03a9f4; color:black;';
			} else {
				lowcolor = '';
			}
			
			if (med == 'on') {
				medcolor = 'background-color: #03a9f4; color:black;';
			} else {
				medcolor = '';
			}
			
			if (high == 'on') {
				hicolor = 'background-color: #03a9f4; color:black;';
			} else {
				hicolor = '';
			}
			
			if (offstate == 'on') {
				offcolor = 'background-color: #ffd1d4; color: #a0898b;';
			} 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('fan-control-row', FanControlRow);

Activate in your ui-lovelace.yaml at the top in resources: section

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

Turn on the custom display for any fan entity

type: custom:fan-control-row
entity: fan.ge_12730_fan_control_switch_level_4

hass-lovelace-fan

1 Like

Good day and well done on the great work. I have just migrated to Lovelace.
Where do I find the www folder ?