Moving from other topic.
Here is an alternative way of getting MiFlora plant sensor data into openhab:
There are several threads about this already. Iām posting my setup,
it can probably be labeled as hack, itās not clean, itās not beautiful, itās not easy.
However it works for me, and itās easy to maintain.
First This is the monitor Iām talking about
http://xiaomi-mi.com/smart-home/xiaomi-huahuacacao-flower-care-smart-monitor/
http://xiaomi-mi.com/uploads/CatalogueImage/pvm_xiaomi-flower-monitor-02_14361_1466174108.jpg
It can be bought on ebay aliexpress and similar, I payed 11 euros a piece on aliexpress.
This thing transfers data using Bluetooth (BT). BT is short ranged, typically you will have plants/flowers scattered around your house on different floors and whatnot.
Therefor Iām using RPis (2-3) to collect data and to poll the devices.
The RPI:s will then post data to Openhab using MQTT.
Source code in java, bash script is available here:
(Extract them from the jar file if you wish to alter)
http://www.zoidberg.se/pub/sproute.jar
Java source files (they are included in the jar as well):
http://www.zoidberg.se/pub/SprouteConfig.java
http://www.zoidberg.se/pub/Sproute.java
http://www.zoidberg.se/pub/PlantConfig.java
- Get some RPI or similar
- Install Bluetooth dongle or use the built in in RPi3 (not tested this)
https://www.raspberrypi.org/learning/robo-butler/bluetooth-setup/
- Install Java 8
http://www.rpiblog.com/2014/03/installing-oracle-jdk-8-on-raspberry-pi.html
- Install mqtt clients: sudo apt-get install mosquitto-clients
- Install git: sudo apt-get install git
- Install python3
sudo apt-get install python3
sudo apt-get install python3-pip
sudo apt-get install python3-gattlib (or sudo pip3 install gattlib)
- Install miflora python library: https://github.com/open-homeautomation/miflora
git clone https://github.com/open-homeautomation/miflora
(Iām not the author of miflora)
- Build it, or use the build source inside the repo
- Building (./build.sh)
- Verify that the lib works by invoking python3 demo.py (change the macaddress inside)
Add this python script to miflora:
import sys
import time
import datetime
from miflora.miflora_poller import MiFloraPoller, \
MI_CONDUCTIVITY, MI_MOISTURE, MI_LIGHT, MI_TEMPERATURE
poller = MiFloraPoller(str(sys.argv[1]))
now = time.time()
dtnow=datetime.datetime.fromtimestamp(now)
millis = int(round(now * 1000))
yyyymmddhhmmss = datetime.datetime.strftime(dtnow, '%Y-%m-%d %H:%M:%S')
temp = poller.parameter_value("temperature")
moist = poller.parameter_value(MI_MOISTURE)
light = poller.parameter_value(MI_LIGHT)
cond = poller.parameter_value(MI_CONDUCTIVITY)
battery = poller.battery_level()
print(yyyymmddhhmmss + " C: {:.2f} M: {:d} L: {:d} CD: {:d} B: {:d}".format(temp, moist, light, cond, battery) + " time:" + str(millis))
Edit the sproute.sh file (located inside the jar if you want to extract it):
Change the parameters on top so the locations are correct:
#!/bin/bash -
#sproute.sh -l - Will list all mac-addresses with Mi Flower
#sproute.sh -o - Will generate Openhab items calling java program
#sproute.sh -p - Will poll and publish data using mqtt
MOSQ_SERVER="10.1.1.1"
CHECK_PLANT="/home/pi/miflora/checkplant.py"
SCAN_RESULT_FILE="/tmp/result.txt"
PLANT_ITEMS_FILE="/home/pi/plants.items"
SPROUTE_JAR="/home/pi/sproute/sproute.jar"
SPROUTE_PROPS="/home/pi/sproute.properties"
PLANT_FILES_DIR="/home/pi/plants"
plantCheck() {
LOGROW=`python3 $CHECK_PLANT "${plant_mac}"`
echo $LOGROW >> "/var/log/plant.${plant_log_suffix}.log"
TEMP0=`echo $LOGROW | awk '{print $4}'`
MOIST0=`echo $LOGROW | awk '{print $6}'`
LIGHT0=`echo $LOGROW | awk '{print $8}'`
COND0=`echo $LOGROW | awk '{print $10}'`
BATTERY0=`echo $LOGROW | awk '{print $12}'`
mosquitto_pub -h $MOSQ_SERVER -m $TEMP0 -t plants/"${plant_name,,}"/temp -q 1
mosquitto_pub -h $MOSQ_SERVER -m $MOIST0 -t plants/"${plant_name,,}"/moist -q 1
mosquitto_pub -h $MOSQ_SERVER -m $LIGHT0 -t plants/"${plant_name,,}"/light -q 1
mosquitto_pub -h $MOSQ_SERVER -m $COND0 -t plants/"${plant_name,,}"/cond -q 1
mosquitto_pub -h $MOSQ_SERVER -m $BATTERY0 -t plants/"${plant_name,,}"/battery -q 1
mosquitto_pub -h $MOSQ_SERVER -m ${plant_moist_low} -t plants/"${plant_name,,}"/moistlow -q 1
mosquitto_pub -h $MOSQ_SERVER -m ${plant_moist_high} -t plants/"${plant_name,,}"/moisthigh -q 1
mosquitto_pub -h $MOSQ_SERVER -m ${plant_conductivity_low} -t plants/"${plant_name,,}"/condlow -q 1
mosquitto_pub -h $MOSQ_SERVER -m ${plant_conductivity_high} -t plants/"${plant_name,,}"/condhigh -q 1
echo "Published ${plant_log_suffix}: TEMP=$TEMP0 MOIST=$MOIST0 LIGHT=$LIGHT0 COND=$COND0 BATTERY=$BATTERY0"
echo "Published COND_LOW=${plant_conductivity_low} COND_HIGH=${plant_conductivity_high}"
sleep 10
MILLIS=`date +%s%N | cut -b1-13`
mosquitto_pub -h $MOSQ_SERVER -m $MILLIS -t plants/update -q 1
}
readPlantConfig() {
configFile=$1
if [ -f "$configFile" ]; then
echo "$configFile found."
while IFS='=' read -r key value
do
key=$(echo $key | tr '.' '_')
eval "${key}='${value}'"
done < "$configFile"
echo "Plant name = " ${plant_name}
echo "MacAddress = " ${plant_mac}
else
echo "$configFile not found."
fi
verbose='false'
}
lflag=''
oflag=''
pflag=''
files=''
if [ "$#" -ne 1 ]; then
echo "sproute.sh -l - Will list all mac-addresses with Mi Flower"
echo "sproute.sh -o - Will generate Openhab items calling java program"
echo "sproute.sh -p - Will poll and publish data using mqtt"
fi
while getopts 'lofp' flag; do
case "${flag}" in
l) lflag='true' ;;
o) oflag='true' ;;
p) pflag='true' ;;
f) files="${OPTARG}" ;;
*) error "Unexpected option ${flag}" ;;
esac
done
if [ "$lflag" == "true" ]; then
echo "Searching for mi flower firmware 2.6.6"
##Hack to restart hci, when kill will stop working otherwise
#
sudo hciconfig hci0 down
sudo hciconfig hci0 up
# End Hack
sudo hcitool lescan> $SCAN_RESULT_FILE &
sleep 5
sudo pkill --signal SIGINT hcitool
sudo hciconfig hci0 down
sudo hciconfig hci0 up
result=$(sudo timeout 5s hcitool lescan)
##Hack to restart hci, when kill will stop working otherwise
sudo hciconfig hci0 down
sudo hciconfig hci0 up
# End Hack
echo "Firmware 2.6.6"
sudo cat $SCAN_RESULT_FILE |grep "Flower care"
echo "Firmware 2.6.2"
sudo cat $SCAN_RESULT_FILE |grep "Flower mate"
fi
if [ "$oflag" == "true" ]; then
rm $PLANT_ITEMS_FILE
java -jar $SPROUTE_JAR $SPROUTE_PROPS -o $PLANT_ITEMS_FILE
echo "Wrote $PLANT_ITEMS_FILE"
cat $PLANT_ITEMS_FILE
fi
if [ "$pflag" == "true" ]; then
PLANT_FILES=`ls ${PLANT_FILES_DIR}/*`
echo $PLANT_FILES
for i in $PLANT_FILES; do
readPlantConfig $i
plantCheck
done
fi
- Check your plants with this command:
pi@colibri:~/plants $ /sbin/sproute.sh -l
Searching for mi flower firmware 2.6.6
Firmware 2.6.6
C4:7C:8D:61:CB:75 Flower care
C4:7C:8D:61:CD:11 Flower care
Firmware 2.6.2
C4:7C:8D:62:51:51 Flower mate
- Create plants file inside the plant folder (see sh-script)
i@colibri:~/plants $ cat benji.zpc
plant.name=Benji
plant.mac=C4:7C:8D:61:CB:75
plant.moist.low=20
plant.moist.high=60
plant.temp.low=8.0
plant.temp.high=32.0
plant.conductivity.low=500
plant.conductivity.high=2000
plant.log.suffix=p0
Create openhab items:
This will create openhab items for all plants you have.
pi@colibri:~/plants $ /sbin/sproute.sh -o
Wrote file successfully: /home/pi/plants.items
Wrote /home/pi/plants.items
Group Plants
Group PlantTemperature
Group PlantMoisture
Group PlantLight
Group PlantConductivity
Group PlantBattery
Number PlantsUpdate "Plants Updated [%s]" <clock> (Plants) { mqtt="<[mosquitto:plants/update:state:default]" }
Group PlantBenji "Plant Benji" <plant2> (Plants)
Number PlantBenjiTemperature "Benji [%.2f Ā°C]" <ptemp> (Temperature, PlantTemperature, PlantBenji) { mqtt="<[mosquitto:plants/benji/temp:state:default]" }
Number PlantBenjiTempHigh "Benji [%.2f Ā°C]" (PlantBenji) { mqtt="<[mosquitto:plants/benji/temphigh:state:default]" }
Number PlantBenjiTempLow "Benji [%.2f Ā°C]" (PlantBenji) { mqtt="<[mosquitto:plants/benji/templow:state:default]" }
Number PlantBenjiMoisture "Benji [%d %%]" <pmoisture> (PlantMoisture, PlantBenji) { mqtt="<[mosquitto:plants/benji/moist:state:default]" }
Number PlantBenjiMoistLow "Benji [%d %%]" <pmoisture> (PlantMoisture, PlantBenji) { mqtt="<[mosquitto:plants/benji/moistlow:state:default]" }
Number PlantBenjiMoistHigh "Benji [%d %%]" <pmoisture> (PlantMoisture, PlantBenji) { mqtt="<[mosquitto:plants/benji/moisthigh:state:default]" }
Switch PlantBenjiMoistWarn "Benji Moisture Level Warning" (PlantMoisture, PlantBenji)
Number PlantBenjiConductivity "Benji [%d uS/cm]" <pconduct> (PlantConductivity, PlantBenji) { mqtt="<[mosquitto:plants/benji/cond:state:default]" }
Number PlantBenjiConductHigh "Benji [%d uS/cm]" (PlantConductivity, PlantBenji) { mqtt="<[mosquitto:plants/benji/condhigh:state:default]" }
Number PlantBenjiConductLow "Benji [%d uS/cm]" (PlantConductivity, PlantBenji) { mqtt="<[mosquitto:plants/benji/condlow:state:default]" }
Switch PlantBenjiConductWarn "Benji Conductivity Level Warning" (PlantConductivity, PlantBenji)
Number PlantBenjiLight "Benji [%d Lux]" <psun> (PlantLight, PlantBenji) { mqtt="<[mosquitto:plants/benji/light:state:default]" }
Number PlantBenjiBattery "Benji [%d %%]" <pbattery> (PlantBattery, Battery, PlantBenji) { mqtt="<[mosquitto:plants/benji/battery:state:default]" }
DateTime PlantBenjiLastUpdate "Last Update [%1$tY-%1$tm-%1$td %1$tH:%1$tM]" <clock> (PlantLastUpdate, PlantBenji)
- Send result to openhab
pi@colibri:~/plants $ /sbin/sproute.sh -p
/home/pi/plants/benji.zpc found.
Plant name = Benji
MacAddress = C4:7C:8D:61:CB:75
Published p0: TEMP=20.60 MOIST=79 LIGHT=2185 COND=3471 BATTERY=92
Published COND_LOW=500 COND_HIGH=2000
In openhab you can add the following warning to send out notification when to water the plant:
import java.util.Map
import java.util.HashMap
val String LOG_PLANTS = "Plants"
var Map<String, Integer> mNameToMoistLow = new HashMap<String, Integer>()
var Map<String, Integer> mNameToMoistHigh = new HashMap<String, Integer>()
val Functions$Function2 populateMoistHighLow = [Map<String, Integer> mNameToMoistLow, Map<String, Integer> mNameToMoistHigh |
mNameToMoistLow.clear()
mNameToMoistHigh.clear()
PlantMoistLow.members.forEach[ moistLow |
mNameToMoistLow.put(moistLow.label, new Integer(moistLow.state.toString))
]
PlantMoistHigh.members.forEach[ moistHigh |
mNameToMoistHigh.put(moistHigh.label, new Integer(moistHigh.state.toString))
]
]
rule "PlantThirstyWarning"
when
Item PlantsUpdate received update
then
if (mNameToMoistLow == null) {
mNameToMoistLow = new HashMap()
}
if (mNameToMoistHigh == null) {
mNameToMoistHigh = new HashMap()
}
if (mNameToMoistLow.empty || mNameToMoistHigh.empty) {
populateMoistHighLow.apply(mNameToMoistLow, mNameToMoistHigh)
logInfo(LOG_PLANTS, "Created map for plants high low low:" + mNameToMoistLow + " high: " + mNameToMoistHigh)
}
logInfo(LOG_PLANTS, "Moisture updated, checking if any plant is thirsty")
PlantMoist.members.forEach[ moist |
val int moistLow = mNameToMoistLow.get(moist.label)
val int moistHigh = mNameToMoistHigh.get(moist.label)
var int moistValue = (moist.state as DecimalType).intValue
logInfo("Plants", "Parsed low: " + moistLow + " high: " + moistHigh + " moist: " + moist.state.toString)
if (moistValue <= moistLow) {
logInfo(LOG_PLANTS, "Warning plant: " + moist.label + " is Below lower threshold")
NotifyPlants.postUpdate("My thirsty warning")
} else if (moistValue >= moistHigh) {
logInfo(LOG_PLANTS, "Warning plant: " + moist.label + " is above higher threshold")
} else {
logInfo(LOG_PLANTS, "Plant is " + moist.label + " is ok on water level")
}
]
end
Edit crontab (I run this every 3 hours)
1 */3 * * * root /sbin/sproute.sh -p
So some things
- I use java to generate the openhab items, why because I know java better than python, and I have limited time.
- I use bash because I know bash, could be done in python as well.
- I log each check to a log-file, why because I graph this data with Graphite/Grafana
- This is a hack, but it enables me to add or remove plants just by creating a plant file, giving the plant a name and specify a mac-address. My goal is to be able to add and change plants on the fly, but without rewriting code.
- Watering rule is generic and will not have to be altered.
- Is this solution ugly, yes, but still does the job for me, feel free to change whatever, or perhaps it can inspire to something better