First of all: Big kudos to @ThomDietrich for assembling all the parts and this fantastic tutorial. It worked from the first moment on.
Setting up the miflora environment was to achieve a brief overview over the status of my plants and answer the main question: Do i need to water and /or fertilize a plant?
Based on this, i created a very simple status view in the sitemap.
Below you find all the items, sitemaps, rules and so on. I did not translate the labels because from the item name the usage should be clear.
Items and Groups
Based on my group concept all plats are organized in serveral groups
Group Plants "Planzen" <edit_settings> (Context)
Group PlantThings "Planzen" <edit_settings> (Plants)
Group PlantMonitoring "Planzendaten" <edit_settings> (Plants)
Group PlantMoisture "Feuchtigkeit" <edit_settings> (PlantMonitoring, Charting)
Group PlantConductivity "Düngung" <edit_settings> (PlantMonitoring, Charting)
Group PlantTemperature "Temperatur" <edit_settings> (PlantMonitoring, Charting)
Group PlantBrightness "Helligkeit" <edit_settings> (PlantMonitoring, Charting)
Group PlantStatus "Status" <edit_settings> (PlantMonitoring)
The items for each plant are structured the same way. I use the botanical name für the item.
//----------------------------------------------------------------------------------------------------------------------------------------------------
//
// MiFlora sensor at Zyperngras C4:7C:8D:65:B5:7D
//
// Required values
// Temperature: 10,0 - 35,0°C
// Conductivity: 350 - 2000µs/cm
// Moisture: 15 - 60%
//
//----------------------------------------------------------------------------------------------------------------------------------------------------
Group GF_BR_CyperusAlternifolius "Zyperngras Schlafzimmer" <weather_pollen> (GF_Bedroom, PlantThings)
Number GF_BR_CyperusAlternifolius_Brightness "Helligkeit Zyperngras [%d Lux]" <weather_light_meter> (GF_BR_CyperusAlternifolius, PlantBrightness) {mqtt="<[mqtt:miflora/Zyperngras:state:JSONPATH($.light)]"}
Number GF_BR_CyperusAlternifolius_Temperature "Temperatur Zyperngras [%.1f °C]" <temp_soil> (GF_BR_CyperusAlternifolius, PlantTemperature) {mqtt="<[mqtt:miflora/Zyperngras:state:JSONPATH($.temperature)]"}
Number GF_BR_CyperusAlternifolius_Conductivity "Düngung Zyperngras [%d µS/cm]" <weather_humidity_soil> (GF_BR_CyperusAlternifolius, PlantConductivity) {mqtt="<[mqtt:miflora/Zyperngras:state:JSONPATH($.conductivity)]"}
Number GF_BR_CyperusAlternifolius_Moisture "Bodenfeuchte Zyperngras [%d %%]" <weather_humidity_soil> (GF_BR_CyperusAlternifolius, PlantMoisture) {mqtt="<[mqtt:miflora/Zyperngras:state:JSONPATH($.moisture)]"}
Number GF_BR_CyperusAlternifolius_BatteryLevel "Batterie Zyperngras [%d %%]" <measure_battery> (GF_BR_CyperusAlternifolius, BatterieLevel) {mqtt="<[mqtt:miflora/Zyperngras:state:JSONPATH($.battery)]"}
Switch GF_BR_CyperusAlternifolius_Battery "Batterie Zyperngras [MAP(battery.map):%s]" <measure_battery_50> (GF_BR_CyperusAlternifolius, Batteries) {mqtt="<[mqtt:miflora/Zyperngras:state:JS(battery2switch.js)]"}
Number GF_BR_CyperusAlternifolius_Status "Zyperngras [MAP(plantstatus.map):%s]" <weather_pollen> (GF_BR_CyperusAlternifolius, PlantStatus)
Transformations
As you see i use some transformations in the labels. you will find them below.
battery.map - Battery status human readable
ON=Leer
OFF=OK
NULL=N/A
-=N/A
plantstatus.map (Translated) - Battery status human readable
NULL=No Data
-=No Data
0=Perfect
1=Water
2=Fertilize
3=Water with fertilizer
4=Too damp
6=Fertilize & Too damp
8=overfertilized
9=Water & overfertilized
12=Too damp & overfertilized
battery2switch.js - Transform the battery level to a switch see battery.map
(function(i) {
var json = JSON.parse(i);
if(json.battery <= 10) return "ON"
else return "OFF"
})(input)
Rules
The only rule at the moment. It calculates every hour the plant status.
//------------------------------------------------------------------------------------------------------------------------------------------------------------
//
// Constants and variables
//
//------------------------------------------------------------------------------------------------------------------------------------------------------------
// Values are taken from the Miflora app
val Map<String, Double> PlantDataMap = newHashMap (
"GF_KI_Chilli_Moisture_Min" -> 15.0, "GF_KI_Chilli_Moisture_Max" -> 60.0, "GF_KI_Chilli_Conductivity_Min" -> 350.0, "GF_KI_Chilli_Conductivity_Max" -> 2000.0,
"GF_LR_DypsisLutescens_Moisture_Min" -> 15.0, "GF_LR_DypsisLutescens_Moisture_Max" -> 60.0, "GF_LR_DypsisLutescens_Conductivity_Min" -> 350.0, "GF_LR_DypsisLutescens_Conductivity_Max" -> 2000.0,
"GF_LR_PterisCretica_Moisture_Min" -> 15.0, "GF_LR_PterisCretica_Moisture_Max" -> 60.0, "GF_LR_PterisCretica_Conductivity_Min" -> 350.0, "GF_LR_PterisCretica_Conductivity_Max" -> 1500.0,
"GF_LR_PhlebodiumAureum_Moisture_Min" -> 15.0, "GF_LR_PhlebodiumAureum_Moisture_Max" -> 60.0, "GF_LR_PhlebodiumAureum_Conductivity_Min" -> 350.0, "GF_LR_PhlebodiumAureum_Conductivity_Max" -> 2000.0,
"GF_BR_CyperusAlternifolius_Moisture_Min" -> 15.0, "GF_BR_CyperusAlternifolius_Moisture_Max" -> 60.0, "GF_BR_CyperusAlternifolius_Conductivity_Min" -> 350.0, "GF_BR_CyperusAlternifolius_Conductivity_Max" -> 2000.0,
"GF_BR_CalatheaZebrina_Moisture_Min" -> 15.0, "GF_BR_CalatheaZebrina_Moisture_Max" -> 65.0, "GF_BR_CalatheaZebrina_Conductivity_Min" -> 350.0, "GF_BR_CalatheaZebrina_Conductivity_Max" -> 1000.0
)
//------------------------------------------------------------------------------------------------------------------------------------------------------------
//
// Rule: Check the plant status watering and fertilisation every hour and update the status flag
//
//------------------------------------------------------------------------------------------------------------------------------------------------------------
rule "Check Plant Status"
when
Time cron "0 0 * ? * *" //every Hour
then
PlantThings.members.forEach[ Plant |
var ActualMoisture = PlantMoisture.members.filter[ pm | pm.name == Plant.name+"_Moisture"].head.state as DecimalType
var ActualConductivity = PlantConductivity.members.filter[ pm | pm.name == Plant.name+"_Conductivity"].head.state as DecimalType
var ActualStatus = 0
if (ActualMoisture <= PlantDataMap.get(Plant.name+"_Moisture_Min")) {
ActualStatus = ActualStatus + 1
}
if (ActualMoisture > PlantDataMap.get(Plant.name+"_Moisture_Max")) {
ActualStatus = ActualStatus + 4
}
if (ActualConductivity <= PlantDataMap.get(Plant.name+"_Conductivity_Min")) {
ActualStatus = ActualStatus + 2
}
if (ActualConductivity > PlantDataMap.get(Plant.name+"_Conductivity_Max")) {
ActualStatus = ActualStatus + 8
}
PlantStatus.members.filter[ pm | pm.name == Plant.name+"_Status"].head.postUpdate(ActualStatus)
logInfo("rule.CheckPlantStatus", "Update status of {} to {}", Plant.name, transform("MAP", "plantstatus.map", ActualStatus.toString))
]
end
Sitemap
And finaly the sitemap. My plant are organized by room, so the sitemap is. Translated not alle the Strings
Text label="Plant overview" icon="weather_pollen" {
Frame label="Livingroom" {
Text item=GF_LR_DypsisLutescens_Status label="Goldfruchtpalme [MAP(plantstatus.map):%s]" icon="weather_pollen" valuecolor=[0="green", !=0="red"]
Text item=GF_LR_PterisCretica_Status label="Saumfarn [MAP(plantstatus.map):%s]" icon="weather_pollen" valuecolor=[0="green", !=0="red"]
Text item=GF_LR_PhlebodiumAureum_Status label="Goldtüpfelfarn [MAP(plantstatus.map):%s]" icon="weather_pollen" valuecolor=[0="green", !=0="red"]
}
Frame label="Kitchen" {
Text item=GF_KI_Chilli_Status label="Chilli [MAP(plantstatus.map):%s]" icon="weather_pollen" valuecolor=[0="green", !=0="red"]
}
Frame label="Bedroom" {
Text item=GF_BR_CyperusAlternifolius_Status label="Zyperngras [MAP(plantstatus.map):%s]" icon="weather_pollen" valuecolor=[0="green", !=0="red"]
Text item=GF_BR_CalatheaZebrina_Status label="Zebramarante [MAP(plantstatus.map):%s]" icon="weather_pollen" valuecolor=[0="green", !=0="red"]
}
}
The next step is to write a rule that once a day sends out the status of the plants that need “help”.
Any comments and suggestions are welcome.
@ThomDietrich It would be great if you could integrate the Daemon into the next release of openhabian.
Thomas