• Stars
    star
    239
  • Rank 168,763 (Top 4 %)
  • Language
    C
  • License
    Apache License 2.0
  • Created over 9 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

I2C based soil moisture sensor

i2c-moisture-sensor

I2C based soil moisture sensor. A continuation of the Chirp - plant watering alarm project. There is also an RS485 and an analog version available.

I2C protocol

Available registers for reading and writing.

Name Register R/W Data length
GET_CAPACITANCE 0x00 (r) 2
SET_ADDRESS 0x01 (w) 1
GET_ADDRESS 0x02 (r) 1
MEASURE_LIGHT 0x03 (w) 0
GET_LIGHT 0x04 (r) 2
GET_TEMPERATURE 0x05 (r) 2
RESET 0x06 (w) 0
GET_VERSION 0x07 (r) 1
SLEEP 0x08 (w) 0
GET_BUSY 0x09 (r) 1

GET_BUSY returns 1 if any measurement is in progress, 0 otherwise.

How to interpret the readings

16bit values are returned most significant byte first.

Both light and moisture sensors give relative values. Meaning, more moisture will give you higher reading, more light, lower reading. They are not calibrated to any particular si units - this is up to you.

Moisture is somewhat linear. I test all sensors before shipping and they give about 290 - 310 in free air at 5V supply.

Temperature is in Celsius, value is in tenths of degrees Celsius. I.e. value 252 would mean 25.2°C.

I didn't measure linearity of the light sensor, it gives 65535 in a dark room away form desk lamp. When it's dark, it takes longer to measure light, reading the light register while measurement is in progress will return the previous reading. Be aware, light sensor is pretty noisy.

Temperature is measured by the thermistor on the body of the sensor. Calculated absolute measurement accuracy is better than 2%.

Note Upon reading the moisture or temperature value, a value form the previous read command is returned and the new measurement is started. If you do rare measurements and want to act instantly, do two consecutive readings to get the most up to date data. Also you can read GET_BUSY register via i2c - it will indicate when the measurement is done. Basically the process goes like this: read from GET_CAPACITANCE, discard results, then read from GET_BUSY until you get '0' as an answer, then read form GET_CAPACITANCE again - the returned value is the soil moisture NOW.

Python library for Raspberry Pi

NOTE: if you experience problems on Raspberry Pi 3, slow down I2C bus speed by adding this line to /boot/config.txt: dtparam=i2c1_baudrate=30000

Göran Lundberg has released a Python library for Raspberry Pi: https://github.com/ageir/chirp-rpi It has a very comprehensive documentation and covers a lot of functionality.

Some features:

  • Uses a trigger function to trigger all enabled sensors. User selectable.
  • Get soil moisture in percent (requires calibration) or capacitance value.
  • Several temperature scales to choose from. Celcius, Fahrenheit and Kelvin.
  • Offset to calibrate the temperature sensor.
  • Measurement timestamps for all on board sensors.
  • Built in support for changing the I2C address of the sensor.
  • Deep sleep mode to conserve power.
  • Calibration tool for soil moisture.

Raspberry Pi examples

This is interface class provided by Daniel Tamm and Jasper Wallace

#!/usr/bin/python
# cannot use python3 because smbus not working there
# Modified script from https://github.com/JasperWallace/chirp-graphite/blob/master/chirp.py
# by DanielTamm

import smbus, time, sys

class Chirp:
	def __init__(self, bus=1, address=0x20):
		self.bus_num = bus
		self.bus = smbus.SMBus(bus)
		self.address = address
    
	def get_reg(self, reg):
		# read 2 bytes from register
		val = self.bus.read_word_data(self.address, reg)
		# return swapped bytes (they come in wrong order)
		return (val >> 8) + ((val & 0xFF) << 8)

	def reset(self):
		# To reset the sensor, write 6 to the device I2C address
		self.bus.write_byte(self.address, 6)

	def set_addr(self, new_addr):
		# To change the I2C address of the sensor, write a new address
		# (one byte [1..127]) to register 1; the new address will take effect after reset
		self.bus.write_byte_data(self.address, 1, new_addr)
		# second request is required since FW 0x26 to protect agains spurious address changes
		self.bus.write_byte_data(self.address, 1, new_addr)
		self.reset()
		self.address = new_addr

	def moist(self):
		# To read soil moisture, read 2 bytes from register 0
		return self.get_reg(0)

	def temp(self):
		# To read temperature, read 2 bytes from register 5
		return self.get_reg(5)

	def light(self):
		# To read light level, start measurement by writing 3 to the
		# device I2C address, wait for 3 seconds, read 2 bytes from register 4
		self.bus.write_byte(self.address, 3)
		time.sleep(1.5)
		return self.get_reg(4)

	def __repr__(self):
		return "<Chirp sensor on bus %d, addr %d>" % (self.bus_num, self.address)

if __name__ == "__main__":
	addr = 0x20
	if len(sys.argv) == 2:
		if sys.argv[1].startswith("0x"):
			addr = int(sys.argv[1], 16)
		else:
			addr = int(sys.argv[1])
	chirp = Chirp(1, addr)

	print chirp
	print "Moisture\tTemperature\tBrightness"
	while True:
		print "%d\t%d\t%d" % (chirp.moist(), chirp.temp(), chirp.light())
		time.sleep(1)

This is another RasPi example provided by user krikk

#!/usr/bin/python

#https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code/tree/master/Adafruit_I2C
from Adafruit_I2C import Adafruit_I2C
from time import sleep, strftime
from datetime import datetime
deviceAddr = 0x20

i2c = Adafruit_I2C( deviceAddr, -1, False )

#to change adress
#i2c.write8( 1, 0x22 )

#reset sensor, we need this otherwise i get inconsistent light reading in the dark...
i2c.write8( deviceAddr, 0x06 )
sleep(5)

i2c.write8(deviceAddr, 3)
sleep(3)
light = i2c.readU16(4, False)
temp = i2c.readS16(5, False)/float(10)
moisture = i2c.readU16(0, False)
print "Temperature\tMoisture\tBrightness"
print str(temp) + ":" + str(moisture) + ":" + str(light)

Arduino library

Ingo Fischer has written an Arduino library for the sensor, it has a couple of ready made examples: https://github.com/Apollon77/I2CSoilMoistureSensor

Below are old examples for bare-bones Arduino illustrating a basic I2C use.

Arduino example

#include <Wire.h>

void writeI2CRegister8bit(int addr, int value) {
  Wire.beginTransmission(addr);
  Wire.write(value);
  Wire.endTransmission();
}

unsigned int readI2CRegister16bit(int addr, int reg) {
  Wire.beginTransmission(addr);
  Wire.write(reg);
  Wire.endTransmission();
  delay(20);
  Wire.requestFrom(addr, 2);
  unsigned int t = Wire.read() << 8;
  t = t | Wire.read();
  return t;
}

void setup() {
  Wire.begin();
  Serial.begin(9600);
  writeI2CRegister8bit(0x20, 6); //reset
}

void loop() {
  Serial.print(readI2CRegister16bit(0x20, 0)); //read capacitance register
  Serial.print(", ");
  Serial.print(readI2CRegister16bit(0x20, 5)); //temperature register
  Serial.print(", ");
  writeI2CRegister8bit(0x20, 3); //request light measurement 
  Serial.println(readI2CRegister16bit(0x20, 4)); //read light register
}

Note for ESP8266 based systems

In some cases the default ESP8266 Arduino I2C library has the clock stretching timeout set too low. If you experience intermittent communication, add this to your code:

Wire.setClockStretchLimit(2500)

Micropython

Micropython library is available here: https://github.com/scopelemanuele/pyChirpLib

Address change example

By default the sensor comes with 0x20 set as an address, this is an example on how to change address for indivitual sensor:

#include <Wire.h>
 
void writeI2CRegister8bit(int addr, int reg, int value) {
  Wire.beginTransmission(addr);
  Wire.write(reg);
  Wire.write(value);
  Wire.endTransmission();
}
 
void writeI2CRegister8bit(int addr, int value) {
  Wire.beginTransmission(addr);
  Wire.write(value);
  Wire.endTransmission();
}
 
void setup() {
  Wire.begin();
  Serial.begin(9600);
                                       //talking to the default address 0x20
  writeI2CRegister8bit(0x20, 1, 0x21); //change address to 0x21
  writeI2CRegister8bit(0x20, 6);       //reset
  delay(1000);                         //give it some time to boot
}
 
/*loop scans I2C bus and displays foud addresses*/ 
void loop()
{
  byte error, address;
  int nDevices;
 
  Serial.println("Scanning...");
 
  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
 
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknow error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
 
  delay(5000);           // wait 5 seconds for next scan
}

Particle Photon

There is a great tutorial by Miriam Cox for Particle Photon boards. Also there is a library available by Mike.

Links and mentions

More Repositories

1

PlantWateringAlarm

A soil humidity level sensor based on ATTINY44. Uses capacitive sensing.
Jupyter Notebook
335
star
2

rs485-moist-sensor

Digital (RS485 - based) soil moisture and temperature sensor
C
62
star
3

triac-bloc

An universal power block based on triac. In essence this is a solid state relay with some bells and whistles
Python
49
star
4

docker-compose-mosquitto-influxdb-telegraf-grafana

34
star
5

k-thermocouple-lib

Converts K thermocouple voltage to temperature with linearization and cold junction compensation
Jupyter Notebook
30
star
6

ble-soil-moisture-sensor

Bluetooth Low Energy - based soil moisture sensor
C
27
star
7

paper-wifi

Low power E-paper display devboard with WiFi and BLE connectivity. Open source hardware.
C
23
star
8

VFD

Open source Variable Frequency Drive for Induction Motor.
IDL
18
star
9

soil-moisture-sensor-analog

Analog soil moisture sensor
KiCad Layout
13
star
10

StepperOverDMX

A system to control a stepper motor over DMX protocol.
C++
12
star
11

ScaleHack

Hack conventional scales to connect to computer via usb serial and/or bluetooth
Python
12
star
12

BatteryCharger

Smart lead acid battery charger
C++
9
star
13

USBLiPoCharger

Various LiPo / Li-Ion chargers based on MAX1555, MAX1551 and MCP73831
7
star
14

pidgenetics

A research in using genetic algorithm to tune PID controller
Python
6
star
15

astromotor

Drive controller for EQ-2 equatorial tracking motor
C
5
star
16

CatNip

LPC1343 Developement board
5
star
17

PhonoPreamp

A simple phono preamplifier
5
star
18

sht25-micropython

Micropython implementation of API of SHT25 Humidity and Temperature Sensor
Python
4
star
19

dmx-wireless

DMX over 2.4GHz radio link
Makefile
3
star
20

USBtoUART

Home PCB etching compliant MCP2200 based USB to UART adapter and commandline configuration utility
3
star
21

SoilMoistureSensor

A Time Domain Reflectometry - based soil humidity sensor
IDL
3
star
22

radiobus

Low power LoRaWAN node designed to work with RS485, I2C, SPI sensors.
AMPL
3
star
23

TV-B-Gone

TV be gone implementation on attiny44
C
3
star
24

plotfilt

IIR filter analysis utility - useful while creating lightweight digital filters for use in microcontrollers
C++
3
star
25

ciurlys

A light art installation support electronics
KiCad Layout
2
star
26

drawduino

A drawdio-like device based on attiny85. Ment to be quick and easy electronics workshop for noobs.
KiCad Layout
2
star
27

h-bridge

High voltage H-bridge driver
Prolog
2
star
28

can-boosterpack

CAN bus boosterpack for TI Stellaris LaunchPad
2
star
29

rs485-breakout

A tiny development board to quickly prototype RS485/Modbus devices
C
2
star
30

geek-watch

My take on building a watch.
PostScript
1
star
31

linear-led-dimmer

A linear dimmer for 6W - 12W LED pannels.
KiCad Layout
1
star
32

framework-arduino-samr-catnip

Platformio framework for SAMR34 microcontrollers
C++
1
star
33

DmxLedDimmerBasic

A basic DMX LED dimmer based on AVR ATMEGA8. Only single channel is used, output via hardware PWM.
1
star
34

leds-got-waxed

A LED based effect box for a music band
Makefile
1
star
35

ThermocoupleShieldForLPC1343

Thermocouple shieldFor LPC1343ReferenceDesign board
1
star
36

reflow-oven-controller

C
1
star
37

TitleBoard

Some code to show subtitles on couple specific LED boards and a beamer.
Java
1
star
38

LEDCard

A business card with blinky leds
Assembly
1
star
39

thermocouple-modbus

Thermocouple frontend accessible via industrial modbus protocol
C
1
star
40

motoplugas

A revolution counting jig for variable frequency drive driven pulley system
C
1
star
41

incubator

1
star
42

SolarCampingLentern

Solar powered camping lantern
Jupyter Notebook
1
star
43

camera-crane

Electronics of camera crane for stop motion animation
KiCad Layout
1
star
44

contact-microphone-preamp

A preamplifier for contact microphone
1
star