IOError: [Errno 2] No such file or directory when using i2c

I’m working on the project below in a container:

docker-compose:

version: '2'
services:
   system:
     build: ./system
     restart: always
     privileged: true
     labels:
      io.balena.features.dbus: '1'
      io.balena.features.firmware: '1'
      io.balena.features.kernel-modules: '1'

docker.template:

# base-image for python on any machine using a template variable,
# see more about dockerfile templates here:http://docs.resin.io/pages/deployment/docker-templates
FROM resin/%%RESIN_MACHINE_NAME%%-python

# use apt-get if you need to install dependencies
RUN apt-get update && apt-get install -yq \
		python-smbus && \
		apt-get clean && rm -rf /var/lib/apt/lists/*

# Set our working directory
WORKDIR /usr/src/app

# Copy requirements.txt first for better cache on later pushes
COPY ./requirements.txt /requirements.txt

# pip install python deps from requirements.txt on the resin.io build server
#RUN pip install -r /requirements.txt

# This will copy all files in our root to the working	directory in the container
COPY . ./

# switch on systemd init system in container
ENV INITSYSTEM on

# start.sh will run when container starts up on the device
CMD ["bash", "start.sh"]

start.sh:

#/bin/bash

# Strips device-type from hostname (only works on resin.io base images)
DEVICE_TYPE=${HOSTNAME%-*}
I2C_BUS=0 # Default i2c bus number

# Enables i2c for the platform and set the appropriate bus number.
if [[ "$DEVICE_TYPE" =~ "raspberrypi" ]]; then
	modprobe i2c-dev
	export I2C_BUS=1
elif [[ "$DEVICE_TYPE" = "odroid-c1" ]]; then
	modprobe i2c-dev
	modprobe aml_i2c
	export I2C_BUS=1
elif [[ "$DEVICE_TYPE" = "beaglebone" ]]; then
	# i2c0: Not exposed in the expansion headers
	# i2c1: pins P9 17,18 (and 24,26)
	# i2c2: pins P9 19,20 (and 21,22)
	# load cape-universaln if you need i2c-1
	#echo cape-universaln > /sys/devices/platform/bone_capemgr/slots
	export I2C_BUS=2
elif [[ "$DEVICE_TYPE" = "artik5" ]]; then
	# Currently not working :/
	export I2C_BUS=9
elif [[ "$DEVICE_TYPE" = "artik10" ]]; then
	# Currently not working :/
	export I2C_BUS=7
else
	echo "Unable to detect device type!!!"
fi

echo "detected $DEVICE_TYPE"

#Starts our sensor read script.
python src/sensor.py

And the python script is:

import smbus, os
from time import sleep

busNumber = int(os.getenv("I2C_BUS"))

bus = smbus.SMBus(busNumber)

# ADXL345 constants
EARTH_GRAVITY_MS2   = 9.80665
SCALE_MULTIPLIER    = 0.004

DATA_FORMAT         = 0x31
BW_RATE             = 0x2C
POWER_CTL           = 0x2D

BW_RATE_1600HZ      = 0x0F
BW_RATE_800HZ       = 0x0E
BW_RATE_400HZ       = 0x0D
BW_RATE_200HZ       = 0x0C
BW_RATE_100HZ       = 0x0B
BW_RATE_50HZ        = 0x0A
BW_RATE_25HZ        = 0x09

RANGE_2G            = 0x00
RANGE_4G            = 0x01
RANGE_8G            = 0x02
RANGE_16G           = 0x03

MEASURE             = 0x08
AXES_DATA           = 0x32

class ADXL345:

    address = None

    def __init__(self, address = 0x53):
        self.address = address
        self.setBandwidthRate(BW_RATE_100HZ)
        self.setRange(RANGE_2G)
        self.enableMeasurement()

    def enableMeasurement(self):
        bus.write_byte_data(self.address, POWER_CTL, MEASURE)

    def setBandwidthRate(self, rate_flag):
        bus.write_byte_data(self.address, BW_RATE, rate_flag)

    # set the measurement range for 10-bit readings
    def setRange(self, range_flag):
        value = bus.read_byte_data(self.address, DATA_FORMAT)

        value &= ~0x0F
        value |= range_flag
        value |= 0x08

        bus.write_byte_data(self.address, DATA_FORMAT, value)

    # returns the current reading from the sensor for each axis
    #
    # parameter gforce:
    #    False (default): result is returned in m/s^2
    #    True           : result is returned in gs
    def getAxes(self, gforce = False):
        bytes = bus.read_i2c_block_data(self.address, AXES_DATA, 6)

        x = bytes[0] | (bytes[1] << 8)
        if(x & (1 << 16 - 1)):
            x = x - (1<<16)

        y = bytes[2] | (bytes[3] << 8)
        if(y & (1 << 16 - 1)):
            y = y - (1<<16)

        z = bytes[4] | (bytes[5] << 8)
        if(z & (1 << 16 - 1)):
            z = z - (1<<16)

        x = x * SCALE_MULTIPLIER
        y = y * SCALE_MULTIPLIER
        z = z * SCALE_MULTIPLIER

        if gforce == False:
            x = x * EARTH_GRAVITY_MS2
            y = y * EARTH_GRAVITY_MS2
            z = z * EARTH_GRAVITY_MS2

        x = round(x, 4)
        y = round(y, 4)
        z = round(z, 4)

        return {"x": x, "y": y, "z": z}

if __name__ == "__main__":
    # if run directly we'll just create an instance of the class and output
    # the current readings
    adxl345 = ADXL345()
    while False:
        axes = adxl345.getAxes(True)
        print "ADXL345 on address 0x%x:" % (adxl345.address)
        print "   x = %.3fG" % ( axes['x'] )
        print "   y = %.3fG" % ( axes['y'] )
        print "   z = %.3fG" % ( axes['z'] )
        sleep(5)

I can’t figure out what I’m doing wrong here. The log I get is this:

02.11.19 12:59:36 (-0700)  system  detected raspberrypi3
02.11.19 12:59:36 (-0700)  system  Traceback (most recent call last):
02.11.19 12:59:36 (-0700)  system    File "src/sensor.py", line 6, in <module>
02.11.19 12:59:36 (-0700)  system      bus = smbus.SMBus(busNumber)
02.11.19 12:59:36 (-0700)  system  IOError: [Errno 2] No such file or directory

So essentially the error is IOError. This is listed as something that happens in this project:

Which tells you to restart the service and that it’s normal the first time:

However restarting the service doesn’t seem to help.

It seems the issue was in the fleet settings. I had to activate this RESIN_HOST_CONFIG_dtparam

This will turn on i2c, spi, and audio

For some reason I thought I had already done that but apparently not. It’s working just fine now!