0MiFlora Plant Sensors in Home Assistant

I’ve been suing the MiFlora Home Assistant integration to get data on various house plants for a while. However along the way I’ve had to overcome various hurdles including limited range of bluetooth, battery life issues, and getting the battery values to report. I finally seem to have cracked all of these and now have a system that works reliably with lots of plants around the house. I’ve summarised what I’ve used below.

Hardware

The first thing to say is that I do have a bluetooth USB dongle attached to my home assistant system. This monitors the plants in range directly (i.e. the ones in the same room as the HA box). To monitor more distance devices I have used an ESP32 board with built-in bluetooth module which I have inside a cheap little case and have powered with an old micro-USB phone charger

  • USB Dongle: the one I got is no longer available – due to age – but there are plenty of amazon and elsewhere – just make sure it has support in linux
  • ESP32 board: I got a JZK ESP32-S which is currently £6.49 on amazon
  • Case for ESP32: I found the case for a NodeMCU Wroom-32D (short aerial) fitted my board – this was £4.20 from ebay

Integrations for Home Assistant

Whilst the basic MiFlora integration is built in to home assistant I found it uses a lot of battery when used natively. Instead I use the Bluetooth Low Energy Monitor 3rd party integration which you can install easily using HACS
I then also installed the ESPHome integration for home assistant to manage my ESP32 BLE repeater
Finally, to display the plants in a nice way I added a particular fork of the lovelace plant card addon via HACS

Configuration

Once BLE Monitor was installed and configured with my bluetooth dongle it picked up the MiFlora sensors within range and listed them in its “devices” drop down as well as listing the devices and entities on it’s card in the HA configuration
The great thing about BLE monitor is that it listens for the sensors to transmit, rather than actively polling them, which would run down their batteries. However, the sensors don’t transmit battery information so to get this we have to actively poll for it. Polling just for this, and passively listening for the other data seems to be the best compromise if you want to have all the data available but also maximise the sensor’s battery life. I have separated my configuration.yaml into multiple separate files to keep things a bit easier to manage so I just have the following line in my configuration.yaml –

sensor: !include sensors.yaml

Then in sensors.yaml I have each plant listed as follows

 - platform: miflora
   mac: 'mac:address:of:miflora:sensor:here'
   name: basil
   force_update: true
   scan_interval: 08:00
   median: 3
   go_unavailable_timeout: 43200
   monitored_conditions:
     - battery

Next – to make the plants appear nicely I have a plants config. As before a single line in configuration.yaml to start with:

plant: !include plants.yaml

And then in plants.yaml I have as follows

basil:
  sensors:
    moisture: sensor.ble_moisture_basil
    battery: sensor.basil_battery
    temperature: sensor.ble_temperature_basil
    conductivity: sensor.ble_conductivity_basil
    brightness: sensor.ble_illuminance_basil
  min_battery: 15
  min_brightness: 2500
  max_brightness: 60000
  min_temperature: 8
  max_temperature: 32
  min_moisture: 15
  max_moisture: 60
  min_conductivity: 350
  max_conductivity: 2000

Note the subtle difference between the entity name for the battery compared with the other sensors. The battery entity is coming from the miflora platform in sensors.yaml whilst the other 4 sensors are coming from the BLE integration. There IS a battery entity listed by the BLE integration but this just shows as “unknown” for this plant. This configuration is needed for the plant card to show the plant in a nicely presented way
Then simply go to a the place you want to add your plant and add the lovelace plant card. You will have to “configure” the card manually, but it only takes 3 lines…

type: custom:flower-card
entity: plant.basil
species: ocimum basilicum

Note that the species is listed for 2 reasons. Firstly it will display the name on the card, but more importantly, it will also display a picture of the plant if you have downloaded the plant images and added them into \config\www\images\plants using the latin names – the information on the database is available on the lovelace plant card documentation

Extending range

Finally, we need to extend the range we can reach. For this we need the ESP32 device. The first thing to do is to get it hooked up to your computer via USB and flash it with a basic ESPHome image
I used the ESPHome Flasher and the cp210x universal windows driver from SiLabs and followed the guide provided by the ESPHome HomeAssistant integration
The config I used for my ESP32 device is below

esphome:
  name: jzk-esp-32s
  platform: ESP32
  board: esp32doit-devkit-v1

# Enable logging
logger:

# Enable Home Assistant API
api:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esp32 Fallback Hotspot"
    password: "random-password-here"
    
external_components:
  - source: github://myhomeiot/esphome-components
    
esp32_ble_tracker:
    
ble_gateway:
  devices:
    - mac_address: mac:address:of:miflora:sensor:to:monitor:goes:here
  on_ble_advertise:
    then:
      homeassistant.event:
        event: esphome.on_ble_advertise
        data:
          packet: !lambda return packet;
          
myhomeiot_ble_host:

myhomeiot_ble_client:
  - mac_address: mac:address:of:miflora:sensor:to:monitor:goes:here
    service_uuid: '1204'
    characteristic_uuid: '1A02'
    update_interval: 4h
    on_value:
      then:
        homeassistant.event:
          event: esphome.on_ble_advertise
          data:
            packet: !lambda |-
              if (x.size() < 2)
              {
                ESP_LOGE("myhomeiot_ble_client", "payload has wrong size (%d)", x.size());
                return "";
              };
              ESP_LOGI("myhomeiot_ble_client", "Battery (%d%%), firmware (%s)", x[0], std::string(x.begin(), x.end()).substr(2).c_str());
              char buffer[70 + 1];
              const uint8_t *remote_bda = xthis.remote_bda();
              snprintf(buffer, sizeof(buffer), "043E2002010000%02X%02X%02X%02X%02X%02X14020106030295FE0C1695FE41209800000A1001%02X00",
                remote_bda[5], remote_bda[4], remote_bda[3], remote_bda[2], remote_bda[1], remote_bda[0], x[0]);
              return std::string(buffer).c_str();

Then save and update to your esp32 device via wifi. The ESP32 device will pick up the data from the miflora sensor and will 'push' it via wifi to the BLE integration which will create a device and entities automatically. Devices pushed in this way do appear to show their batteyr level (thanks to the code at the bottom of the myhomeiot_ble_client section I believe). You then just need to give the device a nice name (and let the entities be renamed too) and then create an entry in plants.yaml with the right entities

Found this useful? Please do let us know by dropping a comment below. If you would like to subscribe please use the subscribe link on the menu at the top right. You can also share this with your friends by using the social links below. Cheers.

Leave a Reply