From 422ddde6c7296e1d9204d8fa30a78a822dac6c4c Mon Sep 17 00:00:00 2001 From: Johannes Schilling Date: Thu, 9 Apr 2026 21:57:45 +0200 Subject: [PATCH] basic working version needs wlan env vars, only requests at startup once, no ssl verification (unverified encryption though) --- .cargo/config.toml | 4 +- Cargo.lock | 839 ++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 46 ++- letsencrypt-root.pem | 26 ++ src/bin/main.rs | 380 +++++++++++++------- 5 files changed, 1151 insertions(+), 144 deletions(-) create mode 100644 letsencrypt-root.pem diff --git a/.cargo/config.toml b/.cargo/config.toml index d5e39a5..b4c34f6 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,5 @@ -[target.xtensa-esp32-none-elf] -runner = "espflash flash --monitor --chip esp32s3 --log-format defmt" +[target.xtensa-esp32s3-none-elf] +runner = "espflash flash --monitor --chip esp32s3 --log-format defmt -- " [env] DEFMT_LOG="info" diff --git a/Cargo.lock b/Cargo.lock index b8f71ad..6e39fb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,41 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array 0.14.7", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "allocator-api2" version = "0.3.1" @@ -14,6 +49,27 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "as-slice" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0" +dependencies = [ + "generic-array 0.12.4", + "generic-array 0.13.3", + "generic-array 0.14.7", + "stable_deref_trait", +] + +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -26,12 +82,30 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + [[package]] name = "bit_field" version = "0.10.3" @@ -70,6 +144,49 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "bt-hci" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb938a3b4c5cc6c2409275bad789c0346a0495fa071a0acc5d72b9bd3175a2f7" +dependencies = [ + "btuuid", + "defmt 1.0.1", + "embassy-sync 0.7.2", + "embedded-io 0.6.1", + "embedded-io-async 0.6.1", + "futures-intrusive", + "heapless 0.9.2", +] + +[[package]] +name = "btuuid" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5f48f1e9b0aad0a4f05d17bdeae0fa20ff798e272a03a6940ca27ad9c5a6ae7" +dependencies = [ + "defmt 0.3.100", +] + +[[package]] +name = "buffered-io" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a4372fa7a38648577b85b4a0c2a559be9fbc131ca27f6f2f2cf250a4bd45a03" +dependencies = [ + "embedded-io 0.7.1", + "embedded-io-async 0.7.0", +] + [[package]] name = "bytemuck" version = "1.25.0" @@ -82,34 +199,118 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "const-default" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + [[package]] name = "critical-section" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "darling" version = "0.20.11" @@ -265,13 +466,61 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid 0.9.6", + "zeroize", +] + +[[package]] +name = "der" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +dependencies = [ + "bytes", + "const-oid 0.10.2", + "der_derive", + "heapless 0.9.2", + "pem-rfc7468", + "time", + "zeroize", +] + +[[package]] +name = "der_derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59600e2c2d636fde9b65e99cc6445ac770c63d3628195ff39932b8d6d7409903" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ + "block-buffer", + "const-oid 0.9.6", "crypto-common", + "subtle", ] [[package]] @@ -289,11 +538,14 @@ version = "0.1.0" dependencies = [ "critical-section", "defmt 1.0.1", + "der 0.8.0", "embassy-executor", "embassy-net", "embassy-time", "embedded-graphics", "embedded-hal-bus", + "embedded-nal-async", + "embedded-tls 0.17.0", "epd-waveshare", "esp-alloc", "esp-bootloader-esp-idf", @@ -302,10 +554,66 @@ dependencies = [ "esp-radio", "esp-rtos", "jiff", + "picojson", + "reqwless", + "smoltcp 0.12.0", "sntpc", "static_cell", ] +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der 0.7.10", + "digest", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "sha2", + "subtle", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array 0.14.7", + "group", + "hkdf", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "embassy-embedded-hal" version = "0.5.0" @@ -374,19 +682,20 @@ dependencies = [ [[package]] name = "embassy-net" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71f0aa32082b7df00164f485322d6edab59122c9718b363b07ec23424c2c06a0" +checksum = "97a788d93a10705db3350e81dc743c323e3e40371c5e52024afe7816d3ff05cf" dependencies = [ + "defmt 1.0.1", "document-features", "embassy-net-driver", - "embassy-sync 0.7.2", + "embassy-sync 0.8.0", "embassy-time", "embedded-io-async 0.7.0", "embedded-nal-async", - "heapless 0.8.0", + "heapless 0.9.2", "managed", - "smoltcp", + "smoltcp 0.13.0", ] [[package]] @@ -394,6 +703,9 @@ name = "embassy-net-driver" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524eb3c489760508f71360112bca70f6e53173e6fe48fc5f0efd0f5ab217751d" +dependencies = [ + "defmt 0.3.100", +] [[package]] name = "embassy-sync" @@ -424,11 +736,25 @@ dependencies = [ "heapless 0.8.0", ] +[[package]] +name = "embassy-sync" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bbd85cf5a5ae56bdf26f618364af642d1d0a4e245cdd75cd9aabda382f65a81" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io-async 0.7.0", + "futures-core", + "futures-sink", + "heapless 0.9.2", +] + [[package]] name = "embassy-time" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" +checksum = "592b0c143ec626e821d4d90da51a2bd91d559d6c442b7c74a47d368c9e23d97a" dependencies = [ "cfg-if", "critical-section", @@ -443,9 +769,9 @@ dependencies = [ [[package]] name = "embassy-time-driver" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" +checksum = "6ee71af1b3a0deaa53eaf2d39252f83504c853646e472400b763060389b9fcc9" dependencies = [ "document-features", ] @@ -619,6 +945,58 @@ dependencies = [ "embedded-storage", ] +[[package]] +name = "embedded-tls" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6efb76fdd004a4ef787640177237b83449e6c5847765ea50bf15900061fd601" +dependencies = [ + "aes-gcm", + "atomic-polyfill", + "defmt 0.3.100", + "digest", + "embedded-io 0.6.1", + "embedded-io-async 0.6.1", + "generic-array 0.14.7", + "heapless 0.6.1", + "heapless 0.8.0", + "hkdf", + "hmac", + "p256", + "rand_core 0.6.4", + "sha2", + "typenum", +] + +[[package]] +name = "embedded-tls" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d1e46155b61b5b5cc486e01dacc55a623689bded89835965b15436734f078a" +dependencies = [ + "aes-gcm", + "const-oid 0.10.2", + "defmt 1.0.1", + "der 0.8.0", + "digest", + "ecdsa", + "ed25519-dalek", + "embedded-io 0.7.1", + "embedded-io-async 0.7.0", + "generic-array 0.14.7", + "heapless 0.6.1", + "heapless 0.9.2", + "hkdf", + "hmac", + "p256", + "p384", + "portable-atomic", + "rand_core 0.6.4", + "sha2", + "signature", + "typenum", +] + [[package]] name = "enumset" version = "1.1.10" @@ -789,6 +1167,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1facf348e1e251517278fc0f5dc134e95e518251f5796cfbb532ca226a29bf" dependencies = [ "cfg-if", + "defmt 1.0.1", "document-features", "esp-config", "esp-hal", @@ -818,9 +1197,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "684c4de2f8907b73c9b891fbda65286a86d34fced4b856f36a7896c211f2f265" dependencies = [ "allocator-api2", + "bt-hci", "cfg-if", + "defmt 1.0.1", "document-features", "embassy-net-driver", + "embedded-io 0.6.1", + "embedded-io 0.7.1", + "embedded-io-async 0.6.1", + "embedded-io-async 0.7.0", "enumset", "esp-alloc", "esp-config", @@ -837,6 +1222,7 @@ dependencies = [ "num-traits", "portable-atomic", "portable_atomic_enum", + "smoltcp 0.12.0", "xtensa-lx-rt", ] @@ -883,6 +1269,7 @@ dependencies = [ "embassy-sync 0.7.2", "embassy-time-driver", "embassy-time-queue-utils", + "esp-alloc", "esp-config", "esp-hal", "esp-hal-procmacros", @@ -928,6 +1315,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b6544f6f0cb86169d1f93ba2101a8d50358a040c5043676ed86b793e09b12c" dependencies = [ "anyhow", + "defmt 1.0.1", ] [[package]] @@ -1007,6 +1395,22 @@ dependencies = [ "vcell", ] +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "float-cmp" version = "0.9.0" @@ -1038,6 +1442,16 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", +] + [[package]] name = "futures-sink" version = "0.3.32" @@ -1067,6 +1481,24 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" +dependencies = [ + "typenum", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1075,6 +1507,37 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hash32" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc" +dependencies = [ + "byteorder", ] [[package]] @@ -1092,13 +1555,26 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +[[package]] +name = "heapless" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422" +dependencies = [ + "as-slice", + "generic-array 0.14.7", + "hash32 0.1.1", + "stable_deref_trait", +] + [[package]] name = "heapless" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ - "hash32", + "defmt 0.3.100", + "hash32 0.3.1", "stable_deref_trait", ] @@ -1108,7 +1584,8 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" dependencies = [ - "hash32", + "defmt 1.0.1", + "hash32 0.3.1", "stable_deref_trait", ] @@ -1118,6 +1595,36 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + [[package]] name = "ident_case" version = "1.0.1" @@ -1143,6 +1650,15 @@ dependencies = [ "rustversion", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array 0.14.7", +] + [[package]] name = "instability" version = "0.3.12" @@ -1211,6 +1727,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.29" @@ -1250,6 +1775,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" +[[package]] +name = "nourl" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa07b0722c63805057dec824444fdc814bdfd30d1c782a3a8f63bbcf67c4ed1c" +dependencies = [ + "defmt 0.3.100", +] + +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + [[package]] name = "num-derive" version = "0.4.2" @@ -1279,18 +1819,85 @@ dependencies = [ "memchr", ] +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pem-rfc7468" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" +dependencies = [ + "base64ct", +] + +[[package]] +name = "picojson" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d890937a3c6368ddfd10a87f47f0b7ef0efb1b90f085d56ec980003168ae43fe" + [[package]] name = "pin-project-lite" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der 0.7.10", + "spki", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "portable-atomic" version = "1.13.1" @@ -1327,6 +1934,30 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-crate" version = "3.5.0" @@ -1382,6 +2013,16 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46b71a9d9206e8b46714c74255adcaea8b11e0350c1d8456165073c3f75fc81a" +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -1394,6 +2035,39 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +[[package]] +name = "reqwless" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836acee7034acc981677b98cd9e6cf123c7d9174be376281c86d8248fe5169eb" +dependencies = [ + "base64 0.21.7", + "buffered-io", + "defmt 0.3.100", + "embedded-io 0.7.1", + "embedded-io-async 0.7.0", + "embedded-nal-async", + "embedded-tls 0.18.0", + "heapless 0.9.2", + "hex", + "httparse", + "nourl", + "p256", + "pkcs8", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "riscv" version = "0.15.0" @@ -1467,6 +2141,15 @@ dependencies = [ "svgbobdoc", ] +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -1479,6 +2162,31 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der 0.7.10", + "generic-array 0.14.7", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -1522,6 +2230,27 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + [[package]] name = "smoltcp" version = "0.12.0" @@ -1531,10 +2260,25 @@ dependencies = [ "bitflags 1.3.2", "byteorder", "cfg-if", + "defmt 0.3.100", "heapless 0.8.0", "managed", ] +[[package]] +name = "smoltcp" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac729b0a77bd092a3f06ddaddc59fe0d67f48ba0de45a9abe707c2842c7f8767" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "cfg-if", + "defmt 0.3.100", + "heapless 0.9.2", + "managed", +] + [[package]] name = "sntpc" version = "0.6.1" @@ -1560,6 +2304,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0f368519fc6c85fc1afdb769fb5a51123f6158013e143656e25a3485a0d401c" +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "der 0.7.10", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -1602,13 +2355,19 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "svgbobdoc" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" dependencies = [ - "base64", + "base64 0.13.1", "proc-macro2", "quote", "syn 1.0.109", @@ -1666,6 +2425,24 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + [[package]] name = "toml_datetime" version = "1.0.1+spec-1.1.0" @@ -1720,6 +2497,16 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -1818,3 +2605,29 @@ dependencies = [ "quote", "syn 2.0.117", ] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" diff --git a/Cargo.toml b/Cargo.toml index 8024c5f..2de745e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ path = "./src/bin/main.rs" [dependencies] esp-hal = { version = "1.0.0", default-features = false, features = ["defmt", "esp32s3", "unstable"] } -esp-rtos = { version = "0.2.0", features = ["defmt", "embassy", "esp32s3", "esp-radio"] } +esp-rtos = { version = "0.2.0", features = ["defmt", "embassy", "esp32s3", "esp-radio", "esp-alloc"] } defmt = "1.0.1" esp-bootloader-esp-idf = { version = "0.4.0", features = ["defmt", "esp32s3"] } @@ -21,18 +21,28 @@ embassy-time = { version = "0.5.0", features = ["defmt"] } esp-println = { version = "0.16.1", features = ["defmt-espflash", "esp32s3"] } critical-section = "1.2.0" -static_cell = "2.1.1" +static_cell = { version = "2.1.1", features = [ "nightly" ] } epd-waveshare = { version = "0.6", features = [ "graphics" ] } embedded-hal-bus = { version = "0.3" } embedded-graphics = "0.8.1" +embedded-nal-async = "0.9.0" + esp-alloc = "0.9" -esp-radio = { version = "0.17.0", features = ["esp32s3", "wifi"] } -embassy-net = { version = "0.8.0", features = [ +esp-radio = { version = "=0.17.0", features = [ + "defmt", + "esp-alloc", + "esp32s3", + "smoltcp", + "unstable", + "wifi", +] } +embassy-net = { version = "0.9.0", features = [ + "defmt", "dhcpv4", "medium-ethernet", - "udp", + "tcp", "dns", ] } sntpc = { version = "0.6.0", default-features = false, features = [ @@ -40,6 +50,32 @@ sntpc = { version = "0.6.0", default-features = false, features = [ ] } jiff = { version = "0.2.10", default-features = false, features = ["static"] } +smoltcp = { version = "0.12.0", default-features = false, features = [ + "defmt", + "medium-ethernet", + "multicast", + "proto-dhcpv4", + "proto-dns", + "proto-ipv4", + "socket-icmp", + "socket-raw", + "socket-tcp", + "dns-max-server-count-4", +]} + +reqwless = { version = "0.14.0", default-features = false, features = [ + "embedded-tls", + "defmt", +] } + +embedded-tls = { version = "0.17.0", default-features = false, features = [ + "defmt", + "alloc", +]} +der = { version = "0.8.0", default-features = false, features = ["heapless", "alloc", "bytes", "pem"]} + +picojson = "0.2" + [profile.dev] # Rust debug is too slow. diff --git a/letsencrypt-root.pem b/letsencrypt-root.pem new file mode 100644 index 0000000..12b583e --- /dev/null +++ b/letsencrypt-root.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEVjCCAj6gAwIBAgIQY5WTY8JOcIJxWRi/w9ftVjANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy +Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa +Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF +bmNyeXB0MQswCQYDVQQDEwJFODB2MBAGByqGSM49AgEGBSuBBAAiA2IABNFl8l7c +S7QMApzSsvru6WyrOq44ofTUOTIzxULUzDMMNMchIJBwXOhiLxxxs0LXeb5GDcHb +R6EToMffgSZjO9SNHfY9gjMy9vQr5/WWOrQTZxh7az6NSNnq3u2ubT6HTKOB+DCB +9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB +MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI8NE6L2Ln7RUGwzGDhdWY4j +cpHKMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB +BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE +DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j +ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBnE0hGINKsCYWi0Xx1ygxD5qihEjZ0 +RI3tTZz1wuATH3ZwYPIp97kWEayanD1j0cDhIYzy4CkDo2jB8D5t0a6zZWzlr98d +AQFNh8uKJkIHdLShy+nUyeZxc5bNeMp1Lu0gSzE4McqfmNMvIpeiwWSYO9w82Ob8 +otvXcO2JUYi3svHIWRm3+707DUbL51XMcY2iZdlCq4Wa9nbuk3WTU4gr6LY8MzVA +aDQG2+4U3eJ6qUF10bBnR1uuVyDYs9RhrwucRVnfuDj29CMLTsplM5f5wSV5hUpm +Uwp/vV7M4w4aGunt74koX71n4EdagCsL/Yk5+mAQU0+tue0JOfAV/R6t1k+Xk9s2 +HMQFeoxppfzAVC04FdG9M+AC2JWxmFSt6BCuh3CEey3fE52Qrj9YM75rtvIjsm/1 +Hl+u//Wqxnu1ZQ4jpa+VpuZiGOlWrqSP9eogdOhCGisnyewWJwRQOqK16wiGyZeR +xs/Bekw65vwSIaVkBruPiTfMOo0Zh4gVa8/qJgMbJbyrwwG97z/PRgmLKCDl8z3d +tA0Z7qq7fta0Gl24uyuB05dqI5J1LvAzKuWdIjT1tP8qCoxSE/xpix8hX2dt3h+/ +jujUgFPFZ0EVZ0xSyBNRF3MboGZnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS +u1igv3OefnWjSQ== +-----END CERTIFICATE----- diff --git a/src/bin/main.rs b/src/bin/main.rs index ccaba80..eb0f496 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -6,13 +6,18 @@ holding buffers for the duration of a data transfer." )] -use defmt::info; +#[macro_use] +extern crate alloc; + +use defmt::{error, info}; use embassy_executor::Spawner; +use embassy_net::{DhcpConfig, Stack}; use embassy_time::{Delay, Duration, Timer}; use embedded_graphics::primitives::{Line, Polyline, PrimitiveStyle}; use embedded_hal_bus::spi::ExclusiveDevice; use esp_hal::clock::CpuClock; use esp_hal::gpio::{Input, InputConfig, Level, Output, OutputConfig, Pull}; +use esp_hal::rng::Rng; use esp_hal::timer::timg::TimerGroup; use esp_println as _; @@ -33,8 +38,44 @@ use embedded_graphics::mono_font::ascii::FONT_10X20; use embedded_graphics::prelude::*; use embedded_graphics::text::{Baseline, Text}; +// wifi +use esp_radio::wifi::{ClientConfig, Config, ModeConfig, ScanConfig, WifiController, WifiDevice, WifiEvent}; + +use embassy_net::{ + Runner, + StackResources, + dns::DnsSocket, + tcp::client::{TcpClient, TcpClientState}, +}; + +// time handling +use jiff::{tz::{self, TimeZone}, Timestamp}; + +use picojson::{SliceParser, PullParser, Event}; +// tls +use reqwless::client::{HttpClient, TlsConfig, TlsVerify}; + +const WLAN_SSID: &str = env!("WLAN_SSID"); +const WLAN_PASS: &str = env!("WLAN_PASS"); + +// (a little clumsy to have to specify the byte length here, but currently no way around that..) +const LETSENCRYPT_ROOT_PEM: &'static [u8; 1566] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/letsencrypt-root.pem")); + +static TZ_EUROPE_BERLIN: TimeZone = tz::include!("/usr/share/zoneinfo/Europe/Berlin"); + +// from: https://github.com/esp-rs/esp-hal/blob/8281e43ba17f2140dea5e0d7e0cac4a7fa7318f2/examples/wifi/embassy_dhcp/src/main.rs +macro_rules! mk_static { + ($t:ty,$val:expr) => {{ + static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); + #[deny(unused_attributes)] + let x = STATIC_CELL.uninit().write(($val)); + x + }} +} + #[panic_handler] -fn panic(_: &core::panic::PanicInfo) -> ! { +fn panic(pi: &core::panic::PanicInfo) -> ! { + error!("panic: {}", pi); loop {} } @@ -54,12 +95,126 @@ async fn main(spawner: Spawner) -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_rtos::start(timg0.timer0); - info!("Embassy initialized!"); - // TODO: Spawn some tasks - let _ = spawner; + // wlan setup + let controller = &*mk_static!(esp_radio::Controller<'static>, esp_radio::init().expect("init radio controller")); + let (wifi_controller, interfaces) = + esp_radio::wifi::new(controller, peripherals.WIFI, Config::default()).expect("wifi init"); + + let wifi_interface = interfaces.sta; + let dhcp_config = embassy_net::Config::dhcpv4(DhcpConfig::default()); + + let rng = Rng::new(); + let net_seed = (rng.random() as u64) << 32 | rng.random() as u64; + + let (stack, runner) = embassy_net::new(wifi_interface, dhcp_config, mk_static!(StackResources::<3>, StackResources::<3>::new()), net_seed); + + spawner.spawn(connection(wifi_controller)).expect("spawn wifi connection task"); + spawner.spawn(net_task(runner)).expect("spawn net task"); + + wait_for_network_up(stack).await; + + let dns = DnsSocket::new(stack); + let tcp_state = TcpClientState::<1, 4096, 4096>::new(); + let tcp = TcpClient::new(stack, &tcp_state); + info!("tcp client"); + + let tls_seed = (rng.random() as u64) << 32 | rng.random() as u64; + let mut tls_tx_buf = [0u8; 4096]; + let mut tls_rx_buf = [0u8; 4096]; + + // TODO: tls verify + let tls_config = TlsConfig::new(tls_seed, &mut tls_rx_buf, &mut tls_tx_buf, TlsVerify::None); + let mut http_client = HttpClient::new_with_tls(&tcp, &dns, tls_config); + info!("http client"); + + let mut buf = [0u8; 16384]; + let http_req = http_client + .request(reqwless::request::Method::GET, "https://e.q0b.de/price?bzn=DE-LU") + .await; + + // reverse proxy e.q0b.de/.* -> https://api.energy-charts.info/$1 with tls1_3 because api.energy-charts.info only does tlsv1.2... + let mut http_req = match http_req { + Ok(r) => r, + Err(e) => { + error!("{}", e); + panic!("failed to make http req"); + } + }; + + let rsp = http_req.send(&mut buf).await.expect("http send"); + info!("rsp made"); + let res = rsp.body().read_to_end().await.expect("read rsp body"); + info!("energy price: {}", str::from_utf8(res).expect("utf8")); + + + // parsing the response + enum ParseNext { + Nothing, + Timestamps, + Prices, + } + + let mut scratch = [0u8; 128]; + let mut parser = SliceParser::with_buffer_from_slice(res, &mut scratch); + + // 24 hours * 4 items/hour (15min resolution) = 96 items total per day + const MAX_ITEMS: usize = 96; + let mut timestamps = [0i64; MAX_ITEMS]; + let mut timestamps_idx = 0; + let mut prices = [0f32; MAX_ITEMS]; + let mut prices_idx = 0; + let mut parse_next = ParseNext::Nothing; + + let mut max_price = f32::MIN; + let mut min_price = f32::MAX; + + while let Some(ref parse_result) = parser.next() { + match parse_result { + Err(e) => { + // TODO: defmt error printing impl for picojson + error!("json parse error"); + continue; + } + Ok(Event::Key(k)) => { + if k.as_str() == "unix_seconds" { + parse_next = ParseNext::Timestamps; + } else if k.as_str() == "price" { + parse_next = ParseNext::Prices; + } + } + Ok(Event::Number(n)) => { + match parse_next { + ParseNext::Timestamps => { + if timestamps_idx < MAX_ITEMS { + timestamps[timestamps_idx] = n.as_int().unwrap(); + timestamps_idx += 1; + } + } + ParseNext::Prices => { + if prices_idx < MAX_ITEMS { + prices[prices_idx] = n.as_f64().unwrap() as f32 / 10.0; + + max_price = max_price.max(prices[prices_idx]); + min_price = min_price.min(prices[prices_idx]); + + prices_idx += 1; + } + } + _ => error!("got a number, but not in a number parser state"), + } + } + Ok(_) => {}, + } + } + + for i in 0..MAX_ITEMS { + info!("{}: {}", timestamps[i], prices[i]); + } + + // spi display drawing let spi_bus = Spi::new( peripherals.SPI2, spi::master::Config::default() @@ -93,120 +248,30 @@ async fn main(spawner: Spawner) -> ! { epd.update_and_display_frame(&mut spi_dev, display.buffer(), &mut Delay) .unwrap(); - let prices = [ - 124.51, - 120.29, - 117.14, - 115.63, - 122.15, - 119.4, - 119.33, - 117.12, - 120.92, - 118.14, - 115.3, - 115.01, - 116.5, - 119.49, - 117.0, - 118.34, - 117.67, - 118.73, - 120.93, - 123.66, - 119.8, - 129.0, - 143.99, - 153.06, - 152.2, - 168.99, - 179.1, - 190.23, - 203.74, - 191.36, - 170.92, - 139.56, - 194.19, - 151.4, - 136.77, - 107.87, - 136.41, - 122.21, - 109.38, - 88.01, - 101.21, - 90.13, - 86.53, - 71.17, - 85.31, - 77.93, - 68.83, - 59.17, - 70.74, - 64.99, - 61.01, - 56.54, - 61.21, - 59.19, - 57.9, - 60.1, - 58.27, - 67.62, - 82.3, - 88.11, - 78.83, - 91.99, - 95.32, - 103.15, - 90.64, - 100.02, - 100.98, - 120.69, - 105.61, - 130.77, - 146.59, - 173.23, - 145.81, - 159.0, - 163.46, - 167.46, - 192.98, - 177.61, - 158.25, - 144.14, - 174.9, - 150.14, - 127.52, - 119.0, - 124.13, - 122.5, - 119.78, - 109.57, - 123.1, - 117.9, - 117.59, - 108.05, - 113.65, - 106.89, - 105.25, - 98.26, - ]; - - let mut points = [Point::new(0, 0); 96 /* TODO: same size as prices? or assume+validate/truncate first 96? */]; - let mut foo = [0u8; 2]; + // draw values for min/max + draw_text(&mut display, &format!("{}", max_price), 10, 20); + draw_text(&mut display, &format!("{}", min_price), 10, 260); + + // current date, probably from the first timestamp (i.e. we assume we get things starting from 00:00) + let ts = Timestamp::from_second(timestamps[0]).unwrap().to_zoned(TZ_EUROPE_BERLIN.clone()); + draw_text(&mut display, &format!("{}", ts.date()), 180, 10); + + // some padding for the min/max + max_price *= 1.1; + min_price *= 1.1; + + let mut points = [Point::new(0, 0); MAX_ITEMS]; for (i, pr) in prices.iter().enumerate() { - points[i] = Point::new(i as i32 * 4, 300 - *pr as i32); - - if i % 18 == 0 { - Line::new(Point::new(i as i32 *4, 300), Point::new(i as i32 * 4, 290)) - .into_styled(PrimitiveStyle::with_stroke(Color::Black, 5)) - .draw(&mut display) - .expect("draw x-axis tick"); - - // no proper write/format library.. - foo[0] = b'0' + (i / 10) as u8; - foo[1] = b'0' + (i % 10) as u8; - draw_text(&mut display, str::from_utf8(&foo[..]).unwrap(), i as i32 * 4, 280); + // fancyer calculations + // scale from price range price_min..price_max to pixel coordinates 270..0 + points[i] = Point::new(i as i32 * 4, ((max_price - *pr) / (max_price - min_price) * 270.0) as i32); + + let ts = Timestamp::from_second(timestamps[i]).expect("timestamp"); + let ts_tz = ts.to_zoned(TZ_EUROPE_BERLIN.clone()); + let hour = ts_tz.hour(); + + if hour != 0 && hour % 3 == 0 && ts_tz.minute() == 0 { + draw_text(&mut display, &format!("{}", hour), i as i32 * 4, 280); } } let line_style = PrimitiveStyle::with_stroke(Color::Black, 3); @@ -246,10 +311,77 @@ fn draw_text(display: &mut Display4in2, text: &str, x: i32, y: i32) { // * rtc initialization, and/or NTP query, to print times. // - maybe we can just convert the time steps from the returned data set, and e.g. do x axis ticks on multiples of 3hours from that // * wifi -// * tls -// * json parser +// * tls: reqless, esp-mbedtls +// * json parser: https://lib.rs/crates/picojson maybe? // => fetch data from https://api.energy-charts.info/price?bzn=DE-LU -// -// -// ## drawing prettier -// * chrono: timestamp -> datetime -> .hours() % 3 == 0, then x-axis tick \ No newline at end of file + + +async fn wait_for_network_up(stack: Stack<'_>) { + loop { + if stack.is_link_up() { + info!("network link up"); + break; + } + Timer::after(Duration::from_millis(500)).await; + } + + info!("Waiting to get IP address..."); + loop { + if let Some(config) = stack.config_v4() { + info!("Got IP: {}", config.address); + break; + } + Timer::after(Duration::from_millis(500)).await; + } +} + +// from: https://github.com/esp-rs/esp-hal/blob/8281e43ba17f2140dea5e0d7e0cac4a7fa7318f2/examples/wifi/embassy_dhcp/src/main.rs +#[embassy_executor::task] +async fn connection(mut controller: WifiController<'static>) { + info!("start connection task"); + loop { + if matches!(controller.is_connected(), Ok(true)) { + // wait until we're no longer connected + controller + .wait_for_event(WifiEvent::StaDisconnected) + .await; + Timer::after(Duration::from_millis(5000)).await + } + + if !matches!(controller.is_started(), Ok(true)) { + let wlan_cfg = ModeConfig::Client( + ClientConfig::default() + .with_ssid(WLAN_SSID.into()) + .with_password(WLAN_PASS.into()) + ); + controller.set_config(&wlan_cfg).unwrap(); + info!("Starting wifi"); + controller.start_async().await.unwrap(); + info!("Wifi started!"); + + info!("Scan"); + let scan_config = ScanConfig::default().with_max(10); + let result = controller + .scan_with_config_async(scan_config) + .await + .unwrap(); + for ap in result { + info!("{:?}", ap); + } + } + info!("About to connect..."); + + match controller.connect_async().await { + Ok(_) => info!("Wifi connected!"), + Err(e) => { + info!("Failed to connect to wifi: {:?}", e); + Timer::after(Duration::from_millis(5000)).await + } + } + } +} + +#[embassy_executor::task] +async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) { + runner.run().await +} \ No newline at end of file