TrĂšs bonne idĂ©e, je viens de lâinstaller !
Si une de mes enceintes diffuse de la musique (button-card + card-mod) :
code de la carte
name: Sonorisation
show_name: true
icon: 'mdi:speaker'
styles:
custom_fields:
wave:
- background-color: 'rgba(0, 0, 0, 0)'
- position: absolute
- right: 5%
- top: 5%
- font-size: 13px
- line-height: 20px
- display: |
[[[
if (states["input_boolean.test2"].state == 'on') return '';
else return 'none';
]]]
- '--icon-color': |
[[[
if (states["input_boolean.test2"].state == 'on') return 'var(--mail-color)';
else return 'var(--primary-color)';
]]]
card:
- border: 2px solid var(--primary-color)
- border-radius: 10px
icon:
- color: var(--primary-color)
name:
- font-variant: small-caps
- color: var(--primary-color)
custom_fields:
wave: |
[[[
return `
<div class="loader-container">
<div class="loader-3">
<div class="item-1"></div>
<div class="item-2"></div>
<div class="item-3"></div>
<div class="item-4"></div>
<div class="item-5"></div>
</div>
</div>`
]]]
type: 'custom:button-card'
style: |
.loader-3{
width: 40px;
height: 40px;
}
.loader-3 div {
height: 100%;
width: 3px;
display: inline-block;
}
.loader-3 div .item-1{
height: 50%;
}
.loader-3 .item-1 {
animation: loader-3-first-div 1.2s infinite linear;
background-color: red;
}
.loader-3 .item-2 {
animation: loader-3-second-div 1.2s infinite linear;
animation-delay: -1.1s;
background-color: darkorange;
}
.loader-3 .item-3 {
animation: loader-3-third-div 1.2s infinite linear;
animation-delay: -1.0s;
background-color: gold;
}
.loader-3 .item-4 {
animation: loader-3-fourth-div 1.2s infinite linear;
animation-delay: -0.9s;
background-color: green;
}
.loader-3 .item-5 {
animation: loader-3-last-div 1.2s infinite linear;
animation-delay: -0.8s;
background-color: DarkOrchid;
}
@keyframes loader-3-first-div {
25%,75% {
transform: scaleY(0.2);
}
0%,50%,100%{
transform: scaleY(0.6);
}
}
@keyframes loader-3-second-div {
25%,75% {
transform: scaleY(0.4);
}
0%,50%,100%{
transform: scaleY(1);
}
}
@keyframes loader-3-third-div {
25%,75% {
transform: scaleY(0.4);
}
0%,50%,100%{
transform: scaleY(1);
}
}
@keyframes loader-3-fourth-div {
25%,75% {
transform: scaleY(0.4);
}
0%,50%,100%{
transform: scaleY(1);
}
}
@keyframes loader-3-last-div {
25%,75% {
transform: scaleY(0.2);
}
0%,50%,100%{
transform: scaleY(0.6);
}
}
Inspiré par https://codepen.io/ruslan_khomiak/pen/MbqWaK
Toujours dans les animations :
Si le facteur est passĂ©, une automatisation met Ă Vrai un boolĂ©en (lâanimation de la porte se fait si une ouverture (porte,fenetre,garage,cagibi) est ouverte et nâest normalement pas la mĂȘme entitĂ© que lâentrĂ©e boolĂ©enne)
Code de la carte
entity: input_boolean.test2
name: Ouvertures
show_name: true
state:
- icon: 'mdi:door-open'
value: 'on'
- icon: 'mdi:door'
value: 'off'
styles:
custom_fields:
courrier:
- border-radius: 50%
- position: absolute
- right: 5%
- top: 5%
- font-size: 13px
- line-height: 20px
- display: |
[[[
if (states["input_boolean.test2"].state == 'on') return '';
else return 'none';
]]]
- '--icon-color': |
[[[
if (states["input_boolean.test2"].state == 'on') return 'var(--mail-color)';
]]]
card:
- border-radius: 10px
- border: 2px solid var(--primary-color)
icon:
- color: var(--primary-color)
name:
- font-variant: small-caps
- color: var(--primary-color)
custom_fields:
courrier: |
[[[
return `
<ha-icon
icon="mdi:mail"
style="width: 30px; height: 30px; color: var(--icon-color);">
</ha-icon>`
]]]
type: 'custom:button-card'
style: |
@keyframes pulsation {
0% {
box-shadow: var(--shadow-mail-color-hidden);
}
50% {
transform: scale(1);
box-shadow: var(--shadow-mail-color-hidden);
}
25%,75% {
transform: scale(1.2);
box-shadow: var(--shadow-mail-color-visible);
}
100% {
box-shadow: var(--shadow-mail-color-hidden);
transform: scale(1);
}
}
#courrier{
animation:
{% if is_state('input_boolean.test2', 'on') %}
pulsation 1.3s ease infinite
{% else %}
none
{% endif %}
;
Les variables Ă ajouter au thĂšme :
mail-color: "rgba(247, 193, 57)"
shadow-mail-color-visible: "0px 0px 0px 20px rgba(247, 193, 57, 0.3) inset, 0px 0px 0px 20px rgba(247, 193, 57, 0.3)"
shadow-mail-color-hidden: "0px 0px 0px 20px transparent inset, 0px 0px 0px 20px
Tes boutons sont trĂšs bien fait et super pratiques. Beau travail!
Merci. Ăa fait plaisir. Si câest possible câest grĂące aux superbes cartes .
Le but premier nâest pas forcĂ©ment dâutiliser ce que je montre (vous pouvez bien sĂ»r) mais câest surtout de donner des exemples concrets de ce que lâon peux faire (et on peut en faire )
Mise Ă jour de lâanimation :
Code de la carte
style: |
@keyframes pulsation {
25% {
transform: scale(1.3);
}
100% {
box-shadow: 0 0 0 40px rgba(128, 0, 128, 0), 0 0 0 6px rgba(128, 0, 128, 0) inset;
transform: scale(1)
}
}
#courrier{
animation:
{% if is_state('input_boolean.test2', 'on') %}
pulsation 1s infinite ease-in;
{% else %}
None
{% endif %}
;
entity: input_boolean.test2
name: Ouvertures
show_name: true
state:
- icon: 'mdi:door-open'
value: 'on'
- icon: 'mdi:door'
value: 'off'
styles:
custom_fields:
courrier:
- border-radius: 50%
- box-shadow: >-
rgb(247 193 57 / 60%) 0px 0px 0px 0px, rgb(247 193 57 / 60%) 0px 0px
0px 6px inset
- position: absolute
- right: 5%
- top: 5%
- font-size: 13px
- line-height: 20px
- display: |
[[[
if (states["input_boolean.test2"].state == 'on') return '';
else return 'none';
]]]
- '--icon-color': |
[[[
if (states["input_boolean.test2"].state == 'on') return 'var(--mail-color)';
]]]
card:
- border-radius: 10px
- border: 2px solid var(--primary-color)
icon:
- color: var(--primary-color)
name:
- font-variant: small-caps
- color: var(--primary-color)
custom_fields:
courrier: |
[[[
return `
<ha-icon
icon="mdi:mail"
style="width: 30px; height: 30px; color: var(--icon-color);">
</ha-icon>`
]]]
type: 'custom:button-card'
Inspiration : https://codepen.io/matchboxhero/pen/pWLOQb?editors=1100
Apparemment, je nâai jamais publiĂ© ma carte pour lâaspirateur (je ne lâutilise quasiment jamais, car la commande vocale est plus rapide) :
Code du premier bouton
color: auto
color_type: icon
confirmation:
text: Nettoyage de la Maison
entity: input_select.vacuum_aspiro_in_progress
icon: 'mdi:home'
name: Maison
show_icon: true
show_label: false
show_last_changed: false
show_name: true
show_state: false
state:
- styles:
icon:
- animation: blink 0.9s ease infinite
name:
- animation: blink 0.9s ease infinite
value: Maison
styles:
card:
- border-radius: 10px
- border: '2px solid #257236'
- height: 75px
- width: 75px
- margin: 5px 5px 0px 11px
- padding: 0px 0px
- background-color: '#319847'
grid:
- position: relative
icon:
- position: absolute
- left: 2px
- top: '-15px'
- color: var(--light-text-color)
name:
- position: absolute
- left: 5px
- bottom: 10px
- font-variant: small-caps
- font-size: 14px
- color: var(--light-text-color)
tap_action:
action: call-service
service: script.aspiro_maison
type: 'custom:button-card'
pour le rendu sur mon tĂ©lĂ©phone jâai du mettre un margin de 11px sur la gauche pour le premier bouton :
card:
- margin: 5px 5px 0px 11px
Les trois boutons suivant sur la ligne nâen ont pas :
card:
- margin: 5px 5px 0px 0px
Affichage dâun timer directement sur la carte :
(on peut imaginer un changement de couleur de lâenceinte, du nom, etc. suivant lâĂ©tat du timer
)
Code de la carte
name: |
[[[
var finishes_at = new Date(states['timer.hacf_timer'].attributes.finishes_at);
var remaining = states['timer.hacf_timer'].attributes.remaining;
if (finishes_at == 'Invalid Date') {
if (remaining) {
var remaining_first_element = remaining.split(':');
if (remaining_first_element[0].length < 2 ) {
if (remaining_first_element[0] == '0' ) {
remaining_first_element = remaining_first_element.splice(1);
} else {
remaining_first_element[0] = '0' + remaining_first_element[0];
}
}
result = remaining_first_element.toString().replaceAll(',',':');
} else {
result = 'Sonorisation';
}
} else {
var timestamp = finishes_at.getTime();
var timestamp_now = Date.now();
var difference_between = timestamp - timestamp_now
var time_remaining = new Date(difference_between).toUTCString();
var hours = time_remaining.split(' ');
var hours_split = hours[4].split(':');
if (parseInt(hours_split[0]) == 0 ) {
hours_split = hours_split.splice(1);
}
var result = hours_split.toString().replaceAll(',',':');;
}
return result;
]]]
triggers_update:
- sensor.aleatoire
show_name: true
icon: 'mdi:speaker'
styles:
custom_fields:
wave:
- background-color: 'rgba(0, 0, 0, 0)'
- position: absolute
- right: 5%
- top: 5%
- font-size: 13px
- line-height: 20px
- display: |
[[[
if (states["input_boolean.test2"].state == 'on') return '';
else return 'none';
]]]
- '--icon-color': |
[[[
if (states["input_boolean.test2"].state == 'on') return 'var(--mail-color)';
else return 'var(--primary-color)';
]]]
card:
- border: 2px solid var(--primary-color)
- border-radius: 10px
icon:
- color: var(--primary-color)
name:
- font-variant: small-caps
- color: var(--primary-color)
custom_fields:
wave: |
[[[
return `
<div class="loader-container">
<div class="loader-3">
<div class="item-1"></div>
<div class="item-2"></div>
<div class="item-3"></div>
<div class="item-4"></div>
<div class="item-5"></div>
</div>
</div>`
]]]
type: 'custom:button-card'
style: |
.loader-3{
width: 40px;
height: 40px;
}
.loader-3 div {
height: 100%;
width: 3px;
display: inline-block;
}
.loader-3 div .item-1{
height: 50%;
}
.loader-3 .item-1 {
animation: loader-3-first-last-div 1.2s infinite linear;
background-color: red;
}
.loader-3 .item-2 {
animation: loader-3-middle-div 1.2s infinite linear;
animation-delay: -1.1s;
background-color: darkorange;
}
.loader-3 .item-3 {
animation: loader-3-middle-div 1.2s infinite linear;
animation-delay: -1.0s;
background-color: gold;
}
.loader-3 .item-4 {
animation: loader-3-middle-div 1.2s infinite linear;
animation-delay: -0.9s;
background-color: green;
}
.loader-3 .item-5 {
animation: loader-3-first-last-div 1.2s infinite linear;
animation-delay: -0.8s;
background-color: DarkOrchid;
}
@keyframes loader-3-first-last-div {
25%,75% {
transform: scaleY(0.2);
}
0%,50%,100%{
transform: scaleY(0.6);
}
}
@keyframes loader-3-middle-div {
25%,75% {
transform: scaleY(0.4);
}
0%,50%,100%{
transform: scaleY(1);
}
}
Il faut ajouter une entité timer
:
timer:
hacf_timer:
duration: "01:00:05"
Il faut ajouter une entité aléatoire (qui sert de déclencheur pour mettre à jour la carte button-card):
sensor:
- platform: random
name: Aléatoire
maximum: 999
Il faut une automatisation qui sâĂ©xĂ©cute toutes les secondes afin de mettre Ă jour cette entitĂ© :
alias: mise a jour de sensor.aleatoire
description: Mise Ă jour pour affichage des timers sur les cartes
trigger:
- platform: time_pattern
seconds: '*'
condition: []
action:
- service: homeassistant.update_entity
target:
entity_id: sensor.aleatoire
mode: restart
Ah pas bien tout sa⊠sa donne des ideeeeeees mais ou commencer!
Une chose mâintĂ©resse encore. Jâai vu quâon pouvais faire un floorplan ou visuellement on peut trĂšs bien reprĂ©senter les Ă©tage et pour les lumiĂšres ou mĂȘme le chauffage par piĂšces etc etc sa serai vraiment super.
Jâai dĂ©jĂ commencer par dessiner les floorplan, sa prend tu temps mais sa vaut le rĂ©sultat. Par contre pour lâintĂ©grer je plante complĂ©tement pour le moment.
je te conseille de te rendre dans PrĂ©sentations et de chercher une prĂ©sentation qui lâutilise⊠afin de demander conseille
Superbe taf, felicitations
Peux-tu donner plus de détails sur la carte aspirateur avec les boutons sur les differentes pieces ? Merci
Tu peux le faire avec un peu de sorcellerie sans avoir besoin de sensor random qui se met Ă jour
type: custom:button-card
variables:
update: |
[[[
if (CONDITION POUR DECLANCHER LE REFRESH TOUS LES X) {
if (this._myTimer === undefined) {
this._myTimer = window.setInterval(() => { this.update() }, 1000 * 10) // 1000 * 10 = Temps entre les refresh en millisecondes
}
} else {
if (this._myTimer !== undefined) {
window.clearInterval(this._myTimer);
delete this._myTimer;
}
}
]]]
xxx: RESTE DE LA CONFIG...
Tu as corrigĂ© nâest ce pas ? sinon je commence a devenir fouâŠ
Merci pour le partage (de tes cartes, de tes réponses ici et là -bas, du temps passé !).
Câest clair que câest beaucoup plus sympa comme ceci
Câest documentĂ© et je ne le trouve pas ou tu le sors de ton chapeau (dâoĂč la sorcellerie ) ?
Non, pas documentĂ©, câest juste du pur javascript
Oui, jâai edit le post
Je parlais du fait de la clé update
dans variables
(toi aussi ? jâai lâimpression que tu me rĂ©ponds par rapport au code du timer )
Je suis ravi de cette explication et je me demande ce que tu as encore comme sort
Tu peux lâappeler toto
si tu veux, ça fera la mĂȘme chose Câest juste pour que le code soit executĂ© quelque part.
Ca y est ! Jây suis !
Merci !
Edit:
Code de la carte sans automatisation toutes les secondes et sans entité aléatoire :
variables:
update: |
[[[
var finishes_at = new Date(states['timer.hacf_timer'].attributes.finishes_at);
if (finishes_at != 'Invalid Date') {
if (this._myTimer === undefined) {
this._myTimer = window.setInterval(() => { this.update() }, 1000 * 1) // 1000 * 1 = Temps entre les refresh en millisecondes
}
} else {
if (this._myTimer !== undefined) {
window.clearInterval(this._myTimer);
delete this._myTimer;
}
}
]]]
name: |
[[[
var finishes_at = new Date(states['timer.hacf_timer'].attributes.finishes_at);
var remaining = states['timer.hacf_timer'].attributes.remaining;
if (finishes_at == 'Invalid Date') {
if (remaining) {
var remaining_first_element = remaining.split(':');
if (remaining_first_element[0].length < 2 ) {
if (remaining_first_element[0] == '0' ) {
remaining_first_element = remaining_first_element.splice(1);
} else {
remaining_first_element[0] = '0' + remaining_first_element[0];
}
}
result = remaining_first_element.toString().replaceAll(',',':');
} else {
result = 'Sonorisation';
}
} else {
var timestamp = finishes_at.getTime();
var timestamp_now = Date.now();
var difference_between = timestamp - timestamp_now
var time_remaining = new Date(difference_between).toUTCString();
var hours = time_remaining.split(' ');
var hours_split = hours[4].split(':');
if (parseInt(hours_split[0]) == 0 ) {
hours_split = hours_split.splice(1);
}
var result = hours_split.toString().replaceAll(',',':');;
}
return result;
]]]
show_name: true
icon: 'mdi:speaker'
styles:
custom_fields:
wave:
- background-color: 'rgba(0, 0, 0, 0)'
- position: absolute
- right: 5%
- top: 5%
- font-size: 13px
- line-height: 20px
- display: |
[[[
if (states["input_boolean.test2"].state == 'on') return '';
else return 'none';
]]]
- '--icon-color': |
[[[
if (states["input_boolean.test2"].state == 'on') return 'var(--mail-color)';
else return 'var(--primary-color)';
]]]
card:
- border: 2px solid var(--primary-color)
- border-radius: 10px
icon:
- color: var(--primary-color)
name:
- font-variant: small-caps
- color: var(--primary-color)
custom_fields:
wave: |
[[[
return `
<div class="loader-container">
<div class="loader-3">
<div class="item-1"></div>
<div class="item-2"></div>
<div class="item-3"></div>
<div class="item-4"></div>
<div class="item-5"></div>
</div>
</div>`
]]]
type: 'custom:button-card'
style: |
.loader-3{
width: 40px;
height: 40px;
}
.loader-3 div {
height: 100%;
width: 3px;
display: inline-block;
}
.loader-3 div .item-1{
height: 50%;
}
.loader-3 .item-1 {
animation: loader-3-first-last-div 1.2s infinite linear;
background-color: red;
}
.loader-3 .item-2 {
animation: loader-3-middle-div 1.2s infinite linear;
animation-delay: -1.1s;
background-color: darkorange;
}
.loader-3 .item-3 {
animation: loader-3-middle-div 1.2s infinite linear;
animation-delay: -1.0s;
background-color: gold;
}
.loader-3 .item-4 {
animation: loader-3-middle-div 1.2s infinite linear;
animation-delay: -0.9s;
background-color: green;
}
.loader-3 .item-5 {
animation: loader-3-first-last-div 1.2s infinite linear;
animation-delay: -0.8s;
background-color: DarkOrchid;
}
@keyframes loader-3-first-last-div {
25%,75% {
transform: scaleY(0.2);
}
0%,50%,100%{
transform: scaleY(0.6);
}
}
@keyframes loader-3-middle-div {
25%,75% {
transform: scaleY(0.4);
}
0%,50%,100%{
transform: scaleY(1);
}
}