I was looking to acquire some cool and cheap sensors for monitoring my indoor plants’ health. I’d never clicked so fast to purchase a $20 Xiaomi plant sensor on ebay claiming to measure light intensity, temperature, soil moisture and plant fertility.

How does this piece of plastic measure ‘fertility’ I wondered. After peaking under the hood of this sensor’s operations using the MiFlora python module I saw there was an attribute called ‘conductivity’ instead of fertility. Turns out soil electrical conductivity (EC) is a metric correlated with soil moisture, drainage ability, organic matter level, crop productivity, salinity and is used worldwide as a yardstick for soil health.
Depending on the amount of moisture in the soil and soil salinity (water alone does not conduct electricity so the salts dissolved in the water does) the sensor can deduce in milliSiemens per meter (mS/m) the amount of moisture held by soil particles. It makes sense then that sand would have a low conductivity, silt a medium conductivity, and clay a high conductivity. More on soil conductivity here: Measuring EC.
What units does Xiaomi use?
- Moisture (%)
- Temperature (ºC)
- Conductivity (µS/cm)
- Brightness (Lux)
- Battery (%)
The sensor comes with a companion app – Plant care – which I would rate as OK. You can pair the sensor with your phone using bluetooth. The app has a database of plants and their required optimal conditions. I swapped the sensor around on my plants but with the app you cannot select more than one plant to monitor (as in if you change from monitoring a cucumber to a chilli pepper it doesn’t save the historical data from the time spent monitoring the cucumber.)
I also occasionally faced difficulty connecting to the sensor via bluetooth on my phone to sync the data. The app’s major shortcoming is that its analytics and time series graphs are not portable, meaning you can’t email them or download them. There are somehow full days of data missing from the graphs.
I took this screenshot in the evening when there was no sunlight in my room and I hadn’t watered the plant for a few days. I also compared the temperature reading to that of my Aqara temperature and humidity sensor and they were on par. So I’m happy to vouch for this little device in terms of accuracy. I’m also impressed with the battery life. I’ve been using it for over 6 months and the battery level is still at 98%.
RPi – time to boot up!
To overcome the limitations of this app and to collect data directly from the sensor it was time to boot up the raspberry pi and look for an API. I was delighted to find a python module online over on https://pypi.org/project/miflora
I downloaded it and used the following code to insert data into a postgresql database every 3 hours with the intention of making my own graphs.
Instructions
Install prerequisite modules
sudo apt-get install python3-pip sudo pip3 install miflora sudo pip3 install bluepy
To find the sensor’s MAC address
sudo hcitool lescan
LE Scan ... C4:7C:8D:6A:59:EA Flower care
From reading miflora github I retrieved the methods and modules needed to connect to the sensor https://github.com/open-homeautomation/miflora
import psycopg2
import datetime
from miflora.miflora_poller import MiFloraPoller, MI_CONDUCTIVITY, MI_MOISTURE, MI_LIGHT, MI_TEMPERATURE, MI_BATTERY
from btlewrap.bluepy import BluepyBackend
def connectPlantcare(MAC):
data = {}
conn = MiFloraPoller(MAC, BluepyBackend)
data["Entry_date"] = datetime.datetime.now()
data["Light"] = poller.parameter_value(MI_LIGHT)
data["Temperature"] = poller.parameter_value(MI_TEMPERATURE)
data["Conductivity"] = poller.parameter_value(MI_CONDUCTIVITY)
data["Moisture"] = poller.parameter_value(MI_MOISTURE)
data["Battery"] = poller.parameter_value(MI_BATTERY)
return data
def connectPsql():
try:
conn = psycopg2.connect('dbname=plantcare user=postgres host=localhost password=secret port=5432')
except ConnectionError as e:
return e
return conn
def insertSensorData():
try:
conn = connect_psql()
cur = conn.cursor()
data = connect_plantcare("C4:7C:8D:6A:59:EA")
query = u"INSERT INTO sensor_data(entry_date, temperature, moisture, light, conductivity, battery) VALUES (%s, %s, %s, %s, %s, %s)"
vars= (data["Entry_date"], data["Temperature"], data["Conductivity"], data["Moisture"], data["Light"], data["Conductivity"])
cur.execute(query, vars)
conn.commit()
conn.close()
print("Data inserted into plantcare database ", datetime.datetime.now())
except ConnectionError as e:
return e
finally:
if(conn):
conn.close()
print("PostgresSQL connection closed")
if __name__ == "__main__":
insertSensorData()
Originally I had used the above script, scheduled to run with a cronjob to insert data into the database every 3 hours. However, I fried my SD card by sticking it into my laptop and trying to read it when the SD adapter had a drop of water on it. Don’t ask! So I lost over 3 months of historical plant data of monitoring my chilli pepper from a seedling to a mature bush.
Fairly devastating, but motivation to port my database to a cloud solution instead of my local RPi. Part 2 of this series will include a time series visualization.
This is all so far beyond my knowledge, but I am fascinated. MIDI sprout eat your heart out,
LikeLike