Categories
Connected Farm

Oil / Water Level Monitor and Distance Sensor.

Arduino Pro Mini

In previous posts I used mostly off the shelf IOT devices from Tuya, Sonoff and Shelly, these are great becasue they are cheap and easily integrated into many projects. The issue though when you want sensors for custom applications is there are not many cheap off the shelf options.

Thankfully there are a few well supported communitys of DIYers who have developed their own solutions for all kinds of sensors using different development hardware such as Arduino and ESP. 2 that I’ve tried are MySensors.org and ESPHome.io.

ESP32 Node MCU

I have made a couple of fluid level sensors out of Distance sensors similar to car reversing sensors. The first one I made used an ESP32 Node MCU board using the ESP Home Home Assitant Addon. This is probably the easiest way to develop DIY sensors to work with Home Assistant, but there are some limitations like it depends on WiFi signal to work and the device requires more power than the likes of an Arduino Pro mini so not a great choice for battery operated sensors.

esphome:
  name: oil_monitor
  platform: ESP32
  board: nodemcu-32s


wifi:
  ssid: "WiFi SSID"
  password: "Wifi Password"

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Oil Monitor Fallback Hotspot"
    password: "AP Password"

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:
  password: "API Password"

ota:
  password: "API Password"
  

#web_server:
 #port: 80



# Ultrasonic sensor - tank measurement
sensor:
  - platform: ultrasonic
    id: sensor_cm1
    trigger_pin: GPIO15
    echo_pin: GPIO16
    name: "Oil Ultrasonic Sensor"
    icon: "mdi: arrow"
    update_interval: 10s
    accuracy_decimals: 2
    unit_of_measurement: "cm"
    filters:
     - filter_out: nan
     - multiply: 100
     #- sliding_window_moving_average:
      #   window_size: 12
       #  send_every: 12

# Oil Level Sensor
  - platform: template
    id: sensor_cm2
    name: "Oil Level"
    icon: "mdi: arrow"
    update_interval: 10s
    accuracy_decimals: 2
    unit_of_measurement: "cm"
    lambda: 
      return 120 - id (sensor_cm1) .state;

# Oil Percentage Sensor
  - platform: template
    name: "Oil Percentage"
    icon: "mdi: water"
    update_interval: 10s
    accuracy_decimals: 2
    unit_of_measurement: "%"
    lambda: 
      return id (sensor_cm2) .state;
    filters:
      - calibrate_linear:
        - 0 -> 0
        - 110 -> 100

# Oil Litres Sensor
  - platform: template
    name: "Oil Litres"
    icon: "mdi: oil"
    update_interval: 10s
    accuracy_decimals: 0
    unit_of_measurement: "L"
    lambda: 
      return id (sensor_cm2) .state;
    filters:
      - calibrate_linear:
        - 0 -> 0
        - 110 -> 1300
    

Code language: PHP (php)

The ESPHome Addon has a wizard to setup the WiFi and API/server section of the config so only the sensor config needs to be edited manualy, which is mostly cut and paste from examples on their site or in the forums. The ESP32 worked fine for me heating oil tank which is behind my garage, is within Wifi Range and can be powered by a 5V USB charger in the Garage.

Arduino Pro Mini

.However for better range on the farm and ability to run for months or years on a battery then I tried an Arduino Pro Mini with NRF24 radio using Mysensors.org. To load the program or sketch you need the Arduino IDE installed on a PC and an FTDI serial adapter.


#define SENSOR_NAME "Distance Sensor"
#define SENSOR_VERSION "1.1"

#define CHILD_ID 1  // Each radio node can report data for up to 254 different child sensors. You are free to choose the child id yourself. 
                    // You should avoid using child-id 255 because it is used for things like sending in battery level and other (protocol internal) node specific information.
#define TRIGGER_PIN  6  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     5  // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 300 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
unsigned long SLEEP_TIME = 3600000; // Sleep time between reads (in milliseconds)


NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
MyMessage msg(CHILD_ID, V_DISTANCE);
int lastDist;
bool metric = true;

void setup()  
{ 
  metric = getControllerConfig().isMetric;
}

void presentation() {
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo(SENSOR_NAME, SENSOR_VERSION);

  // Register all sensors to gw (they will be created as child devices) by their ID and S_TYPE
  present(CHILD_ID, S_DISTANCE);
}

void loop()      
{ 
  // use the build-in digital filter to discard out of range pings
  int echoTime = sonar.ping_median(10);
  int dist = (metric?sonar.convert_cm(echoTime):sonar.convert_in(echoTime))*2;
  Serial.print("Ping: ");
  Serial.print(dist);
  Serial.println(metric?" cm":" in");

  if (dist != lastDist) {
      send(msg.set(dist));
      lastDist = dist;
  }

  sleep(SLEEP_TIME);Code language: PHP (php)

MySensors requires a gateway device to be connected to same network as Home Assistant (or other controller). Optionally a serial Gateway can be used connected directly. See https://www.mysensors.org/build/select_gateway for examles. Alternativly you can buy one from Adverts.ie

StemEdu LoRa Radio Node V1.0

Finaly for maximim long range and low power I used this device, a Stemedu LoRa Radio Node V1.0 which is basically an Arduino Mini with built in Lora Radio. Its the perfect choice for battery powered lora nodes as there is no need for soldering and is fitted with a battery holder.

#define MY_DEBUG

// Enable and select radio type attached
#define MY_RADIO_RFM95
//#define MY_DEBUG_VERBOSE_RFM95
#define MY_RFM95_FREQUENCY (RFM95_868MHZ)
#define MY_RFM95_MAX_POWER_LEVEL_DBM (100) 
//#define MY_RFM95_MODEM_CONFIGRUATION RFM95_BW125CR45SF1288
#define MY_TRANSPORT_STATE_TIMEOUT_MS  (3*1000ul)
#define RFM95_RETRY_TIMEOUT_MS  (3000ul) 
#define MY_RFM95_MODEM_CONFIGRUATION  RFM95_BW125CR48SF4096
//Enable Signing <Make Sure you Change Password>
//#define MY_SIGNING_SIMPLE_PASSWD "password"

//Enable Encryption This uses less memory, and hides the actual data. <Make Sure you Change Password>
//#define MY_ENCRYPTION_SIMPLE_PASSWD "password"


#define MY_NODE_ID 44

//#define MY_RADIO_RF24
//#define MY_RF24_CHANNEL  91


#include <SPI.h>
#include <MySensors.h>  
#include <NewPing.h>

#define SENSOR_NAME "Distance Sensor"
#define SENSOR_VERSION "1.1"

#define CHILD_ID 1  // Each radio node can report data for up to 254 different child sensors. You are free to choose the child id yourself. 
                    // You should avoid using child-id 255 because it is used for things like sending in battery level and other (protocol internal) node specific information.
#define TRIGGER_PIN  3  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     4  // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 300 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
unsigned long SLEEP_TIME = 3600000; // Sleep time between reads (in milliseconds)


NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
MyMessage msg(CHILD_ID, V_DISTANCE);
int lastDist;
bool metric = true;

void setup()  
{ 
  metric = getControllerConfig().isMetric;
}

void presentation() {
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo(SENSOR_NAME, SENSOR_VERSION);

  // Register all sensors to gw (they will be created as child devices) by their ID and S_TYPE
  present(CHILD_ID, S_DISTANCE);
}

void loop()      
{ 
  // use the build-in digital filter to discard out of range pings
  int echoTime = sonar.ping_median(10);
  int dist = metric?sonar.convert_cm(echoTime):sonar.convert_in(echoTime);
  Serial.print("Ping: ");
  Serial.print(dist);
  Serial.println(metric?" cm":" in");

  if (dist != lastDist) {
      send(msg.set(dist));
      lastDist = dist;
  }

  sleep(SLEEP_TIME);
}Code language: PHP (php)

MySensors Lora Node sketch

heltec ESP32 LoRa Dev Board

This also required a new Lora Gateway and I choose a Heltec ESP32 LoRa Development Board, This required no additional hardware as it also had built in Lora Radio as well as WiFi to connect to local network.

/*
 * The MySensors Arduino library handles the wireless radio link and protocol
 * between your home built sensors/actuators and HA controller of choice.
 * The sensors forms a self healing radio network with optional repeaters. Each
 * repeater and gateway builds a routing tables in EEPROM which keeps track of the
 * network topology allowing messages to be routed to nodes.
 *
 * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
 * Copyright (C) 2013-2018 Sensnology AB
 * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
 *
 * Documentation: http://www.mysensors.org
 * Support Forum: http://forum.mysensors.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 *******************************
 *
 * REVISION HISTORY
 * Version 1.0 - tekka
 *
 * DESCRIPTION
 * The ESP32 gateway sends data received from sensors to the WiFi link.
 * The gateway also accepts input on ethernet interface, which is then sent out to the radio network.
 *
 * Make sure to fill in your ssid and WiFi password below.
 */

// Enable debug prints to serial monitor
// #define MY_DEBUG

// Enables and select radio type (if attached)
//#define MY_RADIO_RF24
//#define MY_RADIO_RFM69
#define MY_RADIO_RFM95
#define MY_DEBUG_VERBOSE_RFM95
#define MY_RFM95_RST_PIN 14
#define MY_RFM95_CS_PIN 18
#define MY_RFM95_IRQ_PIN 26
#define MY_RFM95_IRQ_NUM MY_RFM95_IRQ_PIN
#define MY_SOFT_SPI_MOSI_PIN 27
#define MY_SOFT_SPI_SCK_PIN 5
//#define MY_RFM95_MODEM_CONFIGRUATION RFM95_BW125CR45SF128
#define MY_RFM95_FREQUENCY (RFM95_868MHZ)
#define MY_RFM95_MAX_POWER_LEVEL_DBM (100) 
#define MY_TRANSPORT_STATE_TIMEOUT_MS  (3*1000ul)
#define RFM95_RETRY_TIMEOUT_MS  (3000ul) 
#define MY_RFM95_MODEM_CONFIGRUATION  RFM95_BW125CR48SF4096

//Enable Signing <Make Sure you Change Password>
//#define MY_SIGNING_SIMPLE_PASSWD "password"

//Enable Encryption This uses less memory, and hides the actual data. <Make Sure you Change Password>
//#define MY_ENCRYPTION_SIMPLE_PASSWD "password"

#define MY_GATEWAY_ESP32

#define MY_WIFI_SSID "WiFi ssid"
#define MY_WIFI_PASSWORD "Wifi Password"

// Set the hostname for the WiFi Client. This is the hostname
// it will pass to the DHCP server if not static.
#define MY_HOSTNAME "ESP32_GW_LoRa"

// Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP)
#define MY_IP_ADDRESS 192,168,1,202

// If using static ip you can define Gateway and Subnet address as well
#define MY_IP_GATEWAY_ADDRESS 192,168,1,1
#define MY_IP_SUBNET_ADDRESS 255,255,255,0

// The port to keep open on node server mode
#define MY_PORT 5003

// How many clients should be able to connect to this gateway (default 1)
#define MY_GATEWAY_MAX_CLIENTS 2

#include <MySensors.h>
// #include "heltec.h"




void setup()
{
	// Setup locally attached sensors
  Heltec.begin(true /*DisplayEnable Enable*/, false /*LoRa Disable*/, true /*Serial Enable*/);
  
  Heltec.display->setContrast(255);

 Heltec.display->clear();
 Heltec.display->setFont(ArialMT_Plain_16);
 Heltec.display->drawString(30, 10, "LoRa GW");
 Heltec.display->setFont(ArialMT_Plain_10);
 Heltec.display->drawString(30, 40, WiFi.localIP().toString());
 Heltec.display->display();

}

void presentation()
{
	// Present locally attached sensors here
}

void loop()
{
	// Send locally attached sensors data here
}Code language: PHP (php)

Facebook Comments