Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,10 @@ This is easily achieved by downloading
or individual libraries can be installed using
`circup <https://github.com/adafruit/circup>`_.



.. todo:: Describe the Adafruit product this library works with. For PCBs, you can also add the
image from the assets folder in the PCB's GitHub repo.

`Purchase one from the Adafruit shop <http://www.adafruit.com/products/5810>`_

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.

On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from
PyPI <https://pypi.org/project/adafruit-circuitpython-vcnl4020/>`_.
Expand Down Expand Up @@ -101,8 +92,21 @@ Or the following command to update an existing version:
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.
.. code-block:: python

import time
import board
import adafruit_vcnl4020

i2c = board.I2C()

# Initialize VCNL4020
sensor = adafruit_vcnl4020.Adafruit_VCNL4020(i2c)

while True:
print(f"Proximity is: {sensor.proximity}")
print(f"Ambient is: {sensor.lux}")
time.sleep(0.1)

Documentation
=============
Expand Down
265 changes: 256 additions & 9 deletions adafruit_vcnl4020.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2023 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT

# Written by Liz Clark (Adafruit Industries) with OpenAI ChatGPT v4 September 25, 2023 build
# https://help.openai.com/en/articles/6825453-chatgpt-release-notes

# https://chat.openai.com/share/f4f94c37-66a1-42d9-879b-9624c13f3e26
"""
`adafruit_vcnl4020`
================================================================================
Expand All @@ -16,22 +20,265 @@
**Hardware:**
.. todo:: Add links to any specific hardware product page(s), or category page(s).
Use unordered list & hyperlink rST inline format: "* `Link Text <url>`_"
* Adafruit VCNL4020 Proximity and Light Sensor <https://www.adafruit.com/product/5810>
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://circuitpython.org/downloads
.. 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
* 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
from adafruit_bus_device.i2c_device import I2CDevice
from adafruit_register.i2c_struct import Struct, ROUnaryStruct
from adafruit_register.i2c_bit import ROBit, RWBit
from adafruit_register.i2c_bits import RWBits

try:
import typing # pylint: disable=unused-import
from busio import I2C
except ImportError:
pass

__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_VCNL4020.git"

_I2C_ADDRESS = const(0x13)
_REG_COMMAND = const(0x80)
_REG_PRODUCT_ID = const(0x81)
_REG_PROX_RATE = const(0x82)
_REG_IR_LED_CURRENT = const(0x83)
_REG_AMBIENT_PARAM = const(0x84)
_REG_AMBIENT_RESULT_HIGH = const(0x85)
_REG_AMBIENT_RESULT_LOW = const(0x86)
_REG_PROX_RESULT_HIGH = const(0x87)
_REG_PROX_RESULT_LOW = const(0x88)
_REG_INT_CTRL = const(0x89)
_REG_LOW_THRES_HIGH = const(0x8A)
_REG_LOW_THRES_LOW = const(0x8B)
_REG_HIGH_THRES_HIGH = const(0x8C)
_REG_HIGH_THRES_LOW = const(0x8D)
_REG_INT_STATUS = const(0x8E)
_REG_PROX_ADJUST = const(0x8F)
_INT_TH_HI = const(0x01)
_INT_TH_LOW = const(0x02)
_INT_ALS_READY = const(0x04)
_INT_PROX_READY = const(0x08)


# pylint: disable=too-many-instance-attributes
class Adafruit_VCNL4020:
"""Adafruit VCNL4020 Proximity/Ambient Light sensor driver"""

auto_offset_comp = RWBit(_REG_AMBIENT_PARAM, 3)
"""Auto offset compensation for ambient light measurement."""
_command_reg = RWBits(8, _REG_COMMAND, 0)
continuous_conversion = RWBit(_REG_AMBIENT_PARAM, 7)
"""Continuous conversion mode for ambient light measurement."""
_int_ctrl_reg = RWBits(8, _REG_INT_CTRL, 0)
_int_status_reg = RWBits(3, _REG_INT_STATUS, 0)
_led_current = RWBits(6, _REG_IR_LED_CURRENT, 0)
_product_revision = ROUnaryStruct(_REG_PRODUCT_ID, "<B")
lux = ROUnaryStruct(_REG_AMBIENT_RESULT_HIGH, ">H")
"""Reads the ambient light/lux sensor (ALS) measurement result"""
_lux_averaging = RWBits(3, _REG_AMBIENT_PARAM, 0)
lux_enabled = RWBit(_REG_COMMAND, 2)
"""Enable/disable lux sensor"""
lux_on_demand = RWBit(_REG_COMMAND, 4)
"""On-demand setting for lux measurements"""
_lux_rate = RWBits(3, _REG_AMBIENT_PARAM, 4)
lux_ready = ROBit(_REG_COMMAND, 6)
"""Status of ambient light data"""
proximity = ROUnaryStruct(_REG_PROX_RESULT_HIGH, ">H")
"""Reads the proximity measurement result"""
proximity_enabled = RWBit(_REG_COMMAND, 1)
"""Enable/disable proximity sensor"""
_proximity_frequency = RWBits(2, _REG_PROX_ADJUST, 3)
promixity_on_demand = RWBit(_REG_COMMAND, 3)
"""On-demand setting for proximity measurements"""
_proximity_rate = RWBits(3, _REG_PROX_RATE, 0)
proximity_ready = ROBit(_REG_COMMAND, 5)
"""Status of proximity data."""
low_threshold = Struct(_REG_LOW_THRES_HIGH, ">H")
"""Sets the low threshold for proximity measurement"""
high_threshold = Struct(_REG_HIGH_THRES_HIGH, ">H")
"""Sets the high threshold for proximity measurement."""
_interrupt_count = RWBits(3, _REG_INT_CTRL, 5)
proximity_interrupt = RWBit(_REG_INT_CTRL, 3)
"""Enable/disable proximity interrupt"""
lux_interrupt = RWBit(_REG_INT_CTRL, 2)
"""Enable/disable lux interrupt"""
high_threshold_interrupt = RWBit(_REG_INT_CTRL, 1)
"""Enable/disable proximity high threshold interrupt"""
low_threshold_interrupt = RWBit(_REG_INT_CTRL, 0)
"""Enable/disable proximity low threshold interrupt"""
selftimed_enabled = RWBit(_REG_COMMAND, 0)
"""Enable/disable selftimed reading"""

_proximity_rates = [1.95, 3.9, 7.8, 16.6, 31.2, 62.5, 125, 250]
_lux_rates = [1, 2, 3, 4, 5, 6, 8, 10]
_avg_samples = [1, 2, 4, 8, 16, 32, 64, 128]
_int_counts = [1, 2, 4, 8, 16, 32, 64, 128]
_proximity_frequencies = [390.625, 781.25, 1.5625, 3.125]

def __init__(self, i2c: I2C, addr: int = _I2C_ADDRESS) -> None:
"""
Initializes the VCNL4020 sensor and checks for a valid Product ID Revision.
:param i2c: The I2C interface to use
:param addr: The I2C address of the VCNL4020, defaults to _I2C_ADDRESS
"""
self.i2c_device = I2CDevice(i2c, addr)

# Check the Product ID Revision
if self._product_revision != 0x21:
raise RuntimeError(f"Invalid Product ID Revision {self._product_revision}")
try:
# Configuration settings
self.proximity_rate = 250
self.led_current = 200
self.lux_rate = 10
self.lux_averaging = 1
except Exception as error:
raise RuntimeError(f"Failed to initialize: {error}") from error

@property
def _enable(self) -> bool:
return self.lux_enabled, self.proximity_enabled, self.selftimed_enabled

@_enable.setter
def _enable(self, value: bool) -> None:
self.lux_enabled = value
self.proximity_enabled = value
self.selftimed_enabled = value

@property
def clear_interrupts(self) -> None:
"""
Clears the interrupt flags.
:param value: True to clear all interrupt flags.
"""
clear_bits = 0
clear_bits |= _INT_PROX_READY
clear_bits |= _INT_ALS_READY
clear_bits |= _INT_TH_LOW
clear_bits |= _INT_TH_HI
self._int_status_reg |= clear_bits

@property
def interrupt_count(self) -> int:
"""
Interrupt count setting
:rtype: int
"""
return self._int_counts[self._interrupt_count]

@interrupt_count.setter
def interrupt_count(self, value: int) -> None:
self._enable = False
if value not in self._int_counts:
raise ValueError(
f"Invalid interrupt count: {value}. Available counts: {self._int_counts}"
)
count = self._int_counts.index(value)
self._interrupt_count = count
self._enable = True

@property
def led_current(self) -> int:
"""
The LED current for proximity mode in mA.
:return: The LED current in mA.
"""
return self._led_current * 10

@led_current.setter
def led_current(self, value: int) -> None:
self._enable = False
self._led_current = value // 10
self._enable = True

@property
def lux_averaging(self) -> int:
"""
Ambient averaging sample rate
:rtype: int
"""
return self._avg_samples[self._lux_averaging]

@lux_averaging.setter
def lux_averaging(self, value: int) -> None:
self._enable = False
if value not in self._avg_samples:
raise ValueError(
f"Invalid sample rate: {value}. Available sample rates: {self._avg_samples}"
)
sample_rate = self._avg_samples.index(value)
self._lux_averaging = sample_rate
self._enable = True

@property
def lux_rate(self) -> int:
"""
Ambient light measurement rate
:rtype: int
"""
return self._lux_rates[self._lux_rate]

@lux_rate.setter
def lux_rate(self, value: int) -> None:
self._enable = False
if value not in self._lux_rates:
raise ValueError(
f"Invalid ambient rate: {value}. Available rates: {self._lux_rates}"
)
rate = self._lux_rates.index(value)
self._lux_rate = rate
self._enable = True

@property
def proximity_frequency(self) -> int:
"""
Proximity frequency setting
:rtype: int
"""
return self._proximity_frequencies[self._proximity_frequency]

@proximity_frequency.setter
def proximity_frequency(self, value: int) -> None:
self._enable = False
if value not in self._proximity_frequencies:
raise ValueError(
f"Invalid frequency: {value}. Available frequencies: {self._proximity_frequencies}"
)
freq = self._proximity_frequencies.index(value)
self._proximity_frequency = freq
self._enable = True

@property
def proximity_rate(self) -> int:
"""
Proximity measurement rate
:rtype: int
"""
return self._proximity_rates[self._proximity_rate]

@proximity_rate.setter
def proximity_rate(self, value: int) -> None:
self._enable = False
if value not in self._proximity_rates:
raise ValueError(
f"Invalid proximity rate: {value}. Available rates: {self._proximity_rates}"
)
rate = self._proximity_rates.index(value)
self._proximity_rate = rate
self._enable = True
14 changes: 8 additions & 6 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,19 @@
"sphinx.ext.todo",
]

# TODO: Please Read!
# Uncomment the below if you use native CircuitPython modules such as
# digitalio, micropython and busio. List the modules you use. Without it, the
# autodoc module docs will fail to generate with a warning.
# autodoc_mock_imports = ["digitalio", "busio"]
autodoc_mock_imports = [
"micropython",
"busio",
"adafruit_bus_device",
"adafruit_register",
]

autodoc_preserve_defaults = True


intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),"BusDevice": ("https://docs.circuitpython.org/projects/busdevice/en/latest/", None),
"python": ("https://docs.python.org/3", None),
"BusDevice": ("https://docs.circuitpython.org/projects/busdevice/en/latest/", None),
"Register": ("https://docs.circuitpython.org/projects/register/en/latest/", None),
"CircuitPython": ("https://docs.circuitpython.org/en/latest/", None),
}
Expand Down
6 changes: 2 additions & 4 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,12 @@ 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.
Adafruit VCNL4020 Breakout Board Learn Guide <https://learn.adafruit.com/adafruit-vcnl4020-proximity-and-light-sensor>

.. 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 VCNL4020 Proximity and Light Sensor <https://www.adafruit.com/product/5810>

.. toctree::
:caption: Other Links
Expand Down
25 changes: 21 additions & 4 deletions examples/vcnl4020_simpletest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2023 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries
# SPDX-License-Identifier: MIT

# Simple demo to read ambient light/lux
# and proximity data from VCNL4020 over I2C

import time
import board
import adafruit_vcnl4020

i2c = board.I2C()

# Initialize VCNL4020
sensor = adafruit_vcnl4020.Adafruit_VCNL4020(i2c)

while True:
print(f"Proximity is: {sensor.proximity}")
print(f"Ambient is: {sensor.lux}")
# uncomment print statement below to log to Mu plotter
# print((sensor.proximity, sensor.lux,))
time.sleep(0.1)