Carte automatique pour suivi des batteries

Bon je remets une pièce dans la machine avec un soucis bien particulier et pourtant bien commun et pas du tout cité ici :

De nombreux capteurs (aqara pour la température par ex) fonctionnent très bien à 0% de batterie (plus d’un an déjà et toujours aussi réactifs les 4 miens) tandis que d’autres meurent à 12% de batterie (signal plat)…

Bref j’ai adapté pour obtenir ce beau tableau qui a la particularité d’adapter l’opacité au niveau de batterie et de tracer la courbe de température en couleur, courbe qui devient grisée avec un petit signal :warning: si le capteur ne répond plus (même si la batterie n’est pas 0%)


:shortcake: (cerise sur le gâteau): les courbes de température sont colorées en dégradé de couleur selon la température, il fait froid chez moi en ce moment

il faut juste installer depuis HACS GitHub - iantrich/config-template-card: 📝 Templatable Lovelace Configurations (qui est bien pratique pour éviter de créer des entités pour un affichage dynamique… certainement utile dans bien d’autres situations)

Voici le code, il devrait bien y avoir quelqu’un pour suggérer des amélioration ? En tout cas je suis parti de ce fil de discussion dans mes essais initialement :slight_smile:

type: custom:config-template-card
entities:
  - sensor.time
card:
  type: vertical-stack
  cards: |-
    ${Object.keys(this.hass.states).filter(e => 
      e.startsWith('sensor.') && 
      e.endsWith('_battery') && 
      !e.includes('battery_plus') && 
      !e.startsWith('sensor.sm') &&
      this.hass.states[e.replace('_battery', '_temperature')]
    ).sort((a, b) => 
      parseFloat(this.hass.states[a].state) - parseFloat(this.hass.states[b].state)
    ).map(batteryId => {
      const tempId = batteryId.replace('_battery', '_temperature');
      const batteryLevel = parseFloat(this.hass.states[batteryId].state) || 0;
      const opacity = Math.max(0.15, batteryLevel / 100);
      const tempState = this.hass.states[tempId];
      const lastChanged = new Date(tempState.last_changed);
      const now = new Date();
      const hoursSinceChange = (now - lastChanged) / (1000 * 60 * 60);
      const isStale = hoursSinceChange > 6;
      const displayName = this.hass.states[batteryId].attributes.friendly_name || batteryId;
      const nameWithWarning = isStale ? '⚠️ ' + displayName : displayName;
      
      // Définir les couleurs : normales ou grisées si capteur mort
      const colorThresholds = isStale ? [
        {value: 0, color: '#666666'}
      ] : [
        {value: 40, color: '#6e0000'},
        {value: 30, color: '#470101'},
        {value: 25, color: '#ff0000'},
        {value: 20, color: '#ffba00'},
        {value: 15, color: '#00aa99'},
        {value: 10, color: '#0090ff'},
        {value: 5, color: '#004e8b'},
        {value: 0, color: '#002542'}
      ];
      
      return {
        type: 'custom:stack-in-card',
        keep: {
          border_radius: false,
          margin: false,
          outer_padding: false,
          box_shadow: false,
          background: false
        },
        card_mod: {
          style: 'ha-card { border-radius: 0px !important; margin: 0px !important; padding: 0px !important; box-shadow: none !important; overflow: hidden !important; margin-bottom: -5px !important; height: 38px !important; }'
        },
        cards: [
          {
            type: 'custom:mini-graph-card',
            entities: [tempId],
            height: 25,
            hours_to_show: 72,
            points_per_hour: 0.5,
            line_width: 1.5,
            smoothing: true,
            color_thresholds: colorThresholds,
            show: {
              name: false,
              icon: false,
              state: false,
              legend: false,
              fill: false,
              labels: false,
              points: false
            },
            card_mod: {
              style: 'ha-card { position: absolute !important; top: 0 !important; left: 0 !important; width: 100% !important; height: 25px !important; border: 0px !important; opacity: 60% !important; pointer-events: none !important; background: transparent !important; box-shadow: none !important; border-radius: 0px !important; overflow: hidden !important; mix-blend-mode: screen !important; } ha-card .graph { height: 25px !important; margin: 0 !important; padding: 0 !important; } ha-card .graph .graph__container { height: 25px !important; margin-top: -18px !important; margin-left: 0 !important; margin-right: 0 !important; padding: 0 !important; }'
            }
          },
          {
            type: 'custom:bar-card',
            entity: batteryId,
            name: nameWithWarning,
            height: 1,
            title_position: 'inside',
            positions: {
              icon: 'inside',
              indicator: 'inside',
              name: 'inside',
              value: 'inside'
            },
            show_icon: true,
            align: 'split',
            max: 100,
            unit_of_measurement: '%',
            color: 'lightgreen',
            card_mod: {
              style: `ha-card { height: 45px; font-size: small; opacity: 100%; border: none !important; background: transparent !important; box-shadow: none !important; border-radius: 0px !important; margin: 0px !important;} ha-icon {opacity: ${opacity} !important; color: white !important; } bar-card-name { color: white !important; opacity: 80%;} bar-card-value { color: white !important; } bar-card-currentbar,bar-card-current {opacity: ${opacity*.2+.05} !important;} bar-card-currentbar, bar-card-current, bar-card-backgroundbar { height: 40px !important; margin-top: -25px !important; margin-left: -16px !important; margin-right: -20px !important; margin-bottom: 0px !important; border-radius: 0px !important;  } bar-card-backgroundbar {opacity: 0% !important;}`
            }
          }
        ]
      };
    })}
1 « J'aime »

bonjour, et merci pourle partage de la carte. :smiling_face_with_sunglasses: