├── .gitignore ├── .gitattributes ├── hacs.json ├── .gitmodules ├── lovelace-flower-card_popup.png ├── webpack.config.js ├── convert.py ├── package.json ├── README.md └── src └── main.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | flower-card.js binary 2 | package-lock.json binary -------------------------------------------------------------------------------- /hacs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flower-card", 3 | "render_readme": true 4 | } -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "MiFloraDB"] 2 | path = MiFloraDB 3 | url = https://github.com/khronimo/MiFloraDB.git 4 | -------------------------------------------------------------------------------- /lovelace-flower-card_popup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yolandavdvegt/lovelace-flower-card/HEAD/lovelace-flower-card_popup.png -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | entry: './src/main.js', 5 | mode: 'production', 6 | output: { 7 | filename: 'flower-card.js', 8 | path: path.resolve(__dirname) 9 | } 10 | } -------------------------------------------------------------------------------- /convert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import sys 4 | import csv 5 | import json 6 | 7 | filename = sys.argv[1] 8 | 9 | data = {} 10 | with open(filename) as csvfile: 11 | reader = csv.reader(csvfile) 12 | for ln, line in enumerate(reader): 13 | if ln > 0: 14 | data[line[0]] = list(line[i] for i in [1,2,19,18,21,20,25,24,27,26]) 15 | 16 | if len(sys.argv) > 2: 17 | for k,v in data.items(): 18 | print('{}: "{}"'.format(v[1], k)) 19 | else: 20 | print("'use strict';") 21 | print("const FlowerData =") 22 | print(json.dumps(data)) 23 | print(";") 24 | print("export {FlowerData};") 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lovelace-flower-card", 3 | "version": "1.0.0", 4 | "description": "MiFlora / Home-Assistant card", 5 | "scripts": { 6 | "build": "webpack", 7 | "build-data": "python3 convert.py MiFloraDB/PlantDB_5335_U0.csv > src/data.js", 8 | "watch": "webpack --watch --mode=development", 9 | "update-card-tools": "npm uninstall card-tools && npm install thomasloven/lovelace-card-tools" 10 | }, 11 | "author": "Yolanda van der Vegt", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "webpack": "^4.42.0", 15 | "webpack-cli": "^3.3.11" 16 | }, 17 | "dependencies": { 18 | "card-tools": "github:thomasloven/lovelace-card-tools" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Release 2 | 3 | See https://community.home-assistant.io/t/miflora-sensor-plant-database/53131 for more information of this particular MiFlora / Home-Assistant card. 4 | Also see my detailed post in this same thread at https://community.home-assistant.io/t/miflora-sensor-plant-database/53131/73 5 | 6 | ![](https://github.com/remkolems/lovelace-flower-card/blob/master/lovelace-flower-card_popup.png) 7 | 8 | ### Disclaimer 9 | I looked into several forks of the original card https://github.com/thomasloven/lovelace-flower-card. Some forks were very interesting and I edited several of those source codes changes into my own new fork. Credits to those original authors. 10 | 11 | ### Dependencies 12 | 1. Plant sensor (https://www.home-assistant.io/integrations/plant) 13 | 14 | ### Instructions 15 | 16 | 1: Install the card 17 | * Ensure HACS is installed. 18 | * Go to Community -> Frontend -> press the three dots (top right corner of screen) -> Custom repositories and add the following information: 19 | Add custom repository URL: https://github.com/Yolandavdvegt/lovelace-flower-card 20 | Category: Lovelace 21 | Press add. 22 | 23 | Press on the just added `Lovelace Flower Card` and press `Install this repository in HACS` 24 | 25 | 2: Setup card 26 | 27 | ```yaml 28 | type: custom:flower-card 29 | entity: plant.my_plant 30 | species: "tulipa 'hollandia'" 31 | ``` 32 | 33 | To get a list of the available species run `python3 convert.py DBFilename.csv species`. The value you want is the one after the colon. Enter it exactly like it says, with quotes and all. 34 | 35 | 3: Place an jpg image with the name of the species in the `/config/www/images/plants` directory. Example: `/local/images/plants/tulipa 'hollandia'.jpg`. Images of species can be found in the https://github.com/khronimo/MiFloraDB repository readme. 36 | 37 | 4: configuration.yaml 38 | 39 | Add the following to configuration.yaml (bottom of this file) 40 | ```plant: !include plants.yaml``` 41 | 42 | I do this to separate my config files. 43 | 44 | 5: plants.yaml 45 | 46 | Create, edit and add the following to plants.yaml. Change accordingly. Repeat this section for other plants. Separate each section with a blank line. 47 | ``` 48 | spathiphyllum_bingo_cupido: 49 | sensors: 50 | moisture: sensor.spathiphyllum_moisture 51 | battery: sensor.spathiphyllum_battery 52 | temperature: sensor.spathiphyllum_temperature 53 | conductivity: sensor.spathiphyllum_conductivity 54 | brightness: sensor.spathiphyllum_brightness 55 | ``` 56 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import { LitElement, css, html } from "card-tools/src/lit-element"; 2 | 3 | import {FlowerData} from './data.js'; 4 | import { moreInfo } from "card-tools/src/more-info"; 5 | 6 | class FlowerCard extends LitElement { 7 | 8 | async setConfig(config) { 9 | this.config = config; 10 | } 11 | 12 | static get styles() { 13 | return css` 14 | ha-card { 15 | margin-top: 32px; 16 | } 17 | .attributes { 18 | white-space: nowrap; 19 | padding: 8px; 20 | } 21 | .attribute ha-icon { 22 | float: left; 23 | margin-right: 4px; 24 | } 25 | .attribute { 26 | display: inline-block; 27 | width: 50%; 28 | white-space: normal; 29 | } 30 | 31 | .header { 32 | padding-top: 8px; 33 | height: 72px; 34 | } 35 | .header > img { 36 | border-radius: 50%; 37 | width: 88px; 38 | margin-left: 16px; 39 | margin-right: 16px; 40 | margin-top: -32px; 41 | float: left; 42 | box-shadow: var( --ha-card-box-shadow, 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2) ); 43 | } 44 | .header > #name { 45 | font-weight: bold; 46 | width: 100%; 47 | margin-top: 16px; 48 | text-transform: capitalize; 49 | display: block; 50 | } 51 | .header > #species { 52 | text-transform: capitalize; 53 | color: #8c96a5; 54 | display: block; 55 | } 56 | .meter { 57 | height: 8px; 58 | background-color: #f1f1f1; 59 | border-radius: 2px; 60 | display: inline-grid; 61 | overflow: hidden; 62 | } 63 | .meter.red { 64 | width: 10%; 65 | } 66 | .meter.green { 67 | width: 50%; 68 | } 69 | .meter > span { 70 | grid-row: 1; 71 | grid-column: 1; 72 | height: 100%; 73 | } 74 | .meter > .good { 75 | background-color: rgba(43,194,83,1); 76 | } 77 | .meter > .bad { 78 | background-color: rgba(240,163,163); 79 | } 80 | .divider { 81 | height: 1px; 82 | background-color: #727272; 83 | opacity: 0.25; 84 | margin-left: 8px; 85 | margin-right: 8px; 86 | } 87 | .tooltip { 88 | position: relative; 89 | } 90 | .tooltip:after { 91 | opacity: 0; 92 | visibility: hidden; 93 | position: absolute; 94 | content: attr(data-tooltip); 95 | padding: 6px 10px; 96 | top: 1.4em; 97 | left: 50%; 98 | -webkit-transform: translateX(-50%) translateY(-180%); 99 | transform: translateX(-50%) translateY(-180%); 100 | background: grey; 101 | color: white; 102 | white-space: nowrap; 103 | z-index: 2; 104 | border-radius: 2px; 105 | transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), -webkit-transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); 106 | transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); 107 | transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), -webkit-transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); 108 | } 109 | .tooltip:hover:after, .tooltip:active:after { 110 | display: block; 111 | opacity: 1; 112 | visibility: visible; 113 | -webkit-transform: translateX(-50%) translateY(-200%); 114 | transform: translateX(-50%) translateY(-200%); 115 | } 116 | `; 117 | } 118 | 119 | render() { 120 | const species = this.config.species; 121 | const Flower = FlowerData[species]; 122 | if(!this.stateObj) 123 | return html``; 124 | 125 | const attribute = (icon, attr, min, max) => { 126 | const unit = this.stateObj.attributes.unit_of_measurement_dict[attr]; 127 | const val = this.stateObj.attributes[attr]; 128 | const pct = 100*Math.max(0, Math.min(1, (val-min)/(max-min))); 129 | return html` 130 |
131 | 132 |
133 | 134 |
135 |
136 | 137 |
138 |
139 | 140 |
141 |
142 | `; 143 | // ${val} (${min}-${max}) 144 | } 145 | 146 | return html` 147 | 148 |
149 | 150 | ${this.stateObj.attributes.friendly_name} 151 | ${Flower[0]} 152 |
153 |
154 |
155 | ${attribute('mdi:thermometer', 'temperature', Flower[4], Flower[5])} 156 | ${attribute('mdi:white-balance-sunny', 'brightness', Flower[2], Flower[3])} 157 |
158 |
159 | ${attribute('mdi:water-percent', 'moisture', Flower[6], Flower[7])} 160 | ${attribute('mdi:leaf', 'conductivity', Flower[8], Flower[9])} 161 |
162 |
163 | `; 164 | } 165 | 166 | set hass(hass) { 167 | this._hass = hass; 168 | this.stateObj = hass.states[this.config.entity]; 169 | this.requestUpdate(); 170 | } 171 | 172 | } 173 | 174 | customElements.define('flower-card', FlowerCard); 175 | --------------------------------------------------------------------------------