From ff55e9ddb0311e08a7a24bb169b2766cc1c4f8eb Mon Sep 17 00:00:00 2001 From: jimmy Date: Fri, 19 Sep 2025 23:29:17 +1200 Subject: [PATCH] Update project files and add development dependencies - Updated boot.py, main.py, settings.py with latest changes - Updated web interface files (main.css, main.js, index.html) - Updated web.py and wifi.py with improvements - Added Pipfile and Pipfile.lock for Python dependency management - Added p2p.py for peer-to-peer functionality - Added web (1).py backup file --- Pipfile | 13 ++ Pipfile.lock | 470 +++++++++++++++++++++++++++++++++++++++ src/boot.py | 20 +- src/main.py | 68 ++++-- src/p2p.py | 20 ++ src/settings.py | 74 +++++- src/static/main.css | 182 +++++++++------ src/static/main.js | 297 ++++++++++++++++--------- src/templates/index.html | 157 ++++++++++--- src/web (1).py | 43 ++++ src/web.py | 4 +- src/wifi.py | 29 +-- 12 files changed, 1100 insertions(+), 277 deletions(-) create mode 100644 Pipfile create mode 100644 Pipfile.lock create mode 100644 src/p2p.py create mode 100644 src/web (1).py diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..a8b13fe --- /dev/null +++ b/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +esptool = "*" +mpremote = "*" + +[dev-packages] + +[requires] +python_version = "3.12" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..51c534a --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,470 @@ +{ + "_meta": { + "hash": { + "sha256": "4cd5ca9be4f69340ea0ed740b1fd86d155de8e4b40efa538af17ae4e1b34334d" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.12" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "bitarray": { + "hashes": [ + "sha256:002b73bf4a9f7b3ecb02260bd4dd332a6ee4d7f74ee9779a1ef342a36244d0cf", + "sha256:01e3ba46c2dee6d47a4ab22561a01d8ee6772f681defc9fcb357097a055e48cf", + "sha256:03dc877ec286b7f2813185ea6bc5f1f5527fd859e61038d38768883b134e06b3", + "sha256:03eeab48f376c3cd988add2b75c20d2d084b6fcc9a164adb0dc390ef152255b4", + "sha256:05ee46a734b5110c5ac483815da4379f7622f4316362872ec7c0ed16db4b0148", + "sha256:0751596f60f33df66245b2dafa3f7fbe13cb7ac91dd14ead87d8c2eec57cb3ed", + "sha256:08c114cf02a63e13ce6d70bc5b9e7bdcfa8d5db17cece207cfa085c4bc4a7a0c", + "sha256:0ed4a87eda16e2f95d536152c5acccae07841fbdda3b9a752f3dbf43e39f4d6b", + "sha256:101230b8074919970433ef79866570989157ade3421246d4c3afb7a994fdc614", + "sha256:11fcfdf272549a3d876f10d8422bcd5f675750aa746ce04ff04937ec3bb2329e", + "sha256:160f449bb91686f8fc9984200e78b8d793b79e382decf7eb1dc9948d7c21b36f", + "sha256:16426a843b1bc9c552a7c97d6d7555e69730c2de1e2f560503d3fc0e7f6d8005", + "sha256:1f1575cc0f66aa70a0bb5cb57c8d9d1b7d541d920455169c6266919bf804dc20", + "sha256:1f7a8fc5085450635a539c47c9fce6d441b4a973686f88fc220aa20e3921fe55", + "sha256:1fb0a46ae4b8d244a3fb80c3055717baa3dec6be17938e6871042a8d5b4ce670", + "sha256:2965fd8ba31b04c42e4b696fad509dc5ab50663efca6eb06bb3b6d08587f3a09", + "sha256:2b524306104c1296f1e91d74ee4ccbeeea621f6a13e44addf0bb630a1839fd72", + "sha256:2db04b165a57499fbcfe0eaa2f7752f118552bbcfab2163a43fef8d95f4ae745", + "sha256:3092f6bbf4a75b1e6f14a5b1030e27c435f341afeb23987115e45a25cc68ba91", + "sha256:30a2fc37698820cbf9b51d5f801219ef4bed828a04f3307072b8f983dc422a0e", + "sha256:3110b98c5dfb31dc1cf82d8b0c32e3fa6d6d0b268ff9f2a1599165770c1af80f", + "sha256:33f604bffd06b170637f8a48ddcf42074ed1e1980366ac46058e065ce04bfe2a", + "sha256:340c524c7c934b61d1985d805bffe7609180fb5d16ece6ce89b51aa535b936f2", + "sha256:37a6a8382864a1defb5b370b66a635e04358c7334054457bbbb8645610cd95b2", + "sha256:3875578748b484638f6ea776f534e9088cfb15eee131aac051036cba40fd5d05", + "sha256:38b0261483c59bb39ae9300ad46bf0bbf431ab604266382d986a349c96171b36", + "sha256:3b9a2eb7d2e0e9c2f25256d2663c0a2a4798fe3110e3ddbbb1a7b71740b4de08", + "sha256:3bb3cf22c3c03ae698647e6766314149c9cf04aa2018d9f48d5efddc3ced2764", + "sha256:3db0648536f3e08afa7ceb928153c39913f98fd50a5c3adf92a4d0d4268f213e", + "sha256:3dc654da62b3a3027b7c922f7e9f4b27feaabd5d38b2a98ea98de5e8107c72f2", + "sha256:4079857566077f290d35e23ff0e8ba593069c139ae85b0d152b9fa476494f50a", + "sha256:44f468fb4857fff86c65bec5e2fb67067789e40dad69258e9bb78fc6a6df49e7", + "sha256:45660e2fabcdc1bab9699a468b312f47956300d41d6a2ea91c8f067572aaf38a", + "sha256:477b9456eb7d70f385dc8f097a1d66ee40771b62e47b3b3e33406dcfbc1c6a3b", + "sha256:481239cd0966f965c2b8fa78b88614be5f12a64e7773bb5feecc567d39bb2dd5", + "sha256:4a83d247420b147d4b3cba0335e484365e117dc1cfe5ab35acd6a0817ad9244f", + "sha256:53d2abeabb91a822e9d76420c9b44980edd2d6b21767c7bb9cb2b1b4cf091049", + "sha256:55c31bc3d2c9e48741c812ee5ce4607c6f33e33f339831c214d923ffc7777d21", + "sha256:567d6891cb1ddbfd0051fcff3cb1bb86efc82ec818d9c5f98c37d59c1d23cc96", + "sha256:57b9df5d38ab49c13eaa9e0152fdfa8501fc23987f6dcf421b73484bfe573918", + "sha256:59ddb8a9f47ec807009c69e582d0de1c86c005f9f614557f4cebc7b8ac9b7d28", + "sha256:61b9f3cf3a55322baed8f0532b73bce77d688a01446c179392c4056ab74eb551", + "sha256:639389b023315596e0293f85999645f47ec3dc28c892e51242dde6176c91486b", + "sha256:64d1143e90299ba8c967324840912a63a903494b1870a52f6675bda53dc332f7", + "sha256:6542e1cfe060badd160cd383ad93a84871595c14bb05fb8129f963248affd946", + "sha256:69687ef16d501c9217675af36fa3c68c009c03e184b07d22ba245e5c01d47e6b", + "sha256:6f7e1cdf0abb11718e655bb258920453b1e89c2315e9019f60f0775704b12a8c", + "sha256:7378055c9f456c5bb034ac313d9a9028fc6597619a0b16584099adba5a589fdb", + "sha256:78103afbd0a94ac4c1f0b4014545fd149b968d5ea423aaa3b1f6e2c3fc19423e", + "sha256:79038bf1a7b13d243e51f4b6909c6997c2ba2bffc45bcae264704308a2d17198", + "sha256:795b1760418ab750826420ae24f06f392c08e21dc234f0a369a69cc00444f8ec", + "sha256:7998dfb1e9e0255fb8553abb019c3e7f558925de4edc8604243775ff9dd3898d", + "sha256:7afc740ad45ee0e0cef055765faf64789c2c183eb4aa3ecb8cecdb4b607396b3", + "sha256:7b4a41dc183d7d16750634f65566205990f94144755a39f33da44c0350c3e1a8", + "sha256:7f825ebedcad87a2825ddb6cf62f6d7d5b7a56ddaf7c93eef4b974e7ddc16408", + "sha256:7f9f9bb2c5cc1f679605ebbeb72f46fc395d850b93fa7de7addd502a1dc66e99", + "sha256:7fdf059d4e3acec44f512ebe247718ae511fde632e2b06992022df8e637385a6", + "sha256:81e4648c09103bc18f488957c1e0863d2397bab6625c0e6771891f151ee0bd96", + "sha256:8489bff00a1f81ac0754355772e76775878c32a42f16f01d427c3645546761c4", + "sha256:851398428f5604c53371b72c5e0a28163274264ada4a08cd1eafe65fde1f68d0", + "sha256:87a29b8a4cc72af6118954592dcd4e49223420470ccc3f8091c255f6c7330bb1", + "sha256:8b8e07374d60040b24d1a158895d9758424db13be63d4b2fe1870e37f9dec009", + "sha256:8d4aa56782368269eb9402caf7378b2a5ada6f05eb9c7edc2362be258973fd7e", + "sha256:97c448a20aded59727261468873d9b11dfdcce5a6338a359135667d5e3f1d070", + "sha256:98373c273e01a5a7c17103ecb617de7c9980b7608351d58c72198e3525f0002e", + "sha256:98e4a17f55f3cbf6fe06cc79234269572f234467c8355b6758eb252073f78e6b", + "sha256:99124e39658b2f72d296819ec03418609dd4f1b275b00289c2f278a19da6f9c0", + "sha256:9ad0df7886cb9d6d2ff75e87d323108a0e32bdca5c9918071681864129ce8ea8", + "sha256:9bfdfe2e2af434d3f4e47250f693657334e34a7ec557cd703b129a814422b4b8", + "sha256:9faa4c6fcb19a31240ad389426699a99df481b6576f7286471e24efbf1b44dfc", + "sha256:a048e41e1cb0c1a37021269d02698e30d2a7cc9a0205dd3390e0807745b76dae", + "sha256:a05982bb49c73463cb0f0f4bed2d8da82631708a2c2d1926107ba99651b419ec", + "sha256:a23b5f13f9b292004e94b0b13fead4dae79c7512db04dc817ff2c2478298e04a", + "sha256:a393b0f881eff94440f72846a6f0f95b983594a0a50af81c41ed18107420d6a7", + "sha256:a3b6bd81c77d9925809b714980cd30b1831a86bd090316d37cab124d92af1daf", + "sha256:a43f4631ecb87bedc510568fef67db53f2a20c4a5953a9d1e07457e7b1d14911", + "sha256:a569c993942ac26c6c590639ed6712c6c9c3f0c8d287a067bf2a60eb615f3c6b", + "sha256:a5b89349f05431270d1ccc7321aaab91c42ff33f463868779e502438b7f0e668", + "sha256:ac39319e6322c2c093a660c02cea6bb3b1ae53d049b573d4781df8896e443e04", + "sha256:acc56700963f63307ac096689d4547e8061028a66bb78b90e42c5da2898898fb", + "sha256:b723f9d10f7d8259f010b87fa66e924bb4d67927d9dcff4526a755e9ee84fef4", + "sha256:b99a0347bc6131046c19e056a113daa34d7df99f1f45510161bc78bc8461a470", + "sha256:bc0880011b86f81c5353ce4abaeb2472d942ba2320985166a2a3dd4f783563a9", + "sha256:be2f40045432e8aa33d9fd5cb43c91b0c61d77d3d8810f88e84e2e46411c27a7", + "sha256:bebb17125373c499beea009cc5bced757bde52bcb3fa1d6335650e6c2d8111d7", + "sha256:befac6644c6f304a1b6a7948a04095682849c426cebcc44cb2459aa92d3e1735", + "sha256:c1f4880bcb6fb7a8e2ab89128032b3dcf59e1e877ff4493b11c8bf7c3a5b3df2", + "sha256:c3e014f7295b9327fa6f0b3e55a3fd485abac98be145b9597e0cdbb05c44ad07", + "sha256:c427dfcce13a8c814556dfe7c110b8ef61b8fab5fca0d856d4890856807321dc", + "sha256:c44cf0059633470c6bb415091def546adbeb5dcfa91cc3fcb1ac16593f14e52a", + "sha256:c4e04c12f507942f1ddf215cb3a08c244d24051cdd2ba571060166ce8a92be16", + "sha256:c65257899bb8faf6a111297b4ff0066324a6b901318582c0453a01422c3bcd5a", + "sha256:c6c48cf5a92244ef3df4161c8625ee1890bb3d931db9a9f3b699e61a037cd58a", + "sha256:c9bf2bf29854f165a47917b8782b6cf3a7d602971bf454806208d0cbb96f797a", + "sha256:ca4b6298c89b92d6b0a67dfc5f98d68ae92b08101d227263ef2033b9c9a03a72", + "sha256:cc76ad7453816318d794248fba4032967eaffd992d76e5d1af10ef9d46589770", + "sha256:cd7f6bfa2a36fb91b7dec9ddf905716f2ed0c3675d2b63c69b7530c9d211e715", + "sha256:d12c45da97b2f31d0233e15f8d68731cfa86264c9f04b2669b9fdf46aaf68e1f", + "sha256:d160173efdad8a57c22e422a034196df3d84753672c497aee2f94bd5b128f8dd", + "sha256:d2b1ed363a4ef5622dccbf7822f01b51195062c4f382b28c9bd125d046d0324c", + "sha256:d30e7daaf228e3d69cdd8b02c0dd4199cec034c4b93c80109f56f4675a6db957", + "sha256:d3f38373d9b2629dedc559e647010541cc4ec4ad9bea560e2eb1017e6a00d9ef", + "sha256:d7e274ac1975e55ebfb8166cce27e13dc99120c1d6ce9e490d7a716b9be9abb5", + "sha256:d877759842ff9eb16d9c2b8b497953a7d994d4b231c171515f0bf3a2ae185c0c", + "sha256:da3dfd2776226e15d3288a3a24c7975f9ee160ba198f2efa66bc28c5ba76d792", + "sha256:db0441e80773d747a1ed9edfb9f75e7acb68ce8627583bbb6f770b7ec49f0064", + "sha256:dbbaa147cf28b3e87738c624d390a3a9e2a5dfef4316f4c38b4ecaf3155a3eab", + "sha256:ddc646cec4899a137c134b13818469e4178a251d77f9f4b23229267e3da78cfb", + "sha256:df7cc9584614f495f474a5ded365cf72decbcee4efcdc888d2943f8a794c789e", + "sha256:dfde50ae55e075dcd5801e2c3ea0e749c849ed2cbbee991af0f97f1bdbadb2a6", + "sha256:e15e70a3cf5bb519e2448524d689c02ff6bcd4750587a517e2bffee06065bf27", + "sha256:e3572889fcb87e5ca94add412d8b365dbb7b59773a4362e52caa556e5fd98643", + "sha256:e39f5e85e1e3d7d84ac2217cd095b3678306c979e991532df47012880e02215d", + "sha256:e501bd27c795105aaba02b5212ecd1bb552ca2ee2ede53e5a8cb74deee0e2052", + "sha256:e62892645f6a214eefb58a42c3ed2501af2e40a797844e0e09ec1e400ce75f3d", + "sha256:e75eb1734046291c554d9addecca9a8785bdf5d53a64f525569f8549da863dde", + "sha256:e84cff8e8fe71903a6cf873fb3c8731df8bd7c1dac878e7a0fe19d8e2ef39aa9", + "sha256:ea60cf85b4e5a78b5a41eed3a65abc3839a50d915c6e0f6966cbcf81b85991bd", + "sha256:ec3fd30622180cbe2326d48c14a4ab7f98a504b104bdca7dda88b134adad6e31", + "sha256:eccc6829035c8b7b391a0aa124fade54932bb937dd1079f2740b9f1bde829226", + "sha256:eda67136343db96752e58ef36ac37116f36cba40961e79fd0e9bd858f5a09b38", + "sha256:ef5a99a8d1a5c47b4cf85925d1420fc4ee584c98be8efc548651447b3047242f", + "sha256:f0795e2be2aa8afd013635f30ffe599cc00f1bbaca2d1d19b6187b4d1c58fb44", + "sha256:f31d8c2168bf2a52e4539232392352832c2296e07e0e14b6e06a44da574099ba", + "sha256:f41a4b57cbc128a699e9d716a56c90c7fc76554e680fe2962f49cc4d8688b051", + "sha256:f583a1fb180a123c00064fab1a3bfb9d43e574b6474be1be3f6469e0331e3e2e", + "sha256:f7c531722e8c3901f6bb303db464cac98ab44ed422c0fd0c762baa4a8d49ffa1", + "sha256:f8ab90410b2ba5b8276657c66941bcaae556a38be8dd81630a7647e8735f0a20", + "sha256:fa05460dc4f57358680b977b4a254d331b24c8beb501319b998625fd6a22654b", + "sha256:fbe1ef622748d2edb3dd4fef933b934e90e479f9831dfe31bda3fdc16bf5287f", + "sha256:fdb7af369df317527d697c5bb37ab944bb9a17ea1a5e82e47d5c7c638f3ccdd6", + "sha256:fe1f1f4010244cb07f6a079854a12e1627e4fb9ea99d672f2ceccaf6653ca514", + "sha256:fe2493d3f49e314e573022ead4d8c845c9748979b7eb95e815429fe947c4bde2", + "sha256:ffd112646486a31ea5a45aa1eca0e2cd90b6a12f67e848e50349e324c24cc2e7" + ], + "version": "==3.7.1" + }, + "bitstring": { + "hashes": [ + "sha256:69d1587f0ac18dc7d93fc7e80d5f447161a33e57027e726dc18a0a8bacf1711a", + "sha256:a08bc09d3857216d4c0f412a1611056f1cc2b64fd254fb1e8a0afba7cfa1a95a" + ], + "markers": "python_version >= '3.8'", + "version": "==4.3.1" + }, + "cffi": { + "hashes": [ + "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", + "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", + "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", + "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", + "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", + "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2", + "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", + "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", + "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65", + "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", + "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", + "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", + "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", + "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a", + "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", + "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", + "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", + "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", + "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", + "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", + "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", + "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", + "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", + "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", + "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165", + "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", + "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", + "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c", + "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", + "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", + "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", + "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", + "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63", + "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", + "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", + "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", + "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", + "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", + "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", + "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", + "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", + "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", + "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", + "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", + "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", + "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", + "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322", + "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", + "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", + "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", + "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", + "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", + "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", + "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", + "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", + "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", + "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", + "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", + "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", + "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", + "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9", + "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", + "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", + "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", + "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", + "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", + "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f", + "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", + "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", + "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", + "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", + "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", + "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", + "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", + "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", + "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", + "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7", + "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", + "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534", + "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", + "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", + "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", + "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", + "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf" + ], + "markers": "platform_python_implementation != 'PyPy'", + "version": "==2.0.0" + }, + "click": { + "hashes": [ + "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", + "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b" + ], + "markers": "python_version >= '3.10'", + "version": "==8.2.1" + }, + "cryptography": { + "hashes": [ + "sha256:06ce84dc14df0bf6ea84666f958e6080cdb6fe1231be2a51f3fc1267d9f3fb34", + "sha256:16ede8a4f7929b4b7ff3642eba2bf79aa1d71f24ab6ee443935c0d269b6bc513", + "sha256:18fcf70f243fe07252dcb1b268a687f2358025ce32f9f88028ca5c364b123ef5", + "sha256:1993a1bb7e4eccfb922b6cd414f072e08ff5816702a0bdb8941c247a6b1b287c", + "sha256:1f3d56f73595376f4244646dd5c5870c14c196949807be39e79e7bd9bac3da63", + "sha256:258e0dff86d1d891169b5af222d362468a9570e2532923088658aa866eb11130", + "sha256:2f641b64acc00811da98df63df7d59fd4706c0df449da71cb7ac39a0732b40ae", + "sha256:3808e6b2e5f0b46d981c24d79648e5c25c35e59902ea4391a0dcb3e667bf7443", + "sha256:3994c809c17fc570c2af12c9b840d7cea85a9fd3e5c0e0491f4fa3c029216d59", + "sha256:3be4f21c6245930688bd9e162829480de027f8bf962ede33d4f8ba7d67a00cee", + "sha256:465ccac9d70115cd4de7186e60cfe989de73f7bb23e8a7aa45af18f7412e75bf", + "sha256:48c41a44ef8b8c2e80ca4527ee81daa4c527df3ecbc9423c41a420a9559d0e27", + "sha256:4a862753b36620af6fc54209264f92c716367f2f0ff4624952276a6bbd18cbde", + "sha256:4b1654dfc64ea479c242508eb8c724044f1e964a47d1d1cacc5132292d851971", + "sha256:4bd3e5c4b9682bc112d634f2c6ccc6736ed3635fc3319ac2bb11d768cc5a00d8", + "sha256:577470e39e60a6cd7780793202e63536026d9b8641de011ed9d8174da9ca5339", + "sha256:67285f8a611b0ebc0857ced2081e30302909f571a46bfa7a3cc0ad303fe015c6", + "sha256:7285a89df4900ed3bfaad5679b1e668cb4b38a8de1ccbfc84b05f34512da0a90", + "sha256:81823935e2f8d476707e85a78a405953a03ef7b7b4f55f93f7c2d9680e5e0691", + "sha256:8978132287a9d3ad6b54fcd1e08548033cc09dc6aacacb6c004c73c3eb5d3ac3", + "sha256:a20e442e917889d1a6b3c570c9e3fa2fdc398c20868abcea268ea33c024c4083", + "sha256:a24ee598d10befaec178efdff6054bc4d7e883f615bfbcd08126a0f4931c83a6", + "sha256:b04f85ac3a90c227b6e5890acb0edbaf3140938dbecf07bff618bf3638578cf1", + "sha256:b6a0e535baec27b528cb07a119f321ac024592388c5681a5ced167ae98e9fff3", + "sha256:bef32a5e327bd8e5af915d3416ffefdbe65ed975b646b3805be81b23580b57b8", + "sha256:bfb4c801f65dd61cedfc61a83732327fafbac55a47282e6f26f073ca7a41c3b2", + "sha256:c13b1e3afd29a5b3b2656257f14669ca8fa8d7956d509926f0b130b600b50ab7", + "sha256:c987dad82e8c65ebc985f5dae5e74a3beda9d0a2a4daf8a1115f3772b59e5141", + "sha256:ce7a453385e4c4693985b4a4a3533e041558851eae061a58a5405363b098fcd3", + "sha256:d0c5c6bac22b177bf8da7435d9d27a6834ee130309749d162b26c3105c0795a9", + "sha256:d97cf502abe2ab9eff8bd5e4aca274da8d06dd3ef08b759a8d6143f4ad65d4b4", + "sha256:dad43797959a74103cb59c5dac71409f9c27d34c8a05921341fb64ea8ccb1dd4", + "sha256:dd342f085542f6eb894ca00ef70236ea46070c8a13824c6bde0dfdcd36065b9b", + "sha256:de58755d723e86175756f463f2f0bddd45cc36fbd62601228a3f8761c9f58252", + "sha256:f3df7b3d0f91b88b2106031fd995802a2e9ae13e02c36c1fc075b43f420f3a17", + "sha256:f5414a788ecc6ee6bc58560e85ca624258a55ca434884445440a810796ea0e0b", + "sha256:fa26fa54c0a9384c27fcdc905a2fb7d60ac6e47d14bc2692145f2b3b1e2cfdbd" + ], + "markers": "python_version >= '3.7' and python_full_version not in '3.9.0, 3.9.1'", + "version": "==45.0.7" + }, + "esptool": { + "hashes": [ + "sha256:05cc4732eb2a9a7766c9e3531f7943d76ff0ca06dc9cd308d1d3d0b72f74aac2" + ], + "index": "pypi", + "markers": "python_version >= '3.10'", + "version": "==5.0.2" + }, + "intelhex": { + "hashes": [ + "sha256:87cc5225657524ec6361354be928adfd56bcf2a3dcc646c40f8f094c39c07db4", + "sha256:892b7361a719f4945237da8ccf754e9513db32f5628852785aea108dcd250093" + ], + "version": "==2.3.0" + }, + "markdown-it-py": { + "hashes": [ + "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", + "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3" + ], + "markers": "python_version >= '3.10'", + "version": "==4.0.0" + }, + "mdurl": { + "hashes": [ + "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", + "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" + ], + "markers": "python_version >= '3.7'", + "version": "==0.1.2" + }, + "mpremote": { + "hashes": [ + "sha256:7f347318fb6d3bb8f89401d399a05efba39b51c74f747cebe92d3c6a9a4ee0b4", + "sha256:daed9b795fdf98edb0c9c4f7f892bf66f075ec5e728bdcc4ab0915abf23d5d17" + ], + "index": "pypi", + "markers": "python_version >= '3.4'", + "version": "==1.26.0" + }, + "platformdirs": { + "hashes": [ + "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", + "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf" + ], + "markers": "python_version >= '3.9'", + "version": "==4.4.0" + }, + "pycparser": { + "hashes": [ + "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", + "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934" + ], + "markers": "implementation_name != 'PyPy'", + "version": "==2.23" + }, + "pygments": { + "hashes": [ + "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", + "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b" + ], + "markers": "python_version >= '3.8'", + "version": "==2.19.2" + }, + "pyserial": { + "hashes": [ + "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", + "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0" + ], + "version": "==3.5" + }, + "pyyaml": { + "hashes": [ + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.2" + }, + "reedsolo": { + "hashes": [ + "sha256:2b6a3e402a1ee3e1eea3f932f81e6c0b7bbc615588074dca1dbbcdeb055002bd", + "sha256:c1359f02742751afe0f1c0de9f0772cc113835aa2855d2db420ea24393c87732" + ], + "version": "==1.7.0" + }, + "rich": { + "hashes": [ + "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", + "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8" + ], + "markers": "python_full_version >= '3.8.0'", + "version": "==14.1.0" + }, + "rich-click": { + "hashes": [ + "sha256:c3fa81ed8a671a10de65a9e20abf642cfdac6fdb882db1ef465ee33919fbcfe2", + "sha256:fd98c0ab9ddc1cf9c0b7463f68daf28b4d0033a74214ceb02f761b3ff2af3136" + ], + "markers": "python_version >= '3.7'", + "version": "==1.8.9" + }, + "typing-extensions": { + "hashes": [ + "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", + "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" + ], + "markers": "python_version >= '3.9'", + "version": "==4.15.0" + } + }, + "develop": {} +} diff --git a/src/boot.py b/src/boot.py index bc0859a..43c56e5 100644 --- a/src/boot.py +++ b/src/boot.py @@ -1,19 +1,9 @@ +import settings import wifi -import time from settings import Settings -print(wifi.ap('qwerty')) +s = Settings() - -settings = Settings() -ssid = settings.get('wifi', {}).get('ssid', None) -password = settings.get('wifi', {}).get('password', None) -ip = settings.get('wifi', {}).get('ip', None) -gateway = settings.get('wifi', {}).get('gateway', None) - -# for i in range(10): -# config = wifi.connect(ssid, password, ip, gateway) -# if config: -# print(config) -# break -# time.sleep(0.1) \ No newline at end of file +name = s.get('name', 'led') +password = s.get("ap_password", "") +wifi.ap(name, password) diff --git a/src/main.py b/src/main.py index a425974..41c2b99 100644 --- a/src/main.py +++ b/src/main.py @@ -1,34 +1,54 @@ - -from time import sleep -from neopixel import NeoPixel -from machine import UART, Pin, PWM, ADC -import _thread -import network -import espnow - +import asyncio +import aioespnow +from settings import Settings +from web import web from patterns import Patterns +import gc +import utime +import machine +import time +import wifi +import json +from p2p import p2p -adc = ADC(2, atten=ADC.ATTN_11DB) -sta = network.WLAN(network.WLAN.IF_STA) # Or network.WLAN.IF_AP -sta.active(True) +async def main(): + settings = Settings() -e = espnow.ESPNow() -e.active(True) + patterns = Patterns(selected=settings["pattern"]) + if settings["color_order"] == "rbg": color_order = (1, 5, 3) + else: color_order = (1, 3, 5) + patterns.set_color1(tuple(int(settings["color1"][i:i+2], 16) for i in color_order)) + patterns.set_color2(tuple(int(settings["color2"][i:i+2], 16) for i in color_order)) + patterns.set_brightness(int(settings["brightness"])) + patterns.set_delay(int(settings["delay"])) -#e.add_peer(broadcast) + async def tick(): + while True: + patterns.tick() + await asyncio.sleep_ms(0) -p = Patterns() + async def system(): + while True: + gc.collect() + for i in range(60): + wdt.feed() + await asyncio.sleep(1) -_thread.start_new_thread(p.scan_single_led, ((255,0,0),0)) + w = web(settings, patterns) + print(settings) + # start the server in a bacakground task + print("Starting") + server = asyncio.create_task(w.start_server(host="0.0.0.0", port=80)) + wdt = machine.WDT(timeout=10000) + wdt.feed() -while True: - value = adc.read_uv()*2 - if value < 3_500_000: - p.run = False - p.off() - print(f"Voltage {value}") - sleep(1) + asyncio.create_task(tick()) + asyncio.create_task(p2p(settings, patterns)) + asyncio.create_task(system()) -i = 0 + # cleanup before ending the application + await server + +asyncio.run(main()) diff --git a/src/p2p.py b/src/p2p.py new file mode 100644 index 0000000..d73636c --- /dev/null +++ b/src/p2p.py @@ -0,0 +1,20 @@ +import asyncio +import aioespnow +import json + +async def p2p(settings, patterns): + e = aioespnow.AIOESPNow() # Returns AIOESPNow enhanced with async support + e.active(True) + async for mac, msg in e: + try: + data = json.loads(msg) + except: + print(f"Failed to load espnow data {msg}") + continue + print(data) + if "names" not in data or settings.get("name") in data.get("names", []): + if "step" in settings and isinstance(settings["step"], int): + patterns.set_pattern_step(settings["step"]) + else: + settings.set_settings(data.get("settings", {}), patterns, data.get("save", False)) + print("should not print") diff --git a/src/settings.py b/src/settings.py index 7ad5c81..24e843f 100644 --- a/src/settings.py +++ b/src/settings.py @@ -1,4 +1,7 @@ import json +import wifi +import ubinascii +import machine class Settings(dict): SETTINGS_FILE = "/settings.json" @@ -6,15 +9,21 @@ class Settings(dict): def __init__(self): super().__init__() self.load() # Load settings from file during initialization + if self["color_order"] == "rbg": self.color_order = (1, 5, 3) + else: self.color_order = (1, 3, 5) def set_defaults(self): + self["led_pin"] = 10 self["num_leds"] = 50 - self["selected_pattern"] = "blink" - self["color1"] = "#000f00" - self["color2"] = "#0f0000" + self["pattern"] = "on" + self["color1"] = "#00ff00" + self["color2"] = "#ff0000" self["delay"] = 100 - self["brightness"] = 100 - self["wifi"] = {"ssid": "", "password": ""} + self["brightness"] = 10 + self["color_order"] = "rgb" + self["name"] = f"led-hoop" + self["ap_password"] = "" + self["id"] = 0 def save(self): try: @@ -34,6 +43,55 @@ class Settings(dict): except Exception as e: print(f"Error loading settings") self.set_defaults() + self.save() + + def set_settings(self, data, patterns, save): + try: + print(data) + for key, value in data.items(): + print(key, value) + if key == "colors": + buff = [] + for color in value: + buff.append(tuple(int(color[i:i+2], 16) for i in self.color_order)) + patterns.set_colors(buff) + elif key == "color1": + patterns.set_color1(tuple(int(value[i:i+2], 16) for i in self.color_order)) # Convert hex to RGB + elif key == "color2": + patterns.set_color2(tuple(int(value[i:i+2], 16) for i in self.color_order)) # Convert hex to RGB + elif key == "num_leds": + patterns.update_num_leds(self["led_pin"], value) + elif key == "pattern": + if not patterns.select(value): + return "Pattern doesn't exist", 400 + elif key == "delay": + delay = int(data["delay"]) + patterns.set_delay(delay) + elif key == "brightness": + brightness = int(data["brightness"]) + patterns.set_brightness(brightness) + elif key == "name": + self[key] = value + self.save() + machine.reset() + elif key == "color_order": + if value == "rbg": self.color_order = (1, 5, 3) + else: self.color_order = (1, 3, 5) + pass + elif key == "id": + pass + elif key == "led_pin": + patterns.update_num_leds(value, self["num_leds"]) + else: + return "Invalid key", 400 + self[key] = value + #print(self) + patterns.sync() + if save: + self.save() + return "OK", 200 + except (KeyError, ValueError): + return "Bad request", 400 # Example usage def main(): @@ -42,12 +100,14 @@ def main(): settings['num_leds'] = 100 print(f"Updated number of LEDs: {settings['num_leds']}") settings.save() - + # Create a new Settings object to test loading new_settings = Settings() print(f"Loaded number of LEDs: {new_settings['num_leds']}") print(settings) + + # Run the example if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/src/static/main.css b/src/static/main.css index 0c56bb7..15226a5 100644 --- a/src/static/main.css +++ b/src/static/main.css @@ -1,75 +1,109 @@ body { - font-family: Arial, sans-serif; - max-width: 600px; - margin: 0 auto; - padding: 20px; - line-height: 1.6; - } - h1 { - text-align: center; - } - - form { - margin-bottom: 20px; - } - label { - display: block; - margin-bottom: 5px; - } - input[type="text"], input[type="submit"], input[type="range"], input[type="color"] { - width: 100%; - - margin-bottom: 10px; - box-sizing: border-box; - } - input[type="range"] { - -webkit-appearance: none; - appearance: none; - height: 25px; - background: #d3d3d3; - outline: none; - opacity: 0.7; - transition: opacity .2s; - } - input[type="range"]:hover { - opacity: 1; - } - input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - appearance: none; - width: 25px; - height: 25px; - background: #4CAF50; - cursor: pointer; - border-radius: 50%; - } - input[type="range"]::-moz-range-thumb { - width: 25px; - height: 25px; - background: #4CAF50; - cursor: pointer; - border-radius: 50%; - } - #pattern_buttons { - display: flex; - flex-wrap: wrap; - gap: 10px; - margin-bottom: 20px; - } - #pattern_buttons button { - flex: 1 0 calc(33.333% - 10px); - padding: 10px; - background-color: #4CAF50; - color: white; - border: none; - cursor: pointer; - transition: background-color 0.3s; - } - #pattern_buttons button:hover { - background-color: #45a049; - } - @media (max-width: 480px) { - #pattern_buttons button { - flex: 1 0 calc(50% - 10px); - } - } \ No newline at end of file + font-family: Arial, sans-serif; + max-width: 600px; + margin: 0 auto; + padding: 20px; + line-height: 1.6; +} +h1 { + text-align: center; +} + +form { + margin-bottom: 20px; +} +label { + display: block; + margin-bottom: 5px; +} +input[type="text"], +input[type="submit"], +input[type="range"], +input[type="color"] { + width: 100%; + + margin-bottom: 10px; + box-sizing: border-box; +} +input[type="range"] { + -webkit-appearance: none; + appearance: none; + height: 25px; + background: #d3d3d3; + outline: none; + opacity: 0.7; + transition: opacity 0.2s; +} +input[type="range"]:hover { + opacity: 1; +} +input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 25px; + height: 25px; + background: #4caf50; + cursor: pointer; + border-radius: 50%; +} +input[type="range"]::-moz-range-thumb { + width: 25px; + height: 25px; + background: #4caf50; + cursor: pointer; + border-radius: 50%; +} +#pattern_buttons { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 20px; +} +#pattern_buttons button { + flex: 1 0 calc(33.333% - 10px); + padding: 10px; + background-color: #4caf50; + color: white; + border: none; + cursor: pointer; + transition: background-color 0.3s; +} +#pattern_buttons button:hover { + background-color: #45a049; +} +@media (max-width: 480px) { + #pattern_buttons button { + flex: 1 0 calc(50% - 10px); + } +} +#connection-status { + width: 15px; + height: 15px; + border-radius: 50%; + display: inline-block; /* Or block, depending on where you put it */ + margin-left: 10px; /* Adjust spacing as needed */ + vertical-align: middle; /* Align with nearby text */ + background-color: grey; /* Default: Unknown */ +} + +#connection-status.connecting { + background-color: yellow; +} + +#connection-status.open { + background-color: green; +} + +#connection-status.closing, +#connection-status.closed { + background-color: red; +} + +#color_order_form label, +#color_order_form input[type="radio"] { + /* Ensures they behave as inline elements */ + display: inline-block; + /* Adds some space between them for readability */ + margin-right: 10px; + vertical-align: middle; /* Aligns them nicely if heights vary */ +} diff --git a/src/static/main.js b/src/static/main.js index 4cdcc55..9e00994 100644 --- a/src/static/main.js +++ b/src/static/main.js @@ -2,146 +2,243 @@ let delayTimeout; let brightnessTimeout; let colorTimeout; let color2Timeout; +let ws; // Variable to hold the WebSocket connection +let connectionStatusElement; // Variable to hold the connection status element -async function post(path, data) { - console.log(`POST to ${path}`, data); - try { - const response = await fetch(path, { - method: "POST", - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(data) // Convert data to JSON string - }); - if (!response.ok) { - throw new Error(`HTTP error! Status: ${response.status}`); - } - } catch (error) { - console.error('Error during POST request:', error); +// Function to update the connection status indicator +function updateConnectionStatus(status) { + if (!connectionStatusElement) { + connectionStatusElement = document.getElementById("connection-status"); + } + if (connectionStatusElement) { + connectionStatusElement.className = ""; // Clear existing classes + connectionStatusElement.classList.add(status); + // Optionally, you could also update text content based on status + // connectionStatusElement.textContent = status.charAt(0).toUpperCase() + status.slice(1); + } +} + +// Function to establish WebSocket connection +function connectWebSocket() { + // Determine the WebSocket URL based on the current location + const wsUrl = `ws://${window.location.host}/ws`; + ws = new WebSocket(wsUrl); + + updateConnectionStatus("connecting"); // Indicate connecting state + + ws.onopen = function (event) { + console.log("WebSocket connection opened:", event); + updateConnectionStatus("open"); // Indicate open state + // Optionally, you could send an initial message here + }; + + ws.onmessage = function (event) { + console.log("WebSocket message received:", event.data); + }; + + ws.onerror = function (event) { + console.error("WebSocket error:", event); + updateConnectionStatus("closed"); // Indicate error state (treat as closed) + }; + + ws.onclose = function (event) { + if (event.wasClean) { + console.log( + `WebSocket connection closed cleanly, code=${event.code}, reason=${event.reason}`, + ); + updateConnectionStatus("closed"); // Indicate closed state + } else { + console.error("WebSocket connection died"); + updateConnectionStatus("closed"); // Indicate closed state } + // Attempt to reconnect after a delay + setTimeout(connectWebSocket, 1000); + }; +} + +// Function to send data over WebSocket +function sendWebSocketData(data) { + if (ws && ws.readyState === WebSocket.OPEN) { + console.log("Sending data over WebSocket:", data); + ws.send(JSON.stringify(data)); + } else { + console.error("WebSocket is not connected. Cannot send data:", data); + // You might want to queue messages or handle this in a different way + } +} + +// Keep the post and get functions for now, they might still be useful +async function post(path, data) { + console.log(`POST to ${path}`, data); + try { + const response = await fetch(path, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }); + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + } catch (error) { + console.error("Error during POST request:", error); + } } async function get(path) { - try { - const response = await fetch(path); - if (!response.ok) { - throw new Error(`HTTP error! Status: ${response.status}`); - } - return await response.json(); // Assuming you are expecting JSON response - } catch (error) { - console.error('Error during GET request:', error); + try { + const response = await fetch(path); + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); } + return await response.json(); + } catch (error) { + console.error("Error during GET request:", error); + } } async function updateColor(event) { - event.preventDefault(); - clearTimeout(colorTimeout); - colorTimeout = setTimeout(async function() { - const color = document.getElementById('color').value; - await post("/color", { color }); // Send as JSON - }, 500); + event.preventDefault(); + clearTimeout(colorTimeout); + colorTimeout = setTimeout(function () { + const color = document.getElementById("color").value; + sendWebSocketData({ color1: color }); + }, 500); } async function updateColor2(event) { - event.preventDefault(); - clearTimeout(color2Timeout); - color2Timeout = setTimeout(async function() { - const color = document.getElementById('color2').value; - await post("/color2", { color }); // Send as JSON - }, 500); + event.preventDefault(); + clearTimeout(color2Timeout); + color2Timeout = setTimeout(function () { + const color = document.getElementById("color2").value; + sendWebSocketData({ color2: color }); + }, 500); } async function updatePattern(pattern) { - event.preventDefault(); - await post("/pattern", { pattern }); // Send as JSON + sendWebSocketData({ pattern: pattern }); } async function updateBrightness(event) { - event.preventDefault(); - clearTimeout(brightnessTimeout); - brightnessTimeout = setTimeout(async function() { - const brightness = document.getElementById('brightness').value; - await post('/brightness', { brightness }); // Send as JSON - }, 500); + event.preventDefault(); + clearTimeout(brightnessTimeout); + brightnessTimeout = setTimeout(function () { + const brightness = document.getElementById("brightness").value; + sendWebSocketData({ brightness: brightness }); + }, 500); } async function updateDelay(event) { - event.preventDefault(); - clearTimeout(delayTimeout); - delayTimeout = setTimeout(async function() { - const delay = document.getElementById('delay').value; - await post('/delay', { delay }); // Send as JSON - }, 500); + event.preventDefault(); + clearTimeout(delayTimeout); + delayTimeout = setTimeout(function () { + const delay = document.getElementById("delay").value; + sendWebSocketData({ delay: delay }); + }, 500); } async function updateNumLeds(event) { - event.preventDefault(); - const numLeds = document.getElementById('num_leds').value; - await post('/num_leds', { num_leds: numLeds }); // Send as JSON + event.preventDefault(); + const numLeds = document.getElementById("num_leds").value; + sendWebSocketData({ num_leds: parseInt(numLeds) }); } -async function updateWifi(event) { - event.preventDefault(); - const ssid = document.getElementById('ssid').value; - const password = document.getElementById('password').value; - const ip = document.getElementById('ip').value; - const gateway = document.getElementById('gateway').value; +async function updateName(event) { + event.preventDefault(); + const name = document.getElementById("name").value; + sendWebSocketData({ name: name }); +} - const wifiSettings = { ssid, password, ip, gateway }; // Create JSON object - console.log(wifiSettings); - const response = await post('/wifi_settings', wifiSettings); // Send as JSON - if (response === 500) { - alert("Failed to connect to Wi-Fi"); - } +async function updateID(event) { + event.preventDefault(); + const id = document.getElementById("id").value; + sendWebSocketData({ id: parseInt(id) }); +} + +async function updateLedPin(event) { + event.preventDefault(); + const ledpin = document.getElementById("led_pin").value; + sendWebSocketData({ led_pin: parseInt(ledpin) }); +} + +function handleRadioChange(event) { + event.preventDefault(); + console.log("Selected color order:", event.target.value); + // Add your specific logic here + if (event.target.value === "rgb") { + console.log("RGB order selected!"); + } else if (event.target.value === "rbg") { + console.log("RBG order selected!"); + } + sendWebSocketData({ color_order: event.target.value }); } function createPatternButtons(patterns) { - const container = document.getElementById('pattern_buttons'); - container.innerHTML = ''; // Clear previous buttons + const container = document.getElementById("pattern_buttons"); + container.innerHTML = ""; // Clear previous buttons - patterns.forEach(pattern => { - const button = document.createElement('button'); - button.type = 'button'; // Use 'button' instead of 'submit' - button.textContent = pattern; - button.value = pattern; - button.addEventListener('click', async function(event) { - event.preventDefault(); - await updatePattern(pattern); - }); - container.appendChild(button); + patterns.forEach((pattern) => { + const button = document.createElement("button"); + button.type = "button"; + button.textContent = pattern; + button.value = pattern; + button.addEventListener("click", async function (event) { + event.preventDefault(); + await updatePattern(pattern); }); + container.appendChild(button); + }); } -document.addEventListener('DOMContentLoaded', async function() { - document.getElementById('color').addEventListener('input', updateColor); - document.getElementById('color2').addEventListener('input', updateColor2); - document.getElementById('delay').addEventListener('input', updateDelay); - document.getElementById('brightness').addEventListener('input', updateBrightness); - document.getElementById('num_leds_form').addEventListener('submit', updateNumLeds); - document.getElementById('wifi_form').addEventListener('submit', updateWifi); - document.getElementById('delay').addEventListener('touchend', updateDelay); - document.getElementById('brightness').addEventListener('touchend', updateBrightness); +document.addEventListener("DOMContentLoaded", async function () { + // Get the connection status element once the DOM is ready + connectionStatusElement = document.getElementById("connection-status"); - document.querySelectorAll(".pattern_button").forEach(button => { - console.log(button.value); - button.addEventListener('click', async event => { - event.preventDefault(); - await updatePattern(button.value); - }); - }); + // Establish WebSocket connection on page load + connectWebSocket(); + + document.getElementById("color").addEventListener("input", updateColor); + document.getElementById("color2").addEventListener("input", updateColor2); + document.getElementById("delay").addEventListener("input", updateDelay); + document + .getElementById("brightness") + .addEventListener("input", updateBrightness); + document + .getElementById("num_leds_form") + .addEventListener("submit", updateNumLeds); + document.getElementById("name_form").addEventListener("submit", updateName); + document.getElementById("id_form").addEventListener("submit", updateID); + document + .getElementById("led_pin_form") + .addEventListener("submit", updateLedPin); + document.getElementById("delay").addEventListener("touchend", updateDelay); + document + .getElementById("brightness") + .addEventListener("touchend", updateBrightness); + + document.getElementById("rgb").addEventListener("change", handleRadioChange); + document.getElementById("rbg").addEventListener("change", handleRadioChange); + document.querySelectorAll(".pattern_button").forEach((button) => { + console.log(button.value); + button.addEventListener("click", async (event) => { + event.preventDefault(); + await updatePattern(button.value); + }); + }); }); // Function to toggle the display of the settings menu function selectSettings() { - const settingsMenu = document.getElementById('settings_menu'); - controls = document.getElementById('controls'); - settingsMenu.style.display = 'block'; - controls.style.display = 'none'; + const settingsMenu = document.getElementById("settings_menu"); + controls = document.getElementById("controls"); + settingsMenu.style.display = "block"; + controls.style.display = "none"; } function selectControls() { - const settingsMenu = document.getElementById('settings_menu'); - controls = document.getElementById('controls'); - settingsMenu.style.display = 'none'; - controls.style.display = 'block'; + const settingsMenu = document.getElementById("settings_menu"); + controls = document.getElementById("controls"); + settingsMenu.style.display = "none"; + controls.style.display = "block"; } diff --git a/src/templates/index.html b/src/templates/index.html index 6063d30..4e1a112 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -1,41 +1,124 @@ -{% args settings, patterns %} - +{% args settings, patterns, mac %} + - - - - LED Control - - - - -

Control LEDs

- - + + + + {{settings['name']}} + + + + +

{{settings['name']}}

+ + - -
-
- {% for p in patterns %} - - {% endfor %} - - + +
+
+ {% for p in patterns %} + + {% endfor %} + + +
+
+ + +
+
+ + +
+
+ +
+
+ +
-
- - -
-
- - -
-
- -
-
- -
-
- + + + + +
+ diff --git a/src/web (1).py b/src/web (1).py new file mode 100644 index 0000000..a66c4f0 --- /dev/null +++ b/src/web (1).py @@ -0,0 +1,43 @@ +from microdot import Microdot, send_file, Response +from microdot.utemplate import Template +from microdot.websocket import with_websocket +import machine +import wifi +import json + +def web(settings, patterns): + app = Microdot() + Response.default_content_type = 'text/html' + + @app.route('/') + async def index_hnadler(request): + mac = wifi.get_mac().hex() + return Template('/index.html').render(settings=settings, patterns=patterns.patterns.keys(), mac=mac) + + @app.route("/static/") + def static_handler(request, path): + if '..' in path: + # Directory traversal is not allowed + return 'Not found', 404 + return send_file('static/' + path) + + @app.post("/settings") + def settings_handler(request): + # Keep the POST handler for compatibility or alternative usage if needed + # For WebSocket updates, the /ws handler is now primary + return settings.set_settings(request.body.decode('utf-8'), patterns) + + @app.route("/ws") + @with_websocket + async def ws(request, ws): + while True: + data = await ws.receive() + if data: + + # Process the received data + _, status_code = settings.set_settings(json.loads(data), patterns, True) + #await ws.send(status_code) + else: + break + + return app diff --git a/src/web.py b/src/web.py index 3b1278e..a66c4f0 100644 --- a/src/web.py +++ b/src/web.py @@ -11,8 +11,8 @@ def web(settings, patterns): @app.route('/') async def index_hnadler(request): - mac = ''.join(['%02x' % b for b in wifi.get_mac()]) - return Template('/index.html').render(settings=settings, patterns=patterns.patterns.keys()) + mac = wifi.get_mac().hex() + return Template('/index.html').render(settings=settings, patterns=patterns.patterns.keys(), mac=mac) @app.route("/static/") def static_handler(request, path): diff --git a/src/wifi.py b/src/wifi.py index 32a9036..2ca86aa 100644 --- a/src/wifi.py +++ b/src/wifi.py @@ -1,18 +1,16 @@ import network -from machine import Pin from time import sleep -import ubinascii -from settings import Settings def connect(ssid, password, ip, gateway): - if ssid is None or password is None: - print("Missing ssid or password") - return None + try: sta_if = network.WLAN(network.STA_IF) - if ip is not None and gateway is not None: - sta_if.ifconfig((ip, '255.255.255.0', gateway, '1.1.1.1')) if not sta_if.isconnected(): + if ssid == "" or password == "": + print("Missing ssid or password") + return None + if ip != "" and gateway != "": + sta_if.ifconfig((ip, '255.255.255.0', gateway, '1.1.1.1')) print('connecting to network...') sta_if.active(True) sta_if.connect(ssid, password) @@ -26,21 +24,16 @@ def connect(ssid, password, ip, gateway): return None -def ap(password): +def ap(ssid, password): ap_if = network.WLAN(network.AP_IF) ap_mac = ap_if.config('mac') - ssid = f"led-{ubinascii.hexlify(ap_mac).decode()}" print(ssid) ap_if.active(True) - ap_if.config(essid=ssid, password="qwerty1234") + ap_if.config(essid=ssid, password=password) ap_if.active(False) ap_if.active(True) print(ap_if.ifconfig()) - - - - - - - +def get_mac(): + ap_if = network.WLAN(network.AP_IF) + return ap_if.config('mac')