I2c Moisture Sensor

I2C based soil moisture sensor
Alternatives To I2c Moisture Sensor
Project NameStarsDownloadsRepos Using ThisPackages Using ThisMost Recent CommitTotal ReleasesLatest ReleaseOpen IssuesLicenseLanguage
Gobot8,14720232 days ago27May 02, 2022155otherGo
Golang framework for robotics, drones, and the Internet of Things (IoT)
Embd1,2101665 years ago4March 06, 201746mitGo
Embedded Programming Framework in Go
Esp Idf Lib937
2 months ago26C
Component library for ESP32, ESP32-S2, ESP32-C3 and ESP8266
Drivers4672819 days ago53October 01, 2022101bsd-3-clauseGo
TinyGo drivers for sensors, displays, and other devices that use I2C, SPI, GPIO, ADC, and UART interfaces.
2 months agogpl-3.0Python
An open source bike computer based on Raspberry Pi Zero (W, WH, 2W) with GPS and ANT+. Including offline map and navigation.
3 days ago4gpl-3.0C++
ST_Anything is an Arduino library, sketch, and Device Type that works with your SmartThings ThingShield to create an all-in-one SmartThings device.
7 years ago1
嵌入式知识总汇 Embedded Knowledge Structure
I2c Moisture Sensor227
a month ago4apache-2.0C
I2C based soil moisture sensor
Mudpi Core206
2 years ago2mitPython
Configurable automation library for linux SBC boards including raspberry pi
2 years ago35gpl-3.0Python
Software to pull random photos from Google Photos and show them, like a photo frame
Alternatives To I2c Moisture Sensor
Select To Compare

Alternative Project Comparisons


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
SET_ADDRESS 0x01 (w) 1
GET_ADDRESS 0x02 (r) 1
MEASURE_LIGHT 0x03 (w) 0
GET_LIGHT 0x04 (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: 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

# 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.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)
		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)
			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())

This is another RasPi example provided by user krikk


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 )

i2c.write8(deviceAddr, 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: 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) {

unsigned int readI2CRegister16bit(int addr, int reg) {
  Wire.requestFrom(addr, 2);
  unsigned int t = Wire.read() << 8;
  t = t | Wire.read();
  return t;

void setup() {
  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:



Micropython library is available here: 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) {
void writeI2CRegister8bit(int addr, int value) {
void setup() {
                                       //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;
  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.
    error = Wire.endTransmission();
    if (error == 0)
      Serial.print("I2C device found at address 0x");
      if (address<16)
      Serial.println("  !");
    else if (error==4)
      Serial.print("Unknow error at address 0x");
      if (address<16)
  if (nDevices == 0)
    Serial.println("No I2C devices found\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

Popular Sensor Projects
Popular I2c Projects
Popular Hardware Categories
Related Searches

Get A Weekly Email With Trending Projects For These Categories
No Spam. Unsubscribe easily at any time.
Raspberry Pi