Xiaomi Mi Flora Plant Sensor MQTT Client/Daemon

@ThomDietrich
Tanks a lot for your work, this will most likely replace my Koubachi!
I set up an old Rasperry Pi with your daemon and it runs pretty smooth. Didn’t have any prior MQTT experience but setting it up for these sensors was easy enough.
Just got one window between the outdoor sensor and the RPI that’s too much. Got to figure out a good position for sensors / RPI for them to work reliably.

Using the systemd service, is there any log written? I can run “sudo service miflora status” but doesn’t give me a complete picture. If there’s a log written with all successful and unsuccesful attempts of contacting the sensors, I haven’t found it yet.

Just a small update to my status display. I am really to lazy to check the status display every day. To overcome this i added a rule that uses pushover to inform me once a day about the plant status. From my earlier post i have changed the PlantDataMap by adding name and location of the plant as well as chanhing the items names.

Here is the new rule

/ Values are taken from the Miflora app
val Map<String, Double> PlantDataMap = newHashMap (
    "MO_Plant001_Moisture_Min" -> 15.0, "MO_Plant001_Moisture_Max" -> 60.0, "MO_Plant001_Conductivity_Min" -> 350.0, "MO_Plant001_Conductivity_Max" -> 2000.0, "MO_Plant001_Name" -> "Chilli",          "MO_Plant001_Room" -> "Küche",
    "MO_Plant002_Moisture_Min" -> 15.0, "MO_Plant002_Moisture_Max" -> 60.0, "MO_Plant002_Conductivity_Min" -> 350.0, "MO_Plant002_Conductivity_Max" -> 2000.0, "MO_Plant002_Name" -> "Olive",           "MO_Plant002_Room" -> "Büro",
    "MO_Plant003_Moisture_Min" -> 15.0, "MO_Plant003_Moisture_Max" -> 65.0, "MO_Plant003_Conductivity_Min" -> 350.0, "MO_Plant003_Conductivity_Max" -> 1000.0, "MO_Plant003_Name" -> "Zebramarante",    "MO_Plant003_Room" -> "Schlafzimmer",
    "MO_Plant004_Moisture_Min" -> 15.0, "MO_Plant004_Moisture_Max" -> 60.0, "MO_Plant004_Conductivity_Min" -> 350.0, "MO_Plant004_Conductivity_Max" -> 2000.0, "MO_Plant004_Name" -> "Zyperngras",      "MO_Plant004_Room" -> "Schlafzimmer",
    "MO_Plant005_Moisture_Min" -> 15.0, "MO_Plant005_Moisture_Max" -> 60.0, "MO_Plant005_Conductivity_Min" -> 350.0, "MO_Plant005_Conductivity_Max" -> 2000.0, "MO_Plant005_Name" -> "Goldtüpfelfarn",  "MO_Plant005_Room" -> "Wohnzimmer",
    "MO_Plant006_Moisture_Min" -> 15.0, "MO_Plant006_Moisture_Max" -> 60.0, "MO_Plant006_Conductivity_Min" -> 350.0, "MO_Plant006_Conductivity_Max" -> 1500.0, "MO_Plant006_Name" -> "Saumfarn",        "MO_Plant006_Room" -> "Wohnzimmer",
    "MO_Plant007_Moisture_Min" -> 15.0, "MO_Plant007_Moisture_Max" -> 60.0, "MO_Plant007_Conductivity_Min" -> 350.0, "MO_Plant007_Conductivity_Max" -> 2000.0, "MO_Plant007_Name" -> "Goldfruchtpalme", "MO_Plant007_Room" -> "Wohnzimmer"
)

//------------------------------------------------------------------------------------------------------------------------------------------------------------
//
//    Rule: Every day at 16:00 create a pushover message and send it out
//
//------------------------------------------------------------------------------------------------------------------------------------------------------------
rule "Publish Plant Status"
when
    Time cron "0 0 16 ? * *"
then

    var String Message = "-> Pflanzenstatus <-\n"

    PlantThings.members.forEach[ Plant |

        var ActualStatus = PlantStatus.members.filter[ pm | pm.name == Plant.name+"_Status"].head.state as DecimalType
        var ActualName = PlantDataMap.get(Plant.name + "_Name")

        if ((ActualStatus == 1) || (ActualStatus == 2) || (ActualStatus == 3) || (ActualStatus == 6) || (ActualStatus == 9)) {
            Message = Message + ActualName + " -> " + transform("MAP", "plantstatus.map", ActualStatus.toString) + "\n"
        }
    ]
    Message = Message + "-> Ende <-"

    pushover(Message, "Disorganiser")
    pushover(Message, "Froschzilla")

end

pushover could be replaced by any other service.

Things todo:
1.) Rework the status message to be more informative - Suggestions are welcome
2.) Sort plants by room to optimize the care route - Help is welcome, because at the moment if have no idea :frowning:

That’s it for today

Thomas

3 Likes

Just a WAF (Woman Acceptance Factor) update. Include a flag that suppresses the message if there is nothing to do.

New Rule

//------------------------------------------------------------------------------------------------------------------------------------------------------------
//
//    Rule: Every day at 16:00 create a pushover message and send it out
//
//------------------------------------------------------------------------------------------------------------------------------------------------------------
rule "Publish Plant Status"
when
    Time cron "0 0 16 ? * *"
then

    var Boolean ThingsToDo = False
    var String Message = "-> Pflanzenstatus <-\n"

    PlantThings.members.forEach[ Plant |

        var ActualStatus = PlantStatus.members.filter[ pm | pm.name == Plant.name+"_Status"].head.state as DecimalType
        var ActualName = PlantDataMap.get(Plant.name + "_Name")

        if ((ActualStatus == 1) || (ActualStatus == 2) || (ActualStatus == 3) || (ActualStatus == 6) || (ActualStatus == 9)) {
            Message = Message + ActualName + " -> " + transform("MAP", "plantstatus.map", ActualStatus.toString) + "\n"
            ThingsToDo = True
        }
    ]
    Message = Message + "-> Ende <-"

    if (ThingsToDo) {
        pushover(Message, "Disorganiser")
        pushover(Message, "Froschzilla")
    }

end

This flag is not tested.

Thomas

3 Likes

Hallo Patrick,
no there is not. Simply didn’t see the need for it. If you’D be interested we could talk about an improvement of course.
I was thinking about a related issue and plan to implement a better usage of the status message, check: https://github.com/ThomDietrich/miflora-mqtt-daemon/issues/16

So instead of this:

I’d remove the overly redundant error messages and update the “Status” line with the success rate of all plants. What do you think?

Quick question for my understanding…

First, the daemon can be installed in the background on my rpi3 with running openhab2?
Second, if i will not reach the plant sensor with my rpi3 (OH) i can setup rpi0w as a bridge which will send via mqtt the data to my rpi3(oh) mqtt broker?! :thinking::thinking:

Exactly. The RPi0w (or any other device) will act as yet another miflora data collector. Both daemons will run independently and publish their data to your MQTT broker. In the daemon configurations you’ll only set up those sensors which are supposed to be queried by this daemon.

1 Like

Should we prepare an image for the bridge to make a super easy installation?
Is there a smart way to synchronize the /opt/miflora-mqtt-daemon/config.ini file lets say every midnight between bridge(copy) and the openhabian master rpi?

You mean like openHABian :smiley:
Adding the daemon as an optional component is on my todo list! Sadly I am packed with other stuff. If you’d like to help, that would be amazing! @Multisaft7 @skatun @Dibbler42 anyone?

1 Like

I would by i not own a Flora Sensor since now…will take a look at the coming ads in the next day and will try to get one…

Did you get yours from aliexpress?

Yes. https://www.aliexpress.com/wholesale?SearchText=xiaomi+mi+flora+plant+sensor

Back then there were no different versions. Now there is an international Version which is basically more expensive but can be paired with the app outside of China. If you (like me) will not use the app, you can ignore that and go cheaper.

Installation of the daemon is pretty easy. Maybe I’ll add it to openHABian tonight.

1 Like

Thanks for the feedback. Yes, being able to call status on the daemon and get an overview of all plants would be awesome.
But no hurry. By now, I’ve integrated two sensors in my setup and I also added a “Last Update” time to each one that gets updated as soon as one of the values changed (and light intensity basically updates each time).
Set it to 15min and saw now, that both work flawlessly every 15min, so I expect to see almost 100% success rate in the status message. :smiley:

Here we go :smiley:

1 Like

I have 12 of them, really handy for me that does not have green fingers, unfortunately 2 of them is out of the reach for the rpi, so sometime this winter I will add a bridge as rpi0W. I also have some water irragation system that I am working on…

I have the same problem as you. The range does not reach from the pi to the MIflora. If you have any idea how to create a bridge increase the power would be very grateful to collaborate.

Hey, that problem is part of why the daemon relies on MQTT. You can simply set up another RPi0W in Bluetooth range: Xiaomi Mi Flora Plant Sensor MQTT Client/Daemon

A very expensive repeater turns out :frowning:

Very expensive is a relative term i guess :smirk: When i compared it to other solutions, this setup (even with one or two extra rpi0W) was still the cheapest for me if you want several sensors.

For Node-red users there is a node which auto detects your miflowers and get data from them. you need to install a few nodes also, but it works and it’s up and running without any hassel:

Can you confirm that 10 devices is maximum per rpi?

I am not really sure if I setup my config right cause i got an error after the start… :sweat_smile:

[21:24:44] openhabian@openHABianPi:~$ python3 /opt/miflora-mqtt-daemon/miflora-mqtt-daemon.py

Xiaomi Mi Flora Plant Sensor MQTT Client/Daemon
Source: https://github.com/ThomDietrich/miflora-mqtt-daemon

Traceback (most recent call last):
  File "/opt/miflora-mqtt-daemon/miflora-mqtt-daemon.py", line 119, in <module>
    config.read([os.path.join(sys.path[0], 'config.ini.dist'), os.path.join(sys.path[0], 'config.ini')])
  File "/usr/lib/python3.4/configparser.py", line 672, in read
    self._read(fp, filename)
  File "/usr/lib/python3.4/configparser.py", line 1070, in _read
    fpname, lineno)
configparser.DuplicateOptionError: While reading from '/opt/miflora-mqtt-daemon/config.ini' [line 42]: option 'base_topic' in section 'MQTT' already exists

Config.ini

[General]

# The operation mode of the program. Determines wether retrieved sensor data is published via MQTT or stdout/file.
# Currently supported:
#      mqtt-json - Publish to an mqtt broker, json encoded (Default)
#     mqtt-homie - Publish to an mqtt broker following the Homie MQTT convention (https://github.com/marvinroger/homie)
# mqtt-smarthome - Publish to an mqtt broker following the mqtt-smarthome proposal
#                  (https://github.com/mqtt-smarthome/mqtt-smarthome)
#           json - Print to stdout as json encoded string
reporting_method = mqtt-json

# The bluetooth adapter that should be used to connect to Mi Flora devices (Default: hci0)
adapter = hci0

[Daemon]

# Enable or Disable an endless execution loop (Default: true)
enabled = true

# The period between two measurements in seconds (Default: 300)
period = 300

[MQTT]

# The hostname or IP address of the MQTT broker to connect to (Default: localhost)
hostname = localhost

# The TCP port the MQTT broker is listening on. SSL/TLS currently not implemented (Default: 1883)
port = 1883

# Maximum period in seconds between ping messages to the broker. (Default: 60)
keepalive = 60

# The MQTT base topic to publish all Mi Flora sensor data topics under.
# Default depends on the configured reporting_mode (mqtt-json, mqtt-smarthome: miflora, mqtt-homie: homie)
base_topic = miflora
base_topic = homie

# Homie specific: The device ID for this daemon instance (Default: miflora-mqtt-daemon)
homie_device_id = miflora-mqtt-daemon

# The MQTT broker authentification credentials (Default: no authentication)
#username = user
#password = pwd123

[Sensors]

# Add your Mi Flora sensors here. Each sensor consists of a name and a Ethernet MAC address.
# Additional location information can be added to the name, delimited by an '@'.
# Scan for sensors from the command line with:
#    $ sudo hcitool lescan
#
# Examples:
Einblatt@Bedroom = C4:7C:8D:65:DE:85

mmhh? :confused: