├── button-row-example-compare.gif ├── default_fan_ex.gif ├── dist └── fan-control-entity-row.js ├── hacs,json ├── info.md ├── readme.md └── slate_fan_ex.gif /button-row-example-compare.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finity69x2/fan-control-entity-row/d09c3fce36c314f618d05324bdeda5b188bd0e83/button-row-example-compare.gif -------------------------------------------------------------------------------- /default_fan_ex.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finity69x2/fan-control-entity-row/d09c3fce36c314f618d05324bdeda5b188bd0e83/default_fan_ex.gif -------------------------------------------------------------------------------- /dist/fan-control-entity-row.js: -------------------------------------------------------------------------------- 1 | window.customCards = window.customCards || []; 2 | window.customCards.push({ 3 | type: "fan-control-entity-row", 4 | name: "fan control entity row", 5 | description: "A plugin to display your fan controls in a button row.", 6 | preview: false, 7 | }); 8 | 9 | class CustomFanRow extends Polymer.Element { 10 | 11 | static get template() { 12 | return Polymer.html` 13 | 14 | 32 | 33 |
34 | 40 | 46 | 52 | 58 |
59 |
60 | `; 61 | } 62 | 63 | static get properties() { 64 | return { 65 | hass: { 66 | type: Object, 67 | observer: 'hassChanged' 68 | }, 69 | _config: Object, 70 | _stateObj: Object, 71 | _width: String, 72 | _height: String, 73 | _leftColor: String, 74 | _midLeftColor: String, 75 | _midRightColor: String, 76 | _rightColor: String, 77 | _leftText: String, 78 | _midLeftText: String, 79 | _midRightText: String, 80 | _rightText: String, 81 | _leftName: String, 82 | _midLeftName: String, 83 | _midRightName: String, 84 | _rightName: String, 85 | _hideLeft: String, 86 | _hideMidLeft: String, 87 | _hideMidRight: String, 88 | _hideRight: String, 89 | _leftState: Boolean, 90 | _midLeftState: Boolean, 91 | _midRightState: Boolean, 92 | _rightState: Boolean, 93 | 94 | } 95 | } 96 | 97 | setConfig(config) { 98 | this._config = config; 99 | 100 | this._config = { 101 | customTheme: false, 102 | sendStateWithSpeed: false, 103 | reverseButtons: false, 104 | isTwoSpeedFan: false, 105 | hideOff: false, 106 | width: '30px', 107 | height: '30px', 108 | isOffColor: '#f44c09', 109 | isOnLowColor: '#43A047', 110 | isOnMedColor: '#43A047', 111 | isOnHiColor: '#43A047', 112 | buttonInactiveColor: '#759aaa', 113 | customOffText: 'OFF', 114 | customLowText: 'LOW', 115 | customMedText: 'MED', 116 | customHiText: 'HIGH', 117 | ...config 118 | }; 119 | } 120 | 121 | hassChanged(hass) { 122 | 123 | const config = this._config; 124 | const stateObj = hass.states[config.entity]; 125 | const custTheme = config.customTheme; 126 | const sendStateWithSpeed = config.sendStateWithSpeed; 127 | const revButtons = config.reverseButtons; 128 | const twoSpdFan = config.isTwoSpeedFan; 129 | const hide_Off = config.hideOff; 130 | const buttonWidth = config.width; 131 | const buttonHeight = config.height; 132 | const custOnLowClr = config.isOnLowColor; 133 | const custOnMedClr = config.isOnMedColor; 134 | const custOnHiClr = config.isOnHiColor; 135 | const custOffSpdClr = config.buttonInactiveColor; 136 | const custOffClr = config.isOffColor; 137 | const custOffTxt = config.customOffText; 138 | const custLowTxt = config.customLowText; 139 | const custMedTxt = config.customMedText; 140 | const custHiTxt = config.customHiText; 141 | 142 | let speed; 143 | if (stateObj && stateObj.attributes) { 144 | speed = stateObj.attributes.speed || 'off'; 145 | } 146 | 147 | let low; 148 | let med; 149 | let high; 150 | let offstate; 151 | 152 | if (stateObj && stateObj.attributes) { 153 | if (stateObj.state == 'on' && stateObj.attributes.speed == 'low') { 154 | low = 'on'; 155 | } else if (stateObj.state == 'on' && stateObj.attributes.speed == 'medium') { 156 | med = 'on'; 157 | } else if (stateObj.state == 'on' && stateObj.attributes.speed == 'high') { 158 | high = 'on'; 159 | } else { 160 | offstate = 'on'; 161 | } 162 | } 163 | 164 | let lowcolor; 165 | let medcolor; 166 | let hicolor; 167 | let offcolor; 168 | 169 | if (custTheme) { 170 | if (low == 'on') { 171 | lowcolor = 'background-color:' + custOnLowClr; 172 | } else { 173 | lowcolor = 'background-color:' + custOffSpdClr; 174 | } 175 | 176 | if (med == 'on') { 177 | medcolor = 'background-color:' + custOnMedClr; 178 | } else { 179 | medcolor = 'background-color:' + custOffSpdClr; 180 | } 181 | 182 | if (high == 'on') { 183 | hicolor = 'background-color:' + custOnHiClr; 184 | } else { 185 | hicolor = 'background-color:' + custOffSpdClr; 186 | } 187 | 188 | if (offstate == 'on') { 189 | offcolor = 'background-color:' + custOffClr; 190 | } else { 191 | offcolor = 'background-color:' + custOffSpdClr; 192 | } 193 | 194 | } else { 195 | 196 | if (low == 'on') { 197 | lowcolor = 'background-color: var(--primary-color)'; 198 | } else { 199 | lowcolor = 'background-color: var(--disabled-text-color)'; 200 | } 201 | 202 | if (med == 'on') { 203 | medcolor = 'background-color: var(--primary-color)'; 204 | } else { 205 | medcolor = 'background-color: var(--disabled-text-color)'; 206 | } 207 | 208 | if (high == 'on') { 209 | hicolor = 'background-color: var(--primary-color)'; 210 | } else { 211 | hicolor = 'background-color: var(--disabled-text-color)'; 212 | } 213 | 214 | if (offstate == 'on') { 215 | offcolor = 'background-color: var(--primary-color)'; 216 | } else { 217 | offcolor = 'background-color: var(--disabled-text-color)'; 218 | } 219 | } 220 | 221 | let offtext = custOffTxt; 222 | let lowtext = custLowTxt; 223 | let medtext = custMedTxt; 224 | let hitext = custHiTxt; 225 | 226 | let buttonwidth = buttonWidth; 227 | let buttonheight = buttonHeight; 228 | 229 | let hiname = 'high'; 230 | let medname = 'medium'; 231 | let lowname = 'low'; 232 | let offname = 'off'; 233 | 234 | let hideoff = 'display:block'; 235 | let hidemedium = 'display:block'; 236 | let nohide = 'display:block'; 237 | 238 | if (twoSpdFan) { 239 | hidemedium = 'display:none'; 240 | } else { 241 | hidemedium = 'display:block'; 242 | } 243 | 244 | if (hide_Off) { 245 | hideoff = 'display:none'; 246 | } else { 247 | hideoff = 'display:block'; 248 | } 249 | 250 | if (revButtons) { 251 | this.setProperties({ 252 | _stateObj: stateObj, 253 | _leftState: offstate == 'on', 254 | _midLeftState: low == 'on', 255 | _midRightState: med == 'on', 256 | _rightState: high == 'on', 257 | _width: buttonwidth, 258 | _height: buttonheight, 259 | _leftColor: offcolor, 260 | _midLeftColor: lowcolor, 261 | _midRightColor: medcolor, 262 | _rightColor: hicolor, 263 | _leftText: offtext, 264 | _midLeftText: lowtext, 265 | _midRightText: medtext, 266 | _rightText: hitext, 267 | _leftName: offname, 268 | _midLeftName: lowname, 269 | _midRightName: medname, 270 | _rightName: hiname, 271 | _hideLeft: hideoff, 272 | _hideMidLeft: nohide, 273 | _hideMidRight: hidemedium, 274 | _hideRight: nohide, 275 | }); 276 | } else { 277 | this.setProperties({ 278 | _stateObj: stateObj, 279 | _leftState: high == 'on', 280 | _midLeftState: med == 'on', 281 | _midRightState: low == 'on', 282 | _rightState: offstate == 'on', 283 | _width: buttonwidth, 284 | _height: buttonheight, 285 | _leftColor: hicolor, 286 | _midLeftColor: medcolor, 287 | _midRightColor: lowcolor, 288 | _rightColor: offcolor, 289 | _leftText: hitext, 290 | _midLeftText: medtext, 291 | _midRightText: lowtext, 292 | _rightText: offtext, 293 | _leftName: hiname, 294 | _midLeftName: medname, 295 | _midRightName: lowname, 296 | _rightName: offname, 297 | _hideRight: hideoff, 298 | _hideMidRight: nohide, 299 | _hideMidLeft: hidemedium, 300 | _hideLeft: nohide, 301 | }); 302 | } 303 | } 304 | 305 | stopPropagation(e) { 306 | e.stopPropagation(); 307 | } 308 | 309 | setSpeed(e) { 310 | const speed = e.currentTarget.getAttribute('name'); 311 | if( speed == 'off' ){ 312 | this.hass.callService('fan', 'turn_off', {entity_id: this._config.entity}); 313 | this.hass.callService('fan', 'set_speed', {entity_id: this._config.entity, speed: speed}); 314 | } else { 315 | if(this._config.sendStateWithSpeed){ 316 | this.hass.callService('fan', 'turn_on', {entity_id: this._config.entity}); 317 | } 318 | this.hass.callService('fan', 'set_speed', {entity_id: this._config.entity, speed: speed}); 319 | } 320 | } 321 | } 322 | 323 | customElements.define('fan-control-entity-row', CustomFanRow); 324 | -------------------------------------------------------------------------------- /hacs,json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Fan Control Entity Row", 3 | "render_readme": true, 4 | "filename": "dist/fan-control-entity-row.js" 5 | } 6 | -------------------------------------------------------------------------------- /info.md: -------------------------------------------------------------------------------- 1 | Changes: 2 | 3 | - v2.0 - added the ability to hide the medium speed button for use with a two speed fan. 4 | 5 | - v1.8 & v1.9 - BREAKING CHANGES! - I modified the options to be consistent with my other control rows and changed the default button order. I also added the option to reverse the button order. See the readme.md for updated coinfiguration options. 6 | 7 | - v1.6 - added the ability to customize the text for the buttons. defaults to "OFF, LOW, MED, HIGH" 8 | 9 | This is an element to add a fan control row to Home Assistant for 3-speed fans. 10 | 11 | It uses the code that can be found in my fan control package @ https://github.com/finity69x2/Home-Assistant/blob/master/packages/fan_package.yaml 12 | 13 | Installation: 14 | 15 | Copy the fan-control-entity-row.js file to the appropriate folder in your Home Assistant Configuration directory (/config/www/). 16 | 17 | Place the following in your "resources" section in your lovelace configuration (updating the localation to where you placed the above file): 18 | 19 | ``` 20 | - url: /local/fan-control-entity-row.js 21 | type: js 22 | ``` 23 | 24 | Then to use this in a card place the following in your entity card: 25 | 26 | 27 | Options: 28 | 29 | | Name | Type | Required | Default | Description | 30 | | --- | --- | --- | --- | --- | 31 | | entity | String | Yes | none | a fan entity_id | 32 | | type | String | Yes | none | custom:fan-control-entity-row | 33 | | name | String | No | none | A custom name for the entity in the row | 34 | | customTheme | Boolean | No | false | set to true to use a custom theme | 35 | | reverseButtons | Boolean | No | false | Set to true to reverse the button order | 36 | | isTwoSpeedFan | Boolean | No | false | Set to true to hide the Medium Speed button | 37 | | hideOff | Boolean | No | false | Set to true to hide the Off button | 38 | | sendStateWithSpeed | Boolean | No | false | Used only for certain firmware that requires the State command be sent with the Speed command | 39 | | width | String | No | 30px | A custom width for the buttons | 40 | | height | String | No | 30px | A custom height for the buttons | 41 | | isOffColor | String | No | '#f44c09' | Sets the color of the 'Off' button if fan is off | 42 | | isOnLowColor | String | No | '#43A047' | Sets the color of the 'Low' button if fan is on low | 43 | | isOnMedColor | String | No | '#43A047' | Sets the color of the 'Med' button if fan is on Medium | 44 | | isOnHiColor | String | No | '#43A047' | Sets the color of the 'Hi' button if fan is on high | 45 | | buttonInactiveColor | String | No | '#759aaa' | Sets the color of the the buttons if that selection is off | 46 | | customOffText | String | No | 'OFF' | Sets the text of the "off" button | 47 | | customLowText | String | No | 'LOW' | Sets the text of the "low" speed button | 48 | | customMedText | String | No | 'MED' | Sets the text of the "medium" speed button | 49 | | customHiText | String | No | 'HIGH' | Sets the text of the "High" speed button | 50 | | state_color | Boolean | No | false | Sets the icon color of the entity to reflect the current state | 51 | 52 | 53 | The values for the colors can be any valid color string in "HEX", "RGB" or by color name. 54 | 55 | The optional "sendStateWithSpeed" config entry is only needed to be set to true if for some reason your fan needs the state command of "on" to be sent along with the desired speed command. As far as I know this is only needed for use with fans flashed with the ESPHome Firmware. 56 | 57 | Comfguration Examples: 58 | 59 | ``` 60 | cards: 61 | - type: entities 62 | title: Fans 63 | show_header_toggle: false 64 | entities: 65 | ## USE THIS CONFIG TO HAVE IT MATCH YOUR THEME ## 66 | - entity: fan.master_bedroom_fan 67 | type: custom:fan-control-entity-row 68 | name: MBR Fan Not Custom 69 | customTheme: false 70 | ## USE THIS CONFIG TO USE A DEFAULT CUSTOM THEME 71 | - entity: fan.sunroom_fan 72 | type: custom:fan-control-entity-row 73 | name: Sunroom Fan Default Custom 74 | customTheme: true 75 | ## USE THIS CONFIG TO USE A 'CUSTOMZED' CUSTOM THEME 76 | - entity: fan.sunroom_fan 77 | type: custom:fan-control-entity-row 78 | name: Sunroom Fan Custom Custom 79 | reverseButtons: true 80 | customTheme: true 81 | isOnLowColor: 'rgb(255, 0, 0)' 82 | isOnMedColor: '#888888' 83 | isOnHiColor: '#222222' 84 | buttonInactiveColor: '#aaaaaa' 85 | isOffColor: 'purple' 86 | ## USE THIS CONFIG FOR USE WITH THE ESPHOME FIRMWARE (ALONG WITHE THE THEME SETTING ABOVE IF DESIRED) 87 | - entity: fan.master_bedroom_fan 88 | type: custom:fan-control-entity-row 89 | name: MBR Fan Not Custom 90 | sendStateWithSpeed: true 91 | ## USE THIS CONFIG TO SET CUSTOM BUTTON TEXT (NOT REQUIRED TO SET "customTheme: true" TO USE THESE ) 92 | - entity: fan.sunroom_fan 93 | type: custom:fan-control-entity-row 94 | name: Sunroom Fan Custom Custom 95 | customHiText: me 96 | customLowText: do 97 | customMedText: re 98 | customOffText: not 99 | width: '15px' 100 | height: '15px' 101 | ``` 102 | 103 | This is with the default Lovelace frontend theme set: 104 | 105 | ![Default](default_fan_ex.gif) 106 | 107 | 108 | This is with the "Slate" frontend theme set: 109 | 110 | ![Slate](slate_fan_ex.gif) 111 | 112 | This is how this plugin looks with the Light Brightness Preset & Binary Button Rows: 113 | 114 | ![Slate-Compare](button-row-example-compare.gif) 115 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Fan Control Entity Row 2 | 3 | ## This is an element to add a fan control row to Home Assistant. 4 | 5 | ## This plugin is only valid for use with fans that still use a speed list in the fan configuration. That fan control model is deprecated in versions of Home Assistant 2021.3.x and later. For HA versions 2021.3.x and later use fan-percent-button-row or fan-mode-button-row if your fan has been updated to use the new control methods. 6 | 7 | ## https://github.com/finity69x2/fan-percent-button-row 8 | 9 | ## https://github.com/finity69x2/fan-mode-button-row 10 | 11 | It uses the code that can be found in my fan control package @ https://github.com/finity69x2/Home-Assistant/blob/master/packages/fan_package.yaml 12 | 13 | UPDATE: 14 | 15 | I've added the ability to hide the medium speed button to turn it into a two speed fan control, as well. To use it in this mode then your fan speeds must be designated low and high since it simply removes the medium speed button. 16 | 17 | Installation: 18 | 19 | The easiest way to install this is to use the Home Assistant Community Store (HACS) in Home Assistant. 20 | 21 | Follow the instructions there for installation making sure you note the "url:" section for the resources addition. 22 | 23 | Conversely, if you don't use HACS you can install it manually by performing the following: 24 | 25 | Copy the fan-control-entity-row.js file to the appropriate folder in your Home Assistant Configuration directory (/config/www/). 26 | 27 | Place the following in your "resources" section in your lovelace configuration (updating the localation to where you placed the above file): 28 | 29 | ```yaml 30 | - url: /local/fan-control-entity-row.js 31 | type: module 32 | ``` 33 | 34 | Then to use this in a card place the following in your entity card: 35 | 36 | 37 | Options: 38 | 39 | | Name | Type | Required | Default | Description | 40 | | --- | --- | --- | --- | --- | 41 | | entity | String | Yes | none | a fan entity_id | 42 | | type | String | Yes | none | custom:fan-control-entity-row | 43 | | name | String | No | none | A custom name for the entity in the row | 44 | | customTheme | Boolean | No | false | set to true to use a custom theme | 45 | | reverseButtons | Boolean | No | false | Set to true to reverse the button order | 46 | | isTwoSpeedFan | Boolean | No | false | Set to true to hide the Medium Speed button | 47 | | hideOff | Boolean | No | false | Set to true to hide the Off button | 48 | | sendStateWithSpeed | Boolean | No | false | Used only for certain firmware that requires the State command be sent with the Speed command | 49 | | width | String | No | 30px | A custom width for the buttons | 50 | | height | String | No | 30px | A custom height for the buttons | 51 | | isOffColor | String | No | '#f44c09' | Sets the color of the 'Off' button if fan is off | 52 | | isOnLowColor | String | No | '#43A047' | Sets the color of the 'Low' button if fan is on low | 53 | | isOnMedColor | String | No | '#43A047' | Sets the color of the 'Med' button if fan is on Medium | 54 | | isOnHiColor | String | No | '#43A047' | Sets the color of the 'Hi' button if fan is on high | 55 | | buttonInactiveColor | String | No | '#759aaa' | Sets the color of the the buttons if that selection is off | 56 | | customOffText | String | No | 'OFF' | Sets the text of the "off" button | 57 | | customLowText | String | No | 'LOW' | Sets the text of the "low" speed button | 58 | | customMedText | String | No | 'MED' | Sets the text of the "medium" speed button | 59 | | customHiText | String | No | 'HIGH' | Sets the text of the "High" speed button | 60 | | state_color | Boolean | No | false | Sets the icon color of the entity to reflect the current state | 61 | 62 | 63 | The values for the colors can be any valid color string in "HEX", "RGB" or by color name. 64 | 65 | *NOTE: The speeds that your fan uses in Home Assistant need to use all lowercase letters. The only time this should be a concern is if you are using a template fan. Be sure to make your speeds all lowercase in the fan configuration. 66 | 67 | The optional "sendStateWithSpeed" config entry is only needed to be set to true if for some reason your fan needs the state command of "on" to be sent along with the desired speed command. As far as I know this is only needed for use with fans flashed with the ESPHome Firmware. 68 | 69 | Comfguration Examples: 70 | 71 | ```yaml 72 | cards: 73 | - type: entities 74 | title: Fans 75 | show_header_toggle: false 76 | entities: 77 | ## USE THIS CONFIG TO HAVE IT MATCH YOUR THEME ## 78 | - entity: fan.master_bedroom_fan 79 | type: custom:fan-control-entity-row 80 | name: MBR Fan Not Custom 81 | customTheme: false 82 | ## USE THIS CONFIG TO USE A DEFAULT CUSTOM THEME 83 | - entity: fan.sunroom_fan 84 | type: custom:fan-control-entity-row 85 | name: Sunroom Fan Default Custom 86 | customTheme: true 87 | ## USE THIS CONFIG TO USE A 'CUSTOMZED' CUSTOM THEME 88 | - entity: fan.sunroom_fan 89 | type: custom:fan-control-entity-row 90 | name: Sunroom Fan Custom Custom 91 | reverseButtons: true 92 | customTheme: true 93 | isOnLowColor: 'rgb(255, 0, 0)' 94 | isOnMedColor: '#888888' 95 | isOnHiColor: '#222222' 96 | buttonInactiveColor: '#aaaaaa' 97 | isOffColor: 'purple' 98 | ## USE THIS CONFIG FOR USE WITH THE ESPHOME FIRMWARE (ALONG WITHE THE THEME SETTING ABOVE IF DESIRED) 99 | - entity: fan.master_bedroom_fan 100 | type: custom:fan-control-entity-row 101 | name: MBR Fan Not Custom 102 | sendStateWithSpeed: true 103 | ## USE THIS CONFIG TO SET CUSTOM BUTTON TEXT (NOT REQUIRED TO SET "customTheme: true" TO USE THESE ) 104 | - entity: fan.sunroom_fan 105 | type: custom:fan-control-entity-row 106 | name: Sunroom Fan Custom Custom 107 | customHiText: me 108 | customLowText: do 109 | customMedText: re 110 | customOffText: not 111 | width: '15px' 112 | height: '15px' 113 | ``` 114 | 115 | This is with the default Lovelace frontend theme set: 116 | 117 | ![Default](default_fan_ex.gif) 118 | 119 | 120 | This is with the "Slate" frontend theme set: 121 | 122 | ![Slate](slate_fan_ex.gif) 123 | 124 | This is how this plugin looks with the Light Brightness Preset & Binary Button Rows: 125 | 126 | ![Slate-Compare](button-row-example-compare.gif) 127 | -------------------------------------------------------------------------------- /slate_fan_ex.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/finity69x2/fan-control-entity-row/d09c3fce36c314f618d05324bdeda5b188bd0e83/slate_fan_ex.gif --------------------------------------------------------------------------------