peter-l5 / MicroPython_SCD4X

MicroPython driver for Sensirion SCD40 and SCD41. Derived from the Adafruit CircuitPython version
MIT License
8 stars 1 forks source link

TypeError: function takes 1 positional arguments but 2 were given #3

Closed bocephasj closed 1 year ago

bocephasj commented 1 year ago

seem to be getting this error when trying to 'set_ambient_pressure' Traceback to line in code self._buffer[4] = self._crc8(self._crc_buffer) any feedback would be appreciated.

peter-l5 commented 1 year ago

Thanks for raising this issue. On a quick look at the code, I'm not sure why this is occurring. Can you provide more detail so that I could reproduce the error?

peter-l5 commented 1 year ago

Can I also ask if you might have edited the module code at all? For example, I think if you removed the line @staticmethod from the function definition for _crc8() you would likely get this error.

bocephasj commented 1 year ago

here is how we are running:

import xbee import time from machine import I2C from micropython import const

version = "v101" repo = "https://github.com/peter-l5/MicroPython_SCD4X"

SCD4X_DEFAULT_ADDR = 0x62 _SCD4X_GETALTITUDE = const(0x2322) _SCD4X_SETALTITUDE = const(0x2427) _SCD4X_PERSISTSETTINGS = const(0x3615)

Instantiate an I2C peripheral.

i2c_bus = I2C(1, freq=100000)

class SCD4X:

def __init__(self, i2c_bus: I2C, address: int = SCD4X_DEFAULT_ADDR) -> None:
    self.address = address
    self.i2c_device = i2c_bus
    self._buffer = bytearray(18)
    self._cmd = bytearray(2)
    self._crc_buffer = bytearray(2)
    # cached readings
    self._temperature = None
    self._relative_humidity = None
    self._co2 = None
    self.set_altitude(self, 375)

@property   
def get_altitude(self) -> int:
    self._send_command(_SCD4X_GETALTITUDE, cmd_delay=0.001)
    self._read_reply(self._buffer, 3)
    print("altitude is", self._buffer[0], self._buffer[1])
    return (self._buffer[0] << 8) | self._buffer[1]

@altitude_setter
def set_altitude(self, height: int) -> None:
    if height > 65535:
        raise AttributeError("Height must be less than or equal to 65535 meters")
    self._set_command_value(_SCD4X_SETALTITUDE, height)

def _check_buffer_crc(self, buf: bytearray) -> bool:
    for i in range(0, len(buf), 3):
        self._crc_buffer[0] = buf[i]
        self._crc_buffer[1] = buf[i + 1]
        if self._crc8(self._crc_buffer) != buf[i + 2]:
            raise RuntimeError("CRC check failed while reading data")
    return True

def _send_command(self, cmd: int, cmd_delay: float = 0) -> None:
    self._cmd[0] = (cmd >> 8) & 0xFF
    self._cmd[1] = cmd & 0xFF
    try:
        self.i2c_device.writeto(self.address, self._cmd)
    except OSError as err:
        raise RuntimeError("Could not communicate via I2C, some commands/settings unavailable while in working mode") from err
    time.sleep(cmd_delay)

def _read_reply(self, buff, num):
    self.i2c_device.readfrom_into(self.address, buff)
    self._check_buffer_crc(self._buffer[0:num])
    print(buff)

def _set_command_value(self, cmd, value, cmd_delay=0):
    self._buffer[0] = (cmd >> 8) & 0xFF
    self._buffer[1] = cmd & 0xFF
    self._crc_buffer[0] = self._buffer[2] = (value >> 8) & 0xFF
    self._crc_buffer[1] = self._buffer[3] = value & 0xFF
    self._buffer[4] = self._crc8(self._crc_buffer)
    self.i2c_device.i2c.write(self.address, self._buffer)
    time.sleep(cmd_delay)

@staticmethod
def _crc8(buffer: bytearray) -> int:
    crc = 0xFF
    for byte in buffer:
        crc ^= byte
        for _ in range(8):
            if crc & 0x80:
                crc = (crc << 1) ^ 0x31
            else:
                crc = crc << 1
    return crc & 0xFF  # return the bottom 8 bits

SCD4X(i2c_bus, SCD4X_DEFAULT_ADDR)

peter-l5 commented 1 year ago

Thanks for the code. The way it has come through it is a little bit difficult to see if the class is being defined correctly by looking at this. However I notice that you are not following the usage example given in the code. Have you tried doing that? To do so you would need to upload the scd4x.py file to your xbee.

peter-l5 commented 1 year ago

I'm going to close this issue now, but if you still experience the problem having followed the usage example, please raise again.

bocephasj commented 1 year ago

I am having a problem with this section of code:

def _set_command_value(self, cmd, value, cmd_delay=0):
    self._buffer[0] = (cmd >> 8) & 0xFF
    self._buffer[1] = cmd & 0xFF
    self._crc_buffer[0] = self._buffer[2] = (value >> 8) & 0xFF
    self._crc_buffer[1] = self._buffer[3] = value & 0xFF
    self._buffer[4] = self._crc8(self._crc_buffer)
    self.i2c_device.i2c.write(self.address, self._buffer) # error in this line 'AttributeError: 'I2C' object has no attribute 'i2c'

when I remove the second i2c tag in this line I get - "TypeError: function takes 2 positional arguments but 3 were given" - When commenting out this line, rest of code runs fine. time.sleep(cmd_delay) Any Ideas of what has gone wrong?

peter-l5 commented 1 year ago

Hi, thanks for raising this. There are errors in the line referred to. Replacing the problematic line with the following may solve the problem, but haven't tested yet. If @bocephasj you can try this, let me know if it helps!

    self.i2c_device.writeto(self.address, self._buffer[:5])
bocephasj commented 1 year ago

It ALL seems to be working now! Thank you for your help in getting all of this working!