From 8e68e694fb3290c9ade9a2a77fb2be22723b12bf Mon Sep 17 00:00:00 2001 From: thoralmighty Date: Tue, 29 Nov 2022 21:22:30 +0100 Subject: [PATCH] Initial commit --- Pipfile | 12 ++++ Pipfile.lock | 107 ++++++++++++++++++++++++++++ main.py | 83 ++++++++++++++++++++++ static/style.css | 102 +++++++++++++++++++++++++++ static/widgets.js | 147 +++++++++++++++++++++++++++++++++++++++ templates/configure.html | 25 +++++++ templates/index.html | 25 +++++++ 7 files changed, 501 insertions(+) create mode 100644 Pipfile create mode 100644 Pipfile.lock create mode 100644 main.py create mode 100644 static/style.css create mode 100644 static/widgets.js create mode 100644 templates/configure.html create mode 100644 templates/index.html diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..0f41118 --- /dev/null +++ b/Pipfile @@ -0,0 +1,12 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +flask = "*" + +[dev-packages] + +[requires] +python_version = "3.10" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..fd1dd29 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,107 @@ +{ + "_meta": { + "hash": { + "sha256": "295fa60b4ad3b19ec29744ec2dfafba79ad5ee9a0b9ff095ac626e3d3981f117" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.10" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "click": { + "hashes": [ + "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", + "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.3" + }, + "flask": { + "hashes": [ + "sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b", + "sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526" + ], + "index": "pypi", + "version": "==2.2.2" + }, + "itsdangerous": { + "hashes": [ + "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44", + "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a" + ], + "markers": "python_version >= '3.7'", + "version": "==2.1.2" + }, + "jinja2": { + "hashes": [ + "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", + "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.2" + }, + "markupsafe": { + "hashes": [ + "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", + "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", + "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", + "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", + "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", + "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", + "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", + "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", + "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", + "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", + "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", + "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", + "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", + "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", + "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", + "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", + "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", + "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", + "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", + "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", + "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", + "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", + "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", + "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", + "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", + "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", + "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", + "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", + "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", + "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", + "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", + "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", + "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", + "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", + "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", + "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", + "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", + "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", + "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", + "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" + ], + "markers": "python_version >= '3.7'", + "version": "==2.1.1" + }, + "werkzeug": { + "hashes": [ + "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f", + "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5" + ], + "markers": "python_version >= '3.7'", + "version": "==2.2.2" + } + }, + "develop": {} +} diff --git a/main.py b/main.py new file mode 100644 index 0000000..1f8e085 --- /dev/null +++ b/main.py @@ -0,0 +1,83 @@ + +from flask import Flask, render_template, request +from os import system + +app = Flask(__name__) + +#define actuators GPIOs +ledRed = 13 +ledYlw = 19 +ledGrn = 26 +#initialize GPIO status variables +ledRedSts = 0 +ledYlwSts = 0 +ledGrnSts = 0 + +def check_app_states(apps): + for app in apps: + if 'check_cmd' in app: + exitcode = system(app['check_cmd']) + app['default'] = app['default'] if exitcode == 0 else False + +@app.route("/") +def index(): + if request.args.get('cmd') is not None: + exitcode = system(request.args.get('cmd')) + if exitcode == 0: + return "Command was run", 200 + else: + return "Command failed (exit code {0})".format(exitcode), 500 + + templateData = { + 'is_local': True if request.remote_addr == "127.0.0.1" else False, + 'apps': [ + { + 'name': 'clock', + 'cmd': 'espeak "$text"' + }, + { + 'name': 'toggle', + 'text_on': 'ON', + 'text_off': 'OFF', + 'cmd_on': 'espeak "on"', + 'cmd_off': 'espeak "off"', + 'cooldown': 3000 + }, + { + 'name': 'toggle', + 'text_true': '🔊', + 'text_false': '🔇', + 'default': False, + 'cmd_true': 'mpg123 ~/tng_viewscreen_on.mp3', + 'cmd_false': 'mpg123 ~/tng_viewscreen_off.mp3', + 'cooldown': 1000, + 'show_cooldown': False + }, + { + 'name': 'toggle', + 'text_true': '🔊', + 'text_false': '🔇', + 'default': False, + 'cmd_true': 'touch ~/testfile.tmp', + 'cmd_false': 'rm ~/testfile.tmp', + 'check_cmd': 'test -f ~/testfile.tmp', + 'cooldown': 1000, + 'show_cooldown': False + } + ] + } + + check_app_states(templateData) + + return render_template('index.html', **templateData) + +@app.route("/configure") +def configure(): + return render_template('configure.html') + +@app.route("//") +def action(deviceName, action): + templateData = {} + return render_template('index.html', **templateData) +if __name__ == "__main__": + app.run(host='0.0.0.0', port=8081, debug=True) \ No newline at end of file diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..dec5ebd --- /dev/null +++ b/static/style.css @@ -0,0 +1,102 @@ +html +{ + background:#111; + color:grey; + text-align:center; + font-family:sans-serif; + font-size:large; + line-height:1.2em; +} + +ul +{ + text-align:left; +} + +select, button +{ + padding:10px; + font:inherit; +} + +select +{ + min-width:200px; +} + +button +{ + padding:0.5em 1em 0.25em 1em; +} + +body +{ + margin:auto; + max-width:600px; + margin-top:50px; +} + +div.cooldownProgress { + bottom:10px; + z-index:10; + height:3px; + background: #58A; + position:relative; + max-width:85%; +} + +a +{ + color:#58A; +} + +a.block.disabled +{ + filter: grayscale(75%) brightness(60%); +} + +.maximise { + width:100%; + height:100%; +} + +.noselect { + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Old versions of Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently + supported by Chrome, Edge, Opera and Firefox */ + } + +#blocks +{ + margin:auto; + max-width:350px; +} + +a.block +{ + animation:filter; + display:inline-block; + width:100px; + height:100px; + line-height: 100px; + text-align:center; + vertical-align:middle; + border:solid 2px #58A; + color:#FFF; + border-radius:10px; + margin:6px 3px 6px 3px; + text-decoration: none; +} +a.block:hover +{ + cursor:hand; +} +a.block:active +{ + /*box-shadow: royalblue 0px 0px 8px;*/ + opacity:70%; +} \ No newline at end of file diff --git a/static/widgets.js b/static/widgets.js new file mode 100644 index 0000000..df1f83e --- /dev/null +++ b/static/widgets.js @@ -0,0 +1,147 @@ +function runCommand(cmd) +{ + $.ajax({ + url : './', + type : 'GET', + data : { + 'cmd' : cmd + }, + dataType:'json'}); +} + +function addApplet(config) +{ + var fn = window["app_" + config['name']]; + // is object a function? + if (typeof fn === "function") + { + //let cfg = JSON.parse(JSON.stringify(config)); + let cfg = config + + let a = $(""); + let obj = fn(a, cfg); + a.addClass("block"); + a.append(obj); + $("#blocks").append(a); + + if('cmd' in cfg) + { + a.click(function() { + command = cfg['cmd'] + command = command.replace("$text", a.text()); + runCommand(command) + }); + } + + if ('cooldown' in cfg) + { + let progressDiv = $("
"); + progressDiv.addClass("cooldownProgress"); + a.append(progressDiv); + progressDiv.hide(); + + a.click(function() { + a.css("pointer-events", "none"); + a.addClass("disabled"); + + let cooldownTime = cfg['cooldown']; + let fadeInTime = 200; + + if (cooldownTime < fadeInTime) + fadeInTime = cooldownTime*0.2; + + let progBarTime = cooldownTime - fadeInTime; + + progressDiv.css({ + 'width': '100%', + 'margin-left': '8%' + }); + + if (cfg['show_cooldown'] !== false) + { + progressDiv.fadeIn(fadeInTime, function() { + progressDiv.animate({'width': '0%', 'margin-left':'50%'}, progBarTime); + }); + } + + setTimeout(function() { + + a.css("pointer-events", "auto"); + a.removeClass("disabled"); + progressDiv.hide(); + }, cooldownTime); + }) + } + } + else + { + alert("unrecognised applet: " + cfg['name']); + } +} + +function app_clock(a, config) +{ + var span = $(""); + + span.addClass("maximise"); + + function setTime() { + var today = new Date(); + var h = today.getHours(); + var m = today.getMinutes(); + + if (h < 10) h = "0" + h; + if (m < 10) m = "0" + m; + span.html(h + ":" + m); + } + + setInterval(setTime, 1000); + setTime(); + + return span; +} + +function app_toggle(a, config) +{ + var span = $(""); + + span.addClass("maximise"); + + let currentState = false + let onIcon = "ON"; + let offIcon = "OFF"; + + if ('default' in config) { + currentState = config['default']; + } + + if ('text_on' in config) { + onIcon = config['text_on']; + } + + if ('text_off' in config) { + offIcon = config['text_off']; + } + + function setToggleIcon() { + if (currentState == true) { + span.html(onIcon); + } else { + span.html(offIcon); + } + } + + a.click(function() { + currentState = !currentState; + if (currentState == true && 'cmd_on' in config && config['cmd_on'].length > 0) { + runCommand(config['cmd_on']) + } else if (currentState == false && 'cmd_off' in config && config['cmd_off'].length > 0) { + runCommand(config['cmd_off']) + } + setToggleIcon(); + }); + + setToggleIcon(); + + return span; +} \ No newline at end of file diff --git a/templates/configure.html b/templates/configure.html new file mode 100644 index 0000000..eec3982 --- /dev/null +++ b/templates/configure.html @@ -0,0 +1,25 @@ + + + macropad (tbn) + + + +

Configure

+ + Widgets: +
    +
  • app1 - ↑ / ↓ / X
  • +
+ +
+ + +
+ + or
discard + + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..3ffc681 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,25 @@ + + + macropad (tbn) + + + + + {% if is_local %} + Configure + {% endif %} + +
+ +
+ + + + {% for app in apps %} + + {% endfor %} + + + \ No newline at end of file