0

I am currently working with a Raspberry Pi 4B. I have an i2c shield connected to the PI and then my temp/RH sensor connected directly to that. The sensor is here and datasheet - where pgs 11-18 have the most relevant information.

The webpage and datasheet both have C++ code for an Ardiuno, but that obviously doesn't help me trying to use Python to run the sensor. I have tried using some basic websites to convert the C++ to python.

I have very little experience working with Python and no experience working with C++ and/or writing programs to run on my pi. I have been using Node Red without any problems currently. However, now I am stuck. From what I have read online, I would likely need significant knowledge of both python and C++ to translate the code directly which I do not have time to acquire. I am looking for some advice on how to go about writing the code. Examples that I can find elsewhere usually have different bit computer chips which limits the ability to copy and paste.

import smbus
import time

# I2C address of the sensor
SENSOR_ADDRESS = 0x40

# Register addresses
TEMPERATURE_REGISTER = 0x00
HUMIDITY_REGISTER = 0x01
CONFIG_REGISTER = 0x02
ALERT_SETUP_REGISTER = 0x03
MANUFACTURE_ID_REGISTER = 0xFE
VERSION_ID_REGISTER = 0xFF

# Configuration settings 
CONFIG_SETTINGS = 0x1000  

# Create an instance of the SMBus
bus = smbus.SMBus(1)  

def configure_sensor():
    try:
        # Write configuration settings to the configuration register
        bus.write_word_data(SENSOR_ADDRESS, CONFIG_REGISTER, CONFIG_SETTINGS)
        bus.write_word_data(SENSOR_ADDRESS, ALERT_SETUP_REGISTER, ALERT_SETUP_SETTINGS)
        print("Sensor configured with settings: 0x{:04X}, 0x{:04X}".format(CONFIG_SETTINGS, ALERT_SETUP_SETTINGS))
    except Exception as e:
        print("Error configuring sensor:", e)

def trigger_measurement(register):
    try:
        # Write register address to trigger the measurement
        bus.write_byte(SENSOR_ADDRESS, register)
        # Wait for the typical conversion time of 5.50ms
        time.sleep(0.0055)
    except Exception as e:
        print("Error triggering measurement:", e)

def read_sensor_data(register):
    try:
        # Trigger measurement
        trigger_measurement(register)

        # Read data from the sensor
        data = bus.read_word_data(SENSOR_ADDRESS, register)
        # Swap bytes
        data = ((data & 0xFF) << 8) | (data >> 8)
        # Only 14 bits are valid
        data = data >> 2
        return data
    except Exception as e:
        print("Error reading sensor data:", e)
        return None

def convert_temperature(raw_temp):
    # Convert raw temperature data to Celsius
    return (raw_temp / 16383.0) * 165.0 - 40.0

def convert_humidity(raw_hum):
    # Convert raw humidity data to %RH
    return (raw_hum / 16383.0) * 100.0

def main():
    configure_sensor()  # Configure the sensor before reading data
    try:
        while True:
            raw_temp = read_sensor_data(TEMPERATURE_REGISTER)
            raw_hum = read_sensor_data(HUMIDITY_REGISTER)

            if raw_temp is not None and raw_hum is not None:
                temperature = convert_temperature(raw_temp)
                humidity = convert_humidity(raw_hum)
                print("Temperature: {:.2f}°C, Humidity: {:.2f}%".format(temperature, humidity))
            time.sleep(2)  # Read data every 2 seconds
    except KeyboardInterrupt:
        print("Program terminated by user.")

if __name__ == "__main__":
    main()

Currently, I am still getting the dreaded error no 121 Remote i/o error when reading the sensor data.

I am at a loss for what to change... Please let me know if there is any additional information needed

To get some basics out of the way, yes, I am sure of the dev address and the bus address, both have been triple-checked additionally, the device shows up at the address when i2cdetect is run, so I am pretty confident in there not being a wiring issue. Thank you very much in advance!!

11
  • this might get you started ... raspberrypi.stackexchange.com/questions/62612/…
    – jsotola
    Commented May 28 at 23:00
  • Why did you buy the shield? The listed web page is confusing (all Pi have I²C on pins 3,5). You might have more success ditching the shield and connecting your sensor directly.
    – Milliways
    Commented May 28 at 23:45
  • We're using the shield because we have a few MCP23017 expansion boards connected as well and the shield makes it easiest to connect with them.
    – Jack
    Commented May 29 at 16:41
  • The linked "data sheet" provides absolutely no technical details of what the shield ACTUALLY does. Without this no one can answer.
    – Milliways
    Commented May 30 at 3:53
  • when I connect the sensor directly to the PI, it doesn't register with i2cdetect, but if I connect through the shield then I can see the sensor address at 0x40 in i2cdetect. Unfortunately, I cannot find a datasheet on the website. Is there any additional specific info I can provide not available at the link?
    – Jack
    Commented May 30 at 21:30

1 Answer 1

0

Try this and see how far you get and what needs to be focus on.

#!/usr/bin/env python3

import smbus
import time

# I2C address of the sensor
SENSOR_ADDRESS = 0x40

# Register addresses
TEMPERATURE_REGISTER = 0x00
HUMIDITY_REGISTER = 0x01
CONFIG_REGISTER = 0x02
ALERT_SETUP_REGISTER = 0x03
MANUFACTURE_ID_REGISTER = 0xFE
VERSION_ID_REGISTER = 0xFF

print("Configuration setting")
#CONFIG_SETTINGS = 0x1000  ## This sets 'Halt', big  not little endian.
CONFIG_SETTINGS = 0x0000   ## Default is 0x1000, read temp & humidity.

## python3
## >>> import struct
## >>> struct.pack('>H', int(0x1000))
## b'\x10\x00'
## >>> struct.pack('<H', int(0x1000))
## b'\x00\x10'
## >>> quit()
## # '>' = big & '<' = little endian, 'H' = 2 bytes
## # https://docs.python.org/3/library/struct.html#struct-alignment

print("Create an instance of the SMBus")
bus = smbus.SMBus(1)  

print("Configure_sensor")
bus.write_word_data(SENSOR_ADDRESS, CONFIG_REGISTER, CONFIG_SETTINGS)

print("Trigger_measurement")
bus.write_byte(SENSOR_ADDRESS, TEMPERATURE_REGISTER)
# Wait for the typical conversion time of 5.50ms
time.sleep(0.0055)

print("Read_sensor_data")
# Read data from the sensor
data = bus.read_word_data(SENSOR_ADDRESS, TEMPERATURE_REGISTER)
print("Raw data ",  data, ' ', hex(data))

print("Swap bytes")
data = ((data & 0xFF) << 8) | (data >> 8)
print("Swapped data ", data, ' ', hex(data))

## I think if temperature is about 21C (70F), swapped data 
##  should be about around 24234, hex about around 0x5eaa.

print("Convert_temperature")                 # python3
# Convert raw temperature data to Celsius    # >>> 2 ** 16 - 1
print(int(165 * data / 65535 - 40))          # 65535
#                                            # >>> quit()
1
  • So I tried this, and it ran until the Read Sensor Data, at this line it gave me, "OSError: [Errno 121] Remote I/O Error". I tried changing the data line to "read byte, read block, read i2c block" and all returned the same error above, any advice on next steps? Thank you so much for your help.
    – Jack
    Commented 2 days ago

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.