implemented a cut down version of driver and included examples

This commit is contained in:
mrmcwethy 2017-12-29 05:14:36 -07:00
parent 181eeafa1a
commit 26e106461e
11 changed files with 961 additions and 117 deletions

5
.gitignore vendored
View file

@ -1 +1,6 @@
__pycache__
_build
*.pyc
.env
build*
bundles

432
.pylintrc Normal file
View file

@ -0,0 +1,432 @@
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
extension-pkg-whitelist=
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS
# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
ignore-patterns=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint.
# jobs=1
jobs=2
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Pickle collected data for later comparisons.
persistent=yes
# Specify a configuration file.
#rcfile=
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
# disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=
[REPORTS]
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
#msg-template=
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio).You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=text
# Tells whether to display a full report or only the messages
reports=no
# Activate the evaluation score.
score=yes
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
[LOGGING]
# Logging modules to check that the string format arguments are in logging
# function parameter format
logging-modules=logging
[SPELLING]
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,XXX,TODO
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,_cb
# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,future.builtins
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
# expected-line-ending-format=
expected-line-ending-format=LF
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=100
# Maximum number of lines in a module
max-module-lines=1000
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,dict-separator
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[SIMILARITIES]
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
# Minimum lines number of a similarity.
min-similarity-lines=4
[BASIC]
# Naming hint for argument names
argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct argument names
argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Naming hint for attribute names
attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct attribute names
attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Naming hint for class attribute names
class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Regular expression matching correct class attribute names
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Naming hint for class names
# class-name-hint=[A-Z_][a-zA-Z0-9]+$
class-name-hint=[A-Z_][a-zA-Z0-9_]+$
# Regular expression matching correct class names
# class-rgx=[A-Z_][a-zA-Z0-9]+$
class-rgx=[A-Z_][a-zA-Z0-9_]+$
# Naming hint for constant names
const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Regular expression matching correct constant names
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
# Naming hint for function names
function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct function names
function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Good variable names which should always be accepted, separated by a comma
# good-names=i,j,k,ex,Run,_
good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_
# Include a hint for the correct naming format with invalid-name
include-naming-hint=no
# Naming hint for inline iteration names
inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
# Regular expression matching correct inline iteration names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Naming hint for method names
method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct method names
method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Naming hint for module names
module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Regular expression matching correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
property-classes=abc.abstractproperty
# Naming hint for variable names
variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct variable names
variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
[IMPORTS]
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=optparse,tkinter.tix
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,_fields,_replace,_source,_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
[DESIGN]
# Maximum number of arguments for function / method
max-args=5
# Maximum number of attributes for a class (see R0902).
# max-attributes=7
max-attributes=11
# Maximum number of boolean expressions in a if statement
max-bool-expr=5
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of statements in function / method body
max-statements=50
# Minimum number of public methods for a class (see R0903).
min-public-methods=1
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception

30
.travis.yml Normal file
View file

@ -0,0 +1,30 @@
# This is a common .travis.yml for generating library release zip files for
# CircuitPython library releases using circuitpython-build-tools.
# See https://github.com/adafruit/circuitpython-build-tools for detailed setup
# instructions.
dist: trusty
sudo: false
language: python
python:
- "3.6"
cache:
pip: true
deploy:
provider: releases
api_key: $GITHUB_TOKEN
file_glob: true
file: bundles/*
skip_cleanup: true
on:
tags: true
install:
- pip install pylint circuitpython-build-tools
script:
- pylint adafruit_apds9960.py
- ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name examples/*.py)
- circuitpython-build-bundles --filename_prefix adafruit-circuitpython-apds9960 --library_location .

View file

@ -1,103 +0,0 @@
# The MIT License (MIT)
#
# Copyright (c) 2017 Michael McWethy for Adafruit Inc
#
# 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_APDS9960`
====================================================
TODO(description)
* Author(s): Michael McWethy
"""
class APDS9960:
UP = const(1)
DOWN = const(2)
RIGHT = const(3)
LEFT = const(4)
def __init__(self, i2c, interrupt_pin=None):
self._i2c = i2c
self._interrupt_pin = interrupt_pin
self.enable_color = False
self.enable_proximity = False
self.enable_gesture = True
## GESTURE DETECTION
@property
def enable_gesture(self):
return self._enable_gesture
@enable_gesture.setter
def enable_gesture(self, enable_flag):
self._enable_gesture = enable_flag
def gesture(self):
pass
## COLOR DETECTION
@property
def enable_color(self):
return self._enable_color
@enable_color.setter
def enable_color(self, enable_flag):
self._enable_color = enable_flag
@property
def color_data_ready(self):
return True
@property
def color_data(self):
return [None, None, None, None]
### PROXIMITY
@property
def enable_proximity(self):
return self._enable_proximity
@enable_proximity.setter
def enable_proximity(self, enable_flag):
self._enable_proximity = enable_flag
@property
def proximity_interrupt_threshold(self):
return self._proximity_interrupt_threshold
@proximity_interrupt_threshold.setter
def proximity_interrupt_threshold(self, setting_tuple):
self._proximity_interrupt_threshold = setting_tuple
@property
def enable_proximity_interrupt(self):
return _enable_proximity_interrupt
@enable_proximity_interrupt.setter
def enable_proximity_interrupt(self, enable_flag):
self._enable_proximity_interrupt = enable_flag
def proximity(self):
return None
def clear_interrupt(self):
pass

View file

@ -0,0 +1 @@
"""common include for APDS9960 driver """

View file

@ -0,0 +1,386 @@
# The MIT License (MIT)
#
# Copyright (c) 2017 Michael McWethy for Adafruit Inc
#
# 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_APDS9960`
====================================================
TODO(description)
* Author(s): Michael McWethy
"""
import time
import digitalio
from adafruit_register.i2c_bits import RWBits
from adafruit_register.i2c_bit import RWBit
from adafruit_bus_device.i2c_device import I2CDevice
from micropython import const
# ADDRESS_DEF = const(0x39)
# INTEGRATION_TIME_DEF = const(0x01)
# GAIN_DEF = const(0x01)
#pylint: disable-msg=bad-whitespace
#APDS9960_RAM = const(0x00)
APDS9960_ENABLE = const(0x80)
APDS9960_ATIME = const(0x81)
#APDS9960_WTIME = const(0x83)
#APDS9960_AILTIL = const(0x84)
# APDS9960_AILTH = const(0x85)
# APDS9960_AIHTL = const(0x86)
# APDS9960_AIHTH = const(0x87)
APDS9960_PILT = const(0x89)
APDS9960_PIHT = const(0x8B)
APDS9960_PERS = const(0x8C)
# APDS9960_CONFIG1 = const(0x8D)
# APDS9960_PPULSE = const(0x8E)
APDS9960_CONTROL = const(0x8F)
# APDS9960_CONFIG2 = const(0x90)
APDS9960_ID = const(0x92)
APDS9960_STATUS = const(0x93)
APDS9960_CDATAL = const(0x94)
# APDS9960_CDATAH = const(0x95)
# APDS9960_RDATAL = const(0x96)
# APDS9960_RDATAH = const(0x97)
# APDS9960_GDATAL = const(0x98)
# APDS9960_GDATAH = const(0x99)
# APDS9960_BDATAL = const(0x9A)
# APDS9960_BDATAH = const(0x9B)
APDS9960_PDATA = const(0x9C)
# APDS9960_POFFSET_UR = const(0x9D)
# APDS9960_POFFSET_DL = const(0x9E)
# APDS9960_CONFIG3 = const(0x9F)
APDS9960_GPENTH = const(0xA0)
# APDS9960_GEXTH = const(0xA1)
APDS9960_GCONF1 = const(0xA2)
APDS9960_GCONF2 = const(0xA3)
# APDS9960_GOFFSET_U = const(0xA4)
# APDS9960_GOFFSET_D = const(0xA5)
# APDS9960_GOFFSET_L = const(0xA7)
# APDS9960_GOFFSET_R = const(0xA9)
APDS9960_GPULSE = const(0xA6)
APDS9960_GCONF3 = const(0xAA)
APDS9960_GCONF4 = const(0xAB)
# APDS9960_GFLVL = const(0xAE)
APDS9960_GSTATUS = const(0xAF)
# APDS9960_IFORCE = const(0xE4)
# APDS9960_PICLEAR = const(0xE5)
# APDS9960_CICLEAR = const(0xE6)
APDS9960_AICLEAR = const(0xE7)
APDS9960_GFIFO_U = const(0xFC)
# APDS9960_GFIFO_D = const(0xFD)
# APDS9960_GFIFO_L = const(0xFE)
# APDS9960_GFIFO_R = const(0xFF)
#pylint: enable-msg=bad-whitespace
class APDS9960:
"""
APDS9900 provide basic driver services for the ASDS9960 breakout board
"""
_enable = RWBit(APDS9960_ENABLE, 0)
_color_enable = RWBit(APDS9960_ENABLE, 1)
_proximity_enable = RWBit(APDS9960_ENABLE, 2)
_gesture_enable = RWBit(APDS9960_ENABLE, 6)
_gesture_fifo_threshold = RWBits(2, APDS9960_GCONF1, 6)
_gesture_gain = RWBits(2, APDS9960_GCONF2, 5)
_color_gain = RWBits(2, APDS9960_CONTROL, 0)
_gesture_valid = RWBit(APDS9960_GSTATUS, 0)
_gesture_mode = RWBit(APDS9960_GCONF4, 0)
_proximity_persistance = RWBits(4, APDS9960_PERS, 4)
_proximity_enable_interrupt = RWBit(APDS9960_ENABLE, 5)
def __init__(self,
i2c, *,
interrupt_pin=None,
address=0x39,
integration_time=0x01,
gain=0x01):
self.i2c_device = I2CDevice(i2c, address)
self._interrupt_pin = interrupt_pin
if interrupt_pin:
self._interrupt_pin.switch_to_input(pull=digitalio.Pull.UP)
if self.read8(APDS9960_ID) != 0xAB:
raise RuntimeError()
self.enable_gesture = False
self.enable_proximity = False
self.enable_color = False
self._enable_proximity_interrupt = False
self.enable_color_interrupt = False
self.proximity_interrupt = False
self.clear_interrupt()
self.enable = False
time.sleep(0.010)
self.enable = True
time.sleep(0.010)
self._color_gain = gain
self.integration_time = integration_time
self.gesture_dimensions = 0x00 # all
self.gesture_fifo_threshold = 0x01 # fifo 4
self.gesture_gain = 0x02 # gain 4
self.gesture_proximity_threshold = 50
self.reset_counts()
# gesture pulse length=0x2 pulse count=0x3
self.write8(APDS9960_GPULSE, (0x2 << 6) | 0x3)
## BOARD
@property
def enable(self):
return self._enable
@enable.setter
def enable(self, enable_flag):
self._enable = enable_flag
def reset_counts(self):
self._up_count = 0
self._down_count = 0
self._right_count = 0
self._left_count = 0
## GESTURE DETECTION
@property
def enable_gesture(self):
return self._gesture_mode, self._gesture_enable
@enable_gesture.setter
def enable_gesture(self, enable_flag):
if not enable_flag:
self._gesture_mode = False
self._gesture_enable = enable_flag
def gesture(self):
"""Return a gesture code if detected. =0 if no gesture
=1 if an UP, =2 if a DOWN, =3 if an LEFT, =4 if a RIGHT
"""
buffer = bytearray(129)
buffer[0] = APDS9960_GFIFO_U
if not self._gesture_valid:
# print("no valid data")
return 0
time_mark = 0
gesture_received = 0
while True:
up_down_diff = 0
left_right_diff = 0
gesture_received = 0
time.sleep(0.030) # 30 ms
with self.i2c_device as i2c:
i2c.write(buffer, end=1, stop=False)
i2c.readinto(buffer, start=1)
upp, down, left, right = buffer[1:5]
# upp, down, left, right = self._gesture_fifo_read
# if upp or down or left or right:
# print(upp, down, left, right)
if abs(upp - down) > 13:
up_down_diff = upp - down
# print("up down diff {}".format(up_down_diff))
if abs(left - right) > 13:
left_right_diff = left - right
# print("left right diff {}".format(left_right_diff))
if up_down_diff != 0:
if up_down_diff < 0:
if self._down_count > 0:
gesture_received = 0x01
else:
self._up_count += 1
elif up_down_diff > 0:
if self._up_count > 0:
gesture_received = 0x02
else:
self._down_count += 1
if left_right_diff != 0:
if left_right_diff < 0:
if self._right_count > 0:
gesture_received = 0x03
else:
self._left_count += 1
elif left_right_diff > 0:
if self._left_count > 0:
gesture_received = 0x04
else:
self._right_count += 1
if up_down_diff != 0 or left_right_diff != 0:
time_mark = time.monotonic()
if gesture_received or time.monotonic() - time_mark > 0.300:
self.reset_counts()
break
return gesture_received
@property
def gesture_dimensions(self):
return self.read8(APDS9960_GCONF3)
@gesture_dimensions.setter
def gesture_dimensions(self, dims):
self.write8(APDS9960_GCONF3, dims & 0xff)
@property
def gesture_fifo_threshold(self):
return self._gesture_fifo_threshold
@gesture_fifo_threshold.setter
def gesture_fifo_threshold(self, thresh):
self._gesture_fifo_threshold = thresh & 0x3
@property
def gesture_gain(self):
return self._gesture_gain
@gesture_gain.setter
def gesture_gain(self, gain):
self._gesture_gain = gain
## COLOR DETECTION
@property
def enable_color(self):
"""returns True when color is enabled, else False"""
return self._color_enable
@enable_color.setter
def enable_color(self, enable_flag):
self._color_enable = enable_flag
@property
def color_data_ready(self):
return self.read8(APDS9960_STATUS) & 0x01
@property
def color_data(self):
"""Returns tuple containing r, g, b, c values"""
return self.read16(APDS9960_CDATAL + 2), \
self.read16(APDS9960_CDATAL + 4), \
self.read16(APDS9960_CDATAL + 6), \
self.read16(APDS9960_CDATAL)
### PROXIMITY
@property
def enable_proximity(self):
"""Returns or sets the enablement of proximity mode"""
return self._proximity_enable
@enable_proximity.setter
def enable_proximity(self, enable_flag):
self._proximity_enable = enable_flag
@property
def proximity_interrupt_threshold(self):
"""Returns a tuple containing low and high threshold
followed by the proximity interrupt persistance.
Set the proximity interrupt threshold values using a tuple of zero to
three values: low threshold, high threshold, persistance """
return self.read8(APDS9960_PILT), \
self.read8(APDS9960_PIHT), \
self._proximity_persistance
@proximity_interrupt_threshold.setter
def proximity_interrupt_threshold(self, setting_tuple):
if setting_tuple:
self.write8(APDS9960_PILT, setting_tuple[0])
if len(setting_tuple) > 1:
self.write8(APDS9960_PIHT, setting_tuple[1])
if len(setting_tuple) > 2:
self._proximity_persistance = setting_tuple[2]
@property
def enable_proximity_interrupt(self):
return self._proximity_enable_interrupt
@enable_proximity_interrupt.setter
def enable_proximity_interrupt(self, enable_flag):
self._proximity_enable_interrupt = enable_flag
@property
def gesture_proximity_threshold(self):
return self.read8(APDS9960_GPENTH)
@gesture_proximity_threshold.setter
def gesture_proximity_threshold(self, thresh):
self.write8(APDS9960_GPENTH, thresh & 0xff)
def proximity(self):
return self.read8(APDS9960_PDATA)
def clear_interrupt(self):
self.writecmdonly(APDS9960_AICLEAR)
@property
def integration_time(self):
return self.read8(APDS9960_ATIME)
@integration_time.setter
def integration_time(self, int_time):
self.write8(APDS9960_ATIME, int_time & 0xff)
# method for reading and writing to I2C
def write8(self, command, abyte):
buf = bytearray(2)
buf[0] = command
buf[1] = abyte
print(buf)
with self.i2c_device as i2c:
i2c.write(buf)
def writecmdonly(self, command):
buf = bytearray(1)
buf[0] = command
with self.i2c_device as i2c:
i2c.write(buf)
def read8(self, command):
buf = bytearray(1)
buf[0] = command
with self.i2c_device as i2c:
i2c.write(buf)
i2c.readinto(buf)
return buf[0]
def read16(self, command):
buf = bytearray(2)
buf[0] = command
with self.i2c_device as i2c:
i2c.write(buf, end=1, stop=False)
i2c.readinto(buf)
return buf[1] << 8 | buf[0]

View file

@ -0,0 +1,33 @@
"""Helper functions for color calculations"""
def calculate_color_temperature(r, g, b):
"""Converts the raw R/G/B values to color temperature in degrees Kelvin"""
# 1. Map RGB values to their XYZ counterparts.
# Based on 6500K fluorescent, 3000K fluorescent
# and 60W incandescent values for a wide range.
# Note: Y = Illuminance or lux
x = (-0.14282 * r) + (1.54924 * g) + (-0.95641 * b)
y = (-0.32466 * r) + (1.57837 * g) + (-0.73191 * b)
z = (-0.68202 * r) + (0.77073 * g) + (0.56332 * b)
# 2. Calculate the chromaticity co-ordinates
xchrome = x / (x + y + z)
ychrome = y / (x + y + z)
# 3. Use McCamy's formula to determine the CCT
n = (xchrome - 0.3320) / (0.1858 - ychrome)
# 4. Calculate the final CCT
cct = (449.0 * pow(n, 3)) + (3525.0 * pow(n, 2)) + (6823.3 * n) + 5520.33
# Return the results in degrees Kelvin
return cct
def calculate_lux(r, g, b):
"""Calculate ambient light values"""
# This only uses RGB ... how can we integrate clear or calculate lux
# based exclusively on clear since this might be more reliable?
illuminance = (-0.32466 * r) + (1.57837 * g) + (-0.73191 * b)
return illuminance

31
examples/color.py Normal file
View file

@ -0,0 +1,31 @@
import time
import board
import busio
import digitalio
from adafruit_apds9960.apds9960 import APDS9960
from adafruit_apds9960 import colorutility
i2c = busio.I2C(board.SCL, board.SDA)
int_pin = digitalio.DigitalInOut(board.A2)
apds = APDS9960(i2c)
apds.enable_color = True
while True:
#create some variables to store the color data in
#wait for color data to be ready
while not apds.color_data_ready:
time.sleep(0.005)
#get the data and print the different channels
r, g, b, c = apds.color_data
print("red: ", r)
print("green: ", g)
print("blue: ", b)
print("clear: ", c)
print("color temp {}".format(colorutility.calculate_color_temperature(r, b, g)))
print("light lux {}".format(colorutility.calculate_lux(r, b, g)))
time.sleep(0.5)

21
examples/gesture.py Normal file
View file

@ -0,0 +1,21 @@
import board
import busio
from adafruit_apds9960.apds9960 import APDS9960
i2c = busio.I2C(board.SCL, board.SDA)
apds = APDS9960(i2c)
apds.enable_proximity = True
apds.enable_gesture = True
while True:
gesture = apds.gesture()
if gesture == 0x01:
print("up")
elif gesture == 0x02:
print("down")
elif gesture == 0x03:
print("left")
elif gesture == 0x04:
print("right")

22
examples/proximity.py Normal file
View file

@ -0,0 +1,22 @@
import board
import busio
import digitalio
from adafruit_apds9960.apds9960 import APDS9960
i2c = busio.I2C(board.SCL, board.SDA)
int_pin = digitalio.DigitalInOut(board.A2)
apds = APDS9960(i2c, interrupt_pin=int_pin)
apds.enable_proximity = True
apds.proximity_interrupt_threshold = (10, 175)
apds.enable_proximity_interrupt = True
while True:
# print the proximity reading when the interrupt pin goes low
if not int_pin.value:
prox_value = apds.proximity()
if prox_value:
print(prox_value)
# clear the interrupt
apds.clear_interrupt()

View file

@ -1,14 +0,0 @@
import busio
import adafruit_apds9960 as apds9960
from board import SCL, SDA, A1
import digitalio
int_pin = digitalio.DigitalInOut(A1)
with busio.I2C(SCL, SDA) as i2c:
apds = apds9960.APDS9960(i2c, interrupt_pin=int_pin)
print(apds.UP)
print(apds.DOWN)
print(apds.RIGHT)
print(apds.LEFT)