wmmudde1
(Wmmudde)
November 29, 2023, 7:43pm
5662
I need some help with addind a red/warm spinning fan when my AC is on heat mode in stead of cooling mode. (blue)
This is the original code:
icon_fan2:
styles:
custom_fields:
icon:
- width: 75%
- margin-left: -3%
custom_fields:
icon: >
[[[
let path = `
<circle cx="25" cy="25" r="6.6"/>
<path d="M31.9 30.4c-.5.6-1.1 1.1-1.7 1.5-1.4 1.1-3.2 1.7-5.2 1.7-2.3 0-4.5-.9-6-2.4-.9 1.1-1.6 2.3-2.3 3.2l-4.9 5.4c-1.8 2.7.3 5.6 2.5 7 3.9 2.4 9.8 3.1 14.1 1.9 4.6-1.3 7.9-4.7 7.4-9.7-.2-3.4-1.9-6-3.9-8.6zM17 28.3c-.4-1-.6-2.1-.6-3.3a8.7 8.7 0 0 1 6.4-8.4l-1.6-3.5L19 6.2c-1.5-2.8-5-2.5-7.3-1.2-4 2.2-7.5 6.9-8.7 11.3-1.2 4.6.2 9.2 4.7 11.3 3.1 1.3 6.1 1.2 9.3.7zm26.9-17.6c-3.3-3.4-8-4.6-12.1-1.8-2.8 1.8-4.2 4.6-5.5 7.5 4.2.6 7.4 4.2 7.4 8.6 0 .9-.1 1.7-.4 2.5 1.3.2 2.8.3 3.8.4 2.3.4 4.7 1.3 7.1 1.7 3.2.3 4.7-3 4.8-5.6.3-4.6-1.9-10.1-5.1-13.3z"/>
`,
style = `
<svg viewBox="0 0 50 50">
<style>
@keyframes rotate {
0% {
visibility: visible;
transform: rotate(0deg) translateZ(0);
}
100% {
transform: rotate(1080deg) translateZ(0);
}
}
.start {
animation: rotate 2.8s ease-in;
transform-origin: center;
fill: #5daeea;
visibility: hidden;
will-change: transform;
}
.on {
animation: rotate 1.8s linear infinite;
transform-origin: center;
fill: #5daeea;
animation-delay: 2.8s;
visibility: hidden;
will-change: transform;
}
.end {
animation: rotate 2.8s;
transform-origin: center;
fill: #9ca2a5;
animation-timing-function: cubic-bezier(0.61, 1, 0.88, 1);
will-change: transform;
}
.start_timeout {
animation: rotate 1.8s linear infinite;
transform-origin: center;
fill: #5daeea;
visibility: hidden;
will-change: transform;
}
.end_timeout {
fill: #9ca2a5;
}
</style>
`;
if (variables.state_on && variables.timeout < 2000) {
return `${style}<g class="start">${path}</g><g class="on">${path}</g></svg>`;
}
if (variables.state === 'off' && variables.timeout < 2000) {
return `${style}<g class="end">${path}</g></svg>`;
}
if (variables.state_on && variables.timeout > 2000) {
return `${style}<g class="start_timeout">${path}</g></svg>`;
} else {
return `${style}<g class="end_timeout">${path}</g></svg>`;
}
]]]
And this is what i tried but is not working, any help would be higly appreciated:
icon_fan2:
styles:
custom_fields:
icon:
- width: 75%
- margin-left: -3%
custom_fields:
icon: >
[[[
let path = `
<circle cx="25" cy="25" r="6.6"/>
<path d="M31.9 30.4c-.5.6-1.1 1.1-1.7 1.5-1.4 1.1-3.2 1.7-5.2 1.7-2.3 0-4.5-.9-6-2.4-.9 1.1-1.6 2.3-2.3 3.2l-4.9 5.4c-1.8 2.7.3 5.6 2.5 7 3.9 2.4 9.8 3.1 14.1 1.9 4.6-1.3 7.9-4.7 7.4-9.7-.2-3.4-1.9-6-3.9-8.6zM17 28.3c-.4-1-.6-2.1-.6-3.3a8.7 8.7 0 0 1 6.4-8.4l-1.6-3.5L19 6.2c-1.5-2.8-5-2.5-7.3-1.2-4 2.2-7.5 6.9-8.7 11.3-1.2 4.6.2 9.2 4.7 11.3 3.1 1.3 6.1 1.2 9.3.7zm26.9-17.6c-3.3-3.4-8-4.6-12.1-1.8-2.8 1.8-4.2 4.6-5.5 7.5 4.2.6 7.4 4.2 7.4 8.6 0 .9-.1 1.7-.4 2.5 1.3.2 2.8.3 3.8.4 2.3.4 4.7 1.3 7.1 1.7 3.2.3 4.7-3 4.8-5.6.3-4.6-1.9-10.1-5.1-13.3z"/>
`,
style = `
<svg viewBox="0 0 50 50">
<style>
@keyframes rotate {
0% {
visibility: visible;
transform: rotate(0deg) translateZ(0);
}
100% {
transform: rotate(1080deg) translateZ(0);
}
}
.start {
animation: rotate 2.8s ease-in;
transform-origin: center;
fill: #5daeea;
visibility: hidden;
will-change: transform;
}
.startheat {
animation: rotate 2.8s ease-in;
transform-origin: center;
fill: #991c1c;
visibility: hidden;
will-change: transform;
}
.on {
animation: rotate 1.8s linear infinite;
transform-origin: center;
fill: #5daeea;
animation-delay: 2.8s;
visibility: hidden;
will-change: transform;
}
.heat {
animation: rotate 1.8s linear infinite;
transform-origin: center;
fill: #991c1c;
animation-delay: 2.8s;
visibility: hidden;
will-change: transform;
}
.end {
animation: rotate 2.8s;
transform-origin: center;
fill: #9ca2a5;
animation-timing-function: cubic-bezier(0.61, 1, 0.88, 1);
will-change: transform;
}
.start_timeout {
animation: rotate 1.8s linear infinite;
transform-origin: center;
fill: #5daeea;
visibility: hidden;
will-change: transform;
}
.end_timeout {
fill: #9ca2a5;
}
</style>
`;
if (variables.state_on && variables.timeout < 2000) {
return `${style}<g class="start">${path}</g><g class="on">${path}</g></svg>`;
}
if (variables.state === 'heat' && variables.timeout < 2000) {
state = 'heat';
}
if (variables.state_heat && variables.timeout < 2000) {
return `${style}<g class="startheat">${path}</g><g class="heat">${path}</g></svg>`;
}
if (variables.state === 'off' && variables.timeout < 2000) {
return `${style}<g class="end">${path}</g></svg>`;
}
if (variables.state_on && variables.timeout > 2000) {
return `${style}<g class="start_timeout">${path}</g></svg>`;
} else {
return `${style}<g class="end_timeout">${path}</g></svg>`;
}
]]]
I’ll definately buy someone a beer if this can be fixed
VietNgoc
(Ngoc John)
November 29, 2023, 7:55pm
5663
svg style part, pick your color…
fill: #5daeea;
wmmudde1
(Wmmudde)
November 29, 2023, 8:09pm
5664
I want to keep using blue when state is ‘on’ or cooling… and red color when state is heat.
And also that the button itself have the white “on” color
wmmudde1
(Wmmudde)
November 30, 2023, 8:55am
5666
This know indeed, but i want to change the color of the spinning fan when the AC is heating in stead of cooling on the iconfan which mattias made
D34DC3N73R
(D34DC3N73R)
November 30, 2023, 10:05am
5667
You can replace the hex color code with a conditional ternary operator. Assuming the entity of the button card is your HVAC, you could use something like this
icon_fan2:
styles:
custom_fields:
icon:
- width: 75%
- margin-left: -3%
custom_fields:
icon: >
[[[
let path = `
<circle cx="25" cy="25" r="6.6"/>
<path d="M31.9 30.4c-.5.6-1.1 1.1-1.7 1.5-1.4 1.1-3.2 1.7-5.2 1.7-2.3 0-4.5-.9-6-2.4-.9 1.1-1.6 2.3-2.3 3.2l-4.9 5.4c-1.8 2.7.3 5.6 2.5 7 3.9 2.4 9.8 3.1 14.1 1.9 4.6-1.3 7.9-4.7 7.4-9.7-.2-3.4-1.9-6-3.9-8.6zM17 28.3c-.4-1-.6-2.1-.6-3.3a8.7 8.7 0 0 1 6.4-8.4l-1.6-3.5L19 6.2c-1.5-2.8-5-2.5-7.3-1.2-4 2.2-7.5 6.9-8.7 11.3-1.2 4.6.2 9.2 4.7 11.3 3.1 1.3 6.1 1.2 9.3.7zm26.9-17.6c-3.3-3.4-8-4.6-12.1-1.8-2.8 1.8-4.2 4.6-5.5 7.5 4.2.6 7.4 4.2 7.4 8.6 0 .9-.1 1.7-.4 2.5 1.3.2 2.8.3 3.8.4 2.3.4 4.7 1.3 7.1 1.7 3.2.3 4.7-3 4.8-5.6.3-4.6-1.9-10.1-5.1-13.3z"/>
`,
style = `
<svg viewBox="0 0 50 50">
<style>
@keyframes rotate {
0% {
visibility: visible;
transform: rotate(0deg) translateZ(0);
}
100% {
transform: rotate(1080deg) translateZ(0);
}
}
.start {
animation: rotate 2.8s ease-in;
transform-origin: center;
fill: ${variables.state === 'heat' ? '#991c1c' : '#5daeea'};
visibility: hidden;
will-change: transform;
}
.on {
animation: rotate 1.8s linear infinite;
transform-origin: center;
fill: ${variables.state === 'heat' ? '#991c1c' : '#5daeea'};
animation-delay: 2.8s;
visibility: hidden;
will-change: transform;
}
.end {
animation: rotate 2.8s;
transform-origin: center;
fill: #9ca2a5;
animation-timing-function: cubic-bezier(0.61, 1, 0.88, 1);
will-change: transform;
}
.start_timeout {
animation: rotate 1.8s linear infinite;
transform-origin: center;
fill: ${variables.state === 'heat' ? '#991c1c' : '#5daeea'};
visibility: hidden;
will-change: transform;
}
.end_timeout {
fill: #9ca2a5;
}
</style>
`;
if (variables.state_on && variables.timeout < 2000) {
return `${style}<g class="start">${path}</g><g class="on">${path}</g></svg>`;
}
if (variables.state === 'off' && variables.timeout < 2000) {
return `${style}<g class="end">${path}</g></svg>`;
}
if (variables.state_on && variables.timeout > 2000) {
return `${style}<g class="start_timeout">${path}</g></svg>`;
} else {
return `${style}<g class="end_timeout">${path}</g></svg>`;
}
]]]
Edit: for the card to show as white/on add ‘heat’ to the state_on
array in button_card_templates/base.yaml
base:
template:
- settings
- tilt
- extra_styles
variables:
state_on: >
[[[ return ['on', 'home', 'cool', 'heat', 'fan_only', 'playing', 'unlocked'].indexOf(!entity || entity.state) !== -1; ]]]
wmmudde1
(Wmmudde)
November 30, 2023, 12:21pm
5669
I appreciate your help!
The base addition is working, now when the state is ‘heat’ the button is ON. so thats the first step.
now when i use your edited code for the spinning fan the button is disappeared.
i feel we are getting closer! did you manage to get this working?
larryo108
(Larry Overn)
November 30, 2023, 1:30pm
5670
I think I was responding to someone else. I am not sure I can help you with your icon issue. I don’t use Mattias’s HVAC card. I have created my own using the Simple Thermostat card.
cismarine
(cismarine)
November 30, 2023, 3:03pm
5672
Where is your electric pole icon coming from?
D34DC3N73R
(D34DC3N73R)
November 30, 2023, 6:28pm
5673
I had it working on my actual fan, but it failed with my HVAC for some reason. Let’s try a different approach.
icon_fan2:
styles:
custom_fields:
icon:
- width: 75%
- margin-left: -3%
- fill: >
[[[
return variables.state === 'cool' || variables.state === 'fan_only'
? '#5daeea'
: variables.state === 'heat'
? '#991c1c'
: '#9da0a2';
]]]
custom_fields:
icon: >
[[[
let path = `
<circle cx="25" cy="25" r="6.6"/>
<path d="M31.9 30.4c-.5.6-1.1 1.1-1.7 1.5-1.4 1.1-3.2 1.7-5.2 1.7-2.3 0-4.5-.9-6-2.4-.9 1.1-1.6 2.3-2.3 3.2l-4.9 5.4c-1.8 2.7.3 5.6 2.5 7 3.9 2.4 9.8 3.1 14.1 1.9 4.6-1.3 7.9-4.7 7.4-9.7-.2-3.4-1.9-6-3.9-8.6zM17 28.3c-.4-1-.6-2.1-.6-3.3a8.7 8.7 0 0 1 6.4-8.4l-1.6-3.5L19 6.2c-1.5-2.8-5-2.5-7.3-1.2-4 2.2-7.5 6.9-8.7 11.3-1.2 4.6.2 9.2 4.7 11.3 3.1 1.3 6.1 1.2 9.3.7zm26.9-17.6c-3.3-3.4-8-4.6-12.1-1.8-2.8 1.8-4.2 4.6-5.5 7.5 4.2.6 7.4 4.2 7.4 8.6 0 .9-.1 1.7-.4 2.5 1.3.2 2.8.3 3.8.4 2.3.4 4.7 1.3 7.1 1.7 3.2.3 4.7-3 4.8-5.6.3-4.6-1.9-10.1-5.1-13.3z"/>
`,
style = `
<svg viewBox="0 0 50 50">
<style>
@keyframes rotate {
0% {
visibility: visible;
transform: rotate(0deg) translateZ(0);
}
100% {
transform: rotate(1080deg) translateZ(0);
}
}
.start {
animation: rotate 2.8s ease-in;
transform-origin: center;
visibility: hidden;
will-change: transform;
}
.on {
animation: rotate 1.8s linear infinite;
transform-origin: center;
animation-delay: 2.8s;
visibility: hidden;
will-change: transform;
}
.end {
animation: rotate 2.8s;
transform-origin: center;
animation-timing-function: cubic-bezier(0.61, 1, 0.88, 1);
will-change: transform;
}
.start_timeout {
animation: rotate 1.8s linear infinite;
transform-origin: center;
visibility: hidden;
will-change: transform;
}
.end_timeout {
}
</style>
`;
if (variables.state_on && variables.timeout < 2000) {
return `${style}<g class="start">${path}</g><g class="on">${path}</g></svg>`;
}
if (variables.state === 'off' && variables.timeout < 2000) {
return `${style}<g class="end">${path}</g></svg>`;
}
if (variables.state_on && variables.timeout > 2000) {
return `${style}<g class="start_timeout">${path}</g></svg>`;
} else {
return `${style}<g class="end_timeout">${path}</g></svg>`;
}
]]]
This takes the fill out of the CSS and adds the fill ternary operator to the icon custom fields.
Edit: the previous code would work too if I didn’t forget to wrap the hex values in single quotes… whoops. Edited the previous post for clarity.
1 Like
cismarine
(cismarine)
November 30, 2023, 8:39pm
5674
Hi,
This place is a treasure trove! Thanks to all contributors.
I am trying to move image inside card, or card on dash.
It needs to be dynamic, driven by sensor value.
Can this be achieved?
TIA
simi
(Simon)
December 1, 2023, 2:18am
5675
Has anybody achieved to make the circle slider work with cover blinds instead of lights? The circle gets displayed, also the value of the current_position attribute (a number from 0 to 100). But I can’t get the slider to work an set the position using the slider.
This is the code I am using:
cover_circle:
styles:
card:
- --c-stroke-color-on: '#b0b0b0'
- --c-stroke-color-off: none
- --c-fill-color-on: none
- --c-fill-color-off: rgba(255,255,255,0.04)
- --c-stroke-width: 2.3
- --c-stroke-width-dragging: 4
- --c-font-color: '#97989c'
- --c-font-size: 14px
- --c-unit-font-size: 10.5px
- --c-font-weight: 700
- --c-letter-spacing: -0.02rem
custom_fields:
circle:
- display: initial
- width: 88%
- margin: -3% 2% 0 0
- justify-self: end
- opacity: 1
custom_fields:
circle: >
[[[
if (entity) {
let r = 22.1,
c = r * 2 * Math.PI,
tspan = '<tspan dx=".2" dy="-.4">',
domain = "cover",
state = entity.state === "open" || entity.state === "closed",
input = entity.attributes.current_position || ' ',
unit = '%';
/* * * * * * * * * * * * * * * * * *
* *
* CIRCLE *
* *
* * * * * * * * * * * * * * * * * */
let circle = (state, input, unit) => {
return `
<svg viewBox="0 0 50 50">
<style>
circle {
transform: rotate(-90deg);
transform-origin: 50% 50%;
stroke-dasharray: ${c};
stroke-dashoffset: ${typeof input === 'number' && c - input / 100 * c};
stroke-width: var(--c-stroke-width);
stroke: ${state ? 'var(--c-stroke-color-on)' : 'var(--c-stroke-color-off)'};
fill: ${state ? 'var(--c-fill-color-on)' : 'var(--c-fill-color-off)'};
}
text {
font-size: var(--c-font-size);
font-weight: var(--c-font-weight);
letter-spacing: var(--c-letter-spacing);
fill: var(--c-font-color);
}
tspan {
font-size: var(--c-unit-font-size);
}
#circle_value, tspan {
text-anchor: middle;
dominant-baseline: central;
}
</style>
<circle id="circle_stroke" cx="25" cy="25" r="${r}"/>
<text id="circle_value" x="50%" y="52%">${input}${tspan}${unit}</tspan></text>
</svg>
<input id="circle_slider" type="range" min="0" max="100" value="${input}">
`;
}
/* * * * * * * * * * * * * * * * * *
* *
* Cover *
* *
* * * * * * * * * * * * * * * * * */
if (domain === 'cover') {
// wait 0ms for shadow dom
setTimeout(() => {
// then get elements
let elt = this.shadowRoot,
circle_slider = elt.getElementById('circle_slider'),
circle_value = elt.getElementById('circle_value'),
circle_stroke = elt.getElementById('circle_stroke');
// approximate position of thumb relative to circle
circle_slider.style.top = `${(circle_slider.value - 50) / 1.66 - 1}%`;
// debug position
let debug = false;
if (debug) circle_slider.style.opacity = 0.3;
// pass each event to handler
['click', 'input', 'mousedown', 'mouseup', 'touchstart', 'touchend'].forEach((event) => {
circle_slider.addEventListener(event, handler, { passive: true })
});
function handler(event) {
// "this" refers to slider
if (event.target === this) {
// bypass button-card tap_action
event.stopPropagation();
// update circle_value
circle_value.innerHTML = `${this.value}${tspan}${unit}</tspan>`;
// update stroke
circle_stroke.style.strokeDashoffset = c - this.value / 100 * c;
circle_stroke.style.strokeWidth = 'var(--c-stroke-width-dragging)';
// set cursor while dragging
if (event.type === 'mousedown' || event.type === 'input') {
this.style.cursor = 'grabbing';
} else {
this.style.cursor = 'grab';
}
// reset stroke width if value doesn't change
if (input == this.value && (event.type === 'click' || event.type === 'touchend'))
circle_stroke.style.strokeWidth = 'var(--c-stroke-width)';
// on release
if (event.type === 'mouseup' || event.type === 'touchend') {
// display loader if brightness is 0
if (circle_slider.value == 0 && elt.getElementById('loader')) {
elt.getElementById('loader').style.display = 'initial';
elt.getElementById('circle').style.display = 'none';
}
// set brightness
hass.callService('cover', 'set_position', {
entity_id: entity.entity_id,
position: this.value
});
}
}
}
}, 0);
return circle(state, input, unit);
}
}
]]]
Any help is appreciated!
D34DC3N73R
(D34DC3N73R)
December 1, 2023, 5:11am
5676
I haven’t done it personally, since I don’t have any position covers, but I have done something similar with my HVAC. I believe you’ll have to add your template name to this line so the circle CSS is added to your card (assuming the code you shared is a button card template) in button_card_templates/extra_styles.yaml
.
I would think something like this:
${this._config.template.includes('light') || this._config.template.includes('cover_circle') ? `
and of course, you’ll need to include the extra_styles
template in your card.
1 Like
wmmudde1
(Wmmudde)
December 1, 2023, 9:10am
5677
Man, you are truly a legend! This is working smooth!
Thank you very much buddy, i appreciate your help on this one!
i would like to buy you a beer!
simi
(Simon)
December 1, 2023, 9:33am
5678
That did the trick! Thank you so much!! My respect!
I completely missed the extra styles template and only focused on the code from the circle button template.
Now there are only a few little things left to fix, like there is no value shown when the cover blinds are closed completely, but I guess I can figure this out.
Again thank you very much! Replay appreciate your help, time and effort @D34DC3N73R
wmmudde1
(Wmmudde)
December 1, 2023, 1:32pm
5679
Hi buddy, do you want to share me your roller blinds icon please?
D34DC3N73R
(D34DC3N73R)
December 1, 2023, 7:45pm
5680
No problem! Glad it’s working for you. Please donate to your local animal shelter as a show of thanks if you feel the need.
2 Likes
D34DC3N73R
(D34DC3N73R)
December 1, 2023, 7:49pm
5681
you may need to add a circle input variable to your button card. For instance, this is what I use in my HVAC:
...
variables:
circle_input: >
[[[
if (entity) {
return entity.state === 'cool' || entity.state === 'heat'
? Math.round(entity.attributes.temperature)
: Math.round(entity.attributes.current_temperature);
}
]]]
circle_input_unit: '°F'
1 Like
cismarine
(cismarine)
December 2, 2023, 12:07am
5682
I have issue with animation…
It only works when pressing on button.
can anyone spot my mistake?
type: custom:button-card
entity: sensor.humidor_humidity
show_entity_picture: true
entity_picture: /local/img/smoke.png
name: test
tap_action: none
haptic: medium
variables:
circle_input: |
[[[
let progress = states['sensor.dishwasher_progress'];
if (progress) return parseInt(progress.state);
]]]
circle_input_unit: '%'
styles:
entity_picture:
- width: 100%
- height: 100%
- animation:
- smoke1 0.5s linear infinite;
- smoke2 2s linear infinite;
- smoke3 1.5s linear infinite;
extra_styles: |
@keyframes smoke1 {
0% {
filter: blur(0px);
transform: translateY(0px) scale(-1, 1);
opacity: 0;
}
25% {
filter: blur(3px);
transform: translateY(-10px) scale(-1, 1.05);
opacity: 0.5;
}
50% {
filter: blur(5px);
transform: translateY(-20px) scale(-1, 1.1);
opacity: 1;
}
75% {
filter: blur(5px);
transform: translateY(-30px) scale(-1, 1.15);
opacity: 0.5;
}
100% {
filter: blur(7px);
transform: translateY(-40px) scale(-1, 1.2);
opacity: 0;
}
}
@keyframes smoke2 {
0% {
filter: blur(0px);
transform: translateY(0px) scale(1);
opacity: 0;
}
25% {
filter: blur(3px);
transform: translateY(-10px) scale(1.05);
opacity: 0.5;
}
50% {
filter: blur(5px);
transform: translateY(-20px) scale(1.1);
opacity: 1;
}
75% {
filter: blur(5px);
transform: translateY(-30px) scale(1.15);
opacity: 0.5;
}
100% {
filter: blur(7px);
transform: translateY(-40px) scale(1.2);
opacity: 0;
}
}
@keyframes smoke3 {
0% {
filter: blur(0px);
transform: translateY(0px) scale(1);
opacity: 0;
}
25% {
filter: blur(3px);
transform: translateY(-20px) scale(1.05);
opacity: 0.5;
}
50% {
filter: blur(5px);
transform: translateY(-40px) scale(1.1);
opacity: 1;
}
75% {
filter: blur(5px);
transform: translateY(-60px) scale(1.15);
opacity: 0.5;
}
100% {
filter: blur(7px);
transform: translateY(-80px) scale(1.2);
opacity: 0;
}
}
Krivatri
(Krivatri)
December 2, 2023, 7:40am
5684
@Emad131 what are the different states you get from the nest protect called?
and what color goes with what state?