Idea

laurenceh avatar image
laurenceh suggested

Getting i2c running for humidity and temperature sensor Venus OS 2.42 Rpi3B+

As a an owner of a narrow boat I wanted to get Humidity and temperature sensors working as a means of monitoring the conditions on the boat over winter. We leave low power oil filled (electric) radiators onboard to stop the boat freezing. We will also monitor the AC heating load via the Victron VRM.

Key words: i2c RaspberryPi Humidity (these do not seem to be available as article tags)

The following has been tested with Venus OS 2.42 on Rpi3B+ in Feb 2020.

I had found historic posts on the internet about how this might be difficult but it is certainly not difficult on Venus OS 2.42 once you have worked it out. Here are the steps:

Add the following line to /u-boot/config.txt

dtparam=i2c_arm=on


On reboot the i2c-dev module should be started but this did not appear to happen. As a work round add a file rc.local to the /data partition (or edit the file if it exists)


root@raspberrypi2:# cd rc.local

root@raspberrypi2:/data# nano rc.local


To include the following line.


modprobe i2c-dev


Ensure the rc.local file can be executed


root@raspberrypi2:~# chmod 775 rc.local


Then reboot


In Venus OS 2.42 i2c tools are already included (in /usr/bin) so the command i2cdetect should work to list the active i2c busses


root@raspberrypi2:~# i2cdetect -l

i2c-1 i2c bcm2835 I2C adapter I2C adapter


This shows that i2c bus 1 has been detected which is the arm i2c bus on the Rpi GPIO pins., the bus can then be polled to show connected devices:


root@raspberrypi2:~# i2cdetect -y 1

0 1 2 3 4 5 6 7 8 9 a b c d e f

00: -- -- -- -- -- -- -- -- -- -- -- -- --

10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

50: -- -- -- -- -- -- -- -- -- -- -- -- 5c -- -- --

60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --


70: -- -- -- -- -- -- -- --


This shows that the bus is working and that I have one device connected


Next steps


I'll post separately about driving specific i2c devices such as the am2315 temperature and humidity sensor.


I hope to look at publishing the data from i2c devices on the Venus OS d-bus and what can then be done with it.


If unable to use d-bus I can look at logging Humidity and Temperature in other ways.



Raspberry Pitemperature
2 |3000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

mvader (Victron Energy) avatar image
mvader (Victron Energy) commented

Nice! For temperature its easy to put it on D-Bus: just mimick same service name & paths as we use; for the temperature inputs on the cerbo & venus gx. For humidity we have nothing yet - could be added though.

2 comments
2 |3000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

Please can we add humidity. Where is best place to log a request? We have new batteries in development intended for outdoor use and want to monitor humidity.

laurenceh avatar image
laurenceh commented

Matthijs

Right got my i2c => d-bus loop running and I'm publishing Humidity and temperature to the d-bus. :-)

Currently I have the following working:

  • Service = "com.victronenergy.i2c"
  • Path = '/Humidity
  • Path = '/Temperature

There are also the three additional temperature inputs on the 8 Pin DAC that could be published.

Before I share my code I thought I might check the preferred paths to use.

Perhaps

I could add services for temperatures on inputs 0,1, 7 with the same format service and paths as the existing ones, for example:

  • com.victronenergy.temperature.builtin_adc0_di2
  • com.victronenergy.temperature.builtin_adc1_di3
  • com.victronenergy.temperature.builtin_adc7_di4

Then Either I could add

  • com.victronenergy.temperature.i2c_dev1
  • com.victronenergy.humidity.i2c_dev1

Or I could add a service such as

  • com.victronenergy.i2c

Add add the humidity and temperature as sensors on paths provided by this service.

Do you have a view?




2 comments
2 |3000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

@LaurenceH Very new to this, but I'm trying to get a current sensor working and followed this i2C instructions and it sees the device connected, I got a ADS1115 wired up and without anything connected to the ADS1115 it shows:

0 1 2 3 4 5 6 7 8 9 a b c d e f

00: -- -- -- -- -- -- -- -- -- -- -- -- --

10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --

50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

70: -- -- -- -- -- -- -- --


Did you ever post about driving specific devices?


Hi

I have posted the code below as a comment this thread.

laurenceh avatar image
laurenceh commented

Hi

here is a driver for the i2C device I am using.

It is defined as a class and could be duplicated or extended to support other devices but the core of the driver is here.

For other devices you will need to adjust the registers written and the rating of result.

Also you might not need the wakeup probe - being a single chip temperature sensor the AM2320 shutdown when not communicating to reduce on chip power which might affect the temperature/humidity readings.

The code below is the complete python library file saved as i2c.py and imported into my service code, and called like this.

from i2c import AM2320 as AM2320
#this is a code snippet from my code to wrap multiple dbus connections one service
# it is just an example of how to call the AM2320 class in the i2c.py file

        am2320 = AM2320(1)
        (t,h,e, report) = am2320.readSensor()
#       Returns temperature, humidity, error ststus, and text report
        if e != 0:
            logging.info("Error in i2c bus read, "+ report)
            dbusservice['i2c-humidity']['/Status'] = e
            dbusservice['i2c-temp']['/Status'] = e
            dbusservice['i2c-humidity']['/Humidity'] = []
            dbusservice['i2c-temp']['/Temperature'] = []
        else:
            if dbusservice['i2c-humidity']['/Connected'] != 1:
               logging.info("i2c bus device connected")
               dbusservice['i2c-humidity']['/Connected'] = 1            
               dbusservice['i2c-temp']['/Connected'] = 1
            dbusservice['i2c-humidity']['/Status'] = 0
            dbusservice['i2c-temp']['/Status'] = 0
	    logging.debug("values now are temperature %s, humidity %s" % (t, h))
	    dbusservice['i2c-humidity']['/Humidity'] = h
            dbusservice['i2c-temp']['/Temperature'] = t

Have fun and do let me know here how you get on.

Laurence

#!/usr/bin/python

# Thie file can be extended to add class drivers for additional devices as they are implemented and tested
# https://github.com/Gozem/am2320/blob/master/am2320.py
# file has been updated to catch and report errors (rather than raising an exception
import posix
from fcntl import ioctl
import time

class AM2320:
  I2C_ADDR = 0x5c
  I2C_SLAVE = 0x0703 

  def __init__(self, i2cbus = 1):
    self._i2cbus = i2cbus

  @staticmethod
  def _calc_crc16(data):
    crc = 0xFFFF
    for x in data:
      crc = crc ^ x
      for bit in range(0, 8):
        if (crc & 0x0001) == 0x0001:
          crc >>= 1
          crc ^= 0xA001
        else:
          crc >>= 1
    return crc

  @staticmethod
  def _combine_bytes(msb, lsb):
    return msb << 8 | lsb


  def readSensor(self):
    fd = posix.open("/dev/i2c-%d" % self._i2cbus, posix.O_RDWR)

    ioctl(fd, self.I2C_SLAVE, self.I2C_ADDR)
  
    # wake AM2320 up, goes to sleep to not warm up and affect the humidity sensor 
    # This write will fail as AM2320 won't ACK this write
    try:
      posix.write(fd, b'\0x00')
    except:
      pass
    time.sleep(0.001)  #Wait at least 0.8ms, at most 3ms
  
    # write at addr 0x03, start reg = 0x00, num regs = 0x04 */  
    try:
      posix.write(fd, b'\x03\x00\x04')
    except:
    # the returned object contains (temperature, humidity,error number,'error string')
      return (0,0,1,"Device did not acknowledge request")
    time.sleep(0.0016) #Wait at least 1.5ms for result

    # Read out 8 bytes of result data
    # Byte 0: Should be Modbus function code 0x03
    # Byte 1: Should be number of registers to read (0x04)
    # Byte 2: Humidity msb
    # Byte 3: Humidity lsb
    # Byte 4: Temperature msb
    # Byte 5: Temperature lsb
    # Byte 6: CRC lsb byte
    # Byte 7: CRC msb byte
    data = bytearray(posix.read(fd, 8))
    posix.close(fd)

    # Check data[0] and data[1]
    if data[0] != 0x03 or data[1] != 0x04:
      return (0,0,4,"First two read bytes are a mismatch")
    # raise Exception("First two read bytes are a mismatch")

    # CRC check
    if self._calc_crc16(data[0:6]) != self._combine_bytes(data[7], data[6]):
      return (0,0,4,"CRC failed")
    #  raise Exception("CRC failed")
    
    # Temperature resolution is 16Bit, 
    # temperature highest bit (Bit15) is equal to 1 indicates a
    # negative temperature, the temperature highest bit (Bit15)
    # is equal to 0 indicates a positive temperature; 
    # temperature in addition to the most significant bit (Bit14 ~ Bit0)
    # indicates the temperature sensor string value.
    # Temperature sensor value is a string of 10 times the
    # actual temperature value.
    temp = self._combine_bytes(data[4], data[5])
    if temp & 0x8000:
      temp = -(temp & 0x7FFF)
    temp /= 10.0
  
    humi = self._combine_bytes(data[2], data[3]) / 10.0

    return (temp, humi, 0,'')  

#am2320 = AM2320(1)
#(t,h) = am2320.readSensor()
#print 'temperature', t
#print 'humidiy', h, ' %'

2 |3000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

Your Opinion Counts

Share your great idea, or help out by voting for other people's ideas.