├── .gitignore ├── .pylintrc ├── .readthedocs.yml ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.rst ├── bbq10keyboard.py ├── docs ├── _static │ └── favicon.ico ├── api.rst ├── conf.py ├── examples.rst └── index.rst ├── examples ├── bbq10keyboard_gpiotest.py └── bbq10keyboard_simpletest.py ├── requirements.txt └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.mpy 2 | .idea 3 | __pycache__ 4 | _build 5 | *.pyc 6 | .env 7 | build*/ 8 | bundles 9 | *.DS_Store 10 | .eggs 11 | dist 12 | **/*.egg-info 13 | .vscode 14 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | 3 | # A comma-separated list of package or module names from where C extensions may 4 | # be loaded. Extensions are loading into the active Python interpreter and may 5 | # run arbitrary code 6 | extension-pkg-whitelist= 7 | 8 | # Add files or directories to the blacklist. They should be base names, not 9 | # paths. 10 | ignore=CVS 11 | 12 | # Add files or directories matching the regex patterns to the blacklist. The 13 | # regex matches against base names, not paths. 14 | ignore-patterns= 15 | 16 | # Python code to execute, usually for sys.path manipulation such as 17 | # pygtk.require(). 18 | #init-hook= 19 | 20 | # Use multiple processes to speed up Pylint. 21 | # jobs=1 22 | jobs=2 23 | 24 | # List of plugins (as comma separated values of python modules names) to load, 25 | # usually to register additional checkers. 26 | load-plugins= 27 | 28 | # Pickle collected data for later comparisons. 29 | persistent=yes 30 | 31 | # Specify a configuration file. 32 | #rcfile= 33 | 34 | # Allow loading of arbitrary C extensions. Extensions are imported into the 35 | # active Python interpreter and may run arbitrary code. 36 | unsafe-load-any-extension=no 37 | 38 | 39 | [MESSAGES CONTROL] 40 | 41 | # Only show warnings with the listed confidence levels. Leave empty to show 42 | # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED 43 | confidence= 44 | 45 | # Disable the message, report, category or checker with the given id(s). You 46 | # can either give multiple identifiers separated by comma (,) or put this 47 | # option multiple times (only on the command line, not in the configuration 48 | # file where it should appear only once).You can also use "--disable=all" to 49 | # disable everything first and then reenable specific checks. For example, if 50 | # you want to run only the similarities checker, you can use "--disable=all 51 | # --enable=similarities". If you want to run only the classes checker, but have 52 | # no Warning level messages displayed, use"--disable=all --enable=classes 53 | # --disable=W" 54 | # 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 55 | 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 56 | 57 | # Enable the message, report, category or checker with the given id(s). You can 58 | # either give multiple identifier separated by comma (,) or put this option 59 | # multiple time (only on the command line, not in the configuration file where 60 | # it should appear only once). See also the "--disable" option for examples. 61 | enable= 62 | 63 | 64 | [REPORTS] 65 | 66 | # Python expression which should return a note less than 10 (10 is the highest 67 | # note). You have access to the variables errors warning, statement which 68 | # respectively contain the number of errors / warnings messages and the total 69 | # number of statements analyzed. This is used by the global evaluation report 70 | # (RP0004). 71 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) 72 | 73 | # Template used to display messages. This is a python new-style format string 74 | # used to format the message information. See doc for all details 75 | #msg-template= 76 | 77 | # Set the output format. Available formats are text, parseable, colorized, json 78 | # and msvs (visual studio).You can also give a reporter class, eg 79 | # mypackage.mymodule.MyReporterClass. 80 | output-format=text 81 | 82 | # Tells whether to display a full report or only the messages 83 | reports=no 84 | 85 | # Activate the evaluation score. 86 | score=yes 87 | 88 | 89 | [REFACTORING] 90 | 91 | # Maximum number of nested blocks for function / method body 92 | max-nested-blocks=5 93 | 94 | 95 | [LOGGING] 96 | 97 | # Logging modules to check that the string format arguments are in logging 98 | # function parameter format 99 | logging-modules=logging 100 | 101 | 102 | [SPELLING] 103 | 104 | # Spelling dictionary name. Available dictionaries: none. To make it working 105 | # install python-enchant package. 106 | spelling-dict= 107 | 108 | # List of comma separated words that should not be checked. 109 | spelling-ignore-words= 110 | 111 | # A path to a file that contains private dictionary; one word per line. 112 | spelling-private-dict-file= 113 | 114 | # Tells whether to store unknown words to indicated private dictionary in 115 | # --spelling-private-dict-file option instead of raising a message. 116 | spelling-store-unknown-words=no 117 | 118 | 119 | [MISCELLANEOUS] 120 | 121 | # List of note tags to take in consideration, separated by a comma. 122 | # notes=FIXME,XXX,TODO 123 | notes=FIXME,XXX 124 | 125 | 126 | [TYPECHECK] 127 | 128 | # List of decorators that produce context managers, such as 129 | # contextlib.contextmanager. Add to this list to register other decorators that 130 | # produce valid context managers. 131 | contextmanager-decorators=contextlib.contextmanager 132 | 133 | # List of members which are set dynamically and missed by pylint inference 134 | # system, and so shouldn't trigger E1101 when accessed. Python regular 135 | # expressions are accepted. 136 | generated-members= 137 | 138 | # Tells whether missing members accessed in mixin class should be ignored. A 139 | # mixin class is detected if its name ends with "mixin" (case insensitive). 140 | ignore-mixin-members=yes 141 | 142 | # This flag controls whether pylint should warn about no-member and similar 143 | # checks whenever an opaque object is returned when inferring. The inference 144 | # can return multiple potential results while evaluating a Python object, but 145 | # some branches might not be evaluated, which results in partial inference. In 146 | # that case, it might be useful to still emit no-member and other checks for 147 | # the rest of the inferred objects. 148 | ignore-on-opaque-inference=yes 149 | 150 | # List of class names for which member attributes should not be checked (useful 151 | # for classes with dynamically set attributes). This supports the use of 152 | # qualified names. 153 | ignored-classes=optparse.Values,thread._local,_thread._local 154 | 155 | # List of module names for which member attributes should not be checked 156 | # (useful for modules/projects where namespaces are manipulated during runtime 157 | # and thus existing member attributes cannot be deduced by static analysis. It 158 | # supports qualified module names, as well as Unix pattern matching. 159 | ignored-modules=board 160 | 161 | # Show a hint with possible names when a member name was not found. The aspect 162 | # of finding the hint is based on edit distance. 163 | missing-member-hint=yes 164 | 165 | # The minimum edit distance a name should have in order to be considered a 166 | # similar match for a missing member name. 167 | missing-member-hint-distance=1 168 | 169 | # The total number of similar names that should be taken in consideration when 170 | # showing a hint for a missing member. 171 | missing-member-max-choices=1 172 | 173 | 174 | [VARIABLES] 175 | 176 | # List of additional names supposed to be defined in builtins. Remember that 177 | # you should avoid to define new builtins when possible. 178 | additional-builtins= 179 | 180 | # Tells whether unused global variables should be treated as a violation. 181 | allow-global-unused-variables=yes 182 | 183 | # List of strings which can identify a callback function by name. A callback 184 | # name must start or end with one of those strings. 185 | callbacks=cb_,_cb 186 | 187 | # A regular expression matching the name of dummy variables (i.e. expectedly 188 | # not used). 189 | dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ 190 | 191 | # Argument names that match this expression will be ignored. Default to name 192 | # with leading underscore 193 | ignored-argument-names=_.*|^ignored_|^unused_ 194 | 195 | # Tells whether we should check for unused import in __init__ files. 196 | init-import=no 197 | 198 | # List of qualified module names which can have objects that can redefine 199 | # builtins. 200 | redefining-builtins-modules=six.moves,future.builtins 201 | 202 | 203 | [FORMAT] 204 | 205 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. 206 | # expected-line-ending-format= 207 | expected-line-ending-format=LF 208 | 209 | # Regexp for a line that is allowed to be longer than the limit. 210 | ignore-long-lines=^\s*(# )??$ 211 | 212 | # Number of spaces of indent required inside a hanging or continued line. 213 | indent-after-paren=4 214 | 215 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 216 | # tab). 217 | indent-string=' ' 218 | 219 | # Maximum number of characters on a single line. 220 | max-line-length=100 221 | 222 | # Maximum number of lines in a module 223 | max-module-lines=1000 224 | 225 | # List of optional constructs for which whitespace checking is disabled. `dict- 226 | # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. 227 | # `trailing-comma` allows a space between comma and closing bracket: (a, ). 228 | # `empty-line` allows space-only lines. 229 | no-space-check=trailing-comma,dict-separator 230 | 231 | # Allow the body of a class to be on the same line as the declaration if body 232 | # contains single statement. 233 | single-line-class-stmt=no 234 | 235 | # Allow the body of an if to be on the same line as the test if there is no 236 | # else. 237 | single-line-if-stmt=no 238 | 239 | 240 | [SIMILARITIES] 241 | 242 | # Ignore comments when computing similarities. 243 | ignore-comments=yes 244 | 245 | # Ignore docstrings when computing similarities. 246 | ignore-docstrings=yes 247 | 248 | # Ignore imports when computing similarities. 249 | ignore-imports=no 250 | 251 | # Minimum lines number of a similarity. 252 | min-similarity-lines=4 253 | 254 | 255 | [BASIC] 256 | 257 | # Naming hint for argument names 258 | argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ 259 | 260 | # Regular expression matching correct argument names 261 | argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ 262 | 263 | # Naming hint for attribute names 264 | attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ 265 | 266 | # Regular expression matching correct attribute names 267 | attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ 268 | 269 | # Bad variable names which should always be refused, separated by a comma 270 | bad-names=foo,bar,baz,toto,tutu,tata 271 | 272 | # Naming hint for class attribute names 273 | class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ 274 | 275 | # Regular expression matching correct class attribute names 276 | class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ 277 | 278 | # Naming hint for class names 279 | # class-name-hint=[A-Z_][a-zA-Z0-9]+$ 280 | class-name-hint=[A-Z_][a-zA-Z0-9_]+$ 281 | 282 | # Regular expression matching correct class names 283 | # class-rgx=[A-Z_][a-zA-Z0-9]+$ 284 | class-rgx=[A-Z_][a-zA-Z0-9_]+$ 285 | 286 | # Naming hint for constant names 287 | const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ 288 | 289 | # Regular expression matching correct constant names 290 | const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ 291 | 292 | # Minimum line length for functions/classes that require docstrings, shorter 293 | # ones are exempt. 294 | docstring-min-length=-1 295 | 296 | # Naming hint for function names 297 | function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ 298 | 299 | # Regular expression matching correct function names 300 | function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ 301 | 302 | # Good variable names which should always be accepted, separated by a comma 303 | # good-names=i,j,k,ex,Run,_ 304 | good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_ 305 | 306 | # Include a hint for the correct naming format with invalid-name 307 | include-naming-hint=no 308 | 309 | # Naming hint for inline iteration names 310 | inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ 311 | 312 | # Regular expression matching correct inline iteration names 313 | inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ 314 | 315 | # Naming hint for method names 316 | method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ 317 | 318 | # Regular expression matching correct method names 319 | method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ 320 | 321 | # Naming hint for module names 322 | module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ 323 | 324 | # Regular expression matching correct module names 325 | module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ 326 | 327 | # Colon-delimited sets of names that determine each other's naming style when 328 | # the name regexes allow several styles. 329 | name-group= 330 | 331 | # Regular expression which should only match function or class names that do 332 | # not require a docstring. 333 | no-docstring-rgx=^_ 334 | 335 | # List of decorators that produce properties, such as abc.abstractproperty. Add 336 | # to this list to register other decorators that produce valid properties. 337 | property-classes=abc.abstractproperty 338 | 339 | # Naming hint for variable names 340 | variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ 341 | 342 | # Regular expression matching correct variable names 343 | variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ 344 | 345 | 346 | [IMPORTS] 347 | 348 | # Allow wildcard imports from modules that define __all__. 349 | allow-wildcard-with-all=no 350 | 351 | # Analyse import fallback blocks. This can be used to support both Python 2 and 352 | # 3 compatible code, which means that the block might have code that exists 353 | # only in one or another interpreter, leading to false positives when analysed. 354 | analyse-fallback-blocks=no 355 | 356 | # Deprecated modules which should not be used, separated by a comma 357 | deprecated-modules=optparse,tkinter.tix 358 | 359 | # Create a graph of external dependencies in the given file (report RP0402 must 360 | # not be disabled) 361 | ext-import-graph= 362 | 363 | # Create a graph of every (i.e. internal and external) dependencies in the 364 | # given file (report RP0402 must not be disabled) 365 | import-graph= 366 | 367 | # Create a graph of internal dependencies in the given file (report RP0402 must 368 | # not be disabled) 369 | int-import-graph= 370 | 371 | # Force import order to recognize a module as part of the standard 372 | # compatibility libraries. 373 | known-standard-library= 374 | 375 | # Force import order to recognize a module as part of a third party library. 376 | known-third-party=enchant 377 | 378 | 379 | [CLASSES] 380 | 381 | # List of method names used to declare (i.e. assign) instance attributes. 382 | defining-attr-methods=__init__,__new__,setUp 383 | 384 | # List of member names, which should be excluded from the protected access 385 | # warning. 386 | exclude-protected=_asdict,_fields,_replace,_source,_make 387 | 388 | # List of valid names for the first argument in a class method. 389 | valid-classmethod-first-arg=cls 390 | 391 | # List of valid names for the first argument in a metaclass class method. 392 | valid-metaclass-classmethod-first-arg=mcs 393 | 394 | 395 | [DESIGN] 396 | 397 | # Maximum number of arguments for function / method 398 | max-args=5 399 | 400 | # Maximum number of attributes for a class (see R0902). 401 | # max-attributes=7 402 | max-attributes=11 403 | 404 | # Maximum number of boolean expressions in a if statement 405 | max-bool-expr=5 406 | 407 | # Maximum number of branch for function / method body 408 | max-branches=12 409 | 410 | # Maximum number of locals for function / method body 411 | max-locals=15 412 | 413 | # Maximum number of parents for a class (see R0901). 414 | max-parents=7 415 | 416 | # Maximum number of public methods for a class (see R0904). 417 | max-public-methods=20 418 | 419 | # Maximum number of return / yield for function / method body 420 | max-returns=6 421 | 422 | # Maximum number of statements in function / method body 423 | max-statements=50 424 | 425 | # Minimum number of public methods for a class (see R0903). 426 | min-public-methods=1 427 | 428 | 429 | [EXCEPTIONS] 430 | 431 | # Exceptions that will emit a warning when being caught. Defaults to 432 | # "Exception" 433 | overgeneral-exceptions=Exception 434 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | python: 2 | version: 3 3 | requirements_file: requirements.txt 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Adafruit Community Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and leaders pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level or type of 9 | experience, education, socio-economic status, nationality, personal appearance, 10 | race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | We are committed to providing a friendly, safe and welcoming environment for 15 | all. 16 | 17 | Examples of behavior that contributes to creating a positive environment 18 | include: 19 | 20 | * Be kind and courteous to others 21 | * Using welcoming and inclusive language 22 | * Being respectful of differing viewpoints and experiences 23 | * Collaborating with other community members 24 | * Gracefully accepting constructive criticism 25 | * Focusing on what is best for the community 26 | * Showing empathy towards other community members 27 | 28 | Examples of unacceptable behavior by participants include: 29 | 30 | * The use of sexualized language or imagery and sexual attention or advances 31 | * The use of inappropriate images, including in a community member's avatar 32 | * The use of inappropriate language, including in a community member's nickname 33 | * Any spamming, flaming, baiting or other attention-stealing behavior 34 | * Excessive or unwelcome helping; answering outside the scope of the question 35 | asked 36 | * Trolling, insulting/derogatory comments, and personal or political attacks 37 | * Public or private harassment 38 | * Publishing others' private information, such as a physical or electronic 39 | address, without explicit permission 40 | * Other conduct which could reasonably be considered inappropriate 41 | 42 | The goal of the standards and moderation guidelines outlined here is to build 43 | and maintain a respectful community. We ask that you don’t just aim to be 44 | "technically unimpeachable", but rather try to be your best self. 45 | 46 | We value many things beyond technical expertise, including collaboration and 47 | supporting others within our community. Providing a positive experience for 48 | other community members can have a much more significant impact than simply 49 | providing the correct answer. 50 | 51 | ## Our Responsibilities 52 | 53 | Project leaders are responsible for clarifying the standards of acceptable 54 | behavior and are expected to take appropriate and fair corrective action in 55 | response to any instances of unacceptable behavior. 56 | 57 | Project leaders have the right and responsibility to remove, edit, or 58 | reject messages, comments, commits, code, issues, and other contributions 59 | that are not aligned to this Code of Conduct, or to ban temporarily or 60 | permanently any community member for other behaviors that they deem 61 | inappropriate, threatening, offensive, or harmful. 62 | 63 | ## Moderation 64 | 65 | Instances of behaviors that violate the Adafruit Community Code of Conduct 66 | may be reported by any member of the community. Community members are 67 | encouraged to report these situations, including situations they witness 68 | involving other community members. 69 | 70 | You may report in the following ways: 71 | 72 | In any situation, you may send an email to . 73 | 74 | On the Adafruit Discord, you may send an open message from any channel 75 | to all Community Helpers by tagging @community moderators. You may also send an 76 | open message from any channel, or a direct message to @kattni#1507, 77 | @tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or 78 | @Andon#8175. 79 | 80 | Email and direct message reports will be kept confidential. 81 | 82 | In situations on Discord where the issue is particularly egregious, possibly 83 | illegal, requires immediate action, or violates the Discord terms of service, 84 | you should also report the message directly to Discord. 85 | 86 | These are the steps for upholding our community’s standards of conduct. 87 | 88 | 1. Any member of the community may report any situation that violates the 89 | Adafruit Community Code of Conduct. All reports will be reviewed and 90 | investigated. 91 | 2. If the behavior is an egregious violation, the community member who 92 | committed the violation may be banned immediately, without warning. 93 | 3. Otherwise, moderators will first respond to such behavior with a warning. 94 | 4. Moderators follow a soft "three strikes" policy - the community member may 95 | be given another chance, if they are receptive to the warning and change their 96 | behavior. 97 | 5. If the community member is unreceptive or unreasonable when warned by a 98 | moderator, or the warning goes unheeded, they may be banned for a first or 99 | second offense. Repeated offenses will result in the community member being 100 | banned. 101 | 102 | ## Scope 103 | 104 | This Code of Conduct and the enforcement policies listed above apply to all 105 | Adafruit Community venues. This includes but is not limited to any community 106 | spaces (both public and private), the entire Adafruit Discord server, and 107 | Adafruit GitHub repositories. Examples of Adafruit Community spaces include 108 | but are not limited to meet-ups, audio chats on the Adafruit Discord, or 109 | interaction at a conference. 110 | 111 | This Code of Conduct applies both within project spaces and in public spaces 112 | when an individual is representing the project or its community. As a community 113 | member, you are representing our community, and are expected to behave 114 | accordingly. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 1.4, available at 120 | , 121 | and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html). 122 | 123 | For other projects adopting the Adafruit Community Code of 124 | Conduct, please contact the maintainers of those projects for enforcement. 125 | If you wish to use this code of conduct for your own project, consider 126 | explicitly mentioning your moderation policy or making a copy with your 127 | own moderation policy so as to avoid confusion. 128 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 arturo182 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | CircuitPython library for interfacing the BB Q10 and BB Q20 Keyboards over I2C. 5 | 6 | The firmwares that this library should be used with can be found here: 7 | 8 | * BB Q10: https://github.com/solderparty/bbq10kbd_i2c_sw 9 | * BB Q20: https://github.com/solderparty/i2c_puppet 10 | 11 | Dependencies 12 | ============= 13 | This driver depends on: 14 | 15 | * `Adafruit CircuitPython `_ 16 | * `Bus Device `_ 17 | 18 | Please ensure all dependencies are available on the CircuitPython filesystem. 19 | This is easily achieved by downloading 20 | `the Adafruit library and driver bundle `_. 21 | 22 | Usage Example 23 | ============= 24 | 25 | See examples/ for a quick examples on how to use the library. 26 | -------------------------------------------------------------------------------- /bbq10keyboard.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2021 arturo182 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | """ 23 | `bbq10keyboard` 24 | ================================================================================ 25 | 26 | CircuitPython library for interfacing the BB Q10 Keyboard over I2C. 27 | 28 | * Author(s): arturo182 29 | 30 | Implementation Notes 31 | -------------------- 32 | 33 | **Hardware:** 34 | 35 | * `BBQ10 Keyboard PMOD `_ 36 | * `Keyboard FeatherWing `_ 37 | 38 | **Software and Dependencies:** 39 | 40 | * Adafruit CircuitPython firmware for the supported boards: 41 | https://github.com/adafruit/circuitpython/releases 42 | 43 | * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice 44 | """ 45 | 46 | from micropython import const 47 | from adafruit_bus_device.i2c_device import I2CDevice 48 | import digitalio 49 | import time 50 | 51 | __version__ = "0.2.0-auto.0" 52 | __repo__ = "https://github.com/solderparty/arturo182_CircuitPython_bbq10keyboard.git" 53 | 54 | 55 | _ADDRESS_KBD = const(0x1F) 56 | 57 | _REG_VER = const(0x01) # fw version 58 | _REG_CFG = const(0x02) # config 59 | _REG_INT = const(0x03) # interrupt status 60 | _REG_KEY = const(0x04) # key status 61 | _REG_BKL = const(0x05) # backlight 62 | _REG_DEB = const(0x06) # debounce cfg 63 | _REG_FRQ = const(0x07) # poll freq cfg 64 | _REG_RST = const(0x08) # reset 65 | _REG_FIF = const(0x09) # fifo 66 | _REG_BK2 = const(0x0A) # backlight 2 67 | _REG_DIR = const(0x0B) # gpio direction 68 | _REG_PUE = const(0x0C) # gpio input pull enable 69 | _REG_PUD = const(0x0D) # gpio input pull direction 70 | _REG_GIO = const(0x0E) # gpio value 71 | _REG_GIC = const(0x0F) # gpio interrupt config 72 | _REG_GIN = const(0x10) # gpio interrupt status 73 | 74 | _WRITE_MASK = const(1 << 7) 75 | 76 | CFG_OVERFLOW_ON = const(1 << 0) 77 | CFG_OVERFLOW_INT = const(1 << 1) 78 | CFG_CAPSLOCK_INT = const(1 << 2) 79 | CFG_NUMLOCK_INT = const(1 << 3) 80 | CFG_KEY_INT = const(1 << 4) 81 | CFG_PANIC_INT = const(1 << 5) 82 | CFG_REPORT_MODS = const(1 << 6) 83 | CFG_USE_MODS = const(1 << 7) 84 | 85 | INT_OVERFLOW = const(1 << 0) 86 | INT_CAPSLOCK = const(1 << 1) 87 | INT_NUMLOCK = const(1 << 2) 88 | INT_KEY = const(1 << 3) 89 | INT_PANIC = const(1 << 4) 90 | INT_GPIO = const(1 << 5) # since FW 0.4 91 | 92 | KEY_CAPSLOCK = const(1 << 5) 93 | KEY_NUMLOCK = const(1 << 6) 94 | KEY_COUNT_MASK = const(0x1F) 95 | 96 | DIR_OUTPUT = const(0) 97 | DIR_INPUT = const(1) 98 | 99 | PUD_DOWN = const(0) 100 | PUD_UP = const(1) 101 | 102 | STATE_IDLE = const(0) 103 | STATE_PRESS = const(1) 104 | STATE_LONG_PRESS = const(2) 105 | STATE_RELEASE = const(3) 106 | 107 | 108 | class DigitalInOut: 109 | def __init__(self, pin, kbd): 110 | if pin < 0 or pin > 7: 111 | raise ValueError('Only pins 0-7 supported right now') 112 | 113 | self._pin = pin 114 | self._kbd = kbd 115 | 116 | def switch_to_output(self, value=False): 117 | self.direction = digitalio.Direction.OUTPUT 118 | self.value = value 119 | 120 | def switch_to_input(self, pull=None): 121 | self.direction = digitalio.Direction.INPUT 122 | self.pull = pull 123 | 124 | @property 125 | def value(self): 126 | return self._kbd._get_register_bit(_REG_GIO, self._pin) 127 | 128 | @value.setter 129 | def value(self, value): 130 | self._kbd._update_register_bit(_REG_GIO, self._pin, value) 131 | 132 | @property 133 | def direction(self): 134 | if self._kbd._get_register_bit(_REG_DIR, self._pin) == DIR_INPUT: 135 | return digitalio.Direction.INPUT 136 | 137 | return digitalio.Direction.OUTPUT 138 | 139 | @direction.setter 140 | def direction(self, value): 141 | self._kbd._update_register_bit(_REG_DIR, self._pin, value == digitalio.Direction.INPUT) 142 | 143 | @property 144 | def pull(self): 145 | if self.direction == digitalio.Direction.OUTPUT: 146 | raise AttributeError('Pull not used when direction is output') 147 | 148 | if self._kbd._get_register_bit(_REG_PUE, self._pin): 149 | if self._kbd._get_register_bit(_REG_PUD, self._pin) == PUD_UP: 150 | return digitalio.Pull.UP 151 | 152 | return digitalio.Pull.DOWN 153 | 154 | return None 155 | 156 | @pull.setter 157 | def pull(self, value): 158 | if self.direction == digitalio.Direction.OUTPUT: 159 | raise AttributeError('Pull not used when direction is output') 160 | 161 | if value is None: 162 | self._kbd._update_register_bit(_REG_PUE, self._pin, False) 163 | else: 164 | self._kbd._update_register_bit(_REG_PUD, self._pin, value == digitalio.Pull.UP) 165 | self._kbd._update_register_bit(_REG_PUE, self._pin, True) 166 | 167 | 168 | class BBQ10Keyboard: 169 | def __init__(self, i2c): 170 | self._i2c = I2CDevice(i2c, _ADDRESS_KBD) 171 | self._buffer = bytearray(2) 172 | 173 | self.reset() 174 | 175 | def reset(self): 176 | with self._i2c as i2c: 177 | self._buffer[0] = _REG_RST 178 | i2c.write(self._buffer, end=1) 179 | 180 | # need to wait! 181 | time.sleep(0.05) 182 | 183 | @property 184 | def version(self): 185 | ver = self._read_register(_REG_VER) 186 | return (ver >> 4, ver & 0x0F) 187 | 188 | @property 189 | def status(self): 190 | return self._read_register(_REG_KEY) 191 | 192 | @property 193 | def key_count(self): 194 | return self.status & KEY_COUNT_MASK 195 | 196 | @property 197 | def key(self): 198 | if self.key_count == 0: 199 | return None 200 | 201 | with self._i2c as i2c: 202 | self._buffer[0] = _REG_FIF 203 | i2c.write(self._buffer, end=1) 204 | i2c.readinto(self._buffer, end=2) 205 | 206 | return (int(self._buffer[0]), chr(self._buffer[1])) 207 | 208 | @property 209 | def keys(self): 210 | keys = [] 211 | 212 | for _ in range(self.key_count): 213 | keys.append(self.key) 214 | 215 | return keys 216 | 217 | @property 218 | def backlight(self): 219 | return self._read_register(_REG_BKL) / 255 220 | 221 | @backlight.setter 222 | def backlight(self, value): 223 | self._write_register(_REG_BKL, int(255 * value)) 224 | 225 | @property 226 | def backlight2(self): 227 | if self.version < (0, 4): 228 | raise NotImplementedError('This function requires FW version 0.4 or newer') 229 | 230 | return self._read_register(_REG_BK2) / 255 231 | 232 | @backlight.setter 233 | def backlight2(self, value): 234 | if self.version < (0, 4): 235 | raise NotImplementedError('This function requires FW version 0.4 or newer') 236 | 237 | self._write_register(_REG_BK2, int(255 * value)) 238 | 239 | @property 240 | def gpio(self): 241 | return self._read_register(_REG_GIO) 242 | 243 | @gpio.setter 244 | def gpio(self, value): 245 | self._write_register(_REG_GIO, value) 246 | 247 | def get_pin(self, pin): 248 | if pin < 0 or pin > 7: 249 | raise ValueError('Only pins 0-7 supported right now') 250 | 251 | return DigitalInOut(pin, self) 252 | 253 | def _read_register(self, reg): 254 | with self._i2c as i2c: 255 | self._buffer[0] = reg 256 | i2c.write(self._buffer, end=1) 257 | i2c.readinto(self._buffer, end=1) 258 | 259 | return self._buffer[0] 260 | 261 | def _write_register(self, reg, value): 262 | with self._i2c as i2c: 263 | self._buffer[0] = reg | _WRITE_MASK 264 | self._buffer[1] = value 265 | i2c.write(self._buffer, end=2) 266 | 267 | def _update_register_bit(self, reg, bit, value): 268 | reg_val = self._read_register(reg) 269 | old_val = reg_val 270 | 271 | if value: 272 | reg_val |= (1 << bit) 273 | else: 274 | reg_val &= ~(1 << bit) 275 | 276 | if reg_val != old_val: 277 | self._write_register(reg, reg_val) 278 | 279 | def _get_register_bit(self, reg, bit): 280 | return self._read_register(reg) & (1 << bit) != 0 281 | 282 | keyboard_backlight = backlight 283 | display_backlight = backlight2 284 | 285 | -------------------------------------------------------------------------------- /docs/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solderparty/arturo182_CircuitPython_BBQ10Keyboard/c61cd5649bc3ad33b17e4f07cfe101135e301e85/docs/_static/favicon.ico -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | 2 | .. If you created a package, create one automodule per module in the package. 3 | 4 | .. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py) 5 | .. use this format as the module name: "adafruit_foo.foo" 6 | 7 | .. automodule:: bbq10keyboard 8 | :members: 9 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | import sys 5 | sys.path.insert(0, os.path.abspath('..')) 6 | 7 | # -- General configuration ------------------------------------------------ 8 | 9 | # Add any Sphinx extension module names here, as strings. They can be 10 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 11 | # ones. 12 | extensions = [ 13 | 'sphinx.ext.autodoc', 14 | 'sphinx.ext.intersphinx', 15 | 'sphinx.ext.napoleon', 16 | 'sphinx.ext.todo', 17 | ] 18 | 19 | # TODO: Please Read! 20 | # Uncomment the below if you use native CircuitPython modules such as 21 | # digitalio, micropython and busio. List the modules you use. Without it, the 22 | # autodoc module docs will fail to generate with a warning. 23 | # autodoc_mock_imports = ["digitalio", "busio"] 24 | 25 | 26 | intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'BusDevice': ('https://circuitpython.readthedocs.io/projects/busdevice/en/latest/', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)} 27 | 28 | # Add any paths that contain templates here, relative to this directory. 29 | templates_path = ['_templates'] 30 | 31 | source_suffix = '.rst' 32 | 33 | # The master toctree document. 34 | master_doc = 'index' 35 | 36 | # General information about the project. 37 | project = u'bbq10keyboard Library' 38 | copyright = u'2020 arturo182' 39 | author = u'arturo182' 40 | 41 | # The version info for the project you're documenting, acts as replacement for 42 | # |version| and |release|, also used in various other places throughout the 43 | # built documents. 44 | # 45 | # The short X.Y version. 46 | version = u'1.0' 47 | # The full version, including alpha/beta/rc tags. 48 | release = u'1.0' 49 | 50 | # The language for content autogenerated by Sphinx. Refer to documentation 51 | # for a list of supported languages. 52 | # 53 | # This is also used if you do content translation via gettext catalogs. 54 | # Usually you set "language" from the command line for these cases. 55 | language = None 56 | 57 | # List of patterns, relative to source directory, that match files and 58 | # directories to ignore when looking for source files. 59 | # This patterns also effect to html_static_path and html_extra_path 60 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.env', 'CODE_OF_CONDUCT.md'] 61 | 62 | # The reST default role (used for this markup: `text`) to use for all 63 | # documents. 64 | # 65 | default_role = "any" 66 | 67 | # If true, '()' will be appended to :func: etc. cross-reference text. 68 | # 69 | add_function_parentheses = True 70 | 71 | # The name of the Pygments (syntax highlighting) style to use. 72 | pygments_style = 'sphinx' 73 | 74 | # If true, `todo` and `todoList` produce output, else they produce nothing. 75 | todo_include_todos = False 76 | 77 | # If this is True, todo emits a warning for each TODO entries. The default is False. 78 | todo_emit_warnings = True 79 | 80 | napoleon_numpy_docstring = False 81 | 82 | # -- Options for HTML output ---------------------------------------------- 83 | 84 | # The theme to use for HTML and HTML Help pages. See the documentation for 85 | # a list of builtin themes. 86 | # 87 | on_rtd = os.environ.get('READTHEDOCS', None) == 'True' 88 | 89 | if not on_rtd: # only import and set the theme if we're building docs locally 90 | try: 91 | import sphinx_rtd_theme 92 | html_theme = 'sphinx_rtd_theme' 93 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), '.'] 94 | except: 95 | html_theme = 'default' 96 | html_theme_path = ['.'] 97 | else: 98 | html_theme_path = ['.'] 99 | 100 | # Add any paths that contain custom static files (such as style sheets) here, 101 | # relative to this directory. They are copied after the builtin static files, 102 | # so a file named "default.css" will overwrite the builtin "default.css". 103 | html_static_path = ['_static'] 104 | 105 | # The name of an image file (relative to this directory) to use as a favicon of 106 | # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 107 | # pixels large. 108 | # 109 | html_favicon = '_static/favicon.ico' 110 | 111 | # Output file base name for HTML help builder. 112 | htmlhelp_basename = 'Bbq10keyboardLibrarydoc' 113 | 114 | # -- Options for LaTeX output --------------------------------------------- 115 | 116 | latex_elements = { 117 | # The paper size ('letterpaper' or 'a4paper'). 118 | # 119 | # 'papersize': 'letterpaper', 120 | 121 | # The font size ('10pt', '11pt' or '12pt'). 122 | # 123 | # 'pointsize': '10pt', 124 | 125 | # Additional stuff for the LaTeX preamble. 126 | # 127 | # 'preamble': '', 128 | 129 | # Latex figure (float) alignment 130 | # 131 | # 'figure_align': 'htbp', 132 | } 133 | 134 | # Grouping the document tree into LaTeX files. List of tuples 135 | # (source start file, target name, title, 136 | # author, documentclass [howto, manual, or own class]). 137 | latex_documents = [ 138 | (master_doc, 'bbq10keyboardLibrary.tex', u'bbq10keyboard Library Documentation', 139 | author, 'manual'), 140 | ] 141 | 142 | # -- Options for manual page output --------------------------------------- 143 | 144 | # One entry per manual page. List of tuples 145 | # (source start file, name, description, authors, manual section). 146 | man_pages = [ 147 | (master_doc, 'bbq10keyboardlibrary', u'bbq10keyboard Library Documentation', 148 | [author], 1) 149 | ] 150 | 151 | # -- Options for Texinfo output ------------------------------------------- 152 | 153 | # Grouping the document tree into Texinfo files. List of tuples 154 | # (source start file, target name, title, author, 155 | # dir menu entry, description, category) 156 | texinfo_documents = [ 157 | (master_doc, 'bbq10keyboardLibrary', u' bbq10keyboard Library Documentation', 158 | author, 'bbq10keyboardLibrary', 'One line description of project.', 159 | 'Miscellaneous'), 160 | ] 161 | -------------------------------------------------------------------------------- /docs/examples.rst: -------------------------------------------------------------------------------- 1 | Simple test 2 | ------------ 3 | 4 | Ensure your device works with this simple test. 5 | 6 | .. literalinclude:: ../examples/bbq10keyboard_simpletest.py 7 | :caption: examples/bbq10keyboard_simpletest.py 8 | :linenos: 9 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | 3 | Table of Contents 4 | ================= 5 | 6 | .. toctree:: 7 | :maxdepth: 4 8 | :hidden: 9 | 10 | self 11 | 12 | .. toctree:: 13 | :caption: Examples 14 | 15 | examples 16 | 17 | .. toctree:: 18 | :caption: API Reference 19 | :maxdepth: 3 20 | 21 | api 22 | 23 | .. toctree:: 24 | :caption: Tutorials 25 | 26 | .. todo:: Add any Learn guide links here. If there are none, then simply delete this todo and leave 27 | the toctree above for use later. 28 | 29 | .. toctree:: 30 | :caption: Related Products 31 | 32 | .. todo:: Add any product links here. If there are none, then simply delete this todo and leave 33 | the toctree above for use later. 34 | 35 | .. toctree:: 36 | :caption: Other Links 37 | 38 | Download 39 | CircuitPython Reference Documentation 40 | CircuitPython Support Forum 41 | Discord Chat 42 | Adafruit Learning System 43 | Adafruit Blog 44 | Adafruit Store 45 | 46 | Indices and tables 47 | ================== 48 | 49 | * :ref:`genindex` 50 | * :ref:`modindex` 51 | * :ref:`search` 52 | -------------------------------------------------------------------------------- /examples/bbq10keyboard_gpiotest.py: -------------------------------------------------------------------------------- 1 | from bbq10keyboard import BBQ10Keyboard 2 | import board 3 | import digitalio 4 | import time 5 | 6 | i2c = board.I2C() 7 | kbd = BBQ10Keyboard(i2c) 8 | 9 | card_detect = kbd.get_pin(1) 10 | card_detect.switch_to_input(pull=digitalio.Pull.UP) 11 | 12 | prev_value = card_detect.value 13 | 14 | while True: 15 | if card_detect.value != prev_value: 16 | print('Card Detect: %d' % card_detect.value) 17 | 18 | prev_value = card_detect.value 19 | 20 | time.sleep(0.5) 21 | -------------------------------------------------------------------------------- /examples/bbq10keyboard_simpletest.py: -------------------------------------------------------------------------------- 1 | import board 2 | from bbq10keyboard import BBQ10Keyboard, STATE_PRESS, STATE_RELEASE, STATE_LONG_PRESS 3 | 4 | i2c = board.I2C() 5 | kbd = BBQ10Keyboard(i2c) 6 | 7 | kbd.backlight = 0.5 8 | 9 | while True: 10 | key_count = kbd.key_count 11 | if key_count > 0: 12 | key = kbd.key 13 | state = 'pressed' 14 | if key[0] == STATE_LONG_PRESS: 15 | state = 'held down' 16 | elif key[0] == STATE_RELEASE: 17 | state = 'released' 18 | 19 | print("key: '%s' (dec %d, hex %02x) %s" % (key[1], ord(key[1]), ord(key[1]), state)) 20 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Adafruit-Blinka 2 | adafruit-circuitpython-busdevice 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """A setuptools based setup module. 2 | 3 | See: 4 | https://packaging.python.org/en/latest/distributing.html 5 | https://github.com/pypa/sampleproject 6 | """ 7 | 8 | from setuptools import setup, find_packages 9 | # To use a consistent encoding 10 | from codecs import open 11 | from os import path 12 | 13 | here = path.abspath(path.dirname(__file__)) 14 | 15 | # Get the long description from the README file 16 | with open(path.join(here, 'README.rst'), encoding='utf-8') as f: 17 | long_description = f.read() 18 | 19 | setup( 20 | name='arturo182-circuitpython-bbq10keyboard', 21 | 22 | use_scm_version=True, 23 | setup_requires=['setuptools_scm'], 24 | 25 | description='CircuitPython library for interfacing the BB Q10 Keyboard over I2C.', 26 | long_description=long_description, 27 | long_description_content_type='text/x-rst', 28 | 29 | # The project's main homepage. 30 | url='https://github.com/solderparty/arturo182_CircuitPython_bbq10keyboard', 31 | 32 | # Author details 33 | author='arturo182', 34 | author_email='bbq10kbd@solder.party', 35 | 36 | install_requires=[ 37 | 'Adafruit-Blinka', 38 | 'adafruit-circuitpython-busdevice' 39 | ], 40 | 41 | # Choose your license 42 | license='MIT', 43 | 44 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 45 | classifiers=[ 46 | 'Development Status :: 3 - Alpha', 47 | 'Intended Audience :: Developers', 48 | 'Topic :: Software Development :: Libraries', 49 | 'Topic :: System :: Hardware', 50 | 'License :: OSI Approved :: MIT License', 51 | 'Programming Language :: Python :: 3', 52 | 'Programming Language :: Python :: 3.4', 53 | 'Programming Language :: Python :: 3.5', 54 | ], 55 | 56 | # What does your project relate to? 57 | keywords='adafruit blinka circuitpython micropython bbq10keyboard keyboard qwerty i2c ' 58 | 'blackberry', 59 | 60 | # You can just specify the packages manually here if your project is 61 | # simple. Or you can use find_packages(). 62 | # TODO: IF LIBRARY FILES ARE A PACKAGE FOLDER, 63 | # CHANGE `py_modules=['...']` TO `packages=['...']` 64 | py_modules=['bbq10keyboard'], 65 | ) 66 | --------------------------------------------------------------------------------