light: initial commit

This commit is contained in:
Konstantin Koslowski 2021-04-11 21:22:16 +02:00
commit c4826219bf
10 changed files with 407 additions and 0 deletions

147
.gitignore vendored Normal file
View file

@ -0,0 +1,147 @@
# Created by https://www.gitignore.io/api/python,visualstudiocode
# Edit at https://www.gitignore.io/?templates=python,visualstudiocode
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
# End of https://www.gitignore.io/api/python,visualstudiocode
### Micropy Cli ###
.micropy/
!micropy.json
!src/lib

22
.pylintrc Normal file
View file

@ -0,0 +1,22 @@
[MASTER]
# Loaded Stubs: esp8266-micropython-1.11.0
init-hook='import sys;sys.path[1:1]=["src/lib",".micropy/BradenM-micropy-stubs-c89b5ef/frozen", ".micropy/BradenM-micropy-stubs-e1b8ce6/frozen", ".micropy/BradenM-micropy-stubs-c89b5ef/stubs", ".micropy/light", ]'
[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 = missing-docstring, line-too-long, trailing-newlines, broad-except, logging-format-interpolation, invalid-name, empty-docstring,
no-method-argument, assignment-from-no-return, too-many-function-args, unexpected-keyword-arg
# the 2nd line deals with the limited information in the generated stubs.

9
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,9 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"ms-python.python", // micropy-cli: required for vscode micropython integrations
"VisualStudioExptTeam.vscodeintellicode" // micropy-cli: optional for advanced intellisense
]
}

23
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,23 @@
{
"python.linting.enabled": true,
"python.jediEnabled": false,
"python.autoComplete.extraPaths": [
".micropy/BradenM-micropy-stubs-c89b5ef/frozen",
".micropy/BradenM-micropy-stubs-e1b8ce6/frozen",
".micropy/BradenM-micropy-stubs-c89b5ef/stubs",
".micropy/light"
],
"python.autoComplete.typeshedPaths": [
".micropy/BradenM-micropy-stubs-c89b5ef/frozen",
".micropy/BradenM-micropy-stubs-e1b8ce6/frozen",
".micropy/BradenM-micropy-stubs-c89b5ef/stubs",
".micropy/light"
],
"python.analysis.typeshedPaths": [
".micropy/BradenM-micropy-stubs-c89b5ef/frozen",
".micropy/BradenM-micropy-stubs-e1b8ce6/frozen",
".micropy/BradenM-micropy-stubs-c89b5ef/stubs",
".micropy/light"
],
"python.linting.pylintEnabled": true
}

1
dev-requirements.txt Normal file
View file

@ -0,0 +1 @@
micropy-cli

14
micropy.json Normal file
View file

@ -0,0 +1,14 @@
{
"name": "light",
"stubs": {
"esp8266-micropython-1.11.0": "1.2.0"
},
"dev-packages": {
"micropy-cli": "*"
},
"packages": {},
"config": {
"vscode": true,
"pylint": true
}
}

21
pymakr.conf Normal file
View file

@ -0,0 +1,21 @@
{
"address": "/dev/ttyUSB0",
"username": "micro",
"password": "python",
"sync_folder": "src",
"open_on_start": true,
"safe_boot_on_upload": false,
"py_ignore": [
"pymakr.conf",
".vscode",
".gitignore",
".git",
"project.pymakr",
"env",
"venv",
".python-version",
".micropy/",
"micropy.json"
],
"fast_upload": false
}

0
requirements.txt Normal file
View file

1
src/boot.py Normal file
View file

@ -0,0 +1 @@
# boot.py - - runs on boot-up

169
src/main.py Normal file
View file

@ -0,0 +1,169 @@
# main.py
import machine
import neopixel
import time
# Pins
PIN_NP = 5
PIN_Y= 0
PIN_G= 4
PIN_B= 2
# NeoPixel
NUM_LED = 16
# y - Mode
MODE_MAX = 5
MODES = [ "off", "on", "color_chase", "rainbow", "strobe" ]
MODE_STEP = 1
# g - Color
COLOR_MAX = 255
COLOR_STEP = 5
# b - Brightness
BRIGHTNESS_MAX = 250
BRIGHTNESS_STEP = 50
# Delay
DELAY = 0.1
DELAY_IRQ = 0.5
DELAY_CHASE = 0.05
DELAY_STROBE = 0.2
light = None
state = None
def handle_y(pin):
global light, state
if state is None:
state = machine.disable_irq()
light.set_fn("mode")
def handle_g(pin):
global light, state
light.set_fn("color")
def handle_b(pin):
global light, state
light.set_fn("brightness")
class Light:
def __init__(self):
self.mode = 0
self.color = 0
self.brightness = 0
self.np = neopixel.NeoPixel(machine.Pin(PIN_NP), NUM_LED)
self.sw_y = machine.Pin(PIN_Y, machine.Pin.IN, machine.Pin.PULL_UP)
self.sw_g = machine.Pin(PIN_G, machine.Pin.IN, machine.Pin.PULL_UP)
self.sw_b = machine.Pin(PIN_B, machine.Pin.IN, machine.Pin.PULL_UP)
self.sw_y.irq(trigger=machine.Pin.IRQ_FALLING, handler=handle_y)
self.sw_g.irq(trigger=machine.Pin.IRQ_FALLING, handler=handle_g)
self.sw_b.irq(trigger=machine.Pin.IRQ_FALLING, handler=handle_b)
def set_fn(self, fn):
if fn == "mode":
self.mode = (self.mode + MODE_STEP) % MODE_MAX
print("set fn {} to {}".format(fn, MODES[self.mode]))
elif fn == "color":
self.color = (self.color + COLOR_STEP) % COLOR_MAX
print("set fn {} to {}".format(fn, self.color))
elif fn == "brightness":
self.brightness = (self.brightness + BRIGHTNESS_STEP) % BRIGHTNESS_MAX
print("set fn {} to {}".format(fn, self.brightness))
else:
print("invalid fn {}".format(fn))
def set_color(self, color):
for i in range(NUM_LED):
self.np[i] = self.wheel(color)
self.np.write()
def wheel(self, pos):
if pos < 0 or pos > 255:
return (0, 0, 0)
if pos < 85:
return (255 - pos * 3, pos * 3, 0)
if pos < 170:
pos -= 85
return (0, 255 - pos * 3, pos * 3)
pos -= 170
return (pos * 3, 0, 255 - pos * 3)
def start(self):
global state
old_mode = self.mode
old_color = self.color
old_brightness = self.brightness
i = 0
j = 0
while True:
if state:
time.sleep(DELAY_IRQ)
machine.enable_irq(state)
state = None
if not self.mode == old_mode:
print("mode: {}, old_mode: {}".format(MODES[self.mode], MODES[old_mode]))
if MODES[self.mode] == "off":
if not self.mode == old_mode:
old_mode = self.mode
self.set_color(-1)
time.sleep(DELAY)
# Off
elif MODES[self.mode] == "on":
if not self.mode == old_mode:
old_mode = self.mode
self.set_color(self.color)
if not self.color == old_color:
old_color = self.color
self.set_color(self.color)
time.sleep(DELAY)
# On
elif MODES[self.mode] == "color_chase":
if not self.mode == old_mode:
old_mode = self.mode
self.set_color(-1)
i = 0
j = 0
k = 0
if not self.color == old_color:
old_color = self.color
self.np[i] = self.wheel(self.color)
self.np[(i+1) % NUM_LED] = self.wheel(self.color)
self.np[(i+2) % NUM_LED] = self.wheel(self.color)
self.np.write()
self.np[i] = self.wheel(-1)
i = (i + 1) % NUM_LED
time.sleep(DELAY_CHASE)
# Rainbow
elif MODES[self.mode] == "rainbow":
if not self.mode == old_mode:
old_mode = self.mode
i = 0
j = 0
rc_index = (i * 256 // NUM_LED) + j
self.np[i] = self.wheel(rc_index & 255)
i = (i + 1)
if i == NUM_LED:
i = 0
self.np.write()
j = (j + 1) % 255
# Strobe
elif MODES[self.mode] == "strobe":
if not self.mode == old_mode:
old_mode = self.mode
j = 0
if j == 1:
self.set_color(self.color)
else:
self.set_color(-1)
j = (j + 1) % 2
time.sleep(DELAY)
else:
print("else")
def main():
print("")
global light
light = Light()
light.start()
if __name__ == "__main__":
main()