Initial Commit

This commit is contained in:
admin 2025-03-20 00:18:57 -07:00
commit 343a7f7dd6
92 changed files with 31580 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.venv/

11
data/screen_settings.json Normal file
View File

@ -0,0 +1,11 @@
{
"url": "yahoo.com",
"mediaFolder": "playlist",
"imageDuration": "5",
"player_type": "mpv",
"mediaLocation": "/home/orangepi/Desktop/playlists/ATA",
"autoStart": true,
"autoStartDelay": 5,
"autoPlayAtBoot": true,
"browserPath": "chromium"
}

View File

@ -0,0 +1,2 @@
# Pyarmor 8.5.10 (trial), 000000, 2025-01-12T20:49:57.897614
from .pyarmor_runtime import __pyarmor__

Binary file not shown.

38
requirements.txt Normal file
View File

@ -0,0 +1,38 @@
beautifulsoup4
blinker
bs4
certifi
cffi
charset-normalizer
click
cryptography
decorator
dogpile.cache
flask
Flask-Cors
gunicorn
idna
importlib-metadata
itsdangerous
jinja2
MarkupSafe
packaging
pbkdf2
pbr
psutil
pyarmor
pyarmor.cli.core
pycparser
pycups
python-vlc
pyudev
requests
soupsieve
spidev
stevedore
swig
typing-extensions
urllib3
werkzeug
zipp

3
src/MPVPlayer.py Normal file

File diff suppressed because one or more lines are too long

3
src/MPVPlayer_orig.py Normal file

File diff suppressed because one or more lines are too long

3
src/VideoPlayer.py Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

3
src/app.py Normal file

File diff suppressed because one or more lines are too long

3
src/find_usb_folder.py Normal file

File diff suppressed because one or more lines are too long

3
src/get_display.py Normal file
View File

@ -0,0 +1,3 @@
# Pyarmor 9.0.7 (trial), 000000, non-profits, 2025-03-05T12:22:13.847182
from pyarmor_runtime_000000 import __pyarmor__
__pyarmor__(__name__, __file__, b'PY000000\x00\x03\n\x00o\r\r\n\x80\x00\x01\x00\x08\x00\x00\x00\x04\x00\x00\x00@\x00\x00\x00e\x03\x00\x00\x12\t\x04\x00:\x81\xd6u\x83\xf4\xacR\xbbSmm\x9d\xa9\xf2\x8c\x00\x00\x00\x00\x00\x00\x00\x00\x85\xb7 \xad\x80\xbb\x7f\x90\x1f\n\x9f7\xe4\xc2R\xae&s\x0c\x11\x97\x12\xa4\x1f\xd53\r\xbbU]\x82t\xfa\t\xd4\xbf\xd2oTl\xfe\xf7\x92\xea\x9c4\x94\x13b\xc9\xc9\xe6+,\x98\x81\xa3\xc8w\xb5"\xd3\x0e6j\x00\x01\x01\xcb\xce\xa3\x1bC\xcf\xb5\xec\x06|(a\xe5\xaf}.\xb1\xef\xfbC\xe7\xce\xcaqFA\xf5\xf7\x1d:\x13\x0b<\x86\r\x0cx\xb8))"\xbb!\xef\x18\xd9l\xe0\xf27\x97\xec\x8a}P>\xdd\xd1(\xd1>c\xaf\x96,C\x04\xacQ\xecZ\xf3x\xaf\xc3\xa1\xcf`\xb7y\xba\xad\xe0\x10\xb3Ni\x1e\xa9\xe2.\xfa5\xe5Nnl|c@\x9c\x8a\x95\x189\xc9\xcfbP\xca\xb0\xbf\xedr-rO$\xab\x05qH\xb2\x01\r\xeaC*f><\xfb\xa0E<Vd\x98\x8bt\xae\x1bU\xfepF\xf3H\xbe)\x94\xe6sM\xde8\xc9\xd7\xa6 \x06\x12D[9\xd8\xed\x0f\xa48\xc0\xa4\x80]$\xd8\x1c\x1a\xee\xde\\\xab\x1b\xd6\xb5\x8c,?\xae\x8f\xf4%\x7fh\xef.\x1c\xd1\xdc\xf2\x03"\xa0\xf4A\x00\xe0\xb5\xff\xfb8\xa1\xfe\xabN\t\xb0v\\/X\xff\xd3\n\xf6\t\'F\xa6M\xb5\xdb\xba\xc3\x00\xecO\xe0O\x8a\x04P8U\xb1\x8f\x14\xf4\xe3\x05\x0eP\xff\xae\xfc\xda\x1d\x1a\xa7?Y-\x8c1Z\xb6\xd9CX[\xef\x03\x0f\x86\xe1\xb69oz\x01\x05{{\xdcz,qt;\x88\xceL\xe3\xaa\xe8}\x83\x0f\xb6#\xf7\xfc8\xcc\xee\xc3\xd3\xed\x0f\x14\xe3\xf8\x8a\x95F*:\xa0)LG\x07\x13\x12\xef7qk\':\xd4Y\xe1\xd8\x8d`*\xf4\tvDeo\x10<\x8a\x94\xc6/\xd6\xd2P\xd6\xb4~\xd4N\xca\x1d\xb5\xf3\xae\xaa\x9a\xc5c\x15\xba\x97%G\x96\xf8g\xbaYv\xb0m\xe16\\\x80\xb5\x1a\xa1(B+\xdfq\xc6\xa9\xdc>gh\xce\xe3c\xe6t\xec\xed\x89\x82c\x12;(\tF\x15\xc1\x9e\xeer\x10\xde\x99\xe2\xe8\xaeS\x81\xb0\xa0\xb8\xd2\xbc\xf0v\xe5T\xe8\xc8\x00\x88|\x82\xb8\x03\xa2\x92\xd3\xd0\xdd#\xf5\xd5T\xcc\xd9\xe3%\xec\x83ZN\x98\xeer\xcc\x19<|\xbdh\xf1*:)j\xe9;/\'[\xe5\xcaA\x94p\xf2\xfd\xbb\xbe^RC\xc8\x9a\xb9\xf21\x06\xbd&\xe8u\x94\x19!\xdat6\xe9\x0f\x8c\xfc\x15\x06."\xe0\x1e\xeb\x1e\xf5\xbb\r\x01W\x83\x92sm\xb3m\xc8\xe9e\x01O\xba\xfa1oy-Lo\xd3R$I\xc4\x83\r\'t\xf1\xfc\x12\xda\\\n\xb1\xc67\xa3wq=\xa9\xda\x80\x06\xb2\x87\xbd\x90T\xc2\xf5m5\xd2qP\x00\x88u\xba\x8d\x7f\x8d\x95\x8f\x9e\x90\x879^\xd7\xe2)\xe3\x94X\xa1\xa4\x1a\x01\xe3\xc8\rB\xccI:\x93\x9fZ\xc2\xb4\xb4\x0b\xaa\xd5\xc7\x05\tf\xf5c\xb8&`\xd0\xa8\xa3\x82\x0coe]\x056\x8cu\x87\xd3\x82\t\x80\x846\xc7\xbb\xaf#\xcaam5w\x03`\x91n\'\xc8:\x94\x13\x89\xd9\x98s\x15]9\x90\xf1\xdd\xa9,\x98\xa3\x1f\xcf0_cK\x86\x84#\xb0\r\x19\xf9Z\xd0\xe3\x1c\x83.\xa1\xd9%e<^M\xa7/\x14\xf7\x89O\x89D\xa2*\xdd2\xd0\xcc\xad\x0f\xfa\xd2\x8c\x83\xb3\x94\xcb|p\xb2\xdb\xa3)\x9a\x8d\x03H\x07\xa3\x15\xfc\n<\\\x1d\xeb\x07\xfb\xbe\xd3\xbbc?qm\xee\x08\x89\xb5\x19|J\xab\xe7g}R\x11\xbb\xb4l\x93\xa3\x0f\xd2]\xa2>\xe3U\xcdh\xb0\x8e\xd3\xf5YS/Y\xc1/\xfa\xd8\xb8\xc5BP\xa4')

3
src/get_playlists.py Normal file

File diff suppressed because one or more lines are too long

3
src/globals.py Normal file

File diff suppressed because one or more lines are too long

3
src/license_checker.py Normal file

File diff suppressed because one or more lines are too long

BIN
src/mpv-shot0001.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

3
src/play_usb_media.py Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
# Pyarmor 9.0.7 (trial), 000000, 2025-03-05T12:22:13.488747
from .pyarmor_runtime import __pyarmor__

Binary file not shown.

3
src/resources.py Normal file
View File

@ -0,0 +1,3 @@
# Pyarmor 9.0.7 (trial), 000000, non-profits, 2025-03-05T12:22:14.160307
from pyarmor_runtime_000000 import __pyarmor__
__pyarmor__(__name__, __file__, b'PY000000\x00\x03\n\x00o\r\r\n\x80\x00\x01\x00\x08\x00\x00\x00\x04\x00\x00\x00@\x00\x00\x00\x0b\x03\x00\x00\x12\t\x04\x00\xa5\xad=\xdfl\x98\xc7s{G\x13\xa1\xc0i\r\xc9\x00\x00\x00\x00\x00\x00\x00\x00\xff\x8en<\x1c\x85K@\r\xfd\x04\xdbX\xb1f\x03\x17\x89\xb6\xf7\xf5}2\xfd[\x1b\x08\xd6s\x8a\xb4\xbd\xdaU\x94\x8e\xbb-<@b\x9a+\xdf\xac\xc7\xc1\x92\x1e\x8f\xf1At\xf6\xc7bh\'ly*\x9f\x94?MXOb\xf4\xa8\xc7\x07\xcdx$+U\xdf<a<\nN\xdb\xd6M\x03\xd8\xe2\x007h1\xb4\x8e\xe9\x8b^\x80XA\xd9\xd5\x97*\x860\x19\x97]\x1bI\xc2$95\x90\xe3\x91\xb6\xb6_\xc6\x80>8\xad\r\xe1\x83\x15)\x87\x9eq\xcfN\xc2GL\x83\x01d\xa1v6\x1a\xfe\xc6\xe7\x86\xc2\tZ,\xfa\xc6iv\x90\xcd1&\x1d\xb8\x18\x8b\x7fW!\x9a%\xf4;#\x12\xdd\xa9\x1c(w\xca\xb6\xc7\x85\xee60\xefI\x93\xd0x.$\\\x80n1\x9en\xde\x1e\xd6\xfc\x07\xed\x1b?\xa9\xc5F\xa9\nR\x16\xb1.\xa4\x87\xb67#\xd5;\x8a\xdbH\x02W\xf2\x83\x8eK\x1b\x8bP_\xdby\x82\xdc\x83\x13\x86w\xcf\x9di\x93\xbe`S\x96\x8bP\x93}X\xe7C\x02\xed1\x07b=<\xe7\xf9.\x96\x9c7\xa8\xb3\xc2\x0f\xe5mA\x87q\xbb\xb5\x16;\xe0\xf3\x13\xc3\x05\xd8\xbd\xd9\x07}\x17\x7fk\x82\x91\xe3\xfb- \\m\x05\x8d\xb5)\x0f\xa6\x00G\xb2\xa0\xc1\xca\xc1\xd0\x8bu\x87\xbf\x18K\xd9T\x8cs\te\xd4s`\xb2VG\xdc!\xb4\xed\x7f\xcc]N\x9f|{\xe8W\xfb@V%p=\x93,\xa4\xa9\xd3\\\xfc\xe7\x9e\xfbAG\x08\xb3\x0f\xd8\xf4\x8c\xb6\x80~\xaa\xd2\xf8)\n\x19\xaa?\x0eD\xd1\xb3\xf1\tJ\xf6\xa1 ^\x05\xcbbk\xea\x08\xa3\xb1T\x0f\xcb\xc7\x82\xcbD\xc7\x94<\x93\x17\x9a\x8f#\x16\xe6\xc6\r\x05i\x19\x8a\x08\xb5r\xf2 \xa1\x1f)\xd0\x81\xc3\xd339o\xeaY\x036?\xd5\x1c\x98W\xf1A\xd4\xfd\xba\xd5\x9a\x10\xfe\xd4 \x03\xe4\xd0F\xf3\x984\xb2F\xad1]\xb3}a\xd6\xa8{"\x16\xdan`\x0f\x8e\x81\'\xf6\x88\x9f_\x02\xce\xff\xd3\x12\x05\x17[9I\x11:W\x1f\x1a\xd2\xa8\x02\x97\x9cQ6\x9dP)\x1f\x8f\xa6P_pg\x98d\x84\x85&5\xc6b\xd6\xf9s\xcb\xd1x\x16\xb2[\xa7\xa8E\x8ed\xbasc;|h\x88\xa6\xae:\x0e\xb8\xf5\xbb \x01<{:\x04D/|t\xc9^\xfe\xb0\x1a\xc6\x85\x91\n<\x13[\xf0I\xe2\xc0\xfa\xa7\x7f\xc0\xc9U\xd1\xc1\xeb\xba\xc6d{\x07\xa9o\xc6\xac\x84\xdf,V\xd8\r\xa3\xbf\x1e\x9f\x93\xb7}b\xcd\x16\x85\xd5\x9b%\x86\x87\xaf\xd0\x83\xc4\xc7\xb6_aR\xa7-\xa5\xfd2e\xd3\xcb\xa7\xcd\xb2\xf8i\x8b\x03\x87\xa3\xa3\xbf\xea\x18\x95;\xd1W\xe0\xa4F\xf4\xa5(\xc5B]\x0b\xacP\x8d\x11\x9c\xb7\'\xa3X\x99\xa6\x9c\x88\xc7\x89V1O\xc7;wie\xc3\xc4\x82}l\xe5\x109\x8d\xcc\xb8\xda \xfc`\xec\x17*B\xbaR\xb8T8Y!\x86\xd8W":-&\xcc\xbd\x8b\xc3\xc9\x10M\xda,\x05\xc6"\xcaBK\xf4k{\xa64D\xc1\xda\x11\xe7\'\xbaF=e\xafB\xf0\xa4A\x8b0B\xf0F\x81$A\xd7N]\xbe\xc0\xa2')

3
src/spi_flash.py Normal file

File diff suppressed because one or more lines are too long

3
src/t_test.py Normal file
View File

@ -0,0 +1,3 @@
# Pyarmor 8.5.10 (trial), 000000, non-profits, 2025-02-02T07:28:54.847953
from pyarmor_runtime_000000 import __pyarmor__
__pyarmor__(__name__, __file__, b'PY000000\x00\x03\n\x00o\r\r\n\x80\x00\x01\x00\x08\x00\x00\x00\x04\x00\x00\x00@\x00\x00\x00\xed\x05\x00\x00\x12\t\x04\x00g\xc0\x883\xe7\x9e\xe8S\xdc0\x90\xe9K\xb3S\xe1\x00\x00\x00\x00\x00\x00\x00\x009\xa70\xcc\xf95\x12*O\x87\xea}\xf3\x9b\xf1\xedm\x0f\xf3\xd9T\xe1\xff\xf5P\x1bX\xf6b\x91\xe6ej\xb8_\x1c`&Y4/\xd6\x84h>>|\xa5F\x9fu7\x8b7T\x17J+A\xe6\x11\xf3\xdcg\xf7\x7f\xf7\xb3\xa7,O\x95\xa6\xc3\xb4 \x97x\x17]\xd3\xe8\xb9\x87dPr+\x06\\\xedbg\x0fa\xa0\xe0w5C\x9f\xd0\xf0\x91\xa3_\xcf\xee\xbb`\xa7x\xff\xdat\xf9\xa8"\xde\x98\xe2\xac\xc9\x0c+\x1f_\x12G\xfbL\x9b\xa5C\r\x86\'7\x08r\xe0\x07\xf8\x0e3*e\xc6%\xd6U\xd6\xfd\xd1\xac\xfd\xads\xda\xd0,\x81h1-\xf7\xc1w\xb8\x87\'\x04\x88\xddX%\x1c\xc3Q\xc2\x1b=F\x83\x91\xb9\x0f~\x93\xa7\x8fo\x84G6k\x92zJ\x12\xd0\xf0\x9b-\xc9\xf85[3\xa4#\xbd\xc5\x18|\xda\x84\xca\x9f\xa9\x03\x11\x00\xd7\xa7"\xed\x83X\xda\xec>\x89\x12\xae5\xd5\x08A\xcf\x82\xb88|h6[/\x9bS)\xc7C\x97\xd7h\x1e\xbc\xbdM:03\x83\x9d~U\xad\x1b\x9a\xfa\xac\xae\tO|-\x98\xd7S\x92+MP|\x92\xa9\xca\xea\xc5\x14\xcb/Lk=\x03^|m\xa2\x01\x9d.A\xcd\x91\xeb\x059\xcf\x1b5G\xe7"\xc0\xbf\xd1\xc3L\xd9\xbb\xd6\x88\xcd57%\xed\xbd,n=g\xe17\x04\x1b\xb7\xee\xbc\xdc\x98\xf2&\x15\xaa{\xa6\xec\x9a\xe4\x11Q\x95[\x9b\xd3\x03\xef\xfd\xe8\r\xc6b:EK\x12\x8aiar}\x7f\xe6\xc3}%\xb1J\x9a\x01\xd5\x93\xbe~P\xf5P\xd6\xf0^\x08\xc1\xd7B\x8d*\xa8\xa5\x0cJ\x92\xcc#\x00J\x85x\xbe\xe25\xabbm\x02\xa8\x04|m\xcb\xc4(\x06\xca\x947\xb1\xe9*\x06\xca\xa0X\xd7\xd4\x91\xafW\x95\xdb*\x1b\\\x08\xaf<\xae\xf57d`\x92\xdffe\x9b\xc4\xf6i\x94%C\x99\x16\xec_\x95\xd6w\xaex8\\\xc9\x07\xe4\x81\xa4\xa3\xed\xc7\xed\xfd\xe0\xfb<\x1c\x96\x87\xdbK6d\xe4\xa9\x99\x17\x1fhmN\xa4U\xd3ct\t\xfb~\xd0Q\x0f\xf7&\xe5p=\x1b\xa7\x11\x08\xad\xcc\xd0\xa33\xc8\xf7\xa6K\xecZy\xee\xc9\xca\xbeTU\xee8\x85\x8f\xf7*\xb45\xb5\x0e,\x06\x1dG46\xa9\xae?\x9c\x7f$\xa7A\x17k\x81s\xdd\x85\x99\xfa\x84Q+$\x0eR\x162\x0c\xc6\x15\xf4\x82vQ\xf1"\xf2\x904\xef\x13t\x17dwTw\x00\xf7\t\x9a\xb5\xec\t\xf0\x9c\xb8\xd5a\xb0\xdc\x97]\xd4\xaf\x0cY\xa7\xca\x82\x03\xcb\xb1\xec\x8b\xb5Y\xba\xb1j\x91S\x04\x8e\xf6\xacQ\xf5\xf0\x94)\xdc0\xc4XG7\xf7\xd3=\x9b\xd8\xc8\x989\xb2\x89O\xc98\xcf-,"\x8f\x06\xad\xd9\xdf\x98\x8a\xac\x84iN\xc9X\xb3y\x8b\xe6%t^\xd6\x93\x19\xbc\x04\xa6\xfd3Q\xb5\xb1Q\xbd6\x0f\xc9x\xeeH\x14\xed\xe8FRFd\xb1\x03\x9c4Q\x9d\x9cU\xf4h\x85j\x04M\xd6\x9d\xc7~\xec\x8d\x82O\xba\x1b\xcc\x14>\x87<*\xcf\x99\x1f\x07A*T\x06\x85f%Q{\xbb!5G\xf2\x82\xb8\xbb7%V\x9ev\x08\xb4|\xd0\xe7b\xfc\x1f\xb6C5\xa1\x80\xc9\x1c\xe4\x9c\xee\xe6\x95\xf0\x8ay\x80\xaaR1\x97\xe2\x0f$\xcb\x99\x91\xe7\xb4>\xb9\xbfu\xcd\xbe\xaci\x016hT\xfc\x9a\x0bA\x0e3\x7f\xca\xc8\x0e\x087\xd1\x82\x14\x99\xd5\x92.5\xd4\x84\x90\xbf\xc4\xd3\xca\x1a\x98\x12\x03\x12fq\xa9(\x92|\xad\x80\tW^\xbd\x9cV\xccx\n\xd1\xf9\xbd\xcd\xa1*\x95\n\\\x16\xfb\xe7\xc7\xe8z\x85\x15\x1e\xbe\xf9\xfa:\xe5e\xd3\xf8\x00\xbc$\x91\xe4\xa4\xb8\n\xb9v\xa9c\x9dr@\r\xcf3U\xae\x05\xdf\xa5}4\x90\xf8QO\xca\xf5\xe2\x8aC\x16\x7f\x96\xb2\x1b\xfe\xfb\xedBs\xe9h\'\xe2\xaaY\x00G\\\x0c\xf0u\x8c\xc5\x95\xdf\xb817\xa4\x88\x1e\xc2o\x8c\xe5\xde\xfe(\xb4#\xc7\xf9\xd3\xe3\xfbQ\x9e\xb3r|\x7f\xad\xaf\x1bd\'\x93\x04\xc0\x07\xd0(c\xf32Q\xc5\x9a\x19\x19\x9ccK\xc9\r\xd1\x94\xf7\x98\xc8\xb8\xf2\x84\xd6\x8f\xec\xdb\xab\x88\x83\xbdT\xebWEB\xb7M\x7f\xa0\x7f\xc5\xb3\xa1S\xa1*Po\xc9{}\x81\xab\xe2BI\xd3\xa9\x91\x8b`\xa9\xf4\x84$\xb0\x1d\xe2\xc3\x90jQ\x93j`^\xf5\xacd\xdeTM.\xe0\xf2\xday\x0e)+\n\x16\x8e\r\x08\xaa\xed*1\xc8p^\x1e\xbc\xabP \xd1\x80\xe8\xe3Ws\xe7\x91\x8f\x8b\x8e\xba\xbf\n\xc1\xb3\xaa\xdc\xdc\xe7\xbc\xed\x11\xa2\xf9\xe7\r\x1c)\xd9\xa8\xe8\x85ON\xf2!6\xdf\xacj\x08\x8c\xda\xe1_\xd1\\\xf76\xe0c\xb4|C\xe9Pk\xd8r\xeeS\xe9!\xc5\xfc\xc7\xb7\xde\\v\xbcu\x99\x94\x10\x86J\x10\xc4\xef}\x8d\xcf,K\xc4_\xe5\xf6\xfe\xb7\xa1\xac\xe9\xb0\xbew-\xbev\xc8^\xd3Co\xb4\xba\xd8\xe46\x9eg2t\x04\x06\xf4-Y\x1b\xb2g\xf2\x8b\xe6+\xde\x01t)ZR>\x9d\xfc\xa0\xf5\x13\xb0\xfeDq_\xbb\xfd\x01(Q:#m\x80-\x0cg:b\x8ePG\xd3\xa7wO\x01\xea+\xee.\x01_\xfanX\xf6\n\x9dh\x82X!\x8c\x11\xd1b\xab\xeb\xfeBT\xb4\xe3\x99\x1e\x80\xda&\x1e\x17`\'\xa1\x92\xe7 L\x8c\xad^Mw\xd8v\xab\xfe\x1au\xa1}\xa8IS?k\xac\x0c\xee+\x03\x87\xfb\xbf\x93\xdc\x99\x1ft\xce\xe2v`\xd4\xc5\xac\x00\xa4\xbb\x92\xe2\xa1\xcaW!\xc2\xc9\xad\xfe\xf5X\xb2;\x8d\x0e\x1e\xc8O\x12\xd2`(*\x1f\xad\xad-\xa5\xbe\x0c\xc78\xfb\xa4)\x12w\xbd\\\xe3\xaa\x84m\xcc\x0c\xe5\x8a<\x0f\xa6t\x86_\n\xe2\xd9z\x07\xbcJ\xf5\x05\x12\x91q\t4\xdb\xfd\x1f\xb5\x8d\x9c\xeee\xc6\xbeN\n\x845\x16\xb7\xb0\xc6\xb8~s\x82DQ\xc3\x9d\x12\xfa\xf6J\xd0\xc5\xf4\xce\x16\x18\xa7\x8f\xd2*\x8bT&\x0b\xdcB\xfc\xeb\xfbD\x01\xf7\x89Is\xa5e\x18"\xc9\xcd\x9e\xf0{\xff\x03\xc5\xaeo\x99j\xfe\xd3Ly\x1a\xa7\xc2\xbf\xc9\x1dy\xbc\x7fm9\x03V\xe9\xd8R\xa6\x88\xb37uEn\x8b\xda\xd88P\xe1')

3
src/wifi_config.py Normal file

File diff suppressed because one or more lines are too long

3
src/wsgi.py Normal file
View File

@ -0,0 +1,3 @@
# Pyarmor 9.0.7 (trial), 000000, non-profits, 2025-03-05T12:22:14.586715
from pyarmor_runtime_000000 import __pyarmor__
__pyarmor__(__name__, __file__, b'PY000000\x00\x03\n\x00o\r\r\n\x80\x00\x01\x00\x08\x00\x00\x00\x04\x00\x00\x00@\x00\x00\x00\x9a\x01\x00\x00\x12\t\x04\x00\xc2\x16\xeb\xdb\x01#\xb1\xd9\xc2\xe2\xf6A^\xf4\xda\x89\x00\x00\x00\x00\x00\x00\x00\x00s\r\xc6\x00\xc4\xb3\x81\'\xb2|yB\xebs\x12\xecdEy\x82S(\xce\xce\x18\xb7\x9e\x08\x99\xf4\xf0]\x863\xe9h\xd8\x98n9O\xf5\xe2\xbf\x16\xd6\xcb\x18p\xc7\xf5\x9b- \x1aY\xdb\xa2Iu\xd5\xe14\xa4As\xb8\xa3t\x1a\xbfB\xce%\x8au\x84\x8b=\x85\x054\x14|\x8c\x00]\xe2)R\xed\xae\xda>\x04U\xceJ:\xd8\x1dW\xfdf\xb6\x1b\x81F\x0b\xd0Oany\xf3\x1e\xf3k\x9f\xbb\xf9\x10i[y\xdbP;\x89\x0c\xa7\xb2\xa2\x91\xf1e\xd5\xd9\xce9fz\xbe\x03\x8dfq\x064\xf4\x1a\x99s\xbf\x08X\x82W\x1ey`^^X\x1ai\xef\xa3\x0bx\xf3\x16K\x106T\x0eOA\x10\xa7{\x9fV\x95\x9d\xc7\xbc\x1d(\xe57\x95\xea\xc4\x02w\x8bu\xe3\x15\x8ea\x7f\xe77\x96\x03\x8c\x08"\xf6\x92\xc3;1\xa8\x919w\xf6g\x1a\x15\xa6Ci\xec=\xee_\x03\x03\x97\xcfl\x9b\xfb\x00\xee\xd0\x1b\xb7\xdb\x9bh\xbe\xa9\x8dJjK\xe4\xab\xe8\xa3<3\x82\x9f\xb2\xb2\x1d\xda\xfd\x13\xb3\xcc\xd8z\xfce\x13#~e\x9a\x11bD\xe8\x91\x82V\xff\x15\xb6\xf3\x8c\xe6zw\xf9\xf5U\x88$\xbc\xef-T\x01\x91R\xec-\xfb;\x8f\xc2\xbdtI\x7f\x98\x88\xbe+\xcd\xca\x9f\x01v\x99T\x9a\x10iJ\xfdo\xdf\x03\xe8\xec\xb8,\x99\xd7\xea\x1c0j\xbc\x18\x9fO;\xdf\x89X\x94>"\xe6\xa6\xd7U\t\xaa\xca\xef\xf0\xda\xd8\xdf\xd6\xc2*\xb9C\xf8\xfcm#z\xc9:\x85+{5\xa3<\xcd\xb2\x94M/\x80\x823u\x06\x7fI\xae\xf5\xc2\xc1\x15\xaf\x9c\xc4Yq\x86|\xd0\x8a')

107
static/css/styles.css Normal file
View File

@ -0,0 +1,107 @@
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f0f0f0;
}
.navbar {
width: 100%;
background-color: black;
border-bottom: 2px solid white;
display: flex;
justify-content: flex-start;
align-items: center;
box-sizing: border-box; /* Ensure padding and border are included in the width */
}
.navbar-left {
padding: 0 10px;
}
.navbar ul {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
align-items: center;
position: relative; /* Ensure relative positioning for the submenu */
}
.navbar ul li {
float: left;
position: relative; /* Ensure relative positioning for the submenu */
}
.navbar ul li a {
display: block;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
border-right: 1px solid white;
}
.navbar ul li a:hover {
background-color: grey;
}
.navbar ul li a.disabled {
color: grey;
pointer-events: none;
}
.navbar ul .submenu {
display: none;
position: absolute;
top: 100%;
left: 0;
background-color: black;
list-style-type: none;
margin: 0;
padding: 0;
border-top: 2px solid white;
z-index: 1000;
}
.navbar ul .submenu li {
float: none;
border-right: none;
}
.navbar ul .submenu li a {
padding: 10px 16px;
border-bottom: 1px solid white;
}
.navbar ul .submenu li a:hover {
background-color: grey;
}
.navbar ul li:hover > .submenu {
display: block;
}
.nav-image {
height: 40px;
width: auto;
}
.content-wrapper {
display: flex;
justify-content: center;
width: 100%;
box-sizing: border-box; /* Ensure padding and border are included in the width */
}
.content {
width: 90%; /* Increased width */
max-width: 1400px; /* Increased max-width */
text-align: center;
box-sizing: border-box; /* Ensure padding and border are included in the width */
}
.content h1 {
color: black;
}

8030
static/fontawesome/css/all.css vendored Normal file

File diff suppressed because it is too large Load Diff

9
static/fontawesome/css/all.min.css vendored Normal file

File diff suppressed because one or more lines are too long

1594
static/fontawesome/css/brands.css vendored Normal file

File diff suppressed because it is too large Load Diff

6
static/fontawesome/css/brands.min.css vendored Normal file

File diff suppressed because one or more lines are too long

6375
static/fontawesome/css/fontawesome.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

19
static/fontawesome/css/regular.css vendored Normal file
View File

@ -0,0 +1,19 @@
/*!
* Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
:root, :host {
--fa-style-family-classic: 'Font Awesome 6 Free';
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; }
@font-face {
font-family: 'Font Awesome 6 Free';
font-style: normal;
font-weight: 400;
font-display: block;
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
.far,
.fa-regular {
font-weight: 400; }

View File

@ -0,0 +1,6 @@
/*!
* Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-weight:400}

19
static/fontawesome/css/solid.css vendored Normal file
View File

@ -0,0 +1,19 @@
/*!
* Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
:root, :host {
--fa-style-family-classic: 'Font Awesome 6 Free';
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; }
@font-face {
font-family: 'Font Awesome 6 Free';
font-style: normal;
font-weight: 900;
font-display: block;
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
.fas,
.fa-solid {
font-weight: 900; }

6
static/fontawesome/css/solid.min.css vendored Normal file
View File

@ -0,0 +1,6 @@
/*!
* Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}

640
static/fontawesome/css/svg-with-js.css vendored Normal file
View File

@ -0,0 +1,640 @@
/*!
* Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
:root, :host {
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Solid';
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Regular';
--fa-font-light: normal 300 1em/1 'Font Awesome 6 Light';
--fa-font-thin: normal 100 1em/1 'Font Awesome 6 Thin';
--fa-font-duotone: normal 900 1em/1 'Font Awesome 6 Duotone';
--fa-font-sharp-solid: normal 900 1em/1 'Font Awesome 6 Sharp';
--fa-font-sharp-regular: normal 400 1em/1 'Font Awesome 6 Sharp';
--fa-font-sharp-light: normal 300 1em/1 'Font Awesome 6 Sharp';
--fa-font-sharp-thin: normal 100 1em/1 'Font Awesome 6 Sharp';
--fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; }
svg:not(:root).svg-inline--fa, svg:not(:host).svg-inline--fa {
overflow: visible;
box-sizing: content-box; }
.svg-inline--fa {
display: var(--fa-display, inline-block);
height: 1em;
overflow: visible;
vertical-align: -.125em; }
.svg-inline--fa.fa-2xs {
vertical-align: 0.1em; }
.svg-inline--fa.fa-xs {
vertical-align: 0em; }
.svg-inline--fa.fa-sm {
vertical-align: -0.07143em; }
.svg-inline--fa.fa-lg {
vertical-align: -0.2em; }
.svg-inline--fa.fa-xl {
vertical-align: -0.25em; }
.svg-inline--fa.fa-2xl {
vertical-align: -0.3125em; }
.svg-inline--fa.fa-pull-left {
margin-right: var(--fa-pull-margin, 0.3em);
width: auto; }
.svg-inline--fa.fa-pull-right {
margin-left: var(--fa-pull-margin, 0.3em);
width: auto; }
.svg-inline--fa.fa-li {
width: var(--fa-li-width, 2em);
top: 0.25em; }
.svg-inline--fa.fa-fw {
width: var(--fa-fw-width, 1.25em); }
.fa-layers svg.svg-inline--fa {
bottom: 0;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0; }
.fa-layers-text, .fa-layers-counter {
display: inline-block;
position: absolute;
text-align: center; }
.fa-layers {
display: inline-block;
height: 1em;
position: relative;
text-align: center;
vertical-align: -.125em;
width: 1em; }
.fa-layers svg.svg-inline--fa {
-webkit-transform-origin: center center;
transform-origin: center center; }
.fa-layers-text {
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
-webkit-transform-origin: center center;
transform-origin: center center; }
.fa-layers-counter {
background-color: var(--fa-counter-background-color, #ff253a);
border-radius: var(--fa-counter-border-radius, 1em);
box-sizing: border-box;
color: var(--fa-inverse, #fff);
line-height: var(--fa-counter-line-height, 1);
max-width: var(--fa-counter-max-width, 5em);
min-width: var(--fa-counter-min-width, 1.5em);
overflow: hidden;
padding: var(--fa-counter-padding, 0.25em 0.5em);
right: var(--fa-right, 0);
text-overflow: ellipsis;
top: var(--fa-top, 0);
-webkit-transform: scale(var(--fa-counter-scale, 0.25));
transform: scale(var(--fa-counter-scale, 0.25));
-webkit-transform-origin: top right;
transform-origin: top right; }
.fa-layers-bottom-right {
bottom: var(--fa-bottom, 0);
right: var(--fa-right, 0);
top: auto;
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
transform: scale(var(--fa-layers-scale, 0.25));
-webkit-transform-origin: bottom right;
transform-origin: bottom right; }
.fa-layers-bottom-left {
bottom: var(--fa-bottom, 0);
left: var(--fa-left, 0);
right: auto;
top: auto;
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
transform: scale(var(--fa-layers-scale, 0.25));
-webkit-transform-origin: bottom left;
transform-origin: bottom left; }
.fa-layers-top-right {
top: var(--fa-top, 0);
right: var(--fa-right, 0);
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
transform: scale(var(--fa-layers-scale, 0.25));
-webkit-transform-origin: top right;
transform-origin: top right; }
.fa-layers-top-left {
left: var(--fa-left, 0);
right: auto;
top: var(--fa-top, 0);
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
transform: scale(var(--fa-layers-scale, 0.25));
-webkit-transform-origin: top left;
transform-origin: top left; }
.fa-1x {
font-size: 1em; }
.fa-2x {
font-size: 2em; }
.fa-3x {
font-size: 3em; }
.fa-4x {
font-size: 4em; }
.fa-5x {
font-size: 5em; }
.fa-6x {
font-size: 6em; }
.fa-7x {
font-size: 7em; }
.fa-8x {
font-size: 8em; }
.fa-9x {
font-size: 9em; }
.fa-10x {
font-size: 10em; }
.fa-2xs {
font-size: 0.625em;
line-height: 0.1em;
vertical-align: 0.225em; }
.fa-xs {
font-size: 0.75em;
line-height: 0.08333em;
vertical-align: 0.125em; }
.fa-sm {
font-size: 0.875em;
line-height: 0.07143em;
vertical-align: 0.05357em; }
.fa-lg {
font-size: 1.25em;
line-height: 0.05em;
vertical-align: -0.075em; }
.fa-xl {
font-size: 1.5em;
line-height: 0.04167em;
vertical-align: -0.125em; }
.fa-2xl {
font-size: 2em;
line-height: 0.03125em;
vertical-align: -0.1875em; }
.fa-fw {
text-align: center;
width: 1.25em; }
.fa-ul {
list-style-type: none;
margin-left: var(--fa-li-margin, 2.5em);
padding-left: 0; }
.fa-ul > li {
position: relative; }
.fa-li {
left: calc(var(--fa-li-width, 2em) * -1);
position: absolute;
text-align: center;
width: var(--fa-li-width, 2em);
line-height: inherit; }
.fa-border {
border-color: var(--fa-border-color, #eee);
border-radius: var(--fa-border-radius, 0.1em);
border-style: var(--fa-border-style, solid);
border-width: var(--fa-border-width, 0.08em);
padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); }
.fa-pull-left {
float: left;
margin-right: var(--fa-pull-margin, 0.3em); }
.fa-pull-right {
float: right;
margin-left: var(--fa-pull-margin, 0.3em); }
.fa-beat {
-webkit-animation-name: fa-beat;
animation-name: fa-beat;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
.fa-bounce {
-webkit-animation-name: fa-bounce;
animation-name: fa-bounce;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1));
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); }
.fa-fade {
-webkit-animation-name: fa-fade;
animation-name: fa-fade;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
.fa-beat-fade {
-webkit-animation-name: fa-beat-fade;
animation-name: fa-beat-fade;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
.fa-flip {
-webkit-animation-name: fa-flip;
animation-name: fa-flip;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
.fa-shake {
-webkit-animation-name: fa-shake;
animation-name: fa-shake;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, linear);
animation-timing-function: var(--fa-animation-timing, linear); }
.fa-spin {
-webkit-animation-name: fa-spin;
animation-name: fa-spin;
-webkit-animation-delay: var(--fa-animation-delay, 0s);
animation-delay: var(--fa-animation-delay, 0s);
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 2s);
animation-duration: var(--fa-animation-duration, 2s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, linear);
animation-timing-function: var(--fa-animation-timing, linear); }
.fa-spin-reverse {
--fa-animation-direction: reverse; }
.fa-pulse,
.fa-spin-pulse {
-webkit-animation-name: fa-spin;
animation-name: fa-spin;
-webkit-animation-direction: var(--fa-animation-direction, normal);
animation-direction: var(--fa-animation-direction, normal);
-webkit-animation-duration: var(--fa-animation-duration, 1s);
animation-duration: var(--fa-animation-duration, 1s);
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
-webkit-animation-timing-function: var(--fa-animation-timing, steps(8));
animation-timing-function: var(--fa-animation-timing, steps(8)); }
@media (prefers-reduced-motion: reduce) {
.fa-beat,
.fa-bounce,
.fa-fade,
.fa-beat-fade,
.fa-flip,
.fa-pulse,
.fa-shake,
.fa-spin,
.fa-spin-pulse {
-webkit-animation-delay: -1ms;
animation-delay: -1ms;
-webkit-animation-duration: 1ms;
animation-duration: 1ms;
-webkit-animation-iteration-count: 1;
animation-iteration-count: 1;
-webkit-transition-delay: 0s;
transition-delay: 0s;
-webkit-transition-duration: 0s;
transition-duration: 0s; } }
@-webkit-keyframes fa-beat {
0%, 90% {
-webkit-transform: scale(1);
transform: scale(1); }
45% {
-webkit-transform: scale(var(--fa-beat-scale, 1.25));
transform: scale(var(--fa-beat-scale, 1.25)); } }
@keyframes fa-beat {
0%, 90% {
-webkit-transform: scale(1);
transform: scale(1); }
45% {
-webkit-transform: scale(var(--fa-beat-scale, 1.25));
transform: scale(var(--fa-beat-scale, 1.25)); } }
@-webkit-keyframes fa-bounce {
0% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0); }
10% {
-webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
30% {
-webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
50% {
-webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
57% {
-webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
64% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0); }
100% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0); } }
@keyframes fa-bounce {
0% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0); }
10% {
-webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
30% {
-webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
50% {
-webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
57% {
-webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
64% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0); }
100% {
-webkit-transform: scale(1, 1) translateY(0);
transform: scale(1, 1) translateY(0); } }
@-webkit-keyframes fa-fade {
50% {
opacity: var(--fa-fade-opacity, 0.4); } }
@keyframes fa-fade {
50% {
opacity: var(--fa-fade-opacity, 0.4); } }
@-webkit-keyframes fa-beat-fade {
0%, 100% {
opacity: var(--fa-beat-fade-opacity, 0.4);
-webkit-transform: scale(1);
transform: scale(1); }
50% {
opacity: 1;
-webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
@keyframes fa-beat-fade {
0%, 100% {
opacity: var(--fa-beat-fade-opacity, 0.4);
-webkit-transform: scale(1);
transform: scale(1); }
50% {
opacity: 1;
-webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
@-webkit-keyframes fa-flip {
50% {
-webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
@keyframes fa-flip {
50% {
-webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
@-webkit-keyframes fa-shake {
0% {
-webkit-transform: rotate(-15deg);
transform: rotate(-15deg); }
4% {
-webkit-transform: rotate(15deg);
transform: rotate(15deg); }
8%, 24% {
-webkit-transform: rotate(-18deg);
transform: rotate(-18deg); }
12%, 28% {
-webkit-transform: rotate(18deg);
transform: rotate(18deg); }
16% {
-webkit-transform: rotate(-22deg);
transform: rotate(-22deg); }
20% {
-webkit-transform: rotate(22deg);
transform: rotate(22deg); }
32% {
-webkit-transform: rotate(-12deg);
transform: rotate(-12deg); }
36% {
-webkit-transform: rotate(12deg);
transform: rotate(12deg); }
40%, 100% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); } }
@keyframes fa-shake {
0% {
-webkit-transform: rotate(-15deg);
transform: rotate(-15deg); }
4% {
-webkit-transform: rotate(15deg);
transform: rotate(15deg); }
8%, 24% {
-webkit-transform: rotate(-18deg);
transform: rotate(-18deg); }
12%, 28% {
-webkit-transform: rotate(18deg);
transform: rotate(18deg); }
16% {
-webkit-transform: rotate(-22deg);
transform: rotate(-22deg); }
20% {
-webkit-transform: rotate(22deg);
transform: rotate(22deg); }
32% {
-webkit-transform: rotate(-12deg);
transform: rotate(-12deg); }
36% {
-webkit-transform: rotate(12deg);
transform: rotate(12deg); }
40%, 100% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); } }
@-webkit-keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); }
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg); } }
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); }
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg); } }
.fa-rotate-90 {
-webkit-transform: rotate(90deg);
transform: rotate(90deg); }
.fa-rotate-180 {
-webkit-transform: rotate(180deg);
transform: rotate(180deg); }
.fa-rotate-270 {
-webkit-transform: rotate(270deg);
transform: rotate(270deg); }
.fa-flip-horizontal {
-webkit-transform: scale(-1, 1);
transform: scale(-1, 1); }
.fa-flip-vertical {
-webkit-transform: scale(1, -1);
transform: scale(1, -1); }
.fa-flip-both,
.fa-flip-horizontal.fa-flip-vertical {
-webkit-transform: scale(-1, -1);
transform: scale(-1, -1); }
.fa-rotate-by {
-webkit-transform: rotate(var(--fa-rotate-angle, 0));
transform: rotate(var(--fa-rotate-angle, 0)); }
.fa-stack {
display: inline-block;
vertical-align: middle;
height: 2em;
position: relative;
width: 2.5em; }
.fa-stack-1x,
.fa-stack-2x {
bottom: 0;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
z-index: var(--fa-stack-z-index, auto); }
.svg-inline--fa.fa-stack-1x {
height: 1em;
width: 1.25em; }
.svg-inline--fa.fa-stack-2x {
height: 2em;
width: 2.5em; }
.fa-inverse {
color: var(--fa-inverse, #fff); }
.sr-only,
.fa-sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0; }
.sr-only-focusable:not(:focus),
.fa-sr-only-focusable:not(:focus) {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0; }
.svg-inline--fa .fa-primary {
fill: var(--fa-primary-color, currentColor);
opacity: var(--fa-primary-opacity, 1); }
.svg-inline--fa .fa-secondary {
fill: var(--fa-secondary-color, currentColor);
opacity: var(--fa-secondary-opacity, 0.4); }
.svg-inline--fa.fa-swap-opacity .fa-primary {
opacity: var(--fa-secondary-opacity, 0.4); }
.svg-inline--fa.fa-swap-opacity .fa-secondary {
opacity: var(--fa-primary-opacity, 1); }
.svg-inline--fa mask .fa-primary,
.svg-inline--fa mask .fa-secondary {
fill: black; }
.fad.fa-inverse,
.fa-duotone.fa-inverse {
color: var(--fa-inverse, #fff); }

File diff suppressed because one or more lines are too long

26
static/fontawesome/css/v4-font-face.css vendored Normal file
View File

@ -0,0 +1,26 @@
/*!
* Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
@font-face {
font-family: 'FontAwesome';
font-display: block;
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
@font-face {
font-family: 'FontAwesome';
font-display: block;
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
@font-face {
font-family: 'FontAwesome';
font-display: block;
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype");
unicode-range: U+F003,U+F006,U+F014,U+F016-F017,U+F01A-F01B,U+F01D,U+F022,U+F03E,U+F044,U+F046,U+F05C-F05D,U+F06E,U+F070,U+F087-F088,U+F08A,U+F094,U+F096-F097,U+F09D,U+F0A0,U+F0A2,U+F0A4-F0A7,U+F0C5,U+F0C7,U+F0E5-F0E6,U+F0EB,U+F0F6-F0F8,U+F10C,U+F114-F115,U+F118-F11A,U+F11C-F11D,U+F133,U+F147,U+F14E,U+F150-F152,U+F185-F186,U+F18E,U+F190-F192,U+F196,U+F1C1-F1C9,U+F1D9,U+F1DB,U+F1E3,U+F1EA,U+F1F7,U+F1F9,U+F20A,U+F247-F248,U+F24A,U+F24D,U+F255-F25B,U+F25D,U+F271-F274,U+F278,U+F27B,U+F28C,U+F28E,U+F29C,U+F2B5,U+F2B7,U+F2BA,U+F2BC,U+F2BE,U+F2C0-F2C1,U+F2C3,U+F2D0,U+F2D2,U+F2D4,U+F2DC; }
@font-face {
font-family: 'FontAwesome';
font-display: block;
src: url("../webfonts/fa-v4compatibility.woff2") format("woff2"), url("../webfonts/fa-v4compatibility.ttf") format("truetype");
unicode-range: U+F041,U+F047,U+F065-F066,U+F07D-F07E,U+F080,U+F08B,U+F08E,U+F090,U+F09A,U+F0AC,U+F0AE,U+F0B2,U+F0D0,U+F0D6,U+F0E4,U+F0EC,U+F10A-F10B,U+F123,U+F13E,U+F148-F149,U+F14C,U+F156,U+F15E,U+F160-F161,U+F163,U+F175-F178,U+F195,U+F1F8,U+F219,U+F27A; }

View File

@ -0,0 +1,6 @@
/*!
* Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a}

2194
static/fontawesome/css/v4-shims.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

22
static/fontawesome/css/v5-font-face.css vendored Normal file
View File

@ -0,0 +1,22 @@
/*!
* Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
@font-face {
font-family: 'Font Awesome 5 Brands';
font-display: block;
font-weight: 400;
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
@font-face {
font-family: 'Font Awesome 5 Free';
font-display: block;
font-weight: 900;
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
@font-face {
font-family: 'Font Awesome 5 Free';
font-display: block;
font-weight: 400;
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }

View File

@ -0,0 +1,6 @@
/*!
* Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,272 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WiFi Configuration</title>
<link rel="icon" type="image/x-icon" href="/static/images/favicon.ico">
<link rel="stylesheet" href="/static/css/styles.css">
<link rel="stylesheet" href="/static/fontawesome/css/all.min.css">
<script src="/static/js/data-request.js"></script>
<style>
h1 {
margin-top: 30px;
font-size: 36px;
color: #333;
}
.button-container {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 20px;
}
.button-container .btn {
padding: 10px 20px;
font-size: 1.2em;
cursor: pointer;
background-color: blue;
color: white;
width: 120px;
border-radius: 5px;
border: none;
text-decoration: none;
}
.button-container .btn:hover {
background-color: #0056b3;
}
.scan-container {
margin-top: 20px;
}
.scan-container .btn {
background-color: #28a745;
}
.scan-container .btn:hover {
background-color: #218838;
}
.connect-container {
margin-top: 20px;
}
.connect-container .btn {
padding:5px 15px;
border-radius: 5px;
background-color: #ffc107;
}
.connect-container .btn:hover {
background-color: #e0a800;
}
.network-list {
margin-top: 20px;
width: 100%;
max-height: 200px;
overflow-y: auto;
border: 1px solid #ccc;
background-color: white;
box-sizing: border-box;
}
.network-list table {
width: 100%;
border-collapse: collapse;
table-layout: auto;
box-sizing: border-box;
}
.network-list th, .network-list td {
padding: 8px;
text-align: left;
border-bottom: 1px solid #ddd;
white-space: nowrap;
box-sizing: border-box;
}
.network-list th {
background-color: #f2f2f2;
}
.network-list tr.selected {
background-color: #d1e7dd;
}
.status {
margin-top: 20px;
font-size: 18px;
color: #555;
}
.home-btn {
position: absolute;
top: 20px;
left: 20px;
padding: 10px 20px;
background-color: #6c757d;
color: white;
text-decoration: none;
border-radius: 5px;
}
.home-btn:hover {
background-color: #5a6268;
}
.placeholder-img {
position: absolute;
top: 20px;
right: 20px;
}
.placeholder-img img {
top: 20px;
width: 70px;
height: 70px;
}
.header-img {
margin-top: 20px; /* Adjust the margin as needed */
margin-bottom: 30px;
width: auto;
height: 80px; /* Adjust the height as needed */
position: absolute;
left: 30px;
top: 60px
}
</style>
</head>
<body>
<div id="navbar"></div>
<script>
fetch('/static/html/nav.html')
.then(response => response.text())
.then(data => {
document.getElementById('navbar').innerHTML = data;
});
</script>
<div class="content-wrapper">
<div class="content">
<h1>WiFi Internet Access</h1>
<img src="/static/images/internet_icon.png" alt="internet" class="header-img">
<label id="label-status">Status:</label>
<div class="button-container">
<button class="btn" onclick="scanWifi()">Scan</button>
<button class="btn" onclick="cancelScan()">Cancel</button>
<button class="btn" onclick="forgetAll()">Forget All</button>
<button class="btn" onclick="testInternet()">Test Internet</button>
</div>
<div class="scan-container">
<div id="scanStatus" class="status"></div>
</div>
<div class="network-list">
<table id="networksTable">
<thead>
<tr>
<th>SSID</th>
<th>Freq</th>
<th>Signal</th>
</tr>
</thead>
<tbody>
<!-- List of networks will be appended here -->
</tbody>
</table>
</div>
<div class="connect-container">
<button class="btn" onclick="connectToNetwork()">Connect</button>
</div>
<div class="status" id="connectionStatus"></div>
</div>
</div>
<script>
window.onload = function() { OnPageLoad(); };
function scanWifi() {
console.log("Starting WiFi scan...");
document.getElementById('scanStatus').innerText = "Scanning for networks...";
fetch('/scan_wifi')
.then(response => response.json())
.then(data => {
console.log("Scan complete. Data received:", data);
document.getElementById('scanStatus').innerText = "Scan complete.";
let tableBody = document.getElementById('networksTable').getElementsByTagName('tbody')[0];
tableBody.innerHTML = '';
data.networks.forEach(network => {
let row = tableBody.insertRow();
let cell1 = row.insertCell(0);
let cell2 = row.insertCell(1);
let cell3 = row.insertCell(2);
cell1.textContent = network.ssid;
cell2.textContent = network.Freq;
cell3.textContent = network.signal;
row.addEventListener('click', function() {
const rows = document.querySelectorAll('#networksTable tbody tr');
rows.forEach(r => r.classList.remove('selected'));
row.classList.add('selected');
});
});
})
.catch(error => {
console.error("Error during scan:", error);
document.getElementById('scanStatus').innerText = "Error during scan.";
});
}
function cancelScan() {
console.log("Cancelling scan...");
document.getElementById('scanStatus').innerText = "Scan cancelled.";
}
function connectToNetwork() {
console.log("Attempting to connect to network...");
const table = document.getElementById('networksTable');
const selectedRow = table.querySelector('tbody tr.selected');
if (!selectedRow) {
document.getElementById('connectionStatus').innerText = "Please select a network to connect to.";
return;
}
const ssid = selectedRow.cells[0].textContent;
const password = prompt("Enter the WiFi password for " + ssid + ":");
if (!password) {
document.getElementById('connectionStatus').innerText = "Connection cancelled.";
return;
}
fetch('/connect_wifi', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ ssid: ssid, password: password })
})
.then(response => response.json())
.then(data => {
console.log("Connection attempt result:", data);
document.getElementById('connectionStatus').innerText = data.message;
if (data.success) {
checkInternetAccess();
}
})
.catch(error => {
console.error("Error during connection attempt:", error);
document.getElementById('connectionStatus').innerText = "Error during connection attempt.";
});
}
function checkInternetAccess() {
fetch('/check_internet_access')
.then(response => response.json())
.then(data => {
const statusMessage = data.success ? "Internet Access Ok" : "No Internet Access";
document.getElementById('connectionStatus').innerText = statusMessage;
})
.catch(error => {
console.error("Error checking internet access:", error);
document.getElementById('connectionStatus').innerText = "Error checking internet access.";
});
}
function OnPageLoad(){
requestJsonFromServer('/get-status?param1=wifi-status')
.then(data => {
if (data !== null) {
// expecting: {"msg":"message string"}
console.log("Data received:", data);
document.getElementById('label-status').innerText = data.msg;
} else {
console.log("Failed to retrieve data from the server.");
}
});
}
</script>
</body>
</html>

19
static/html/nav.html Normal file
View File

@ -0,0 +1,19 @@
<nav class="navbar">
<div class="navbar-left">
<img src="/static/images/ata_logo.png" alt="Left Image" class="nav-image">
</div>
<ul>
<li><a href="/"><i class="fas fa-home"></i> Home</a></li>
<li><a href="/printio" target="_blank"><i class="fas fa-print"></i> Printio</a></li>
<li><a href="/internet"><i class="fas fa-globe"></i> Internet</a></li>
<!--<li><a href="#" class="disabled"><i class="fas fa-wifi"></i> Hotspot</a></li>-->
<li>
<a href="#"><i class="fas fa-cog"></i> System</a>
<ul class="submenu">
<!--<li><a href="/static/html/mediaconfig.html"><i class="fas fa-wrench"></i> Config</a></li>-->
<li><a href="/static/html/power.html"><i class="fas fa-power-off"></i> Power</a></li>
<li><a href="/about"><i class="fas fa-info-circle"></i> About</a></li>
</ul>
</li>
</ul>
</nav>

119
static/html/power.html Normal file
View File

@ -0,0 +1,119 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Power Off System</title>
<link rel="icon" type="image/x-icon" href="/static/images/favicon.ico">
<link rel="stylesheet" href="/static/css/styles.css">
<link rel="stylesheet" href="/static/fontawesome/css/all.min.css">
<script src="/static/js/jquery-3.7.1.js"></script>
<style>
.header-img {
margin-top: 30px; /* Adjust the margin as needed */
margin-bottom: 30px;
width: auto;
height: 70px; /* Adjust the height as needed */
}
.center-content {
display: flex;
flex-direction: column;
align-items: center;
}
h1 {
margin-bottom: 5px;
}
label, select, #media-sizes, button {
margin: 5px 0;
text-align: center;
font-size: larger;
font-weight: 200;
}
select {
padding: 3px;
font-size: 1.1em;
width: 250px;
}
#media-sizes ul {
list-style-type: none;
padding: 0;
}
#media-sizes li {
display: flex;
align-items: center;
margin-bottom: 5px;
}
#media-sizes input[type="checkbox"] {
transform: scale(1.5);
margin-right: 12px;
}
#media-sizes span {
font-size: 1.2em;
}
button {
background-color: red;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
font-size: 1.2em;
cursor: pointer;
width: 150px;
margin-bottom: 30px;
}
button:hover {
background-color: darkblue;
}
</style>
</head>
<body>
<div id="navbar"></div>
<script>
fetch('/static/html/nav.html')
.then(response => response.text())
.then(data => {
document.getElementById('navbar').innerHTML = data;
});
</script>
<div class="content-wrapper">
<div class="content center-content">
<h1>Power Options</h1>
<img src="/static/images/switch-icon.png" alt="cards" class="header-img">
<button class="button" id="reboot-button">Reboot</button>
<button class="button" id="shutdown-button">Shutdown</button>
</div>
</div>
<script>
$(document).ready(function() {
$('#reboot-button').click(function() {
$.post('/reboot', function(response) {
alert("Reboot initiated");
}).fail(function() {
alert("Reboot failed");
});
});
$('#shutdown-button').click(function() {
$.post('/shutdown', function(response) {
alert("Shutdown initiated");
}).fail(function() {
alert("Shutdown failed");
});
});
});
</script>
</body>
</html>

23
static/html/status.html Normal file
View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Status</title>
<link rel="stylesheet" href="/static/css/styles.css">
<link rel="stylesheet" href="/static/fontawesome/css/all.min.css">
</head>
<body>
<div id="navbar"></div>
<div class="content">
<h1>Status Page</h1>
</div>
<script>
fetch('/static/html/nav.html')
.then(response => response.text())
.then(data => {
document.getElementById('navbar').innerHTML = data;
});
</script>
</body>
</html>

BIN
static/images/ata_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
static/images/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

1
static/js/crypto-js.min.js vendored Normal file

File diff suppressed because one or more lines are too long

29
static/js/data-request.js Normal file
View File

@ -0,0 +1,29 @@
function requestJsonFromServer(route) {
return fetch(route)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json(); // Assuming the server returns a JSON response
})
.then(jsonData => {
//console.log('Received JSON data:', jsonData);
return jsonData; // Return the JSON data
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
return null; // Return null in case of an error
});
}
/* Example usage
requestJsonFromServer('/get_data')
.then(data => {
if (data !== null) {
console.log("Data received:", data);
// You can process the data here as needed
} else {
console.log("Failed to retrieve data from the server.");
}
});
*/

10716
static/js/jquery-3.7.1.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,77 @@
$(document).ready(function() {
console.log('Document is ready');
var printersData = [];
// Fetch printer data from the server when the page loads
$.get('/get_printers', function(data) {
console.log('Fetched printer data:', data);
printersData = data;
data.forEach(function(printer) {
$('#printers').append(new Option(printer["display-name"], printer["display-name"]));
});
console.log('Printers dropdown populated');
}).fail(function() {
console.error('Failed to fetch printer data');
});
// Handle printer selection change
$('#printers').change(function() {
var selectedPrinter = $(this).val();
console.log('Printer selected:', selectedPrinter);
if (selectedPrinter) {
var printer = printersData.find(p => p["display-name"] === selectedPrinter);
console.log('Selected printer data:', printer);
if (printer) {
var mediaSizesHtml = '<ul>';
printer['media-sizes'].forEach(function(media) {
mediaSizesHtml += '<li>';
mediaSizesHtml += '<input type="checkbox" ' + (media.enabled ? 'checked' : '') + '>';
mediaSizesHtml += '<span>' + media['media-size-display'] + ' - (' + media['capacity'] + ')' + '</span>';
mediaSizesHtml += '</li>';
});
mediaSizesHtml += '</ul>';
$('#media-sizes').html(mediaSizesHtml);
console.log('Media sizes displayed for selected printer');
}
} else {
$('#media-sizes').html('');
console.log('No printer selected, media sizes cleared');
}
});
// Handle save button click
$('#save').click(function() {
var selectedPrinter = $('#printers').val();
console.log('Save button clicked for printer:', selectedPrinter);
if (selectedPrinter) {
var printer = printersData.find(p => p["display-name"] === selectedPrinter);
if (printer) {
printer['media-sizes'] = [];
$('#media-sizes li').each(function() {
var enabled = $(this).find('input').is(':checked');
var mediaSizeDisplay = $(this).find('span').text();
var mediaSize = mediaSizeDisplay.match(/\(([^)]+)\)/)[1]; // Extract media-size from display text
printer['media-sizes'].push({ "enabled": enabled, "media-size": mediaSize, "media-size-display": mediaSizeDisplay });
});
console.log('Updated printer data to be saved:', printersData);
$.ajax({
url: '/save_printers',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(printersData),
success: function(response) {
console.log('Save response:', response);
alert('Changes saved successfully!');
},
error: function() {
console.error('Failed to save changes');
}
});
}
} else {
console.warn('Please select a printer before saving');
alert('Please select a printer.');
}
});
});

72
static/js/printers.js Normal file
View File

@ -0,0 +1,72 @@
$(document).ready(function() {
var printersData = [];
// Fetch printer data from the server when the page loads
$.get('/get_printers', function(data) {
printersData = data;
data.forEach(function(printer) {
$('#printers').append(new Option(printer["display-name"], printer["display-name"]));
});
}).fail(function() {
console.error('Failed to fetch printer data');
});
// Handle printer selection change
$('#printers').change(function() {
var selectedPrinter = $(this).val();
if (selectedPrinter) {
var printer = printersData.find(p => p["display-name"] === selectedPrinter);
if (printer) {
var mediaSizesHtml = '<ul>';
printer['media-sizes'].forEach(function(media) {
mediaSizesHtml += '<li>';
mediaSizesHtml += '<input type="checkbox" ' + (media.enabled ? 'checked' : '') + '>';
mediaSizesHtml += '<span>' + 'Size = ' + media['media-size-display'] + ' - cap = ' + media['capacity'] + '</span>';
mediaSizesHtml += '</li>';
});
mediaSizesHtml += '</ul>';
$('#media-sizes').html(mediaSizesHtml);
}
} else {
$('#media-sizes').html('');
}
});
// Handle checkbox change event
$(document).on('change', '#media-sizes input[type="checkbox"]', function() {
var selectedPrinter = $('#printers').val();
if (selectedPrinter) {
var printer = printersData.find(p => p["display-name"] === selectedPrinter);
if (printer) {
$('#media-sizes li').each(function(index) {
var enabled = $(this).find('input').is(':checked');
printer['media-sizes'][index].enabled = enabled;
});
}
}
});
// Handle save button click
$('#save').click(function() {
var selectedPrinter = $('#printers').val();
if (selectedPrinter) {
var printer = printersData.find(p => p["display-name"] === selectedPrinter);
if (printer) {
$.ajax({
url: '/save_printers',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(printersData),
success: function(response) {
alert('Changes saved successfully!');
},
error: function() {
console.error('Failed to save changes');
}
});
}
} else {
alert('Please select a printer.');
}
});
});

15
systemd/atadash.service Normal file
View File

@ -0,0 +1,15 @@
[Unit]
Description=Gunicorn instance to serve atadash app
After=network.target
[Service]
User=orangepi
Group=www-data
WorkingDirectory=/home/orangepi/atadash/src
Environment="PATH=/home/orangepi/atadash/.venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
ExecStart=/home/orangepi/atadash/.venv/bin/gunicorn --workers 1 --bind unix:/home/orangepi/atadash/src/flaskapp.sock -m 007 wsgi:app
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
[Install]
WantedBy=multi-user.target

11
systemd/command.txt Normal file
View File

@ -0,0 +1,11 @@
# Start atadash service
sudo ln -s /home/orangepi/atadash/systemd/atadash.service /etc/systemd/system/atadash.service
sudo systemctl start atadash
PYTHONPATH=/home/orangepi/atadash/src /home/orangepi/atadash/.venv/bin/gunicorn --workers 1 --bind unix:/home/orangepi/atadash/src/flaskapp.sock -m 007 wsgi:app
#Start OverlayFS Mount service
sudo ln -s /home/orangepi/atadash/systemd/overlayfs_mount.service /etc/systemd/system/overlayfs_mount.service
sudo systemctl start overlayfs_mount

View File

@ -0,0 +1,16 @@
[Unit]
Description=Mount OverlayFS at Boot
DefaultDependencies=no
Before=sysinit.target local-fs.target
Wants=local-fs-pre.target
After=local-fs-pre.target
[Service]
Type=oneshot
ExecStart=/home/orangepi/atadash/bash/overlayfs_mount.sh
RemainAfterExit=true
user=root
Group=root
[Install]
WantedBy=sysinit.target

181
templates/about.html Normal file
View File

@ -0,0 +1,181 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>About Printio</title>
<link rel="icon" type="image/x-icon" href="/static/images/favicon.ico">
<link rel="stylesheet" href="/static/css/styles.css">
<link rel="stylesheet" href="/static/fontawesome/css/all.min.css">
<style>
h1 {
margin-bottom: 20px;
}
label, select, #media-sizes, button {
margin: 5px 0;
text-align: center;
}
select {
padding: 3px;
font-size: 1.1em;
}
#media-sizes ul {
list-style-type: none;
padding: 0;
}
#media-sizes li {
display: flex;
align-items: center;
margin-bottom: 5px;
}
#media-sizes input[type="checkbox"] {
transform: scale(1.5);
margin-right: 12px;
}
#media-sizes span {
font-size: 1.2em;
}
button {
background-color: blue;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
font-size: 1.2em;
cursor: pointer;
}
button:hover {
background-color: darkblue;
}
p {
display: block;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
}
.license-section {
margin-top: 30px;
text-align: center;
}
.license-status {
font-size: 1.1em;
margin-bottom: 15px;
}
.license-input {
margin-top: 10px;
}
.license-input input {
padding: 10px;
width: 200px;
font-size: 1.1em;
margin-right: 10px;
}
.license-input button {
background-color: #4CAF50;
padding: 10px 20px;
font-size: 1.1em;
cursor: pointer;
border-radius: 5px;
border: none;
}
.license-input button:hover {
background-color: #45a049;
}
/* New Styles for Layout */
.content-wrapper {
display: flex;
}
.left-column {
width: 280px;
padding-right: 20px;
box-sizing: border-box;
}
.right-column {
width: 70%;
}
.info-box {
padding: 15px;
margin-bottom: 20px;
border: 1px solid #ccc;
border-radius: 5px;
}
.license-box {
padding: 15px;
border: 1px solid #ccc;
border-radius: 5px;
}
#p {
margin-left: 10px;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
</head>
<body>
<div id="navbar"></div>
<script>
fetch('/static/html/nav.html')
.then(response => response.text())
.then(data => {
document.getElementById('navbar').innerHTML = data;
});
</script>
<div class="content-wrapper">
<div class="left-column">
<div class="info-box">
<h3>System Info</h3>
<p>Version: {{info.software_version}}
<p>CPU %: {{info.cpu}}</p>
<p>CPU T: {{info.cpu_t}}</p>
<p>Disk Size: {{info.disk_size}}</p>
<p>Disk Used: {{info.disk_used}}</p>
<p>RAM Size: {{info.ram_size}}</p>
<p>RAM Used: {{info.ram_used}}</p>
<p>Up Time: {{info.uptime}}</p>
</div>
<div class="license-box">
<h3>License Info </h3>
<p>License: {{info.license}}</p>
<!--p>Image Magic: {{info.image_magic}}</p-->
<!--p>Hashtag: {{info.hash}}</p-->
<!--p>Drop Folder: {{info.drop_folder}}</p-->
</div>
</div>
<div class="right-column">
<h1>About ATA Dash</h1>
<p>
ATA Dash is a simple interface to control your LCD Advertising display.
</p>
<p>
Warning: Unauthorized reproduction or distribution of this product
is strictly prohibited and may result in severe civil and criminal
penalties.
</p>
</div>
</div>
</body>
</html>

283
templates/index.html Normal file
View File

@ -0,0 +1,283 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Media Dashboard</title>
<link rel="icon" type="image/x-icon" href="../static/images/favicon.ico">
<link rel="stylesheet" href="../static/css/styles.css">
<link rel="stylesheet" href="../static/fontawesome/css/all.min.css">
<style>
h1 {
margin-top: 20px;
font-size: 36px;
color: #333;
}
h2 {
margin-top: 2px;
font-size: 24px;
color: #333;
}
.container {
width: 80%;
max-width: 300px;
margin: 20px auto;
padding: 20px;
border: 2px solid #ccc;
border-radius: 10px;
background-color: #ffffffb6;
position: relative;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.form-group input, .form-group select {
width: 100%;
padding: 8px;
font-size: 16px;
box-sizing: border-box;
}
.checkbox-group {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.checkbox-group input {
margin-right: 10px;
}
.button-group {
display: flex;
justify-content: space-around;
margin-top: 20px;
}
.button-group .btn {
padding: 10px 20px;
font-size: 18px;
cursor: pointer;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
text-decoration: none;
}
.button-group .btn:hover {
background-color: #0056b3;
}
.status {
margin-top: 10px;
font-size: 16px;
color: #555;
}
.side-img {
position: absolute;
top: 80px;
left: 0;
width: 230px; /* Set desired width */
height: auto; /* Adjust height automatically to maintain aspect ratio */
z-index: -1; /* Ensure image is behind other content */
}
.input-label{
text-align: left;
}
.form-group textarea {
width: 100%;
padding: 8px;
font-size: 16px;
box-sizing: border-box;
resize: none; /* Prevents the user from resizing the textarea */
overflow-wrap: break-word; /* Ensures that long URLs wrap to the next line */
white-space: pre-wrap; /* Preserves whitespace and wraps text as necessary */
}
</style>
</head>
<body>
<div id="navbar"></div>
<script>
fetch('/static/html/nav.html')
.then(response => response.text())
.then(data => {
document.getElementById('navbar').innerHTML = data;
});
</script>
<div class="background-image"></div>
<!--<div><img src="/static/images/helio-posh.png" alt="Helio Posh" class="side-img"></div>-->
<div class="content-wrapper">
<div class="content">
<div>
<img src="/static/images/helio-posh.png" alt="Helio Posh" class="side-img">
</div>
<h1>Media Dashboard</h1>
<div class="container">
<h2>Playlist Loop</h2>
<div class="checkbox-group">
<input type="checkbox" id="autoPlayAtBoot" name="autoPlayAtBoot" checked>
<label for="autoPlayAtBoot">Autostart @Boot</label>
</div>
<div class="form-group">
<label class="input-label" for="mediaLocation">Media Sources:</label>
<select id="mediaLocation" name="mediaLocation">
<option value="USB">No Media Available</option>
</select>
</div>
<div class="form-group">
<label class="input-label" for="imageDuration">Image Duration in Secs:</label>
<input type="number" id="imageDuration" name="imageDuration" min="1" max="60">
</div>
<div class="button-group">
<button class="btn" onclick="startMediaLoop()">Start</button>
<button class="btn" onclick="stopMediaLoop()">Stop</button>
</div>
<div class="status" id="mediaLoopStatus">status</div>
</div>
<div class="container">
<h2>Web Gallery</h2>
<div class="checkbox-group">
<input type="checkbox" id="autoStart" name="autoStart" checked>
<label for="autoStart">Autostart</label>
</div>
<div class="form-group">
<button class="btn" onclick="clearURL()">Clear</button>
<label class="input-label" for="galleryURL">URL:</label>
<textarea id="galleryURL" name="galleryURL" rows="3"></textarea>
</div>
<div class="button-group">
<button class="btn" onclick="startWebGallery()">Start</button>
<button class="btn" onclick="stopWebGallery()">Stop</button>
</div>
<div class="status" id="webGalleryStatus">status</div>
</div>
</div>
</div>
<script>
function loadMediaSources() {
fetch('../get_media_sources')
.then(response => response.json())
.then(data => {
media_sources = data.folders; // Access the "folders" array in the JSON
const mediaLocationSelect = document.getElementById('mediaLocation');
// Clear any existing options
while (mediaLocationSelect.options.length > 0) {
mediaLocationSelect.remove(0);
}
// Add new options
media_sources.forEach(media => {
var option = document.createElement('option');
option.text = media.folder_name_display;
option.value = media.folder_path;
mediaLocationSelect.add(option);
});
})
.catch(error => {
console.error("Error loading media sources:", error);
});
}
function loadLastUsedData() {
fetch('../get_screen_settings')
.then(response => response.json())
.then(data => {
console.info(data)
document.getElementById('autoPlayAtBoot').checked = data.autoPlayAtBoot || true;
document.getElementById('imageDuration').value = data.imageDuration || 5;
document.getElementById('autoStart').checked = data.autoStart || true;
document.getElementById('galleryURL').value = data.url || 'google.com';
})
.catch(error => {
console.error("Error loading screen settings:", error);
});
}
function startMediaLoop() {
const mediaLocation = document.getElementById('mediaLocation').value;
const imageDuration = document.getElementById('imageDuration').value;
const autoPlayAtBoot = document.getElementById('autoPlayAtBoot').checked;
fetch('../start_media_loop', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ mediaLocation: mediaLocation, imageDuration: imageDuration , autoPlayAtBoot: autoPlayAtBoot})
})
.then(response => response.json())
.then(data => {
document.getElementById('mediaLoopStatus').innerText = data.message;
})
.catch(error => {
console.error("Error during start media loop:", error);
document.getElementById('mediaLoopStatus').innerText = "Error during start media loop.";
});
}
function stopMediaLoop() {
fetch('../stop_media_loop', {
method: 'POST'
})
.then(response => response.json())
.then(data => {
document.getElementById('mediaLoopStatus').innerText = data.message;
})
.catch(error => {
console.error("Error during stop media loop:", error);
document.getElementById('mediaLoopStatus').innerText = "Error during stop media loop.";
});
}
function startWebGallery() {
const autoStart = document.getElementById('autoStart').checked;
const url = document.getElementById('galleryURL').value
fetch('../start_web_gallery', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ url: url, autoStart: autoStart })
})
.then(response => response.json())
.then(data => {
document.getElementById('webGalleryStatus').innerText = data.message;
})
.catch(error => {
console.error("Error during start web gallery:", error);
document.getElementById('webGalleryStatus').innerText = "Error during start web gallery.";
});
}
function stopWebGallery() {
fetch('../stop_web_gallery', {
method: 'POST'
})
.then(response => response.json())
.then(data => {
document.getElementById('webGalleryStatus').innerText = data.message;
})
.catch(error => {
console.error("Error during stop web gallery:", error);
document.getElementById('webGalleryStatus').innerText = "Error during stop web gallery.";
});
}
function clearURL() {
document.getElementById('galleryURL').value = '';
}
document.addEventListener('DOMContentLoaded', loadLastUsedData);
// Call the function to load media sources when the page loads
window.onload = loadMediaSources;
</script>
</body>
</html>

307
templates/internet.html Normal file
View File

@ -0,0 +1,307 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WiFi Configuration</title>
<link rel="icon" type="image/x-icon" href="/static/images/favicon.ico">
<link rel="stylesheet" href="/static/css/styles.css">
<link rel="stylesheet" href="/static/fontawesome/css/all.min.css">
<style>
h1 {
margin-top: 30px;
font-size: 36px;
color: #333;
}
.button-container {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20px;
}
.btn {
padding: 10px 20px;
font-size: 1.2em;
cursor: pointer;
background-color: blue;
color: white;
width: 150px;
border-radius: 5px;
border: none;
text-decoration: none;
}
.btn:hover {
background-color: #0056b3;
}
.small-btn {
width: 100px;
padding: 5px 10px;
font-size: 0.8em;
background-color: darkslateblue;
}
.small-btn-container {
margin-left: auto;
}
.scan-container {
margin-top: 20px;
}
.scan-container .btn {
background-color: #28a745;
}
.scan-container .btn:hover {
background-color: #218838;
}
.connect-container {
margin-top: 20px;
}
.connect-container .btn {
padding: 5px 15px;
border-radius: 5px;
background-color: #ffc107;
}
.connect-container .btn:hover {
background-color: #e0a800;
}
.network-list {
margin-top: 20px;
width: 100%;
max-height: 200px;
overflow-y: auto;
border: 1px solid #ccc;
background-color: white;
box-sizing: border-box;
}
.network-list table {
width: 100%;
border-collapse: collapse;
table-layout: auto;
box-sizing: border-box;
}
.network-list th, .network-list td {
padding: 8px;
text-align: left;
border-bottom: 1px solid #ddd;
white-space: nowrap;
box-sizing: border-box;
}
.network-list th {
background-color: #f2f2f2;
}
.network-list tr.selected {
background-color: #d1e7dd;
}
.status {
margin-top: 20px;
font-size: 18px;
color: #555;
}
.home-btn {
position: absolute;
top: 20px;
left: 20px;
padding: 10px 20px;
background-color: #6c757d;
color: white;
text-decoration: none;
border-radius: 5px;
}
.home-btn:hover {
background-color: #5a6268;
}
.placeholder-img {
position: absolute;
top: 20px;
right: 20px;
}
.placeholder-img img {
top: 20px;
width: 70px;
height: 70px;
}
.header-img {
margin-top: 20px; /* Adjust the margin as needed */
margin-bottom: 30px;
width: auto;
height: 80px; /* Adjust the height as needed */
position: absolute;
left: 30px;
top: 60px;
}
</style>
</head>
<body>
<div id="navbar"></div>
<script>
fetch('/static/html/nav.html')
.then(response => response.text())
.then(data => {
document.getElementById('navbar').innerHTML = data;
});
</script>
<div class="content-wrapper">
<div class="content">
<h1>WiFi Internet Access</h1>
<img src="/static/images/internet_icon.png" alt="internet" class="header-img">
<label id="label-status">Status:</label>
<div class="button-container">
<button class="btn" id="scanButton" onclick="scanWifi()">Scan</button>
<div class="small-btn-container">
<button class="btn small-btn" id="forgetButton" onclick="checkForgetNetworks()">Forget all</button>
<button class="btn small-btn" id="testButton" onclick="checkInternetAccess()">Test Internet</button>
</div>
</div>
<div class="scan-container">
<div id="scanStatus" class="status"></div>
</div>
<div class="network-list">
<table id="networksTable">
<thead>
<tr>
<th>SSID</th>
<th>Freq</th>
<th>Signal</th>
<th>Bssid</th>
</tr>
</thead>
<tbody>
<!-- List of networks will be appended here -->
</tbody>
</table>
</div>
<div class="connect-container">
<button class="btn" id="connectToNetworkButton"onclick="connectToNetwork()">Connect</button>
</div>
<div class="status" id="connectionStatus"></div>
</div>
</div>
<script>
window.onload = function() { OnPageLoad(); };
function scanWifi() {
console.log("Starting WiFi scan...");
document.getElementById('connectionStatus').innerText = ""
document.getElementById('scanStatus').innerText = "Scanning for networks...";
fetch('/wifi_scan')
.then(response => response.json())
.then(data => {
console.log("Scan complete. Data received:", data);
document.getElementById('scanStatus').innerText = "Scan complete.";
let tableBody = document.getElementById('networksTable').getElementsByTagName('tbody')[0];
tableBody.innerHTML = '';
data.networks.forEach(network => {
let row = tableBody.insertRow();
let cell1 = row.insertCell(0);
let cell2 = row.insertCell(1);
let cell3 = row.insertCell(2);
let cell4 = row.insertCell(3);
cell1.textContent = network.ssid || '';
cell2.textContent = network.Freq || '';
cell3.textContent = network.signal || '';
cell4.textContent = network.bssid || '';
row.addEventListener('click', function() {
const rows = document.querySelectorAll('#networksTable tbody tr');
rows.forEach(r => r.classList.remove('selected'));
row.classList.add('selected');
});
});
})
.catch(error => {
console.error("Error during scan:", error);
document.getElementById('scanStatus').innerText = "Error during scan.";
});
}
function connectToNetwork() {
console.log("Attempting to connect to network...");
const table = document.getElementById('networksTable');
const selectedRow = table.querySelector('tbody tr.selected');
if (!selectedRow) {
document.getElementById('connectionStatus').innerText = "Please select a network to connect to.";
return;
}
const ssid = selectedRow.cells[0].textContent;
const bssid = selectedRow.cells[3].textContent;
const password = prompt("Enter the WiFi password for " + ssid + ":");
if (!password) {
document.getElementById('connectionStatus').innerText = "Connection cancelled.";
return;
}
document.getElementById('connectionStatus').innerText = "Please wait...";
document.getElementById('connectToNetworkButton').disabled = true;
document.getElementById('scanButton').disabled = true;
document.getElementById('testButton').disabled = true;
document.getElementById('forgetButton').disabled = true;
fetch('/wifi_connect', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ ssid: ssid, bssid: bssid, password: password })
})
.then(response => response.json())
.then(data => {
console.log("Connection attempt result:", data);
document.getElementById('connectionStatus').innerText = data.message;
checkWifiStatus();
})
.catch(error => {
console.error("Error during connection attempt:", error);
document.getElementById('connectionStatus').innerText = "Error during connection attempt.";
})
.finally(() => {
// Re-enable buttons after the connection attempt
document.getElementById('connectToNetworkButton').disabled = false;
document.getElementById('scanButton').disabled = false;
document.getElementById('testButton').disabled = false;
document.getElementById('forgetButton').disabled = false;
});
}
function checkInternetAccess() {
fetch('/wifi_test')
.then(response => response.json())
.then(data => {
const statusMessage = data.success ? "Internet Access Ok" : "No Internet Access";
alert(statusMessage); // Display message in a popup
})
.catch(error => {
console.error("Error checking internet access:", error);
alert("Error checking internet access."); // Display error in a popup
});
}
function checkForgetNetworks() {
fetch('/wifi_forget')
.then(response => response.json())
.then(data => {
const statusMessage = data.success ? "All networks forgotten" : "Nothing happened";
alert(statusMessage); // Display message in a popup
})
.catch(error => {
console.error("Error forgetting networks:", error);
alert("Error forgetting networks."); // Display error in a popup
});
}
function checkWifiStatus() {
fetch('/wifi_status')
.then(response => response.json())
.then(data => {
console.log("Data received:", data);
document.getElementById('label-status').innerText = "Status: " + data.msg;
})
.catch(error => {
console.error("Error getting wifi status:", error);
document.getElementById('label-status').innerText = "Status: ...";
});
}
function OnPageLoad(){
checkWifiStatus();
}
</script>
</body>
</html>

234
templates/wifi.html Normal file
View File

@ -0,0 +1,234 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WiFi Configuration</title>
<link rel="icon" type="image/x-icon" href="/static/images/favicon.ico">
<style>
body {
font-family: Arial, sans-serif;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
min-height: 50vh;
margin: 0;
background-color: #f0f0f0;
}
h1 {
margin-top: 30px;
font-size: 36px;
color: #333;
}
.button-container {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 20px;
}
.button-container .btn {
padding: 10px 20px;
font-size: 18px;
cursor: pointer;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
text-decoration: none;
}
.button-container .btn:hover {
background-color: #0056b3;
}
.scan-container {
margin-top: 20px;
}
.scan-container .btn {
background-color: #28a745;
}
.scan-container .btn:hover {
background-color: #218838;
}
.connect-container {
margin-top: 20px;
}
.connect-container .btn {
background-color: #ffc107;
}
.connect-container .btn:hover {
background-color: #e0a800;
}
.network-list {
margin-top: 20px;
width: 80%;
max-height: 200px;
overflow-y: auto;
border: 1px solid #ccc;
background-color: white;
}
.network-list table {
width: 100%;
border-collapse: collapse;
table-layout: auto;
}
.network-list th, .network-list td {
padding: 8px;
text-align: left;
border-bottom: 1px solid #ddd;
white-space: nowrap;
}
.network-list th {
background-color: #f2f2f2;
}
.network-list tr.selected {
background-color: #d1e7dd;
}
.status {
margin-top: 20px;
font-size: 18px;
color: #555;
}
.home-btn {
position: absolute;
top: 20px;
left: 20px;
padding: 10px 20px;
background-color: #6c757d;
color: white;
text-decoration: none;
border-radius: 5px;
}
.home-btn:hover {
background-color: #5a6268;
}
.placeholder-img {
position: absolute;
top: 20px;
right: 20px;
}
.placeholder-img img {
top: 20px;
width: 70px;
height: 70px;
}
</style>
</head>
<body>
<a href="/" class="home-btn">Home</a>
<div class="placeholder-img">
<img src="/static/images/atalogo.png">
</div>
<h1>WiFi Connection</h1>
<div class="button-container">
<button class="btn" onclick="scanWifi()">Scan for Networks</button>
<button class="btn" onclick="cancelScan()">Cancel</button>
</div>
<div class="scan-container">
<div id="scanStatus" class="status"></div>
</div>
<div class="network-list">
<table id="networksTable">
<thead>
<tr>
<th>SSID</th>
<th>Freq</th>
<th>Signal</th>
</tr>
</thead>
<tbody>
<!-- List of networks will be appended here -->
</tbody>
</table>
</div>
<div class="connect-container">
<button class="btn" onclick="connectToNetwork()">Connect</button>
</div>
<div class="status" id="connectionStatus"></div>
<script>
function scanWifi() {
console.log("Starting WiFi scan...");
document.getElementById('scanStatus').innerText = "Scanning for networks...";
fetch('/scan_wifi')
.then(response => response.json())
.then(data => {
console.log("Scan complete. Data received:", data);
document.getElementById('scanStatus').innerText = "Scan complete.";
let tableBody = document.getElementById('networksTable').getElementsByTagName('tbody')[0];
tableBody.innerHTML = '';
data.networks.forEach(network => {
let row = tableBody.insertRow();
let cell1 = row.insertCell(0);
let cell2 = row.insertCell(1);
let cell3 = row.insertCell(2);
cell1.textContent = network.ssid;
cell2.textContent = network.Freq;
cell3.textContent = network.signal;
row.addEventListener('click', function() {
const rows = document.querySelectorAll('#networksTable tbody tr');
rows.forEach(r => r.classList.remove('selected'));
row.classList.add('selected');
});
});
})
.catch(error => {
console.error("Error during scan:", error);
document.getElementById('scanStatus').innerText = "Error during scan.";
});
}
function cancelScan() {
console.log("Cancelling scan...");
document.getElementById('scanStatus').innerText = "Scan cancelled.";
}
function connectToNetwork() {
console.log("Attempting to connect to network...");
const table = document.getElementById('networksTable');
const selectedRow = table.querySelector('tbody tr.selected');
if (!selectedRow) {
document.getElementById('connectionStatus').innerText = "Please select a network to connect to.";
return;
}
const ssid = selectedRow.cells[0].textContent;
const password = prompt("Enter the WiFi password for " + ssid + ":");
if (!password) {
document.getElementById('connectionStatus').innerText = "Connection cancelled.";
return;
}
fetch('/connect_wifi', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ ssid: ssid, password: password })
})
.then(response => response.json())
.then(data => {
console.log("Connection attempt result:", data);
document.getElementById('connectionStatus').innerText = data.message;
if (data.success) {
checkInternetAccess();
}
})
.catch(error => {
console.error("Error during connection attempt:", error);
document.getElementById('connectionStatus').innerText = "Error during connection attempt.";
});
}
function checkInternetAccess() {
fetch('/check_internet_access')
.then(response => response.json())
.then(data => {
const statusMessage = data.success ? "Internet Access Ok" : "No Internet Access";
document.getElementById('connectionStatus').innerText = statusMessage;
})
.catch(error => {
console.error("Error checking internet access:", error);
document.getElementById('connectionStatus').innerText = "Error checking internet access.";
});
}
</script>
</body>
</html>

20
update_atadash.sh Normal file
View File

@ -0,0 +1,20 @@
#!/bin/bash
source /home/orangepi/atadash/.venv/bin/activate
# Stop the services
echo "atadash stopping..."
sudo systemctl stop atadash
echo ""
# Use rsync to copy files if they are different
rsync -avv --progress /home/orangepi/atadash_master/static/ /home/orangepi/atadash/static/
rsync -avv --progress /home/orangepi/atadash_master/templates/ /home/orangepi/atadash/templates/
rsync -avv --progress /home/orangepi/atadash_master/data/ /home/orangepi/atadash/data/
# Use pyarmor to protect Python scripts in the printio directory
pyarmor gen -O /home/orangepi/atadash/src/ /home/orangepi/atadash_master/src/*.py
# Start the services back up
echo ""
sudo systemctl start atadash
echo "atadash restarted..."