diff --git a/README.rst b/README.rst index 73be16c..78fd536 100644 --- a/README.rst +++ b/README.rst @@ -37,9 +37,6 @@ Installing from PyPI .. note:: This library is not available on PyPI yet. Install documentation is included as a standard element. Stay tuned for PyPI availability! -.. todo:: Remove the above note if PyPI version is/will be available at time of release. - If the library is not planned for PyPI, remove the entire 'Installing from PyPI' section. - On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from PyPI `_. To install for current user: @@ -65,8 +62,6 @@ To install in a virtual environment in your current project: Usage Example ============= -.. todo:: Add a quick, simple example. It and other examples should live in the examples folder and be included in docs/examples.rst. - Contributing ============ diff --git a/adafruit_lc709203f.py b/adafruit_lc709203f.py index 440dcad..167db36 100644 --- a/adafruit_lc709203f.py +++ b/adafruit_lc709203f.py @@ -16,21 +16,167 @@ **Hardware:** -.. todo:: Add links to any specific hardware product page(s), or category page(s). Use unordered list & hyperlink rST - inline format: "* `Link Text `_" + * Adafruit LC709023 Breakout: https://www.adafruit.com/product/4712 **Software and Dependencies:** * Adafruit CircuitPython firmware for the supported boards: https://github.com/adafruit/circuitpython/releases -.. todo:: Uncomment or remove the Bus Device and/or the Register library dependencies based on the library's use of either. - # * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice # * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register """ -# imports +from micropython import const +import adafruit_bus_device.i2c_device as i2c_device __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_LC709203F.git" + +LC709023F_I2CADDR_DEFAULT = const(0x0B) +LC709203F_CMD_ICVERSION = const(0x11) +LC709203F_CMD_POWERMODE = const(0x15) +LC709203F_CMD_APA = const(0x0B) +LC709203F_CMD_INITRSOC = const(0x07) +LC709203F_CMD_CELLVOLTAGE = const(0x09) +LC709203F_CMD_CELLITE = const(0x0F) + + +class CV: + """struct helper""" + + @classmethod + def add_values(cls, value_tuples): + """Add CV values to the class""" + cls.string = {} + cls.lsb = {} + + for value_tuple in value_tuples: + name, value, string, lsb = value_tuple + setattr(cls, name, value) + cls.string[value] = string + cls.lsb[value] = lsb + + @classmethod + def is_valid(cls, value): + """Validate that a given value is a member""" + return value in cls.string + + +class PowerMode(CV): + """Options for ``power_mode``""" + + pass # pylint: disable=unnecessary-pass + + +PowerMode.add_values( + (("OPERATE", 0x0001, "Operate", None), ("SLEEP", 0x0002, "Sleep", None),) +) + + +class PackSize(CV): + """Options for ``pack_size``""" + + pass # pylint: disable=unnecessary-pass + + +PackSize.add_values( + ( + ("MAH100", 0x08, "100 mAh", 100), + ("MAH200", 0x0B, "200 mAh", 200), + ("MAH500", 0x10, "500 mAh", 500), + ("MAH1000", 0x19, "1000 mAh", 1000), + ("MAH2000", 0x2D, "2000 mAh", 2000), + ("MAH3000", 0x36, "3000 mAh", 3000), + ) +) + + +class LC709023F: + """Interface library for LC709023F battery monitoring and fuel gauge sensors""" + + def __init__(self, i2c_bus, address=LC709023F_I2CADDR_DEFAULT): + self.i2c_device = i2c_device.I2CDevice(i2c_bus, address) + self._buf = bytearray(10) + self.power_mode = PowerMode.OPERATE # pylint: disable=no-member + self.pack_size = PackSize.MAH500 # pylint: disable=no-member + self.init_RSOC() + + def init_RSOC(self): # pylint: disable=invalid-name + """ Initialize the state of charge calculator """ + self._write_word(LC709203F_CMD_INITRSOC, 0xAA55) + + @property + def cell_voltage(self): + """Returns floating point voltage""" + return self._read_word(LC709203F_CMD_CELLVOLTAGE) / 1000 + + @property + def cell_percent(self): + """Returns percentage of cell capacity""" + return self._read_word(LC709203F_CMD_CELLITE) / 10 + + @property + def ic_version(self): + """Returns read-only chip version""" + return self._read_word(LC709203F_CMD_ICVERSION) + + @property + def power_mode(self): + """Returns current power mode (operating or sleeping)""" + return self._read_word(LC709203F_CMD_POWERMODE) + + @power_mode.setter + def power_mode(self, mode): + if not PowerMode.is_valid(mode): + raise AttributeError("power_mode must be a PowerMode") + self._write_word(LC709203F_CMD_POWERMODE, mode) + + @property + def pack_size(self): + """Returns current battery pack size""" + return self._read_word(LC709203F_CMD_APA) + + @pack_size.setter + def pack_size(self, size): + if not PackSize.is_valid(size): + raise AttributeError("pack_size must be a PackSize") + self._write_word(LC709203F_CMD_APA, size) + + # pylint: disable=no-self-use + def _generate_crc(self, data): + """8-bit CRC algorithm for checking data""" + crc = 0x00 + # calculates 8-Bit checksum with given polynomial + for byte in data: + crc ^= byte + for _ in range(8): + if crc & 0x80: + crc = (crc << 1) ^ 0x07 + else: + crc <<= 1 + return crc & 0xFF + + def _read_word(self, command): + self._buf[0] = LC709023F_I2CADDR_DEFAULT * 2 # write byte + self._buf[1] = command # command / register + self._buf[2] = self._buf[0] | 0x1 # read byte + + with self.i2c_device as i2c: + i2c.write_then_readinto( + self._buf, self._buf, out_start=1, out_end=2, in_start=3, in_end=7 + ) + crc8 = self._generate_crc(self._buf[0:5]) + if crc8 != self._buf[5]: + raise RuntimeError("CRC failure on reading word") + return (self._buf[4] << 8) | self._buf[3] + + def _write_word(self, command, data): + self._buf[0] = LC709023F_I2CADDR_DEFAULT * 2 # write byte + self._buf[1] = command # command / register + self._buf[2] = data & 0xFF + self._buf[3] = (data >> 8) & 0xFF + self._buf[4] = self._generate_crc(self._buf[0:4]) + + with self.i2c_device as i2c: + i2c.write(self._buf[1:5]) diff --git a/docs/conf.py b/docs/conf.py index a9b7226..4771c28 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,8 +29,15 @@ intersphinx_mapping = { - "python": ("https://docs.python.org/3.4", None),"BusDevice": ("https://circuitpython.readthedocs.io/projects/busdevice/en/latest/", None), - "Register": ("https://circuitpython.readthedocs.io/projects/register/en/latest/", None), + "python": ("https://docs.python.org/3.4", None), + "BusDevice": ( + "https://circuitpython.readthedocs.io/projects/busdevice/en/latest/", + None, + ), + "Register": ( + "https://circuitpython.readthedocs.io/projects/register/en/latest/", + None, + ), "CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None), } diff --git a/docs/index.rst b/docs/index.rst index 259784e..243f8ee 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -23,14 +23,10 @@ Table of Contents .. toctree:: :caption: Tutorials -.. todo:: Add any Learn guide links here. If there are none, then simply delete this todo and leave - the toctree above for use later. - .. toctree:: :caption: Related Products -.. todo:: Add any product links here. If there are none, then simply delete this todo and leave - the toctree above for use later. + Adafruit LC709023 Breakout .. toctree:: :caption: Other Links diff --git a/examples/lc709203f_simpletest.py b/examples/lc709203f_simpletest.py index 0d4a377..58b3d41 100644 --- a/examples/lc709203f_simpletest.py +++ b/examples/lc709203f_simpletest.py @@ -1,3 +1,20 @@ # SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense + +import time +import board +from adafruit_lc709203f import LC709023F + +print("LC709023F simple test") +print("Make sure LiPoly battery is plugged into the board!") + +i2c = board.I2C() +sensor = LC709023F(i2c) + +print("IC version:", hex(sensor.ic_version)) +while True: + print( + "Battery: %0.3f Volts / %0.1f %%" % (sensor.cell_voltage, sensor.cell_percent) + ) + time.sleep(1) diff --git a/setup.py b/setup.py index 2669ca8..f244efb 100644 --- a/setup.py +++ b/setup.py @@ -54,7 +54,7 @@ ], # What does your project relate to? keywords="adafruit blinka circuitpython micropython lc709203f battery lipoly status fuel " - "gauge i2c", + "gauge i2c", # You can just specify the packages manually here if your project is # simple. Or you can use find_packages(). # TODO: IF LIBRARY FILES ARE A PACKAGE FOLDER,