Commit 63afa318 authored by Christian Wander's avatar Christian Wander
Browse files

Merge branch 'webapp'

parents d9bbad13 0323d793
.vscode
__pycache__/
venv
*.pyc
instance/
.pytest_cache/
.coverage
htmlcov/
dist/
build/
*.egg-info/
\ No newline at end of file
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
sacn = "*"
flask = "*"
pillow = "*"
[dev-packages]
[requires]
python_version = "3.9"
{
"_meta": {
"hash": {
"sha256": "dfe4fecef9710dd44d04260c9320fe0ea9c483be42b81a9f76852d08fcd0b0f9"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.9"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"click": {
"hashes": [
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==7.1.2"
},
"flask": {
"hashes": [
"sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060",
"sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"
],
"index": "pypi",
"version": "==1.1.2"
},
"itsdangerous": {
"hashes": [
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.1.0"
},
"jinja2": {
"hashes": [
"sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0",
"sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==2.11.2"
},
"markupsafe": {
"hashes": [
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
"sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42",
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
"sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b",
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
"sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15",
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
"sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2",
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.1.1"
},
"pillow": {
"hashes": [
"sha256:006de60d7580d81f4a1a7e9f0173dc90a932e3905cc4d47ea909bc946302311a",
"sha256:0a2e8d03787ec7ad71dc18aec9367c946ef8ef50e1e78c71f743bc3a770f9fae",
"sha256:0eeeae397e5a79dc088d8297a4c2c6f901f8fb30db47795113a4a605d0f1e5ce",
"sha256:11c5c6e9b02c9dac08af04f093eb5a2f84857df70a7d4a6a6ad461aca803fb9e",
"sha256:2fb113757a369a6cdb189f8df3226e995acfed0a8919a72416626af1a0a71140",
"sha256:4b0ef2470c4979e345e4e0cc1bbac65fda11d0d7b789dbac035e4c6ce3f98adb",
"sha256:59e903ca800c8cfd1ebe482349ec7c35687b95e98cefae213e271c8c7fffa021",
"sha256:5abd653a23c35d980b332bc0431d39663b1709d64142e3652890df4c9b6970f6",
"sha256:5f9403af9c790cc18411ea398a6950ee2def2a830ad0cfe6dc9122e6d528b302",
"sha256:6b4a8fd632b4ebee28282a9fef4c341835a1aa8671e2770b6f89adc8e8c2703c",
"sha256:6c1aca8231625115104a06e4389fcd9ec88f0c9befbabd80dc206c35561be271",
"sha256:795e91a60f291e75de2e20e6bdd67770f793c8605b553cb6e4387ce0cb302e09",
"sha256:7ba0ba61252ab23052e642abdb17fd08fdcfdbbf3b74c969a30c58ac1ade7cd3",
"sha256:7c9401e68730d6c4245b8e361d3d13e1035cbc94db86b49dc7da8bec235d0015",
"sha256:81f812d8f5e8a09b246515fac141e9d10113229bc33ea073fec11403b016bcf3",
"sha256:895d54c0ddc78a478c80f9c438579ac15f3e27bf442c2a9aa74d41d0e4d12544",
"sha256:8de332053707c80963b589b22f8e0229f1be1f3ca862a932c1bcd48dafb18dd8",
"sha256:92c882b70a40c79de9f5294dc99390671e07fc0b0113d472cbea3fde15db1792",
"sha256:95edb1ed513e68bddc2aee3de66ceaf743590bf16c023fb9977adc4be15bd3f0",
"sha256:b63d4ff734263ae4ce6593798bcfee6dbfb00523c82753a3a03cbc05555a9cc3",
"sha256:bd7bf289e05470b1bc74889d1466d9ad4a56d201f24397557b6f65c24a6844b8",
"sha256:cc3ea6b23954da84dbee8025c616040d9aa5eaf34ea6895a0a762ee9d3e12e11",
"sha256:cc9ec588c6ef3a1325fa032ec14d97b7309db493782ea8c304666fb10c3bd9a7",
"sha256:d3d07c86d4efa1facdf32aa878bd508c0dc4f87c48125cc16b937baa4e5b5e11",
"sha256:d8a96747df78cda35980905bf26e72960cba6d355ace4780d4bdde3b217cdf1e",
"sha256:e38d58d9138ef972fceb7aeec4be02e3f01d383723965bfcef14d174c8ccd039",
"sha256:eb472586374dc66b31e36e14720747595c2b265ae962987261f044e5cce644b5",
"sha256:fbd922f702582cb0d71ef94442bfca57624352622d75e3be7a1e7e9360b07e72"
],
"index": "pypi",
"version": "==8.0.1"
},
"sacn": {
"hashes": [
"sha256:5a7f0ea471cdf0392254132fbd6f4dba08f50c7a29f005cc9aa03d0c6d52bc04",
"sha256:988669c34847a3db28dbf8ce74b5bf403d161cec2acfb03a4f788f421bf51837"
],
"index": "pypi",
"version": "==1.4.6"
},
"werkzeug": {
"hashes": [
"sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43",
"sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==1.0.1"
}
},
"develop": {}
}
import os
from flask import Flask
## create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'app.sqlite')
)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass # :D :-D :-D
import pixelframe.controllers
# return app
\ No newline at end of file
import unittest
import blink
class TestBlink(unittest.TestCase):
def test_tuplify(self):
......@@ -29,7 +28,7 @@ class TestBlink(unittest.TestCase):
def test_from_png(self):
t = blink.Thing(file='data/min.png')
t = blink.Thing(file='../data/min.png')
expected = [[(255, 0, 255), (255, 0, 255)],
[(0, 255, 255), (0, 255, 255)]]
......
from pixelframe import app
from flask import render_template, request
import pixelframe.pixel_service as pixel_service
import pixelframe.image_config as config
@app.route('/')
def main_page():
return render_template('main.html')
@app.route('/start', methods=["POST"])
def start_pixels():
pixel_service.doit()
return "Started work."
@app.route('/stop', methods=["POST"])
def stop_pixels():
pixel_service.stopit()
return "Stopped work"
@app.route('/images', methods=["GET", "POST"])
def images():
"""
Endpoint used to set/get the image configuration
"""
if request.method == 'POST':
# print(f'>> receiving: {request.json}')
config.update(request.json)
return config.config
config = {
"path": "data",
"images": [
"creeper-12x12.png",
"cyber-12x12.png",
"star2-12x12.png",
"heart-ping-12x12.png"
]
}
def update(data):
# TODO: Check if there's something better to validate json data
print(f'>> updating config: {data}')
if "images" in data:
config['images'] = data['images']
if "path" in data:
config['path'] = data['path']
import threading
import queue
import time
import pixelframe.blink as blink
import pixelframe.image_config as config
import sacn
running = False
def doit():
global running
if running is True:
print(">> DEBUG: already running.")
return
print(f'>> Starting a thread ...')
running = True
x = threading.Thread(target=display_pixels, daemon=True)
x.start()
print(f'>> Thread started.')
def stopit():
global running
running = False
def display_pixels():
universe = 1
sender = sacn.sACNsender()
sender.start()
sender.activate_output(universe)
sender[universe].destination = "192.168.178.37"
while running is True:
# print(f'>> Doing some work within thread, running={running} ')
images = config.config['images']
for i in images:
file = config.config['path'] + "/" + i
print(f'>> current image: {file}')
pic = blink.Thing(file=file)
sender[universe].dmx_data = pic.snake_tuple()
print(f'>> current config: {config.config}')
time.sleep(10)
sender.stop()
print(f'>> pixel_service stopping.')
body {
background-color: black;
color:coral;
font-family: 'Courier New', Courier, monospace;
}
h1 {
color: pink;
}
\ No newline at end of file
console.log("hello")
document.getElementById("buttonOne").onclick = function() {
console.log("button one clicked")
fetch('start', { method: 'POST'})
.then(r => {
console.log(`Status: ${r.status}, text: ${r.statusText}`)
})
}
document.getElementById("buttonTwo").onclick = function() {
console.log("button two clicked")
fetch('stop', { method: 'POST'})
.then(r => {
console.log(`Status: ${r.status}, text: ${r.statusText}`)
})
}
\ No newline at end of file
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="static/main.css" />
</head>
<body>
<title>Pixelframe</title>
<h1>Pixelframe</h1>
<p>This is some text and even more text</p>
{% if name %}
<p>Hello {{ name }}!</p>
{% else %}
<p>Hello, World!</p>
{% endif %}
<button type="button" id="buttonOne">Start</button>
<button type="button" id="buttonTwo">Stop</button>
<script src="static/main.js"></script>
</body>
</html>
\ No newline at end of file
......@@ -4,10 +4,116 @@ run tests:
python3 -m unittest -v test
```
Install dependencies
```
pipenv install
```
run app:
```
python3 dmxfun.py
FLASK_APP="pixelframe" pipenv run flask run
```
## pipenv
### Setup pipenv on linux (mint 20)
[Source](https://pipenv.pypa.io/en/latest/install/#installing-pipenv)
Install pipx
> `Pipx`_ is a tool to help you install and run end-user applications written in Python. It installs applications into an isolated and clean environment on their own.
```
pip3 install --user pipx
```
Install pipenv:
```
pipx install pipenv
```
### Using pipenv
install a dependency with pipenv:
```
pipenv install sacn
```
This should automatically create a virtual environment managed
by pipenv.
Activate the environment:
```
pipenv shell
```
run in the activated env:
```
export FLASK_APP="pixelframe"
flask run
```
Or run it _outside_ of the env:
```
export FLASK_APP="pixelframe"
pipenv run flask run
```
## webapp
In the project directory, create a virtual environment:
```
python3 -m venv venv
```
activate the environment
```
. venv/bin/activate
```
install flask
```
pip install Flask
```
Activate the env in vscode also: ctrl-shift-p, "Python: Select Interpreter"
Following the ["Simple packages"](https://flask.palletsprojects.com/en/1.1.x/patterns/packages/) guide to structure the project, then run it with:
```
$ export FLASK_APP=pixelframe
$ export FLASK_ENV=development
$ flask run
```
### httpie fun
```
$ http POST localhost:5000/images images:='[]'
```
### dependency management
Still todo, but for now the dependen packages are installed manually useing pip,
then written into `requirements.txt`:
```
$ pip install <foo>
$ pip freeze > requirements.txt
```
## todo
......@@ -19,4 +125,4 @@ python3 dmxfun.py
* Make adding new images easier
* scanning directory?
* config file?
* web frontend?
\ No newline at end of file
* Research possibilities to validate REST-API inputs
\ No newline at end of file
from setuptools import setup
setup(
name="pixelframe",
packages=['pixelframe'],
include_package_data=True,
install_requires=[
'flask',
]
)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment