Lovelace: Plant Card


A Home Assistant Lovelace card to report MiFlora plant sensors based on the HA Plant Card.

NOTE: This card has been superseded by MiFlora Card and is no longer being supported.

Install

  • Copy plant-card.js into your config/www folder.
  • Add a reference to the plant-card.js inside your ui-lovelace.yaml
resources:
  - url: /local/plant-card.js
    type: js

Options

Name Type Default Description
type string Required custom:plant-card
title string Required Name of the plant being monitored
image string Required Path to an image of the plant being monitored
min_moisture integer Optional Minimum moisture content for this plant
max_moisture integer Optional Maximum moisture content for this plant
min_conductivity integer Optional Minimum conductivity reading for this plant
min_temperature integer Optional Minimum temperature for this plant
entities list Required A list sensors to be monitored
7 Likes

Hi there
I’m trying to use this card, but I’m getting this error when trying to open the view that contains the card:
/local/plant-card.js:50:44 Uncaught TypeError: this.config.entities[i].split is not a function

Any ideas what the problem might be?

It’s OK, I figured it out; I copied the sensor names over from my configuration.yaml and left the spaces in after the colon… :man_facepalming:

Great to hear you figured it out. Any enhancements you’d like to see?

I’ve actually made an update locally yesterday. It now takes some extra options in the custom card for min and max moisture, min conductivity and min temp, and then formats the state in red with an extra up and down indicator to show if it’s too high or too low.

I’m happy to do a PR on your repo so you can see if you’d like to merge it in. I’ll warn you that I’m not a javascript dev by any stretch of the imagination, and I can see that there must be a more efficient way for me to get that formatting in, but I’ve not spent any time figuring out what that may be… :slight_smile:

1 Like

I get the card showing but now picture underneath. Paths looks alright so I dont get it.

@digi-ghost Great features that I hope will be added to the card.

Here’s the first card that I have in the yaml for one of mine:

  - title: Plants
    icon: mdi:leaf
    cards:
      - type: custom:plant-card
        title: 'Calathea Zebrina'
        image: images/calathea-zebrina.jpg
        entities:
          - moisture:sensor.calathea_zebrina_moisture
          - intensity:sensor.calathea_zebrina_light_intensity
          - temperature:sensor.calathea_zebrina_temperature
          - conductivity:sensor.calathea_zebrina_conductivity
          - battery:sensor.calathea_zebrina_battery

So a space after the colon (unlike the entities, which have no space after the colon), then simply images/filename.jpg. In my config folder I’ve then put that in config/www/images/filename.jpg and it seems to work OK.

One bug I’ve spotted however - in Firefox (on OSX, at least) the background image for all the cards is the same as the last card in the list. It seems that Firefox must be handling the style differently and is overwriting the background image for all the card containers with the last one. Will see if I can solve that whilst I’m fiddling around.

1 Like

Thanks! Works now!

Hi @digi-ghost, sorry I’ve been out of circulation for a few weeks. Please do go ahead and PR, it sounds like a great set of enhancements!

Hi @digi-ghost, did you find anything? I’ve just tested it on Firefox (Windows) and it seems to work fine.

Changes have been merged. Thanks.

1 Like

Weird; I’ve tried it on my Windows PC and get the same thing:

I spent a bit of time last night trying to fix it. Inspecting the elements I can see that the background style of each card is being overridden by the style of the card below. In my case that means everything looks like a Pachira!

I tried all sorts of things, mostly revolving around appending the plant name to various elements of the cards, thinking that would make each one unique. I suspect that would have worked, had it not been for my distinct lack of JS knowledge and the lateness of the hour!

However, since it’s fine for you, perhaps it’s something I’ve done; I did try it with the JS file straight from your repo (before I did my PR) and experienced the same thing, so perhaps there’s something else about my config that’s messing it up.

I will say - I use Chrome, so it works fine for me in normal use :smiley:

I have added the updated js file but value wont turn red if below or above min/max values.

I’m assuming you’ve tried doing a few hard refreshes? It sometimes took a couple of goes before I got the updated JS file. It was even more difficult getting the Home Assistant shortcut that I’ve added to my Android home screen…

To be sure that it’s picked up the new file, as well as the red numbers all the text should have a small drop shadow on it; do you see that?

No drop shadow. Multiple hard refreshes and here comes the kicker. I have removed the js file from www/ and restarted HA and the card is there in the ui.

@M203, that definitely sounds like a caching issue. Have you tried to clear the cache?

So the issue with the backgrounds repeating in Firefox is caused by the Shadow DOM not being enabled by default (this will change in the next version - 63). In the meantime, you can go to “about:config” and change dom.webcomponents.shadowdom.enabled to true.

Next, I need to figure out why the cards are always below each other instead of in multiple columns.

I copy this great card :wink: to my lovelace config. Everything OK but I need inf, min_battery… For this I add part in the script. Problem is how make min battery 8%. If I tray 8% all batteries less 80% make red.

    /* plant-card - version: v0.2.0 */

class PlantCard extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: ‘open’ });

this.sensors = {
  moisture: 'hass:water',
  temperature: 'hass:thermometer',
  intensity: 'hass:white-balance-sunny',
  conductivity: 'hass:emoticon-poop',
  battery: 'hass:battery'
};

}

_computeIcon(sensor, state) {
const icon = this.sensors[sensor];
if (sensor === ‘battery’) {
if (state < 10) {
return ${icon}-alert;
} else if (state < 95) {
return ${icon}-${Math.round((state / 10) - 0.01) * 10};
}
}
return icon;
}

_click(entity) {
this._fire(‘hass-more-info’, { entityId: entity });
}

_fire(type, detail) {

  const event = new Event(type, {
      bubbles: true,
      cancelable: false,
      composed: true
  });
  event.detail = detail || {};
  this.shadowRoot.dispatchEvent(event);
  return event;

}

//Home Assistant will set the hass property when the state of Home Assistant changes (frequent).
set hass(hass) {
const config = this.config;

var _maxMoisture = config.max_moisture;
var _minMoisture = config.min_moisture;
var _minConductivity = config.min_conductivity;
var _minTemperature = config.min_termperature;
var _minBattery = config.min_battery;

var _sensors = [];
for (var i=0; i < config.entities.length; i++) {
 _sensors.push(config.entities[i].split(":")); // Split name away from sensor id
}

this.shadowRoot.getElementById('container').innerHTML = `
<div class="content">
  <div id="sensors"></div>
</div>
`;

for (var i=0; i < _sensors.length; i++) {
  var _name = _sensors[i][0];
  var _sensor = _sensors[i][1];
  var _state = hass.states[_sensor].state || "Invalid State";
  var _uom = hass.states[_sensor].attributes.unit_of_measurement || "";
  var _icon = this._computeIcon(_name, _state);
  var _alertStyle = '';
  var _alertIcon = '';
  if (_name == 'moisture') {
    if (_state > _maxMoisture) {
      _alertStyle = ';color:red; font-weight: bold';
      _alertIcon = '&#9650; '
    } else if (_state < _minMoisture) {
      _alertStyle = ';color:red; font-weight: bold';
      _alertIcon = '&#9660; '
    }
  }
  if (_name == 'conductivity') {
    if (_state < _minConductivity) {
      _alertStyle = ';color:red; font-weight: bold';
      _alertIcon = '&#9660; ';
    }
  }
  if (_name == 'termperature') {
    if (_state < _minTemperature) {
      _alertStyle = ';color:red; font-weight: bold';
      _alertIcon = '&#9660; ';
    }
  }
  if (_name == 'battery') {
    if (_state < _minBattery) {
      _alertStyle = ';color:red; font-weight: bold';
      _alertIcon = '&#9660; ';
    }
  }


  this.shadowRoot.getElementById('sensors').innerHTML += `
  <div id="sensor${i}" class="sensor">
    <div class="icon"><ha-icon icon="${_icon}"></ha-icon></div>
    <div>${_name}</div>
    <div style="float:right${_alertStyle}">${_alertIcon}${_state}${_uom}</div>
  </div>
  `
 }

 for (var i=0; i < _sensors.length; i++) {
   this.shadowRoot.getElementById('sensor'+[i]).onclick = this._click.bind(this, _sensors[i][1]);
 }

}

// Home Assistant will call setConfig(config) when the configuration changes (rare).
setConfig(config) {
if (!config.entities) {
throw new Error(‘Please define an entity’);
}

const root = this.shadowRoot;
if (root.lastChild) root.removeChild(root.lastChild);

this.config = config;

const card = document.createElement('ha-card');
const content = document.createElement('div');
const style = document.createElement('style');

style.textContent = `
  ha-card {
    position: relative;
    padding: 0;
    color: white;
    text-shadow: 2px 2px black;
    background-size: 100%;
    background-image: url(/local/${config.image});
  }
  ha-card .header {
    width: 100%;
    color: black;
    background:rgba(0, 0, 0, var(--dark-secondary-opacity));
  }
  .uom {
    color: var(--secondary-text-color);
  }
  .icon {
    color: var(--paper-item-icon-color);
    margin-bottom: 8px;
  }
  .content {
    justify-content: space-between;
    padding: 4px 8px;
    font-size: 16px;
    background-color: rgba(0, 0, 0, 0.3);
  }
  .sensor {
    cursor: pointer;
  }
  .sensor div {
    text-align: center;
    display: inline;
  }
  `;
  content.id = "container";
  card.header = config.title;
  card.appendChild(content);
  card.appendChild(style);
  root.appendChild(card);
}

// The height of your card. Home Assistant uses this to automatically
// distribute all cards over the available columns.
getCardSize() {
return 2;
}
}

customElements.define(‘plant-card’, PlantCard);Preformatted text

edit: Solved. Value must by with out %.

1 Like

Is there a possibility of being able to capitalize the first letter of the label without it removing the icons?

also is there any possibility of changing the icon colors? It might be nice to have them white with the drop shadow or potentially black if it works well with the image that people are using.

This card is excellent! Thank you for the hard work!

hey,
is this still supported?
ive followed all the insutructions, but i keep getting hit with a “card not found” error.
not sure where im going wrong, sorry to be a pain

Custom element doesn’t exist: plant-card.
{
“entities”: [
“moisture:sensor.bathroom_plant_moisture”,
“intensity:sensor.bathroom_plant_light_intensity”,
“temperature:sensor.bathroom_plant_temperature”,
“conductivity:sensor.bathroom_plant_conductivity”,
“battery:sensor.bathroom_plant_battery”
],
“image”: “calathea-zebrina.jpg”,
“title”: “Calathea Zebrina”,
“type”: “custom:plant-card”
}