AttributeError: 'I2C' object has no attribute '__exit__'



  • I'm trying to port Adafruit's micropython code for the HTU21D sensor to work in Pycom. I took the code and tried to modify some of the parameters to match what I have working from other library files, like for the MPA3115A2 sensor.. but I'm getting this error and can't seem to find info to resolve..
    The code fails with

    Traceback (most recent call last):
      File "main.py",  line 9 in <module>
      File "/flash/lib/htu21d.py", line 71, in __init__
      File"/flash/lib/htu21d.py", line 75, in _command
    AttributeError: 'I2C' object has no attribute '__exit__'
    

    /flash/lib/htu21d.py:

    # The MIT License (MIT)
    #
    # Copyright (c) 2018 ktown for Adafruit Industries
    #
    # Permission is hereby granted, free of charge, to any person obtaining a copy
    # of this software and associated documentation files (the "Software"), to deal
    # in the Software without restriction, including without limitation the rights
    # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    # copies of the Software, and to permit persons to whom the Software is
    # furnished to do so, subject to the following conditions:
    #
    # The above copyright notice and this permission notice shall be included in
    # all copies or substantial portions of the Software.
    #
    # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    # THE SOFTWARE.
    
    """
    `adafruit_htu21d`
    ====================================================
    This is a breakout for the Adafruit HTU21D-F humidity sensor breakout.
    * Author(s): ktown
    Implementation Notes
    --------------------
    **Hardware:**
    * Adafruit `HTU21D-F Temperature & Humidity Sensor Breakout Board
      <https://www.adafruit.com/product/1899>`_ (Product ID: 1899)
    **Software and Dependencies:**
    * Adafruit CircuitPython firmware for the supported boards:
      https://github.com/adafruit/circuitpython/releases
    * Adafruit's Bus Device library:
      https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
    """
    from machine import I2C
    
    
    
    def _crc(data):
        crc = 0
        for byte in data:
            crc ^= byte
            for _ in range(8):
                if crc & 0x80:
                    crc <<= 1
                    crc ^= 0x131
                else:
                    crc <<= 1
        return crc
    
    
    class HTU21D:
        HTU21D_I2CADDR=const(0x40)
        HUMIDITY = const(0xf5)
        TEMPERATURE = const(0xf3)
        _RESET = const(0xfe)
        _READ_USER1 = const(0xe7)
        _USER1_VAL = const(0x3a)
        """
        A driver for the HTU21D-F temperature and humidity sensor.
        :param i2c_bus: The `busio.I2C` object to use. This is the only
        required parameter.
        :param int address: (optional) The I2C address of the device.
        """
        def __init__(self, sda = 'P9', scl = 'P10'):
            self.i2c_device = I2C(0, mode=I2C.MASTER, pins=(sda, scl))
            self._command(_RESET)
            self._measurement = 0
    
        def _command(self, command):
            with self.i2c_device as i2c:
                i2c.writeto_mem(HTU21D_I2CADDR,struct.pack('B', command))
    
        def _data(self):
            data = bytearray(3)
            while True:
                # While busy, the sensor doesn't respond to reads.
                try:
                    with self.i2c_device as i2c:
                        i2c.readinto(data)
                        if data[0] != 0xff:  # Check if read succeeded.
                            break
                except OSError:
                    pass
            value, checksum = struct.unpack('>HB', data)
            if checksum != _crc(data[:2]):
                raise ValueError("CRC mismatch")
            return value
    
        @property
        def relative_humidity(self):
            """The measured relative humidity in percent."""
            self.measurement(HUMIDITY)
            self._measurement = 0
            return self._data() * 125.0 / 65536.0 - 6.0
    
        @property
        def temperature(self):
            """The measured temperature in degrees Celcius."""
            self.measurement(TEMPERATURE)
            self._measurement = 0
            return self._data() * 175.72 / 65536.0 - 46.85
    
        def measurement(self, what):
            """
            Starts a measurement.
            Starts a measurement of either ``HUMIDITY`` or ``TEMPERATURE``
            depending on the ``what`` argument. Returns immediately, and the
            result of the measurement can be retrieved with the
            ``temperature`` and ``relative_humidity`` properties. This way it
            will take much less time.
            This can be useful if you want to start the measurement, but don't
            want the call to block until the measurement is ready -- for instance,
            when you are doing other things at the same time.
            """
            if what not in (HUMIDITY, TEMPERATURE):
                raise ValueError()
            if not self._measurement:
                self._command(what)
            elif self._measurement != what:
                raise RuntimeError("other measurement in progress")
            self._measurement = what
    

    /main.py:

    from htu21d import HTU21D
     
    # Create library object using our Bus I2C port
    #i2c = busio.I2C(board.SCL, board.SDA)
    #from machine import I2C, Pin
    #i2c = I2C(0, pins=("P9","P10"))
    #i2c.init(I2C.MASTER, baudrate=9600)
    
    sensor = HTU21D()
    
    print("\nTemperature: %0.1f C" % sensor.temperature)
    print("Humidity: %0.1f %%" % sensor.relative_humidity)
    


  • Thanks!
    After clearing that error, I ran into several more.
    This is what I ended up with when I got it working finally
    /flash/lib/htu21d.py:

    # The MIT License (MIT)
    #
    # Copyright (c) 2018 ktown for Adafruit Industries
    #
    # Permission is hereby granted, free of charge, to any person obtaining a copy
    # of this software and associated documentation files (the "Software"), to deal
    # in the Software without restriction, including without limitation the rights
    # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    # copies of the Software, and to permit persons to whom the Software is
    # furnished to do so, subject to the following conditions:
    #
    # The above copyright notice and this permission notice shall be included in
    # all copies or substantial portions of the Software.
    #
    # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    # THE SOFTWARE.
    
    """
    `adafruit_htu21d`
    ====================================================
    This is a breakout for the Adafruit HTU21D-F humidity sensor breakout.
    * Author(s): ktown
    Implementation Notes
    --------------------
    **Hardware:**
    * Adafruit `HTU21D-F Temperature & Humidity Sensor Breakout Board
      <https://www.adafruit.com/product/1899>`_ (Product ID: 1899)
    **Software and Dependencies:**
    * Adafruit CircuitPython firmware for the supported boards:
      https://github.com/adafruit/circuitpython/releases
    * Adafruit's Bus Device library:
      https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
    """
    from machine import I2C
    import struct
    HTU21D_I2CADDR=const(0x40)
    HUMIDITY = const(0xf5)
    TEMPERATURE = const(0xf3)
    _RESET = const(0xfe)
    _READ_USER1 = const(0xe7)
    _USER1_VAL = const(0x3a)
    
    
    def _crc(data):
        crc = 0
        for byte in data:
            crc ^= byte
            for _ in range(8):
                if crc & 0x80:
                    crc <<= 1
                    crc ^= 0x131
                else:
                    crc <<= 1
        return crc
    
    
    class HTU21D:
        #HTU21D_I2CADDR=const(0x40)
        #HUMIDITY = const(0xf5)
        #TEMPERATURE = const(0xf3)
        #_RESET = const(0xfe)
        #_READ_USER1 = const(0xe7)
        #_USER1_VAL = const(0x3a)
        """
        A driver for the HTU21D-F temperature and humidity sensor.
        :param i2c_bus: The `busio.I2C` object to use. This is the only
        required parameter.
        :param int address: (optional) The I2C address of the device.
        """
        def __init__(self, sda = 'P9', scl = 'P10'):
            self.i2c_device = I2C(0, mode=I2C.MASTER, pins=(sda, scl))
            self._command(_RESET)
            self._measurement = 0
            self.addr = HTU21D_I2CADDR
    
        def _command(self, command):
            #with self.i2c_device as i2c:
            self.i2c_device.writeto(HTU21D_I2CADDR, command)
    
        def _data(self):
            data = bytearray(3)
            while True:
                # While busy, the sensor doesn't respond to reads.
                try:
                    #with self.i2c_device as i2c:
                   self.i2c_device.readfrom_into(self.addr, data)
                   if data[0] != 0xff:  # Check if read succeeded.
                       break
                except OSError:
                    pass
            value,checksum=struct.unpack('>HB',data)
            if checksum != _crc(data[:2]):
                raise ValueError('CRC mismatch:'+data+':'+checksum+':')
            return value
    
        @property
        def relative_humidity(self):
            """The measured relative humidity in percent."""
            self.measurement(HUMIDITY)
            self._measurement = 0
            return self._data() * 125.0 / 65536.0 - 6.0
    
        @property
        def temperature(self):
            """The measured temperature in degrees Celcius."""
            self.measurement(TEMPERATURE)
            self._measurement = 0
            return self._data() * 175.72 / 65536.0 - 46.85
    
        def measurement(self, what):
            """
            Starts a measurement.
            Starts a measurement of either ``HUMIDITY`` or ``TEMPERATURE``
            depending on the ``what`` argument. Returns immediately, and the
            result of the measurement can be retrieved with the
            ``temperature`` and ``relative_humidity`` properties. This way it
            will take much less time.
            This can be useful if you want to start the measurement, but don't
            want the call to block until the measurement is ready -- for instance,
            when you are doing other things at the same time.
            """
            if what not in (HUMIDITY, TEMPERATURE):
                raise ValueError()
            if not self._measurement:
                self._command(what)
            elif self._measurement != what:
                raise RuntimeError("other measurement in progress")
            self._measurement = what```


  • @dnear1 This is caused by the I2C call in a with statement. Remove with, then it works.


 

Pycom on Twitter