Compare commits
490 Commits
e25ddaca6d
...
1.0.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 4d46f9c52c | |||
| c90a05fcfd | |||
| abdca20a66 | |||
| 88a24565b4 | |||
| 3625188706 | |||
| 58eceeda2d | |||
| c44c6c3bf5 | |||
| 4ef714fdbd | |||
| bab4525908 | |||
| 2ed4299032 | |||
| bcc92da065 | |||
| af83130b63 | |||
| 950b576373 | |||
| 2459b0cf99 | |||
| 814204b4ce | |||
| de8fcfbcfb | |||
| 49a7011d84 | |||
| 39aff8054a | |||
| 850f828dca | |||
| 59383debd2 | |||
| 58cf0a9614 | |||
| f30aaf71dd | |||
| 27ce9e9a96 | |||
| 903dd104f3 | |||
| 205981fbc8 | |||
| 623b0a4671 | |||
| fd25e71cf8 | |||
| 842b48e782 | |||
| e8374a8ef7 | |||
| 347c247285 | |||
| c59aeed4ab | |||
| b7f1beb1b7 | |||
| 4bd700c2db | |||
| 3f1c5e4ac0 | |||
| f77506dc46 | |||
| 5b7554b6bf | |||
| 8fdbcc4f3a | |||
| 9f4c2b0e35 | |||
| 0a7138a82b | |||
| 2ce09a94b1 | |||
| 355b2a71ce | |||
| 6b04bf4261 | |||
| 99c6963210 | |||
| 89cfd3ce21 | |||
| 0c40ff2750 | |||
| 75be1ed1d2 | |||
| 6a2baca3f2 | |||
| 4d0d20b424 | |||
| 05cf488be7 | |||
| b8ecc83668 | |||
| c1912717e4 | |||
| a8780e60d3 | |||
| 5005cf84f9 | |||
| 561992010c | |||
| 4725e67ee1 | |||
| fbb55628be | |||
| 79e49ed5a9 | |||
| 138b9d2dbe | |||
| 3413a1ee21 | |||
| 64055568e0 | |||
| af71b574cc | |||
| 6088237b79 | |||
| 05a033b51c | |||
| 3d3ccf5242 | |||
| 68521c238c | |||
| f03278f8c5 | |||
| a63d1f17de | |||
| bb6d8a8be1 | |||
| 693414b1eb | |||
| f74e86a8db | |||
| 53d4cb1de7 | |||
| 498ca3925a | |||
| 155806df78 | |||
| 79f3668021 | |||
| 660e6e8a5b | |||
| 0e3182434f | |||
| cf2f034e6c | |||
| ddd27519a9 | |||
| e8d2e8b318 | |||
| 0dfc25a918 | |||
| 3078b3c645 | |||
| 9d3bed68af | |||
| 9fe00f149c | |||
| 65164055d6 | |||
| 08680122f2 | |||
| 642366540e | |||
| 482da63a3b | |||
| cade9dc02b | |||
| 9b87025b27 | |||
| 46d3f3580c | |||
| bda9f6a9c9 | |||
| 41380a103f | |||
| 2573778b82 | |||
| 527126d926 | |||
| 9a1104c57b | |||
| bf3e703bb1 | |||
| d7607bc483 | |||
| 306be8272a | |||
| 742bb8e2ed | |||
| e10d7ef478 | |||
| 18ba6c60d6 | |||
| d70562f97a | |||
| b0d192a9aa | |||
| 99f6b17f4e | |||
| 3fff4d624e | |||
| e2f6212a75 | |||
| bff1c88da8 | |||
| 7933c2dae3 | |||
| 15b8a69700 | |||
| 157c77142a | |||
| 25f6e808ed | |||
| 6f298d3238 | |||
| b75e868cc3 | |||
| 6a2b5e320d | |||
| 52637fc401 | |||
| 8ea9da9443 | |||
| b1b4eaa341 | |||
| 94652a82fe | |||
| 832ab86536 | |||
| 32dbbf4678 | |||
| 1f48203564 | |||
| 0b6526f901 | |||
| 741db9e13b | |||
| 061ae8c208 | |||
| 4a68800907 | |||
| 6738d47507 | |||
| acbce81b46 | |||
| 1615531d67 | |||
| 5355b351d1 | |||
| ad10df3e7f | |||
| edf70cb8fc | |||
| 8af3018b34 | |||
| dd96cc4bf3 | |||
| 9e9a227332 | |||
| d701c406d6 | |||
| 74915f109d | |||
| 40af167c1a | |||
| 124fc71c9a | |||
| ac6f93dd4a | |||
| 695fa1fcf4 | |||
| 3131c757a9 | |||
| 60d5be58e1 | |||
| 4b90e0ede1 | |||
| d351aebce4 | |||
| 24d95fff89 | |||
| 11e536fee0 | |||
| e2328b47e5 | |||
| bc790df8e6 | |||
| 104e4f2c15 | |||
| 709671c35d | |||
| e769b2d83b | |||
| 33c3769818 | |||
| 7c5eeaeaa0 | |||
| bcdb72e217 | |||
| 7173d206f2 | |||
| 74a8d3ffbf | |||
| 31bc7898ee | |||
| 27a6d8f7ed | |||
| 43c988b80e | |||
| 9531281fd2 | |||
| e589e2e80c | |||
| 36c127a9c9 | |||
| f0b9683519 | |||
| 2e793770f1 | |||
| ceac6a2683 | |||
| f232a63496 | |||
| adfe006270 | |||
| aa6ca82edd | |||
| d939752aed | |||
| ca6532aee3 | |||
| bd5fc18bab | |||
| 80023ddee3 | |||
| d48094aca6 | |||
| 47e59b7035 | |||
| 6eb9e3df09 | |||
| 0d5f2b90eb | |||
| 8f181ec485 | |||
| 7bb92f7e05 | |||
| 2f2a77f780 | |||
| 789c30faf8 | |||
| 2a9bc65f54 | |||
| 2b96e2a294 | |||
| 0092d09ff9 | |||
| 4bdda28ebf | |||
| 83e130d232 | |||
| 15c394a797 | |||
| 66257b2866 | |||
| 140f1449a7 | |||
| 71b0e54529 | |||
| 4fff948382 | |||
| 13100a728f | |||
| de2fc4a62f | |||
| b5b883df46 | |||
| 285c80926b | |||
| a4eb8f3465 | |||
| 03b1dc1fd7 | |||
| b55215149f | |||
| ad02303a16 | |||
| a2de65d454 | |||
| 2d8d1cf28d | |||
| a8dd9fb08c | |||
| 317de38662 | |||
| 57f06690c4 | |||
| 93554d3719 | |||
| 56f119008b | |||
| e1a82e205e | |||
| 2e3175505f | |||
| 6108a58919 | |||
| 1e5762bb4f | |||
| 71ecf18a2f | |||
| a7069fd0ec | |||
| 5d44bb8a21 | |||
| 78da2b181c | |||
| 9e1de0854d | |||
| edb6279b74 | |||
| fd00a87216 | |||
| 00050c62c5 | |||
| 6824120652 | |||
| 5ed4cc6fed | |||
| c805b03370 | |||
| d97d6bfe56 | |||
| 7151b199f8 | |||
| 40f938efe7 | |||
| ffb8c25428 | |||
| 593719e373 | |||
| 13a9905281 | |||
| 55b354228f | |||
| d751ddc671 | |||
| c5061fdb4d | |||
| 7adbafb831 | |||
| 02397d10f0 | |||
| e3ae017279 | |||
| 30b5155a4d | |||
| 0d04f5d7b2 | |||
| a40dff2820 | |||
| 6fbec9f0cd | |||
| 055e512f77 | |||
| ee769f043f | |||
| 926b265f91 | |||
| b115ba9307 | |||
| 8ada40a5ee | |||
| 100e42ec6d | |||
| cab51c9623 | |||
| 76df0ecf3e | |||
| 85cb7d6a75 | |||
| 69a51e11d3 | |||
| 0ff1d48b90 | |||
| 0d478a10f7 | |||
| a8e2f2d7bf | |||
| e961ea0911 | |||
| 1c1eb53b6e | |||
| 1a2badc138 | |||
| 9323a4a3f5 | |||
| 35cfc73c9d | |||
| dad54c638b | |||
| 4f5be4d08c | |||
| b89aee2dcc | |||
| bbe2c3ebc5 | |||
| 62037db6e3 | |||
| 0bf3bdbaea | |||
| f65df5f22a | |||
| 406a920d7e | |||
| 889ba9b85f | |||
| 12606ba336 | |||
| cb2e17581a | |||
| 4dd5fb4e55 | |||
| 0a162e4a78 | |||
| ba45faf017 | |||
| c4dedb946f | |||
| 5004194567 | |||
| 768f8fc112 | |||
| adf1477c4b | |||
| 7474e25209 | |||
| f33c408c67 | |||
| ccd4125500 | |||
| 9825f2628b | |||
| 9e5797e4ca | |||
| fb562f908c | |||
| ffb00ee668 | |||
| 3ad64e55b8 | |||
| f01df2818c | |||
| da60a57f53 | |||
| 0629bd60c3 | |||
| 995977fd37 | |||
| 9bf15f28b8 | |||
| 8941ec2aef | |||
| b19961ed6a | |||
| 082efa367c | |||
| 3ffcdad666 | |||
| 65db36d097 | |||
| 57bb552950 | |||
| 1d9c539cd1 | |||
| 11d718cfe8 | |||
| 0125b16177 | |||
| d97dcddb96 | |||
| 9eafbd8aeb | |||
| 6aa7fc3a75 | |||
| 345b3566ae | |||
| 22cd346330 | |||
| aee9303f91 | |||
| 6462645d26 | |||
| 4bb76777db | |||
| d79b55b86d | |||
| 665a04c8a0 | |||
| 658b10f5f8 | |||
| c0374e35b1 | |||
| 15f701668f | |||
| 8fdfa19806 | |||
| 22d84e9464 | |||
| a5c5663390 | |||
| 7878fb9686 | |||
| b24642b10d | |||
| ce45d841b2 | |||
| 1b4e5eda9d | |||
| bb1917d1b4 | |||
| b285323bd7 | |||
| ecb161ee82 | |||
| 00c6ae338b | |||
| 814046146c | |||
| f52e992d84 | |||
| dc73882347 | |||
| 5ed8c42b99 | |||
| 0fcb902e9e | |||
| cfafbda77b | |||
| dace42aef2 | |||
| 67401e8faf | |||
| 77a278bd53 | |||
| 6df43fcc0e | |||
| 8add37fc42 | |||
| bfde6531c2 | |||
| 5f6ac7bcfd | |||
| c01f1ca484 | |||
| c6975c2097 | |||
| 2d079403c5 | |||
| 2d408871ad | |||
| 22fd077380 | |||
| 0fba1caf62 | |||
| 7e99cfc086 | |||
| 511011bb4b | |||
| dfca6a04bc | |||
| 4f639522b9 | |||
| 7d9af6af64 | |||
| e1136926a1 | |||
| 4206d9529b | |||
| b606aed10e | |||
| 9a2ceb9804 | |||
| f6bd7b1061 | |||
| 34460500a0 | |||
| 72afa3df62 | |||
| e74f7d6f6d | |||
| 5b09aec93a | |||
| 9f93f76d8e | |||
| 211369a1b2 | |||
| d7c4cd6635 | |||
| 4f78e99f65 | |||
| 4309a19f24 | |||
| 67a0436d02 | |||
| 5ff169d8c2 | |||
| 541f7cbe95 | |||
| 166ac5c8c2 | |||
| 0b53037140 | |||
| 901f6b0e6f | |||
| fc5f9735bf | |||
| 094ff457ac | |||
| ffbbd14ac3 | |||
| e4447e9dcb | |||
| 973190f5b9 | |||
| ededf48977 | |||
| 9a5211812e | |||
| 6f589f3ee4 | |||
| 499c5cb81e | |||
| d72cdbf3cd | |||
| 7ab60c6fe6 | |||
| bf28d1c926 | |||
| 07ca3aa80e | |||
| 4cc18d407d | |||
| 7bcafd782f | |||
| 404fa716f5 | |||
| 43bbb444db | |||
| 71a139af59 | |||
| c40b4acf7a | |||
| 41a228484f | |||
| 9965de686d | |||
| 3cf808df1c | |||
| 40b41688e0 | |||
| 124b0b825c | |||
| 8e4bed012d | |||
| ff79fd968e | |||
| ac26065f10 | |||
| b8b172f17d | |||
| 12fe1abb0f | |||
| acfacf574b | |||
| d0e426bbbc | |||
| 92a9a5741c | |||
| 9a480dfa98 | |||
| f8eafe31bd | |||
| 4330e64489 | |||
| fd5730cfce | |||
| 76acf07b17 | |||
| 315e11a2bb | |||
| 5722ccc2c4 | |||
| 71718151d0 | |||
| 9efd8db8cf | |||
| fc0c86bf8b | |||
| 1a8c3ff9ff | |||
| 4cb05b375e | |||
| f67ccc7cda | |||
| 8a08ff53df | |||
| 2607ac7355 | |||
| e644aa1390 | |||
| e015f01539 | |||
| 37aed38174 | |||
| aa3677a787 | |||
| 549193632c | |||
| 407aeaaf6e | |||
| 36d269dde7 | |||
| 0c4f352815 | |||
| e1abc68292 | |||
| bb0226577d | |||
| 9fcd16784a | |||
| d6e0eccb00 | |||
| dc621984fb | |||
| b2878510d6 | |||
| a059076323 | |||
| f594802523 | |||
| 747d2d819b | |||
| a52868a3fb | |||
| fce38386eb | |||
| cb88a19352 | |||
| c6c34efebd | |||
| eed9637f1e | |||
| 3a64b2b09c | |||
| 8d2f0cb38a | |||
| 5b1cf61832 | |||
| 6cd5d5f93a | |||
| fc409b2584 | |||
| 5a1942cb15 | |||
| 4af8904294 | |||
| 0d1605169d | |||
| 346ea8db11 | |||
| f534a9c61b | |||
| 2ef056da30 | |||
| af16091fab | |||
| 28f81248bf | |||
| cc43f6c78b | |||
| 060ff08c1e | |||
| 57ce643163 | |||
| 7a536ac850 | |||
| 685eef5c5b | |||
| 180126d22a | |||
| e29f01bc62 | |||
| f2abdfe302 | |||
| 598286d1cb | |||
| 30f196aa7a | |||
| 08f1ec6d4d | |||
| d31a568c00 | |||
| 1b25c07e50 | |||
| 96f1640378 | |||
| ccb4ae22f8 | |||
| d66e2b9bf7 | |||
| 0660066941 | |||
| 7476924e0e | |||
| 65c3c534f4 | |||
| 995e1fa07e | |||
| 1735077db3 | |||
| 31bb956a29 | |||
| ff0e548422 | |||
| 837835da7e | |||
| 2d262bb4c9 | |||
| f594ebfbaa | |||
| 57a9c03308 | |||
| 7b9db9c7c3 | |||
| b7720df305 | |||
| 445c1b014e | |||
| aa732af571 | |||
| c365f959e7 | |||
| 9a4c6d2de2 | |||
| 3c20cca915 | |||
| 5aaad54de3 | |||
| b3edfb05d9 | |||
| 45029f24cc | |||
| ec594c0e4d | |||
| fdfbdf093f | |||
| c789056ccf | |||
| f5f783698f | |||
| 823783f307 | |||
| 187a8b3657 | |||
| 2c300109a3 | |||
| 6528de4a9e | |||
| be77e7cb04 |
41
.drone.yml
41
.drone.yml
@@ -5,7 +5,7 @@ name: default
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: web_build
|
- name: web_build
|
||||||
image: node:21
|
image: node:23
|
||||||
volumes:
|
volumes:
|
||||||
- name: web_app
|
- name: web_app
|
||||||
path: /tmp/web_build
|
path: /tmp/web_build
|
||||||
@@ -46,6 +46,11 @@ steps:
|
|||||||
path: /usr/local/cargo/registry
|
path: /usr/local/cargo/registry
|
||||||
- name: web_app
|
- name: web_app
|
||||||
path: /tmp/web_build
|
path: /tmp/web_build
|
||||||
|
- name: releases
|
||||||
|
path: /tmp/releases
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
depends_on:
|
depends_on:
|
||||||
- backend_check
|
- backend_check
|
||||||
- web_build
|
- web_build
|
||||||
@@ -54,17 +59,47 @@ steps:
|
|||||||
- mv /tmp/web_build/dist static
|
- mv /tmp/web_build/dist static
|
||||||
- cargo build --release
|
- cargo build --release
|
||||||
- ls -lah target/release/central_backend
|
- ls -lah target/release/central_backend
|
||||||
|
- mv target/release/central_backend /tmp/releases/central_backend
|
||||||
|
|
||||||
|
# Build ESP32 program
|
||||||
- name: esp32_compile
|
- name: esp32_compile
|
||||||
image: espressif/idf:v5.2.2 # FIXME : upgrade to 5.3.1
|
image: espressif/idf:v5.5.1
|
||||||
|
volumes:
|
||||||
|
- name: releases
|
||||||
|
path: /tmp/releases
|
||||||
commands:
|
commands:
|
||||||
- cd esp32_device
|
- cd esp32_device
|
||||||
- /opt/esp/entrypoint.sh idf.py build
|
- /opt/esp/entrypoint.sh idf.py build
|
||||||
- ls -lah build/main.bin
|
- ls -lah build/main.bin
|
||||||
|
- cp build/main.bin /tmp/releases/wt32-eth01.bin
|
||||||
|
|
||||||
|
# Auto-release to Gitea
|
||||||
|
- name: gitea_release
|
||||||
|
image: plugins/gitea-release
|
||||||
|
depends_on:
|
||||||
|
- backend_compile
|
||||||
|
- esp32_compile
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
|
volumes:
|
||||||
|
- name: releases
|
||||||
|
path: /tmp/releases
|
||||||
|
environment:
|
||||||
|
PLUGIN_API_KEY:
|
||||||
|
from_secret: GITEA_API_KEY # needs permission write:repository
|
||||||
|
settings:
|
||||||
|
base_url: https://gitea.communiquons.org
|
||||||
|
files:
|
||||||
|
- /tmp/releases/central_backend
|
||||||
|
- /tmp/releases/wt32-eth01.bin
|
||||||
|
checksum: sha512
|
||||||
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- name: rust_registry
|
- name: rust_registry
|
||||||
temp: {}
|
temp: {}
|
||||||
- name: web_app
|
- name: web_app
|
||||||
temp: {}
|
temp: {}
|
||||||
|
- name: releases
|
||||||
|
temp: {}
|
||||||
|
|||||||
1903
central_backend/Cargo.lock
generated
1903
central_backend/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,43 +1,46 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "central_backend"
|
name = "central_backend"
|
||||||
version = "0.1.0"
|
version = "1.0.3"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4.22"
|
log = "0.4.28"
|
||||||
env_logger = "0.11.5"
|
env_logger = "0.11.8"
|
||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
clap = { version = "4.5.20", features = ["derive", "env"] }
|
dotenvy = "0.15.7"
|
||||||
anyhow = "1.0.89"
|
clap = { version = "4.5.50", features = ["derive", "env"] }
|
||||||
thiserror = "1.0.64"
|
anyhow = "1.0.100"
|
||||||
openssl = { version = "0.10.66" }
|
thiserror = "2.0.17"
|
||||||
openssl-sys = "0.9.102"
|
openssl = { version = "0.10.74" }
|
||||||
libc = "0.2.159"
|
openssl-sys = "0.9.110"
|
||||||
|
libc = "0.2.177"
|
||||||
foreign-types-shared = "0.1.1"
|
foreign-types-shared = "0.1.1"
|
||||||
asn1 = "0.17"
|
asn1 = "0.23.0"
|
||||||
actix-web = { version = "4", features = ["openssl"] }
|
actix-web = { version = "4.11.0", features = ["openssl"] }
|
||||||
futures = "0.3.31"
|
futures = "0.3.31"
|
||||||
serde = { version = "1.0.210", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
reqwest = { version = "0.12.7", features = ["json"] }
|
reqwest = { version = "0.12.24", features = ["json"] }
|
||||||
serde_json = "1.0.128"
|
serde_json = "1.0.145"
|
||||||
rand = "0.8.5"
|
rand = "0.10.0-rc.0"
|
||||||
actix = "0.13.5"
|
actix = "0.13.5"
|
||||||
actix-identity = "0.8.0"
|
actix-identity = "0.9.0"
|
||||||
actix-session = { version = "0.10.1", features = ["cookie-session"] }
|
actix-session = { version = "0.11.0", features = ["cookie-session"] }
|
||||||
actix-cors = "0.7.0"
|
actix-cors = "0.7.1"
|
||||||
actix-multipart = { version ="0.7.2", features = ["derive"] }
|
actix-multipart = { version = "0.7.2", features = ["derive"] }
|
||||||
actix-remote-ip = "0.1.0"
|
actix-remote-ip = "0.1.0"
|
||||||
futures-util = "0.3.31"
|
futures-util = "0.3.31"
|
||||||
uuid = { version = "1.10.0", features = ["v4", "serde"] }
|
uuid = { version = "1.18.1", features = ["v4", "serde"] }
|
||||||
semver = { version = "1.0.23", features = ["serde"] }
|
semver = { version = "1.0.27", features = ["serde"] }
|
||||||
lazy-regex = "3.3.0"
|
lazy-regex = "3.4.1"
|
||||||
tokio = { version = "1.40.0", features = ["full"] }
|
tokio = { version = "1.48.0", features = ["full"] }
|
||||||
tokio_schedule = "0.3.2"
|
tokio_schedule = "0.3.2"
|
||||||
mime_guess = "2.0.5"
|
mime_guess = "2.0.5"
|
||||||
rust-embed = "8.5.0"
|
rust-embed = "8.8.0"
|
||||||
jsonwebtoken = { version = "9.3.0", features = ["use_pem"] }
|
jsonwebtoken = { version = "10.1.0", features = ["use_pem", "rust_crypto"] }
|
||||||
prettytable-rs = "0.10.0"
|
prettytable-rs = "0.10.0"
|
||||||
chrono = "0.4.38"
|
chrono = "0.4.42"
|
||||||
serde_yml = "0.0.12"
|
serde_yml = "0.0.12"
|
||||||
bincode = "=2.0.0-rc.3"
|
bincode = "2.0.1"
|
||||||
fs4 = { version = "0.10.0", features = ["sync"] }
|
fs4 = { version = "0.13.1", features = ["sync"] }
|
||||||
|
zip = { version = "6.0.0", features = ["bzip2"] }
|
||||||
|
walkdir = "2.5.0"
|
||||||
|
|||||||
33
central_backend/engine_test/test_turn_forced_off.yaml
Normal file
33
central_backend/engine_test/test_turn_forced_off.yaml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
devices:
|
||||||
|
- id: dev1
|
||||||
|
info:
|
||||||
|
reference: A
|
||||||
|
version: 0.0.1
|
||||||
|
max_relays: 1
|
||||||
|
time_create: 1
|
||||||
|
time_update: 1
|
||||||
|
name: Dev1
|
||||||
|
description: Day1
|
||||||
|
validated: true
|
||||||
|
enabled: true
|
||||||
|
relays:
|
||||||
|
- id: dcb3fd91-bf9b-4de3-99e5-92c1c7dd72e9
|
||||||
|
name: R1
|
||||||
|
enabled: true
|
||||||
|
priority: 1
|
||||||
|
consumption: 100
|
||||||
|
minimal_uptime: 10
|
||||||
|
minimal_downtime: 10
|
||||||
|
depends_on: []
|
||||||
|
conflicts_with: []
|
||||||
|
|
||||||
|
on: false
|
||||||
|
for: 5000
|
||||||
|
forced_state:
|
||||||
|
type: Off
|
||||||
|
for_secs: 500
|
||||||
|
should_be_on: false
|
||||||
|
|
||||||
|
online: true
|
||||||
|
|
||||||
|
curr_consumption: -10000
|
||||||
49
central_backend/engine_test/test_turn_forced_on.yaml
Normal file
49
central_backend/engine_test/test_turn_forced_on.yaml
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
devices:
|
||||||
|
- id: dev1
|
||||||
|
info:
|
||||||
|
reference: A
|
||||||
|
version: 0.0.1
|
||||||
|
max_relays: 1
|
||||||
|
time_create: 1
|
||||||
|
time_update: 1
|
||||||
|
name: Dev1
|
||||||
|
description: Day1
|
||||||
|
validated: true
|
||||||
|
enabled: true
|
||||||
|
relays:
|
||||||
|
- id: dcb3fd91-bf9b-4de3-99e5-92c1c7dd72e9
|
||||||
|
name: R1
|
||||||
|
enabled: true
|
||||||
|
priority: 1
|
||||||
|
consumption: 100
|
||||||
|
minimal_uptime: 10
|
||||||
|
minimal_downtime: 10
|
||||||
|
depends_on: []
|
||||||
|
conflicts_with: []
|
||||||
|
|
||||||
|
on: false
|
||||||
|
for: 500
|
||||||
|
forced_state:
|
||||||
|
type: On
|
||||||
|
for_secs: 500
|
||||||
|
should_be_on: true
|
||||||
|
|
||||||
|
- id: dcb3fd91-bf9b-4de3-99e5-92c1c7dd72f0
|
||||||
|
name: R2
|
||||||
|
enabled: true
|
||||||
|
priority: 1
|
||||||
|
consumption: 100
|
||||||
|
minimal_uptime: 10
|
||||||
|
minimal_downtime: 10
|
||||||
|
depends_on: [ ]
|
||||||
|
conflicts_with: [ ]
|
||||||
|
|
||||||
|
on: false
|
||||||
|
for: 500
|
||||||
|
forced_state:
|
||||||
|
type: None
|
||||||
|
should_be_on: false
|
||||||
|
|
||||||
|
online: true
|
||||||
|
|
||||||
|
curr_consumption: 10000
|
||||||
@@ -10,7 +10,7 @@ pub enum ConsumptionHistoryType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Electrical consumption fetcher backend
|
/// Electrical consumption fetcher backend
|
||||||
#[derive(Subcommand, Debug, Clone)]
|
#[derive(Subcommand, Debug, Clone, serde::Serialize)]
|
||||||
pub enum ConsumptionBackend {
|
pub enum ConsumptionBackend {
|
||||||
/// Constant consumption value
|
/// Constant consumption value
|
||||||
Constant {
|
Constant {
|
||||||
@@ -38,16 +38,24 @@ pub enum ConsumptionBackend {
|
|||||||
|
|
||||||
/// Fronius inverter consumption
|
/// Fronius inverter consumption
|
||||||
Fronius {
|
Fronius {
|
||||||
/// The origin of the domain where the webserver of the Fronius Symo can be reacher
|
/// The origin of the domain where the webserver of the Fronius Symo can be reached
|
||||||
|
#[clap(short, long, env)]
|
||||||
|
fronius_orig: String,
|
||||||
|
|
||||||
|
/// Use cURL instead of reqwest to perform request
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
origin: String,
|
curl: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Solar system central backend
|
/// Solar system central backend
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug, serde::Serialize)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
pub struct AppConfig {
|
pub struct AppConfig {
|
||||||
|
/// Read arguments from env file
|
||||||
|
#[clap(short, long, env)]
|
||||||
|
pub config: Option<String>,
|
||||||
|
|
||||||
/// Proxy IP, might end with a star "*"
|
/// Proxy IP, might end with a star "*"
|
||||||
#[clap(short, long, env)]
|
#[clap(short, long, env)]
|
||||||
pub proxy_ip: Option<String>,
|
pub proxy_ip: Option<String>,
|
||||||
@@ -102,6 +110,18 @@ pub struct AppConfig {
|
|||||||
#[arg(short('f'), long, env, default_value_t = 5)]
|
#[arg(short('f'), long, env, default_value_t = 5)]
|
||||||
pub energy_fetch_interval: u64,
|
pub energy_fetch_interval: u64,
|
||||||
|
|
||||||
|
/// Custom current consumption title in dashboard
|
||||||
|
#[arg(long, env)]
|
||||||
|
pub dashboard_custom_current_consumption_title: Option<String>,
|
||||||
|
|
||||||
|
/// Custom relays consumption title in dashboard
|
||||||
|
#[arg(long, env)]
|
||||||
|
pub dashboard_custom_relays_consumption_title: Option<String>,
|
||||||
|
|
||||||
|
/// Custom cached consumption title in dashboard
|
||||||
|
#[arg(long, env)]
|
||||||
|
pub dashboard_custom_cached_consumption_title: Option<String>,
|
||||||
|
|
||||||
/// Consumption backend provider
|
/// Consumption backend provider
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
pub consumption_backend: Option<ConsumptionBackend>,
|
pub consumption_backend: Option<ConsumptionBackend>,
|
||||||
@@ -114,6 +134,21 @@ lazy_static::lazy_static! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AppConfig {
|
impl AppConfig {
|
||||||
|
/// Parse environment variables from file, if requedst
|
||||||
|
pub fn parse_env_file() -> anyhow::Result<()> {
|
||||||
|
if let Some(c) = Self::parse().config {
|
||||||
|
log::info!("Load additional environment variables from {c}");
|
||||||
|
let conf_file = Path::new(&c);
|
||||||
|
|
||||||
|
if !conf_file.is_file() {
|
||||||
|
panic!("Specified configuration is not a file!");
|
||||||
|
}
|
||||||
|
dotenvy::from_path(conf_file)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Get parsed command line arguments
|
/// Get parsed command line arguments
|
||||||
pub fn get() -> &'static AppConfig {
|
pub fn get() -> &'static AppConfig {
|
||||||
&ARGS
|
&ARGS
|
||||||
|
|||||||
@@ -16,11 +16,13 @@ impl CRLDistributionPointExt {
|
|||||||
let crl_bytes = asn1::write(|w| {
|
let crl_bytes = asn1::write(|w| {
|
||||||
w.write_element(&asn1::SequenceWriter::new(&|w| {
|
w.write_element(&asn1::SequenceWriter::new(&|w| {
|
||||||
w.write_element(&asn1::SequenceWriter::new(&|w| {
|
w.write_element(&asn1::SequenceWriter::new(&|w| {
|
||||||
w.write_tlv(tag_a0, |w| {
|
w.write_tlv(tag_a0, None, |w: &mut asn1::WriteBuf| {
|
||||||
w.push_slice(&asn1::write(|w| {
|
w.push_slice(&asn1::write(|w| {
|
||||||
w.write_tlv(tag_a0, |w| {
|
w.write_tlv(tag_a0, None, |w: &mut asn1::WriteBuf| {
|
||||||
w.push_slice(&asn1::write(|w| {
|
w.push_slice(&asn1::write(|w| {
|
||||||
w.write_tlv(tag_86, |b| b.push_slice(self.url.as_bytes()))?;
|
w.write_tlv(tag_86, None, |b| {
|
||||||
|
b.push_slice(self.url.as_bytes())
|
||||||
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})?)
|
})?)
|
||||||
})?;
|
})?;
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ use openssl::pkey::{PKey, Private};
|
|||||||
use openssl::x509::extension::{
|
use openssl::x509::extension::{
|
||||||
BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, SubjectKeyIdentifier,
|
BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, SubjectKeyIdentifier,
|
||||||
};
|
};
|
||||||
use openssl::x509::{CrlStatus, X509Crl, X509Name, X509NameBuilder, X509Req, X509};
|
use openssl::x509::{CrlStatus, X509, X509Crl, X509Name, X509NameBuilder, X509Req};
|
||||||
use openssl_sys::{
|
use openssl_sys::{
|
||||||
X509_CRL_add0_revoked, X509_CRL_new, X509_CRL_set1_lastUpdate, X509_CRL_set1_nextUpdate,
|
X509_CRL_add0_revoked, X509_CRL_new, X509_CRL_set_issuer_name, X509_CRL_set_version,
|
||||||
X509_CRL_set_issuer_name, X509_CRL_set_version, X509_CRL_sign, X509_REVOKED_dup,
|
X509_CRL_set1_lastUpdate, X509_CRL_set1_nextUpdate, X509_CRL_sign, X509_REVOKED_dup,
|
||||||
X509_REVOKED_new, X509_REVOKED_set_revocationDate, X509_REVOKED_set_serialNumber,
|
X509_REVOKED_new, X509_REVOKED_set_revocationDate, X509_REVOKED_set_serialNumber,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ enum GenCertificatSubjectReq<'a> {
|
|||||||
CSR { csr: &'a X509Req },
|
CSR { csr: &'a X509Req },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for GenCertificatSubjectReq<'a> {
|
impl Default for GenCertificatSubjectReq<'_> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Subject { cn: "" }
|
Self::Subject { cn: "" }
|
||||||
}
|
}
|
||||||
@@ -174,17 +174,16 @@ fn gen_certificate(req: GenCertificateReq) -> anyhow::Result<(Option<Vec<u8>>, V
|
|||||||
cert_builder.set_not_after(¬_after)?;
|
cert_builder.set_not_after(¬_after)?;
|
||||||
|
|
||||||
// Specify CRL URL
|
// Specify CRL URL
|
||||||
if let Some(issuer) = req.issuer {
|
if let Some(issuer) = req.issuer
|
||||||
if let Some(crl) = &issuer.crl {
|
&& let Some(crl) = &issuer.crl
|
||||||
let crl_url = format!(
|
{
|
||||||
"{}/pki/{}",
|
let crl_url = format!(
|
||||||
AppConfig::get().unsecure_origin(),
|
"{}/pki/{}",
|
||||||
crl.file_name().unwrap().to_string_lossy()
|
AppConfig::get().unsecure_origin(),
|
||||||
);
|
crl.file_name().unwrap().to_string_lossy()
|
||||||
|
);
|
||||||
|
|
||||||
cert_builder
|
cert_builder.append_extension(CRLDistributionPointExt { url: crl_url }.as_extension()?)?;
|
||||||
.append_extension(CRLDistributionPointExt { url: crl_url }.as_extension()?)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If cert is a CA or not
|
// If cert is a CA or not
|
||||||
@@ -424,12 +423,12 @@ fn refresh_crl(d: &CertData, new_cert: Option<&X509>) -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add old entries
|
// Add old entries
|
||||||
if let Some(old_crl) = old_crl {
|
if let Some(old_crl) = old_crl
|
||||||
if let Some(entries) = old_crl.get_revoked() {
|
&& let Some(entries) = old_crl.get_revoked()
|
||||||
for entry in entries {
|
{
|
||||||
if X509_CRL_add0_revoked(crl, X509_REVOKED_dup(entry.as_ptr())) == 0 {
|
for entry in entries {
|
||||||
return Err(PKIError::GenCRLError("X509_CRL_add0_revoked").into());
|
if X509_CRL_add0_revoked(crl, X509_REVOKED_dup(entry.as_ptr())) == 0 {
|
||||||
}
|
return Err(PKIError::GenCRLError("X509_CRL_add0_revoked").into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -325,9 +325,11 @@ mod tests {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
dep_cycle_1.depends_on = vec![dep_cycle_3.id];
|
dep_cycle_1.depends_on = vec![dep_cycle_3.id];
|
||||||
assert!(dep_cycle_1
|
assert!(
|
||||||
.error(&[dep_cycle_2.clone(), dep_cycle_3.clone()])
|
dep_cycle_1
|
||||||
.is_some());
|
.error(&[dep_cycle_2.clone(), dep_cycle_3.clone()])
|
||||||
|
.is_some()
|
||||||
|
);
|
||||||
|
|
||||||
dep_cycle_1.depends_on = vec![];
|
dep_cycle_1.depends_on = vec![];
|
||||||
assert!(dep_cycle_1.error(&[dep_cycle_2, dep_cycle_3]).is_none());
|
assert!(dep_cycle_1.error(&[dep_cycle_2, dep_cycle_3]).is_none());
|
||||||
@@ -351,21 +353,29 @@ mod tests {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(target_relay
|
assert!(
|
||||||
.error(&[other_dep.clone(), second_dep.clone()])
|
target_relay
|
||||||
.is_some());
|
.error(&[other_dep.clone(), second_dep.clone()])
|
||||||
assert!(target_relay
|
.is_some()
|
||||||
.error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()])
|
);
|
||||||
.is_some());
|
assert!(
|
||||||
|
target_relay
|
||||||
|
.error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()])
|
||||||
|
.is_some()
|
||||||
|
);
|
||||||
|
|
||||||
second_dep.conflicts_with = vec![];
|
second_dep.conflicts_with = vec![];
|
||||||
|
|
||||||
assert!(target_relay
|
assert!(
|
||||||
.error(&[other_dep.clone(), second_dep.clone()])
|
target_relay
|
||||||
.is_none());
|
.error(&[other_dep.clone(), second_dep.clone()])
|
||||||
assert!(target_relay
|
.is_none()
|
||||||
.error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()])
|
);
|
||||||
.is_none());
|
assert!(
|
||||||
|
target_relay
|
||||||
|
.error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()])
|
||||||
|
.is_none()
|
||||||
|
);
|
||||||
|
|
||||||
// self loop
|
// self loop
|
||||||
let mut self_loop = DeviceRelay {
|
let mut self_loop = DeviceRelay {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::devices::device::{
|
|||||||
Device, DeviceGeneralInfo, DeviceId, DeviceInfo, DeviceRelay, DeviceRelayID,
|
Device, DeviceGeneralInfo, DeviceId, DeviceInfo, DeviceRelay, DeviceRelayID,
|
||||||
};
|
};
|
||||||
use crate::utils::time_utils::time_secs;
|
use crate::utils::time_utils::time_secs;
|
||||||
use openssl::x509::{X509Req, X509};
|
use openssl::x509::{X509, X509Req};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::app_config::{AppConfig, ConsumptionBackend};
|
use crate::app_config::{AppConfig, ConsumptionBackend};
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{Rng, rng};
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -9,6 +9,8 @@ pub enum ConsumptionError {
|
|||||||
NonExistentFile,
|
NonExistentFile,
|
||||||
#[error("The file that should contain the consumption has an invalid content!")]
|
#[error("The file that should contain the consumption has an invalid content!")]
|
||||||
FileInvalidContent(#[source] ParseIntError),
|
FileInvalidContent(#[source] ParseIntError),
|
||||||
|
#[error("Failed to execute cURL request!")]
|
||||||
|
CurlReqFailed,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type EnergyConsumption = i32;
|
pub type EnergyConsumption = i32;
|
||||||
@@ -47,7 +49,7 @@ pub async fn get_curr_consumption() -> anyhow::Result<EnergyConsumption> {
|
|||||||
match backend {
|
match backend {
|
||||||
ConsumptionBackend::Constant { value } => Ok(*value),
|
ConsumptionBackend::Constant { value } => Ok(*value),
|
||||||
|
|
||||||
ConsumptionBackend::Random { min, max } => Ok(thread_rng().gen_range(*min..*max)),
|
ConsumptionBackend::Random { min, max } => Ok(rng().random_range(*min..*max)),
|
||||||
|
|
||||||
ConsumptionBackend::File { path } => {
|
ConsumptionBackend::File { path } => {
|
||||||
let path = Path::new(path);
|
let path = Path::new(path);
|
||||||
@@ -63,9 +65,25 @@ pub async fn get_curr_consumption() -> anyhow::Result<EnergyConsumption> {
|
|||||||
.map_err(ConsumptionError::FileInvalidContent)?)
|
.map_err(ConsumptionError::FileInvalidContent)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsumptionBackend::Fronius { origin } => {
|
ConsumptionBackend::Fronius { fronius_orig, curl } => {
|
||||||
let url = format!("{origin}/solar_api/v1/GetPowerFlowRealtimeData.fcgi");
|
let url = format!("{fronius_orig}/solar_api/v1/GetPowerFlowRealtimeData.fcgi");
|
||||||
let response = reqwest::get(url).await?.json::<FroniusResponse>().await?;
|
|
||||||
|
let response = match curl {
|
||||||
|
false => reqwest::get(url).await?.json::<FroniusResponse>().await?,
|
||||||
|
true => {
|
||||||
|
let res = std::process::Command::new("curl")
|
||||||
|
.arg("--connect-timeout")
|
||||||
|
.arg("1.5")
|
||||||
|
.arg(url)
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
if !res.status.success() {
|
||||||
|
return Err(ConsumptionError::CurlReqFailed.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
serde_json::from_slice::<FroniusResponse>(&res.stdout)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(response.body.data.site.grid_production as i32)
|
Ok(response.body.data.site.grid_production as i32)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::energy::consumption;
|
|||||||
use crate::energy::consumption::EnergyConsumption;
|
use crate::energy::consumption::EnergyConsumption;
|
||||||
use crate::energy::consumption_cache::ConsumptionCache;
|
use crate::energy::consumption_cache::ConsumptionCache;
|
||||||
use crate::energy::consumption_history_file::ConsumptionHistoryFile;
|
use crate::energy::consumption_history_file::ConsumptionHistoryFile;
|
||||||
use crate::energy::engine::EnergyEngine;
|
use crate::energy::engine::{EnergyEngine, RelayForcedState};
|
||||||
use crate::utils::time_utils::time_secs;
|
use crate::utils::time_utils::time_secs;
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
use openssl::x509::X509Req;
|
use openssl::x509::X509Req;
|
||||||
@@ -25,7 +25,14 @@ impl EnergyActor {
|
|||||||
pub async fn new() -> anyhow::Result<Self> {
|
pub async fn new() -> anyhow::Result<Self> {
|
||||||
let consumption_cache_size =
|
let consumption_cache_size =
|
||||||
AppConfig::get().refresh_interval / AppConfig::get().energy_fetch_interval;
|
AppConfig::get().refresh_interval / AppConfig::get().energy_fetch_interval;
|
||||||
let curr_consumption = consumption::get_curr_consumption().await?;
|
let curr_consumption = match consumption::get_curr_consumption().await {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Failed to fetch consumption, using default value! {e}");
|
||||||
|
constants::FALLBACK_PRODUCTION_VALUE
|
||||||
|
}
|
||||||
|
};
|
||||||
|
log::info!("Initial consumption value: {curr_consumption}");
|
||||||
let mut consumption_cache = ConsumptionCache::new(consumption_cache_size as usize);
|
let mut consumption_cache = ConsumptionCache::new(consumption_cache_size as usize);
|
||||||
consumption_cache.add_value(curr_consumption);
|
consumption_cache.add_value(curr_consumption);
|
||||||
|
|
||||||
@@ -321,6 +328,19 @@ impl Handler<UpdateDeviceRelay> for EnergyActor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "anyhow::Result<()>")]
|
||||||
|
pub struct SetRelayForcedState(pub DeviceRelayID, pub RelayForcedState);
|
||||||
|
|
||||||
|
impl Handler<SetRelayForcedState> for EnergyActor {
|
||||||
|
type Result = anyhow::Result<()>;
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: SetRelayForcedState, _ctx: &mut Context<Self>) -> Self::Result {
|
||||||
|
self.engine.relay_state(msg.0).set_forced(msg.1);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Delete a device relay
|
/// Delete a device relay
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
#[rtype(result = "anyhow::Result<()>")]
|
#[rtype(result = "anyhow::Result<()>")]
|
||||||
@@ -401,6 +421,7 @@ pub struct ResRelayState {
|
|||||||
pub id: DeviceRelayID,
|
pub id: DeviceRelayID,
|
||||||
pub on: bool,
|
pub on: bool,
|
||||||
pub r#for: usize,
|
pub r#for: usize,
|
||||||
|
pub forced_state: RelayForcedState,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the state of all relays
|
/// Get the state of all relays
|
||||||
@@ -420,6 +441,7 @@ impl Handler<GetAllRelaysState> for EnergyActor {
|
|||||||
id: d.id,
|
id: d.id,
|
||||||
on: state.is_on(),
|
on: state.is_on(),
|
||||||
r#for: state.state_for(),
|
r#for: state.state_for(),
|
||||||
|
forced_state: state.actual_forced_state(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::app_config::AppConfig;
|
use crate::app_config::AppConfig;
|
||||||
use prettytable::{row, Table};
|
use prettytable::{Table, row};
|
||||||
|
|
||||||
use crate::constants;
|
use crate::constants;
|
||||||
use crate::devices::device::{Device, DeviceId, DeviceRelay, DeviceRelayID};
|
use crate::devices::device::{Device, DeviceId, DeviceRelay, DeviceRelayID};
|
||||||
@@ -25,19 +25,83 @@ impl DeviceState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub enum SetRelayForcedStateReq {
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
Off {
|
||||||
|
for_secs: u64,
|
||||||
|
},
|
||||||
|
On {
|
||||||
|
for_secs: u64,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SetRelayForcedStateReq {
|
||||||
|
pub fn to_forced_state(&self) -> RelayForcedState {
|
||||||
|
match &self {
|
||||||
|
SetRelayForcedStateReq::None => RelayForcedState::None,
|
||||||
|
SetRelayForcedStateReq::Off { for_secs } => RelayForcedState::Off {
|
||||||
|
until: time_secs() + for_secs,
|
||||||
|
},
|
||||||
|
SetRelayForcedStateReq::On { for_secs } => RelayForcedState::On {
|
||||||
|
until: time_secs() + for_secs,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub enum RelayForcedState {
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
Off {
|
||||||
|
until: u64,
|
||||||
|
},
|
||||||
|
On {
|
||||||
|
until: u64,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct RelayState {
|
pub struct RelayState {
|
||||||
on: bool,
|
on: bool,
|
||||||
since: usize,
|
since: usize,
|
||||||
|
forced_state: RelayForcedState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RelayState {
|
impl RelayState {
|
||||||
|
/// Get actual forced state (returns None if state is expired)
|
||||||
|
pub fn actual_forced_state(&self) -> RelayForcedState {
|
||||||
|
match self.forced_state {
|
||||||
|
RelayForcedState::Off { until } if until > time_secs() => {
|
||||||
|
RelayForcedState::Off { until }
|
||||||
|
}
|
||||||
|
RelayForcedState::On { until } if until > time_secs() => RelayForcedState::On { until },
|
||||||
|
_ => RelayForcedState::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_on(&self) -> bool {
|
pub fn is_on(&self) -> bool {
|
||||||
self.on
|
let forced_state = self.actual_forced_state();
|
||||||
|
(self.on || matches!(forced_state, RelayForcedState::On { .. }))
|
||||||
|
&& !matches!(forced_state, RelayForcedState::Off { .. })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_off(&self) -> bool {
|
fn is_off(&self) -> bool {
|
||||||
!self.on
|
!self.is_on()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if relay state is enforced
|
||||||
|
pub fn is_forced(&self) -> bool {
|
||||||
|
self.actual_forced_state() != RelayForcedState::None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_forced(&mut self, s: RelayForcedState) {
|
||||||
|
self.since = time_secs() as usize;
|
||||||
|
self.forced_state = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn state_for(&self) -> usize {
|
pub fn state_for(&self) -> usize {
|
||||||
@@ -146,7 +210,11 @@ impl EnergyEngine {
|
|||||||
r.name,
|
r.name,
|
||||||
r.consumption,
|
r.consumption,
|
||||||
format!("{} / {}", r.minimal_downtime, r.minimal_uptime),
|
format!("{} / {}", r.minimal_downtime, r.minimal_uptime),
|
||||||
status.is_on().to_string(),
|
status.is_on().to_string()
|
||||||
|
+ match status.is_forced() {
|
||||||
|
true => " (Forced)",
|
||||||
|
false => "",
|
||||||
|
},
|
||||||
status.since,
|
status.since,
|
||||||
match dev_online {
|
match dev_online {
|
||||||
true => "Online",
|
true => "Online",
|
||||||
@@ -192,19 +260,28 @@ impl EnergyEngine {
|
|||||||
|
|
||||||
let mut new_relays_state = self.relays_state.clone();
|
let mut new_relays_state = self.relays_state.clone();
|
||||||
|
|
||||||
// Forcefully turn off relays that belongs to offline devices
|
// Forcefully turn off disabled relays
|
||||||
for d in devices {
|
for d in devices {
|
||||||
if !self.device_state(&d.id).is_online() {
|
for r in &d.relays {
|
||||||
for r in &d.relays {
|
if !r.enabled || !d.enabled {
|
||||||
new_relays_state.get_mut(&r.id).unwrap().on = false;
|
new_relays_state.get_mut(&r.id).unwrap().on = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forcefully turn off disabled relays
|
// Apply forced relays state
|
||||||
for d in devices {
|
for d in devices {
|
||||||
for r in &d.relays {
|
for r in &d.relays {
|
||||||
if !r.enabled || !d.enabled {
|
if self.relay_state(r.id).is_forced() {
|
||||||
|
new_relays_state.get_mut(&r.id).unwrap().on = self.relay_state(r.id).is_on();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forcefully turn off relays that belongs to offline devices
|
||||||
|
for d in devices {
|
||||||
|
if !self.device_state(&d.id).is_online() {
|
||||||
|
for r in &d.relays {
|
||||||
new_relays_state.get_mut(&r.id).unwrap().on = false;
|
new_relays_state.get_mut(&r.id).unwrap().on = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,7 +293,9 @@ impl EnergyEngine {
|
|||||||
|
|
||||||
for d in devices {
|
for d in devices {
|
||||||
for r in &d.relays {
|
for r in &d.relays {
|
||||||
if new_relays_state.get(&r.id).unwrap().is_off() {
|
if new_relays_state.get(&r.id).unwrap().is_off()
|
||||||
|
|| new_relays_state.get(&r.id).unwrap().is_forced()
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +319,7 @@ impl EnergyEngine {
|
|||||||
for d in devices {
|
for d in devices {
|
||||||
for r in &d.relays {
|
for r in &d.relays {
|
||||||
let state = new_relays_state.get(&r.id).unwrap();
|
let state = new_relays_state.get(&r.id).unwrap();
|
||||||
if state.is_off() {
|
if state.is_off() || state.is_forced() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +350,9 @@ impl EnergyEngine {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_relays_state.get(&r.id).unwrap().is_on() {
|
if new_relays_state.get(&r.id).unwrap().is_on()
|
||||||
|
|| new_relays_state.get(&r.id).unwrap().is_forced()
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,12 +370,16 @@ impl EnergyEngine {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("Forcefully turn on relay {} to catch up running constraints (only {}s this day)", r.name, total_runtime);
|
log::info!(
|
||||||
|
"Forcefully turn on relay {} to catch up running constraints (only {}s this day)",
|
||||||
|
r.name,
|
||||||
|
total_runtime
|
||||||
|
);
|
||||||
new_relays_state.get_mut(&r.id).unwrap().on = true;
|
new_relays_state.get_mut(&r.id).unwrap().on = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Order relays
|
// Order relays to select the ones with the most elevated priorities
|
||||||
let mut ordered_relays = devices
|
let mut ordered_relays = devices
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|d| self.device_state(&d.id).is_online() && d.enabled)
|
.filter(|d| self.device_state(&d.id).is_online() && d.enabled)
|
||||||
@@ -304,10 +389,13 @@ impl EnergyEngine {
|
|||||||
ordered_relays.sort_by_key(|r| r.priority);
|
ordered_relays.sort_by_key(|r| r.priority);
|
||||||
ordered_relays.reverse();
|
ordered_relays.reverse();
|
||||||
|
|
||||||
|
// Select relays to start, starting with those with highest priorities
|
||||||
loop {
|
loop {
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
for relay in &ordered_relays {
|
for relay in &ordered_relays {
|
||||||
if new_relays_state.get(&relay.id).unwrap().is_on() {
|
if new_relays_state.get(&relay.id).unwrap().is_on()
|
||||||
|
|| new_relays_state.get(&relay.id).unwrap().is_forced()
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,7 +467,7 @@ impl EnergyEngine {
|
|||||||
mod test {
|
mod test {
|
||||||
use crate::devices::device::{Device, DeviceId, DeviceRelayID};
|
use crate::devices::device::{Device, DeviceId, DeviceRelayID};
|
||||||
use crate::energy::consumption::EnergyConsumption;
|
use crate::energy::consumption::EnergyConsumption;
|
||||||
use crate::energy::engine::EnergyEngine;
|
use crate::energy::engine::{EnergyEngine, SetRelayForcedStateReq};
|
||||||
use crate::utils::time_utils::time_secs;
|
use crate::utils::time_utils::time_secs;
|
||||||
use rust_embed::Embed;
|
use rust_embed::Embed;
|
||||||
|
|
||||||
@@ -388,6 +476,8 @@ mod test {
|
|||||||
id: DeviceRelayID,
|
id: DeviceRelayID,
|
||||||
on: bool,
|
on: bool,
|
||||||
r#for: usize,
|
r#for: usize,
|
||||||
|
#[serde(default)]
|
||||||
|
forced_state: SetRelayForcedStateReq,
|
||||||
should_be_on: bool,
|
should_be_on: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,6 +525,7 @@ mod test {
|
|||||||
let s = engine.relay_state(r.id);
|
let s = engine.relay_state(r.id);
|
||||||
s.on = r.on;
|
s.on = r.on;
|
||||||
s.since = time_secs() as usize - r.r#for;
|
s.since = time_secs() as usize - r.r#for;
|
||||||
|
s.forced_state = r.forced_state.to_forced_state()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::app_config::AppConfig;
|
use crate::app_config::AppConfig;
|
||||||
use crate::devices::device::{DeviceRelay, DeviceRelayID};
|
use crate::devices::device::{DeviceRelay, DeviceRelayID};
|
||||||
use crate::utils::files_utils;
|
use crate::utils::files_utils;
|
||||||
use crate::utils::time_utils::{day_number, time_start_of_day};
|
use crate::utils::time_utils::{day_number, time_secs, time_start_of_day};
|
||||||
|
|
||||||
const TIME_INTERVAL: usize = 30;
|
const TIME_INTERVAL: usize = 30;
|
||||||
|
|
||||||
@@ -128,15 +128,26 @@ pub fn relay_total_runtime_adjusted(relay: &DeviceRelay) -> usize {
|
|||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
let time_start_day = time_start_of_day().unwrap_or(1726696800);
|
let time_start_day = time_start_of_day().unwrap_or(1726696800);
|
||||||
let start_time = time_start_day + reset_time as u64;
|
|
||||||
let end_time = time_start_day + 3600 * 24 + reset_time as u64;
|
// Check if we have reached reset_time today yet or not
|
||||||
relay_total_runtime(relay.id, start_time, end_time).unwrap_or(3600 * 24)
|
if time_start_day + reset_time as u64 <= time_secs() {
|
||||||
|
let start_time = time_start_day + reset_time as u64;
|
||||||
|
let end_time = time_start_day + 3600 * 24 + reset_time as u64;
|
||||||
|
relay_total_runtime(relay.id, start_time, end_time).unwrap_or(3600 * 24)
|
||||||
|
}
|
||||||
|
// If we have not reached reset time yet, we need to focus on previous day
|
||||||
|
else {
|
||||||
|
let time_start_yesterday = time_start_day - 3600 * 24;
|
||||||
|
let start_time = time_start_yesterday + reset_time as u64;
|
||||||
|
let end_time = time_start_day + reset_time as u64;
|
||||||
|
relay_total_runtime(relay.id, start_time, end_time).unwrap_or(3600 * 24)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::devices::device::DeviceRelayID;
|
use crate::devices::device::DeviceRelayID;
|
||||||
use crate::energy::relay_state_history::{relay_total_runtime, RelayStateHistory};
|
use crate::energy::relay_state_history::{RelayStateHistory, relay_total_runtime};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_relay_state_history() {
|
fn test_relay_state_history() {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ pub fn save_log(
|
|||||||
.as_bytes(),
|
.as_bytes(),
|
||||||
)?;
|
)?;
|
||||||
file.flush()?;
|
file.flush()?;
|
||||||
file.unlock()?;
|
fs4::fs_std::FileExt::unlock(&file)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,13 @@ use central_backend::energy::energy_actor::EnergyActor;
|
|||||||
use central_backend::server::servers;
|
use central_backend::server::servers;
|
||||||
use central_backend::utils::files_utils::create_directory_if_missing;
|
use central_backend::utils::files_utils::create_directory_if_missing;
|
||||||
use futures::future;
|
use futures::future;
|
||||||
use tokio_schedule::{every, Job};
|
use tokio_schedule::{Job, every};
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
|
// Load additional config from file, if requested
|
||||||
|
AppConfig::parse_env_file().expect("Failed to parse environment file!");
|
||||||
|
|
||||||
// Initialize OpenSSL
|
// Initialize OpenSSL
|
||||||
openssl_sys::init();
|
openssl_sys::init();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use actix_identity::Identity;
|
use actix_identity::Identity;
|
||||||
use std::future::{ready, Ready};
|
use std::future::{Ready, ready};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::app_config::AppConfig;
|
use crate::app_config::AppConfig;
|
||||||
@@ -7,8 +7,8 @@ use crate::constants;
|
|||||||
use actix_web::body::EitherBody;
|
use actix_web::body::EitherBody;
|
||||||
use actix_web::dev::Payload;
|
use actix_web::dev::Payload;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
|
|
||||||
Error, FromRequest, HttpResponse,
|
Error, FromRequest, HttpResponse,
|
||||||
|
dev::{Service, ServiceRequest, ServiceResponse, Transform, forward_ready},
|
||||||
};
|
};
|
||||||
use futures_util::future::LocalBoxFuture;
|
use futures_util::future::LocalBoxFuture;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
use actix_web::HttpResponse;
|
||||||
use actix_web::body::BoxBody;
|
use actix_web::body::BoxBody;
|
||||||
use actix_web::http::StatusCode;
|
use actix_web::http::StatusCode;
|
||||||
use actix_web::HttpResponse;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::io::ErrorKind;
|
use zip::result::ZipError;
|
||||||
|
|
||||||
/// Custom error to ease controller writing
|
/// Custom error to ease controller writing
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -31,7 +31,7 @@ impl actix_web::error::ResponseError for HttpErr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||||
log::error!("Error while processing request! {}", self);
|
log::error!("Error while processing request! {self}");
|
||||||
|
|
||||||
HttpResponse::InternalServerError().body("Failed to execute request!")
|
HttpResponse::InternalServerError().body("Failed to execute request!")
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ impl From<serde_json::Error> for HttpErr {
|
|||||||
|
|
||||||
impl From<Box<dyn Error>> for HttpErr {
|
impl From<Box<dyn Error>> for HttpErr {
|
||||||
fn from(value: Box<dyn Error>) -> Self {
|
fn from(value: Box<dyn Error>) -> Self {
|
||||||
HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
|
HttpErr::Err(std::io::Error::other(value.to_string()).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,31 +81,43 @@ impl From<reqwest::header::ToStrError> for HttpErr {
|
|||||||
|
|
||||||
impl From<actix_web::Error> for HttpErr {
|
impl From<actix_web::Error> for HttpErr {
|
||||||
fn from(value: actix_web::Error) -> Self {
|
fn from(value: actix_web::Error) -> Self {
|
||||||
HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
|
HttpErr::Err(std::io::Error::other(value.to_string()).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<actix::MailboxError> for HttpErr {
|
impl From<actix::MailboxError> for HttpErr {
|
||||||
fn from(value: actix::MailboxError) -> Self {
|
fn from(value: actix::MailboxError) -> Self {
|
||||||
HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
|
HttpErr::Err(std::io::Error::other(value.to_string()).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<actix_identity::error::GetIdentityError> for HttpErr {
|
impl From<actix_identity::error::GetIdentityError> for HttpErr {
|
||||||
fn from(value: actix_identity::error::GetIdentityError) -> Self {
|
fn from(value: actix_identity::error::GetIdentityError) -> Self {
|
||||||
HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
|
HttpErr::Err(std::io::Error::other(value.to_string()).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<actix_identity::error::LoginError> for HttpErr {
|
impl From<actix_identity::error::LoginError> for HttpErr {
|
||||||
fn from(value: actix_identity::error::LoginError) -> Self {
|
fn from(value: actix_identity::error::LoginError) -> Self {
|
||||||
HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
|
HttpErr::Err(std::io::Error::other(value.to_string()).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<openssl::error::ErrorStack> for HttpErr {
|
impl From<openssl::error::ErrorStack> for HttpErr {
|
||||||
fn from(value: openssl::error::ErrorStack) -> Self {
|
fn from(value: openssl::error::ErrorStack) -> Self {
|
||||||
HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
|
HttpErr::Err(std::io::Error::other(value.to_string()).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ZipError> for HttpErr {
|
||||||
|
fn from(value: ZipError) -> Self {
|
||||||
|
HttpErr::Err(std::io::Error::other(value.to_string()).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<walkdir::Error> for HttpErr {
|
||||||
|
fn from(value: walkdir::Error) -> Self {
|
||||||
|
HttpErr::Err(std::io::Error::other(value.to_string()).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use crate::logs::logs_manager;
|
use crate::logs::logs_manager;
|
||||||
use crate::logs::severity::LogSeverity;
|
use crate::logs::severity::LogSeverity;
|
||||||
|
use crate::server::WebEnergyActor;
|
||||||
use crate::server::custom_error::HttpResult;
|
use crate::server::custom_error::HttpResult;
|
||||||
use crate::server::devices_api::jwt_parser::JWTRequest;
|
use crate::server::devices_api::jwt_parser::JWTRequest;
|
||||||
use crate::server::WebEnergyActor;
|
use actix_web::{HttpResponse, web};
|
||||||
use actix_web::{web, HttpResponse};
|
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize)]
|
#[derive(Debug, serde::Deserialize, Clone)]
|
||||||
pub struct LogRequest {
|
pub struct LogRequest {
|
||||||
severity: LogSeverity,
|
severity: LogSeverity,
|
||||||
message: String,
|
message: String,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::ota::ota_manager;
|
use crate::ota::ota_manager;
|
||||||
use crate::ota::ota_update::OTAPlatform;
|
use crate::ota::ota_update::OTAPlatform;
|
||||||
use crate::server::custom_error::HttpResult;
|
use crate::server::custom_error::HttpResult;
|
||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
pub struct FirmwarePath {
|
pub struct FirmwarePath {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ pub struct JWTRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl JWTRequest {
|
impl JWTRequest {
|
||||||
pub async fn parse_jwt<E: DeserializeOwned>(
|
pub async fn parse_jwt<E: DeserializeOwned + std::clone::Clone>(
|
||||||
&self,
|
&self,
|
||||||
actor: WebEnergyActor,
|
actor: WebEnergyActor,
|
||||||
) -> anyhow::Result<(Device, E)> {
|
) -> anyhow::Result<(Device, E)> {
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ use crate::energy::energy_actor;
|
|||||||
use crate::energy::energy_actor::RelaySyncStatus;
|
use crate::energy::energy_actor::RelaySyncStatus;
|
||||||
use crate::ota::ota_manager;
|
use crate::ota::ota_manager;
|
||||||
use crate::ota::ota_update::OTAPlatform;
|
use crate::ota::ota_update::OTAPlatform;
|
||||||
|
use crate::server::WebEnergyActor;
|
||||||
use crate::server::custom_error::HttpResult;
|
use crate::server::custom_error::HttpResult;
|
||||||
use crate::server::devices_api::jwt_parser::JWTRequest;
|
use crate::server::devices_api::jwt_parser::JWTRequest;
|
||||||
use crate::server::WebEnergyActor;
|
use actix_web::{HttpResponse, web};
|
||||||
use actix_web::{web, HttpResponse};
|
|
||||||
use openssl::nid::Nid;
|
use openssl::nid::Nid;
|
||||||
use openssl::x509::X509Req;
|
use openssl::x509::X509Req;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
@@ -130,7 +130,7 @@ pub async fn get_certificate(query: web::Query<ReqWithDevID>, actor: WebEnergyAc
|
|||||||
.body(cert))
|
.body(cert))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
struct Claims {
|
struct Claims {
|
||||||
info: DeviceInfo,
|
info: DeviceInfo,
|
||||||
}
|
}
|
||||||
@@ -155,12 +155,11 @@ pub async fn sync_device(body: web::Json<JWTRequest>, actor: WebEnergyActor) ->
|
|||||||
let mut available_update = None;
|
let mut available_update = None;
|
||||||
|
|
||||||
// Check if the version is available
|
// Check if the version is available
|
||||||
if let Some(desired) = device.desired_version {
|
if let Some(desired) = device.desired_version
|
||||||
if claims.info.version < desired
|
&& claims.info.version < desired
|
||||||
&& ota_manager::update_exists(OTAPlatform::from_str(&claims.info.reference)?, &desired)?
|
&& ota_manager::update_exists(OTAPlatform::from_str(&claims.info.reference)?, &desired)?
|
||||||
{
|
{
|
||||||
available_update = Some(desired);
|
available_update = Some(desired);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(SyncResult {
|
Ok(HttpResponse::Ok().json(SyncResult {
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ use crate::server::unsecure_server::*;
|
|||||||
use crate::server::web_api::*;
|
use crate::server::web_api::*;
|
||||||
use crate::server::web_app_controller;
|
use crate::server::web_app_controller;
|
||||||
use actix_cors::Cors;
|
use actix_cors::Cors;
|
||||||
use actix_identity::config::LogoutBehaviour;
|
|
||||||
use actix_identity::IdentityMiddleware;
|
use actix_identity::IdentityMiddleware;
|
||||||
|
use actix_identity::config::LogoutBehavior;
|
||||||
use actix_remote_ip::RemoteIPConfig;
|
use actix_remote_ip::RemoteIPConfig;
|
||||||
use actix_session::storage::CookieSessionStore;
|
|
||||||
use actix_session::SessionMiddleware;
|
use actix_session::SessionMiddleware;
|
||||||
|
use actix_session::storage::CookieSessionStore;
|
||||||
use actix_web::cookie::{Key, SameSite};
|
use actix_web::cookie::{Key, SameSite};
|
||||||
use actix_web::middleware::Logger;
|
use actix_web::middleware::Logger;
|
||||||
use actix_web::{web, App, HttpServer};
|
use actix_web::{App, HttpServer, web};
|
||||||
use openssl::ssl::{SslAcceptor, SslMethod};
|
use openssl::ssl::{SslAcceptor, SslMethod};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
let identity_middleware = IdentityMiddleware::builder()
|
let identity_middleware = IdentityMiddleware::builder()
|
||||||
.logout_behaviour(LogoutBehaviour::PurgeSession)
|
.logout_behavior(LogoutBehavior::PurgeSession)
|
||||||
.visit_deadline(Some(Duration::from_secs(
|
.visit_deadline(Some(Duration::from_secs(
|
||||||
constants::MAX_INACTIVITY_DURATION,
|
constants::MAX_INACTIVITY_DURATION,
|
||||||
)))
|
)))
|
||||||
@@ -231,6 +231,10 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
|
|||||||
"/web_api/relay/{id}",
|
"/web_api/relay/{id}",
|
||||||
web::put().to(relays_controller::update),
|
web::put().to(relays_controller::update),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/web_api/relay/{id}/forced_state",
|
||||||
|
web::put().to(relays_controller::set_forced_state),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/web_api/relay/{id}",
|
"/web_api/relay/{id}",
|
||||||
web::delete().to(relays_controller::delete),
|
web::delete().to(relays_controller::delete),
|
||||||
@@ -243,6 +247,11 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
|
|||||||
"/web_api/relay/{id}/status",
|
"/web_api/relay/{id}/status",
|
||||||
web::get().to(relays_controller::status_single),
|
web::get().to(relays_controller::status_single),
|
||||||
)
|
)
|
||||||
|
// Management API
|
||||||
|
.route(
|
||||||
|
"/web_api/management/download_storage",
|
||||||
|
web::get().to(management_controller::download_storage),
|
||||||
|
)
|
||||||
// Devices API
|
// Devices API
|
||||||
.route(
|
.route(
|
||||||
"/devices_api/utils/time",
|
"/devices_api/utils/time",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::app_config::AppConfig;
|
use crate::app_config::AppConfig;
|
||||||
use crate::server::custom_error::HttpResult;
|
use crate::server::custom_error::HttpResult;
|
||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
pub struct ServeCRLPath {
|
pub struct ServeCRLPath {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::devices::device::DeviceRelayID;
|
use crate::devices::device::DeviceRelayID;
|
||||||
use crate::energy::{energy_actor, relay_state_history};
|
use crate::energy::{energy_actor, relay_state_history};
|
||||||
use crate::server::custom_error::HttpResult;
|
|
||||||
use crate::server::WebEnergyActor;
|
use crate::server::WebEnergyActor;
|
||||||
use actix_web::{web, HttpResponse};
|
use crate::server::custom_error::HttpResult;
|
||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
pub struct LegacyStateRelay {
|
pub struct LegacyStateRelay {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use crate::app_config::AppConfig;
|
|||||||
use crate::server::custom_error::HttpResult;
|
use crate::server::custom_error::HttpResult;
|
||||||
use actix_identity::Identity;
|
use actix_identity::Identity;
|
||||||
use actix_remote_ip::RemoteIP;
|
use actix_remote_ip::RemoteIP;
|
||||||
use actix_web::{web, HttpMessage, HttpRequest, HttpResponse};
|
use actix_web::{HttpMessage, HttpRequest, HttpResponse, web};
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
pub struct AuthRequest {
|
pub struct AuthRequest {
|
||||||
@@ -17,11 +17,11 @@ pub async fn password_auth(
|
|||||||
remote_ip: RemoteIP,
|
remote_ip: RemoteIP,
|
||||||
) -> HttpResult {
|
) -> HttpResult {
|
||||||
if r.user != AppConfig::get().admin_username || r.password != AppConfig::get().admin_password {
|
if r.user != AppConfig::get().admin_username || r.password != AppConfig::get().admin_password {
|
||||||
log::error!("Failed login attempt from {}!", remote_ip.0.to_string());
|
log::error!("Failed login attempt from {}!", remote_ip.0);
|
||||||
return Ok(HttpResponse::Unauthorized().json("Invalid credentials!"));
|
return Ok(HttpResponse::Unauthorized().json("Invalid credentials!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("Successful login attempt from {}!", remote_ip.0.to_string());
|
log::info!("Successful login attempt from {}!", remote_ip.0);
|
||||||
Identity::login(&request.extensions(), r.user.to_string())?;
|
Identity::login(&request.extensions(), r.user.to_string())?;
|
||||||
Ok(HttpResponse::Ok().finish())
|
Ok(HttpResponse::Ok().finish())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::devices::device::{DeviceGeneralInfo, DeviceId};
|
use crate::devices::device::{DeviceGeneralInfo, DeviceId};
|
||||||
use crate::energy::energy_actor;
|
use crate::energy::energy_actor;
|
||||||
use crate::server::custom_error::HttpResult;
|
|
||||||
use crate::server::WebEnergyActor;
|
use crate::server::WebEnergyActor;
|
||||||
use actix_web::{web, HttpResponse};
|
use crate::server::custom_error::HttpResult;
|
||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
|
||||||
/// Get the list of pending (not accepted yet) devices
|
/// Get the list of pending (not accepted yet) devices
|
||||||
pub async fn list_pending(actor: WebEnergyActor) -> HttpResult {
|
pub async fn list_pending(actor: WebEnergyActor) -> HttpResult {
|
||||||
|
|||||||
@@ -2,21 +2,27 @@ use crate::app_config::ConsumptionHistoryType;
|
|||||||
use crate::energy::consumption::EnergyConsumption;
|
use crate::energy::consumption::EnergyConsumption;
|
||||||
use crate::energy::consumption_history_file::ConsumptionHistoryFile;
|
use crate::energy::consumption_history_file::ConsumptionHistoryFile;
|
||||||
use crate::energy::{consumption, energy_actor};
|
use crate::energy::{consumption, energy_actor};
|
||||||
use crate::server::custom_error::HttpResult;
|
|
||||||
use crate::server::WebEnergyActor;
|
use crate::server::WebEnergyActor;
|
||||||
|
use crate::server::custom_error::HttpResult;
|
||||||
use crate::utils::time_utils::time_secs;
|
use crate::utils::time_utils::time_secs;
|
||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
|
|
||||||
#[derive(serde::Serialize)]
|
#[derive(serde::Serialize)]
|
||||||
struct Consumption {
|
struct Consumption {
|
||||||
consumption: i32,
|
consumption: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get current energy consumption
|
/// Get current energy consumption
|
||||||
pub async fn curr_consumption() -> HttpResult {
|
pub async fn curr_consumption() -> HttpResult {
|
||||||
let consumption = consumption::get_curr_consumption().await?;
|
Ok(match consumption::get_curr_consumption().await {
|
||||||
|
Ok(v) => HttpResponse::Ok().json(Consumption {
|
||||||
Ok(HttpResponse::Ok().json(Consumption { consumption }))
|
consumption: Some(v),
|
||||||
|
}),
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to fetch current consumption! {e}");
|
||||||
|
HttpResponse::Ok().json(Consumption { consumption: None })
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get curr consumption history
|
/// Get curr consumption history
|
||||||
@@ -34,7 +40,9 @@ pub async fn curr_consumption_history() -> HttpResult {
|
|||||||
pub async fn cached_consumption(energy_actor: WebEnergyActor) -> HttpResult {
|
pub async fn cached_consumption(energy_actor: WebEnergyActor) -> HttpResult {
|
||||||
let consumption = energy_actor.send(energy_actor::GetCurrConsumption).await?;
|
let consumption = energy_actor.send(energy_actor::GetCurrConsumption).await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(Consumption { consumption }))
|
Ok(HttpResponse::Ok().json(Consumption {
|
||||||
|
consumption: Some(consumption),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get current relays consumption
|
/// Get current relays consumption
|
||||||
@@ -42,7 +50,9 @@ pub async fn relays_consumption(energy_actor: WebEnergyActor) -> HttpResult {
|
|||||||
let consumption =
|
let consumption =
|
||||||
energy_actor.send(energy_actor::RelaysConsumption).await? as EnergyConsumption;
|
energy_actor.send(energy_actor::RelaysConsumption).await? as EnergyConsumption;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(Consumption { consumption }))
|
Ok(HttpResponse::Ok().json(Consumption {
|
||||||
|
consumption: Some(consumption),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn relays_consumption_history() -> HttpResult {
|
pub async fn relays_consumption_history() -> HttpResult {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::logs::logs_manager;
|
|||||||
use crate::logs::severity::LogSeverity;
|
use crate::logs::severity::LogSeverity;
|
||||||
use crate::server::custom_error::HttpResult;
|
use crate::server::custom_error::HttpResult;
|
||||||
use crate::utils::time_utils::curr_day_number;
|
use crate::utils::time_utils::curr_day_number;
|
||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
pub struct LogRequest {
|
pub struct LogRequest {
|
||||||
|
|||||||
66
central_backend/src/server/web_api/management_controller.rs
Normal file
66
central_backend/src/server/web_api/management_controller.rs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
use crate::app_config::AppConfig;
|
||||||
|
use crate::server::custom_error::HttpResult;
|
||||||
|
use crate::utils::time_utils::current_day;
|
||||||
|
use actix_web::HttpResponse;
|
||||||
|
use anyhow::Context;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Cursor, Read, Write};
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
use zip::write::SimpleFileOptions;
|
||||||
|
|
||||||
|
/// Download a full copy of the storage data
|
||||||
|
pub async fn download_storage() -> HttpResult {
|
||||||
|
let mut zip_buff = Cursor::new(Vec::new());
|
||||||
|
let mut zip = zip::ZipWriter::new(&mut zip_buff);
|
||||||
|
|
||||||
|
let options = SimpleFileOptions::default()
|
||||||
|
.compression_method(zip::CompressionMethod::Bzip2)
|
||||||
|
.unix_permissions(0o700);
|
||||||
|
|
||||||
|
let storage = AppConfig::get().storage_path();
|
||||||
|
|
||||||
|
let mut file_buff = Vec::new();
|
||||||
|
for entry in WalkDir::new(&storage) {
|
||||||
|
let entry = entry?;
|
||||||
|
|
||||||
|
let path = entry.path();
|
||||||
|
let name = path.strip_prefix(&storage).unwrap();
|
||||||
|
let path_as_string = name
|
||||||
|
.to_str()
|
||||||
|
.map(str::to_owned)
|
||||||
|
.with_context(|| format!("{name:?} Is a Non UTF-8 Path"))?;
|
||||||
|
|
||||||
|
// Write file or directory explicitly
|
||||||
|
// Some unzip tools unzip files with directory paths correctly, some do not!
|
||||||
|
if path.is_file() {
|
||||||
|
log::debug!("adding file {path:?} as {name:?} ...");
|
||||||
|
zip.start_file(path_as_string, options)?;
|
||||||
|
let mut f = File::open(path)?;
|
||||||
|
|
||||||
|
f.read_to_end(&mut file_buff)?;
|
||||||
|
zip.write_all(&file_buff)?;
|
||||||
|
file_buff.clear();
|
||||||
|
} else if !name.as_os_str().is_empty() {
|
||||||
|
// Only if not root! Avoids path spec / warning
|
||||||
|
// and mapname conversion failed error on unzip
|
||||||
|
log::debug!("adding dir {path_as_string:?} as {name:?} ...");
|
||||||
|
zip.add_directory(path_as_string, options)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inject runtime configuration
|
||||||
|
zip.start_file("/app_config.json", options)?;
|
||||||
|
zip.write_all(&serde_json::to_vec_pretty(&AppConfig::get())?)?;
|
||||||
|
|
||||||
|
zip.finish()?;
|
||||||
|
|
||||||
|
let filename = format!("storage-{}.zip", current_day());
|
||||||
|
|
||||||
|
Ok(HttpResponse::Ok()
|
||||||
|
.content_type("application/zip")
|
||||||
|
.insert_header((
|
||||||
|
"content-disposition",
|
||||||
|
format!("attachment; filename=\"{filename}\""),
|
||||||
|
))
|
||||||
|
.body(zip_buff.into_inner()))
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ pub mod auth_controller;
|
|||||||
pub mod devices_controller;
|
pub mod devices_controller;
|
||||||
pub mod energy_controller;
|
pub mod energy_controller;
|
||||||
pub mod logging_controller;
|
pub mod logging_controller;
|
||||||
|
pub mod management_controller;
|
||||||
pub mod ota_controller;
|
pub mod ota_controller;
|
||||||
pub mod relays_controller;
|
pub mod relays_controller;
|
||||||
pub mod server_controller;
|
pub mod server_controller;
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ use crate::devices::device::DeviceId;
|
|||||||
use crate::energy::energy_actor;
|
use crate::energy::energy_actor;
|
||||||
use crate::ota::ota_manager;
|
use crate::ota::ota_manager;
|
||||||
use crate::ota::ota_update::OTAPlatform;
|
use crate::ota::ota_update::OTAPlatform;
|
||||||
use crate::server::custom_error::HttpResult;
|
|
||||||
use crate::server::WebEnergyActor;
|
use crate::server::WebEnergyActor;
|
||||||
use actix_multipart::form::tempfile::TempFile;
|
use crate::server::custom_error::HttpResult;
|
||||||
use actix_multipart::form::MultipartForm;
|
use actix_multipart::form::MultipartForm;
|
||||||
use actix_web::{web, HttpResponse};
|
use actix_multipart::form::tempfile::TempFile;
|
||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
|
||||||
pub async fn supported_platforms() -> HttpResult {
|
pub async fn supported_platforms() -> HttpResult {
|
||||||
Ok(HttpResponse::Ok().json(OTAPlatform::supported_platforms()))
|
Ok(HttpResponse::Ok().json(OTAPlatform::supported_platforms()))
|
||||||
@@ -123,17 +123,17 @@ pub async fn set_desired_version(
|
|||||||
|
|
||||||
for d in devices {
|
for d in devices {
|
||||||
// Filter per platform
|
// Filter per platform
|
||||||
if let Some(p) = body.platform {
|
if let Some(p) = body.platform
|
||||||
if d.info.reference != p.to_string() {
|
&& d.info.reference != p.to_string()
|
||||||
continue;
|
{
|
||||||
}
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter per device
|
// Filter per device
|
||||||
if let Some(ids) = &body.devices {
|
if let Some(ids) = &body.devices
|
||||||
if !ids.contains(&d.id) {
|
&& !ids.contains(&d.id)
|
||||||
continue;
|
{
|
||||||
}
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
actor
|
actor
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use crate::devices::device::{DeviceId, DeviceRelay, DeviceRelayID};
|
use crate::devices::device::{DeviceId, DeviceRelay, DeviceRelayID};
|
||||||
use crate::energy::energy_actor;
|
use crate::energy::energy_actor;
|
||||||
use crate::server::custom_error::HttpResult;
|
use crate::energy::engine::SetRelayForcedStateReq;
|
||||||
use crate::server::WebEnergyActor;
|
use crate::server::WebEnergyActor;
|
||||||
use actix_web::{web, HttpResponse};
|
use crate::server::custom_error::HttpResult;
|
||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
|
||||||
/// Get the full list of relays
|
/// Get the full list of relays
|
||||||
pub async fn get_list(actor: WebEnergyActor) -> HttpResult {
|
pub async fn get_list(actor: WebEnergyActor) -> HttpResult {
|
||||||
@@ -85,6 +86,29 @@ pub async fn update(
|
|||||||
Ok(HttpResponse::Accepted().finish())
|
Ok(HttpResponse::Accepted().finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set relay forced status
|
||||||
|
pub async fn set_forced_state(
|
||||||
|
actor: WebEnergyActor,
|
||||||
|
req: web::Json<SetRelayForcedStateReq>,
|
||||||
|
path: web::Path<RelayIDInPath>,
|
||||||
|
) -> HttpResult {
|
||||||
|
// Check if relay exists first
|
||||||
|
let list = actor.send(energy_actor::GetAllRelaysState).await?;
|
||||||
|
if !list.into_iter().any(|r| r.id == path.id) {
|
||||||
|
return Ok(HttpResponse::NotFound().json("Relay not found!"));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update relay forced state
|
||||||
|
actor
|
||||||
|
.send(energy_actor::SetRelayForcedState(
|
||||||
|
path.id,
|
||||||
|
req.to_forced_state(),
|
||||||
|
))
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
Ok(HttpResponse::Accepted().finish())
|
||||||
|
}
|
||||||
|
|
||||||
/// Delete an existing relay
|
/// Delete an existing relay
|
||||||
pub async fn delete(actor: WebEnergyActor, path: web::Path<RelayIDInPath>) -> HttpResult {
|
pub async fn delete(actor: WebEnergyActor, path: web::Path<RelayIDInPath>) -> HttpResult {
|
||||||
actor
|
actor
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ struct ServerConfig {
|
|||||||
auth_disabled: bool,
|
auth_disabled: bool,
|
||||||
constraints: StaticConstraints,
|
constraints: StaticConstraints,
|
||||||
unsecure_origin: String,
|
unsecure_origin: String,
|
||||||
|
backend_version: &'static str,
|
||||||
|
dashboard_custom_current_consumption_title: Option<&'static str>,
|
||||||
|
dashboard_custom_relays_consumption_title: Option<&'static str>,
|
||||||
|
dashboard_custom_cached_consumption_title: Option<&'static str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ServerConfig {
|
impl Default for ServerConfig {
|
||||||
@@ -21,6 +25,16 @@ impl Default for ServerConfig {
|
|||||||
auth_disabled: AppConfig::get().unsecure_disable_login,
|
auth_disabled: AppConfig::get().unsecure_disable_login,
|
||||||
constraints: Default::default(),
|
constraints: Default::default(),
|
||||||
unsecure_origin: AppConfig::get().unsecure_origin(),
|
unsecure_origin: AppConfig::get().unsecure_origin(),
|
||||||
|
backend_version: env!("CARGO_PKG_VERSION"),
|
||||||
|
dashboard_custom_current_consumption_title: AppConfig::get()
|
||||||
|
.dashboard_custom_current_consumption_title
|
||||||
|
.as_deref(),
|
||||||
|
dashboard_custom_relays_consumption_title: AppConfig::get()
|
||||||
|
.dashboard_custom_relays_consumption_title
|
||||||
|
.as_deref(),
|
||||||
|
dashboard_custom_cached_consumption_title: AppConfig::get()
|
||||||
|
.dashboard_custom_cached_consumption_title
|
||||||
|
.as_deref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ mod serve_static_debug {
|
|||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
mod serve_static_release {
|
mod serve_static_release {
|
||||||
use actix_web::{web, HttpResponse, Responder};
|
use actix_web::{HttpResponse, Responder, web};
|
||||||
use rust_embed::RustEmbed;
|
use rust_embed::RustEmbed;
|
||||||
|
|
||||||
#[derive(RustEmbed)]
|
#[derive(RustEmbed)]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
/// Get the current time since epoch
|
/// Get the current time since epoch, in seconds
|
||||||
pub fn time_secs() -> u64 {
|
pub fn time_secs() -> u64 {
|
||||||
SystemTime::now()
|
SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
@@ -41,6 +41,12 @@ pub fn time_start_of_day() -> anyhow::Result<u64> {
|
|||||||
Ok(local.timestamp() as u64)
|
Ok(local.timestamp() as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get formatted string containing current day information
|
||||||
|
pub fn current_day() -> String {
|
||||||
|
let dt = Local::now();
|
||||||
|
format!("{}-{:0>2}-{:0>2}", dt.year(), dt.month(), dt.day())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::utils::time_utils::day_number;
|
use crate::utils::time_utils::day_number;
|
||||||
|
|||||||
28
central_frontend/eslint.config.js
Normal file
28
central_frontend/eslint.config.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import js from '@eslint/js'
|
||||||
|
import globals from 'globals'
|
||||||
|
import reactHooks from 'eslint-plugin-react-hooks'
|
||||||
|
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||||
|
import tseslint from 'typescript-eslint'
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
{ ignores: ['dist'] },
|
||||||
|
{
|
||||||
|
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||||
|
files: ['**/*.{ts,tsx}'],
|
||||||
|
languageOptions: {
|
||||||
|
ecmaVersion: 2020,
|
||||||
|
globals: globals.browser,
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
'react-hooks': reactHooks,
|
||||||
|
'react-refresh': reactRefresh,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
...reactHooks.configs.recommended.rules,
|
||||||
|
'react-refresh/only-export-components': [
|
||||||
|
'warn',
|
||||||
|
{ allowConstantExport: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
2852
central_frontend/package-lock.json
generated
2852
central_frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -6,38 +6,40 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
"lint": "eslint .",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.13.3",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.13.0",
|
"@emotion/styled": "^11.14.1",
|
||||||
"@fontsource/roboto": "^5.1.0",
|
"@fontsource/roboto": "^5.2.8",
|
||||||
"@mdi/js": "^7.4.47",
|
"@mdi/js": "^7.4.47",
|
||||||
"@mdi/react": "^1.6.1",
|
"@mdi/react": "^1.6.1",
|
||||||
"@mui/icons-material": "^6.1.3",
|
"@mui/icons-material": "^7.3.4",
|
||||||
"@mui/material": "^6.1.3",
|
"@mui/material": "^7.3.4",
|
||||||
"@mui/x-charts": "^7.20.0",
|
"@mui/x-charts": "^8.15.0",
|
||||||
"@mui/x-date-pickers": "^7.20.0",
|
"@mui/x-date-pickers": "^8.15.0",
|
||||||
"@types/semver": "^7.5.8",
|
"date-and-time": "^4.1.0",
|
||||||
"date-and-time": "^3.6.0",
|
"dayjs": "^1.11.18",
|
||||||
"dayjs": "^1.11.13",
|
"filesize": "^11.0.13",
|
||||||
"filesize": "^10.1.6",
|
"react": "^19.2.0",
|
||||||
"react": "^18.3.1",
|
"react-dom": "^19.2.0",
|
||||||
"react-dom": "^18.3.1",
|
"react-router-dom": "^7.9.4",
|
||||||
"react-router-dom": "^6.27.0",
|
"semver": "^7.7.3"
|
||||||
"semver": "^7.6.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.3.11",
|
"@types/react": "^19.2.2",
|
||||||
"@types/react-dom": "^18.3.1",
|
"@types/react-dom": "^19.2.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.8.0",
|
"@types/semver": "^7.7.1",
|
||||||
"@typescript-eslint/parser": "^8.8.0",
|
"@typescript-eslint/eslint-plugin": "^8.46.2",
|
||||||
"@vitejs/plugin-react": "^4.3.2",
|
"@typescript-eslint/parser": "^8.46.2",
|
||||||
"eslint": "^8.57.1",
|
"@vitejs/plugin-react": "^5.1.0",
|
||||||
"eslint-plugin-react-hooks": "^5.0.0",
|
"eslint": "^9.38.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.12",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
"typescript": "^5.6.3",
|
"eslint-plugin-react-refresh": "^0.4.24",
|
||||||
"vite": "^5.4.8"
|
"globals": "^16.4.0",
|
||||||
|
"typescript": "^5.9.3",
|
||||||
|
"typescript-eslint": "^8.46.2",
|
||||||
|
"vite": "^7.1.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { PendingDevicesRoute } from "./routes/PendingDevicesRoute";
|
|||||||
import { RelaysListRoute } from "./routes/RelaysListRoute";
|
import { RelaysListRoute } from "./routes/RelaysListRoute";
|
||||||
import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage";
|
import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage";
|
||||||
import { OTARoute } from "./routes/OTARoute";
|
import { OTARoute } from "./routes/OTARoute";
|
||||||
|
import { ManagementRoute } from "./routes/ManagementRoute";
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
if (!AuthApi.SignedIn && !ServerApi.Config.auth_disabled)
|
if (!AuthApi.SignedIn && !ServerApi.Config.auth_disabled)
|
||||||
@@ -31,6 +32,7 @@ export function App() {
|
|||||||
<Route path="relays" element={<RelaysListRoute />} />
|
<Route path="relays" element={<RelaysListRoute />} />
|
||||||
<Route path="ota" element={<OTARoute />} />
|
<Route path="ota" element={<OTARoute />} />
|
||||||
<Route path="logs" element={<LogsRoute />} />
|
<Route path="logs" element={<LogsRoute />} />
|
||||||
|
<Route path="management" element={<ManagementRoute />} />
|
||||||
<Route path="*" element={<NotFoundRoute />} />
|
<Route path="*" element={<NotFoundRoute />} />
|
||||||
</Route>
|
</Route>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
import { APIClient } from "./ApiClient";
|
import { APIClient } from "./ApiClient";
|
||||||
import { Device, DeviceRelay } from "./DeviceApi";
|
import { Device, DeviceRelay } from "./DeviceApi";
|
||||||
|
|
||||||
|
export type RelayForcedState =
|
||||||
|
| { type: "None" }
|
||||||
|
| { type: "Off" | "On"; until: number };
|
||||||
|
|
||||||
|
export type SetRelayForcedState =
|
||||||
|
| { type: "None" }
|
||||||
|
| { type: "Off" | "On"; for_secs: number };
|
||||||
|
|
||||||
export interface RelayStatus {
|
export interface RelayStatus {
|
||||||
id: string;
|
id: string;
|
||||||
on: boolean;
|
on: boolean;
|
||||||
for: number;
|
for: number;
|
||||||
|
forced_state: RelayForcedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RelaysStatus = Map<string, RelayStatus>;
|
export type RelaysStatus = Map<string, RelayStatus>;
|
||||||
@@ -48,6 +57,20 @@ export class RelayApi {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set relay forced state
|
||||||
|
*/
|
||||||
|
static async SetForcedState(
|
||||||
|
relay: DeviceRelay,
|
||||||
|
forced: SetRelayForcedState
|
||||||
|
): Promise<void> {
|
||||||
|
await APIClient.exec({
|
||||||
|
method: "PUT",
|
||||||
|
uri: `/relay/${relay.id}/forced_state`,
|
||||||
|
jsonData: forced,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a relay configuration
|
* Delete a relay configuration
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ export interface ServerConfig {
|
|||||||
auth_disabled: boolean;
|
auth_disabled: boolean;
|
||||||
constraints: ServerConstraint;
|
constraints: ServerConstraint;
|
||||||
unsecure_origin: string;
|
unsecure_origin: string;
|
||||||
|
backend_version: string;
|
||||||
|
dashboard_custom_current_consumption_title?: string;
|
||||||
|
dashboard_custom_relays_consumption_title?: string;
|
||||||
|
dashboard_custom_cached_consumption_title?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServerConstraint {
|
export interface ServerConstraint {
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export function DeployOTAUpdateDialogProvider(p: {
|
|||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<FormLabel>Gender</FormLabel>
|
<FormLabel>Deployment target</FormLabel>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
name="radio-buttons-group"
|
name="radio-buttons-group"
|
||||||
value={allDevices}
|
value={allDevices}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
Typography,
|
Typography,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import Grid from "@mui/material/Grid2";
|
import Grid from "@mui/material/Grid";
|
||||||
import { TimePicker } from "@mui/x-date-pickers";
|
import { TimePicker } from "@mui/x-date-pickers";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Device, DeviceRelay } from "../api/DeviceApi";
|
import { Device, DeviceRelay } from "../api/DeviceApi";
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogContentText,
|
||||||
|
DialogTitle,
|
||||||
|
TextField,
|
||||||
|
} from "@mui/material";
|
||||||
|
import { DeviceRelay } from "../api/DeviceApi";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export function SelectForcedStateDurationDialog(p: {
|
||||||
|
relay: DeviceRelay;
|
||||||
|
forcedState: string;
|
||||||
|
onCancel: () => void;
|
||||||
|
onSubmit: (duration: number) => void;
|
||||||
|
}): React.ReactElement {
|
||||||
|
const [duration, setDuration] = React.useState(60);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open onClose={p.onCancel}>
|
||||||
|
<DialogTitle>Set forced relay state</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogContentText>
|
||||||
|
Please specify the number of minutes the relay <i>{p.relay.name}</i>{" "}
|
||||||
|
will remain in forced state <i>{p.forcedState}</i>:
|
||||||
|
</DialogContentText>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
label="Duration (min)"
|
||||||
|
variant="standard"
|
||||||
|
value={Math.floor(duration / 60)}
|
||||||
|
onChange={(e) => {
|
||||||
|
const val = Number.parseInt(e.target.value);
|
||||||
|
setDuration((Number.isNaN(val) ? 1 : val) * 60);
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
style={{ marginTop: "5px" }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p>Equivalent in seconds: {duration} secs</p>
|
||||||
|
<p>Equivalent in hours: {duration / 3600} hours</p>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={p.onCancel}>Cancel</Button>
|
||||||
|
<Button onClick={() => p.onSubmit(duration)} autoFocus>
|
||||||
|
Start timer
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -10,16 +10,16 @@ import {
|
|||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Device, DeviceRelay } from "../../api/DeviceApi";
|
import { Device, DeviceRelay } from "../../api/DeviceApi";
|
||||||
|
import { RelayApi, RelayStatus } from "../../api/RelayApi";
|
||||||
import { EditDeviceRelaysDialog } from "../../dialogs/EditDeviceRelaysDialog";
|
import { EditDeviceRelaysDialog } from "../../dialogs/EditDeviceRelaysDialog";
|
||||||
import { DeviceRouteCard } from "./DeviceRouteCard";
|
import { useAlert } from "../../hooks/context_providers/AlertDialogProvider";
|
||||||
import { useConfirm } from "../../hooks/context_providers/ConfirmDialogProvider";
|
import { useConfirm } from "../../hooks/context_providers/ConfirmDialogProvider";
|
||||||
import { useLoadingMessage } from "../../hooks/context_providers/LoadingMessageProvider";
|
import { useLoadingMessage } from "../../hooks/context_providers/LoadingMessageProvider";
|
||||||
import { RelayApi, RelayStatus } from "../../api/RelayApi";
|
|
||||||
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
|
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
|
||||||
import { useAlert } from "../../hooks/context_providers/AlertDialogProvider";
|
|
||||||
import { AsyncWidget } from "../../widgets/AsyncWidget";
|
import { AsyncWidget } from "../../widgets/AsyncWidget";
|
||||||
import { TimeWidget } from "../../widgets/TimeWidget";
|
|
||||||
import { BoolText } from "../../widgets/BoolText";
|
import { BoolText } from "../../widgets/BoolText";
|
||||||
|
import { TimeWidget } from "../../widgets/TimeWidget";
|
||||||
|
import { DeviceRouteCard } from "./DeviceRouteCard";
|
||||||
|
|
||||||
export function DeviceRelays(p: {
|
export function DeviceRelays(p: {
|
||||||
device: Device;
|
device: Device;
|
||||||
@@ -145,7 +145,8 @@ function RelayEntryStatus(
|
|||||||
errMsg="Failed to load relay status!"
|
errMsg="Failed to load relay status!"
|
||||||
build={() => (
|
build={() => (
|
||||||
<>
|
<>
|
||||||
<BoolText val={state!.on} positive="ON" negative="OFF" /> for{" "}
|
<BoolText val={state!.on} positive="ON" negative="OFF" />{" "}
|
||||||
|
{state?.forced_state.type !== "None" && <b>Forced</b>} for{" "}
|
||||||
<TimeWidget diff time={state!.for} />
|
<TimeWidget diff time={state!.for} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import DeleteIcon from "@mui/icons-material/Delete";
|
import DeleteIcon from "@mui/icons-material/Delete";
|
||||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||||
import { IconButton, Tooltip } from "@mui/material";
|
import { IconButton, Tooltip } from "@mui/material";
|
||||||
import Grid from "@mui/material/Grid2";
|
import Grid from "@mui/material/Grid";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import { Device, DeviceApi } from "../../api/DeviceApi";
|
import { Device, DeviceApi } from "../../api/DeviceApi";
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ function ValidatedDevicesList(p: {
|
|||||||
<Table sx={{ minWidth: 650 }} aria-label="simple table">
|
<Table sx={{ minWidth: 650 }} aria-label="simple table">
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell>#</TableCell>
|
<TableCell>Name</TableCell>
|
||||||
<TableCell align="center">Model</TableCell>
|
<TableCell align="center">Model</TableCell>
|
||||||
<TableCell align="center">Version</TableCell>
|
<TableCell align="center">Version</TableCell>
|
||||||
<TableCell align="center">Max relays</TableCell>
|
<TableCell align="center">Max relays</TableCell>
|
||||||
@@ -99,7 +99,7 @@ function ValidatedDevicesList(p: {
|
|||||||
onDoubleClick={() => navigate(DeviceURL(dev))}
|
onDoubleClick={() => navigate(DeviceURL(dev))}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row">
|
<TableCell component="th" scope="row">
|
||||||
{dev.id}
|
{dev.name}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">{dev.info.reference}</TableCell>
|
<TableCell align="center">{dev.info.reference}</TableCell>
|
||||||
<TableCell align="center">{dev.info.version}</TableCell>
|
<TableCell align="center">{dev.info.version}</TableCell>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Typography } from "@mui/material";
|
import { Typography } from "@mui/material";
|
||||||
import { CurrConsumptionWidget } from "./HomeRoute/CurrConsumptionWidget";
|
import { CurrConsumptionWidget } from "./HomeRoute/CurrConsumptionWidget";
|
||||||
import Grid from "@mui/material/Grid2";
|
import Grid from "@mui/material/Grid";
|
||||||
import { CachedConsumptionWidget } from "./HomeRoute/CachedConsumptionWidget";
|
import { CachedConsumptionWidget } from "./HomeRoute/CachedConsumptionWidget";
|
||||||
import { RelayConsumptionWidget } from "./HomeRoute/RelayConsumptionWidget";
|
import { RelayConsumptionWidget } from "./HomeRoute/RelayConsumptionWidget";
|
||||||
import { RelaysListRoute } from "./RelaysListRoute";
|
import { RelaysListRoute } from "./RelaysListRoute";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from "react";
|
|||||||
import { EnergyApi } from "../../api/EnergyApi";
|
import { EnergyApi } from "../../api/EnergyApi";
|
||||||
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
|
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
|
||||||
import StatCard from "../../widgets/StatCard";
|
import StatCard from "../../widgets/StatCard";
|
||||||
|
import { ServerApi } from "../../api/ServerApi";
|
||||||
|
|
||||||
export function CachedConsumptionWidget(): React.ReactElement {
|
export function CachedConsumptionWidget(): React.ReactElement {
|
||||||
const snackbar = useSnackbar();
|
const snackbar = useSnackbar();
|
||||||
@@ -26,6 +27,12 @@ export function CachedConsumptionWidget(): React.ReactElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StatCard title="Cached consumption" value={val?.toString() ?? "Loading"} />
|
<StatCard
|
||||||
|
title={
|
||||||
|
ServerApi.Config.dashboard_custom_cached_consumption_title ??
|
||||||
|
"Cached consumption"
|
||||||
|
}
|
||||||
|
value={val?.toString() ?? "Loading"}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from "react";
|
|||||||
import { EnergyApi } from "../../api/EnergyApi";
|
import { EnergyApi } from "../../api/EnergyApi";
|
||||||
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
|
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
|
||||||
import StatCard from "../../widgets/StatCard";
|
import StatCard from "../../widgets/StatCard";
|
||||||
|
import { ServerApi } from "../../api/ServerApi";
|
||||||
|
|
||||||
export function CurrConsumptionWidget(): React.ReactElement {
|
export function CurrConsumptionWidget(): React.ReactElement {
|
||||||
const snackbar = useSnackbar();
|
const snackbar = useSnackbar();
|
||||||
@@ -29,7 +30,10 @@ export function CurrConsumptionWidget(): React.ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StatCard
|
<StatCard
|
||||||
title="Current consumption"
|
title={
|
||||||
|
ServerApi.Config.dashboard_custom_current_consumption_title ??
|
||||||
|
"Current consumption"
|
||||||
|
}
|
||||||
data={history ?? []}
|
data={history ?? []}
|
||||||
interval="Last day"
|
interval="Last day"
|
||||||
value={val?.toString() ?? "Loading"}
|
value={val?.toString() ?? "Loading"}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from "react";
|
|||||||
import { EnergyApi } from "../../api/EnergyApi";
|
import { EnergyApi } from "../../api/EnergyApi";
|
||||||
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
|
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
|
||||||
import StatCard from "../../widgets/StatCard";
|
import StatCard from "../../widgets/StatCard";
|
||||||
|
import { ServerApi } from "../../api/ServerApi";
|
||||||
|
|
||||||
export function RelayConsumptionWidget(): React.ReactElement {
|
export function RelayConsumptionWidget(): React.ReactElement {
|
||||||
const snackbar = useSnackbar();
|
const snackbar = useSnackbar();
|
||||||
@@ -29,7 +30,10 @@ export function RelayConsumptionWidget(): React.ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StatCard
|
<StatCard
|
||||||
title="Relays consumption"
|
title={
|
||||||
|
ServerApi.Config.dashboard_custom_relays_consumption_title ??
|
||||||
|
"Relays consumption"
|
||||||
|
}
|
||||||
data={history ?? []}
|
data={history ?? []}
|
||||||
interval="Last day"
|
interval="Last day"
|
||||||
value={val?.toString() ?? "Loading"}
|
value={val?.toString() ?? "Loading"}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import Typography from "@mui/material/Typography";
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
|
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
|
||||||
import { AuthApi } from "../api/AuthApi";
|
import { AuthApi } from "../api/AuthApi";
|
||||||
import Grid from "@mui/material/Grid2";
|
import Grid from "@mui/material/Grid";
|
||||||
|
|
||||||
function Copyright(props: any) {
|
function Copyright(props: any) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
31
central_frontend/src/routes/ManagementRoute.tsx
Normal file
31
central_frontend/src/routes/ManagementRoute.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { Button } from "@mui/material";
|
||||||
|
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
|
||||||
|
import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer";
|
||||||
|
import { APIClient } from "../api/ApiClient";
|
||||||
|
|
||||||
|
export function ManagementRoute(): React.ReactElement {
|
||||||
|
const confirm = useConfirm();
|
||||||
|
|
||||||
|
const downloadBackup = async () => {
|
||||||
|
try {
|
||||||
|
if (
|
||||||
|
!(await confirm(
|
||||||
|
`Do you really want to download a copy of the storage? It will contain sensitive information!`
|
||||||
|
))
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
location.href = APIClient.backendURL() + "/management/download_storage";
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Failed to donwload a backup of the storage! Error: ${e}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SolarEnergyRouteContainer label="Management">
|
||||||
|
<Button variant="outlined" onClick={downloadBackup}>
|
||||||
|
Download a backup of storage
|
||||||
|
</Button>
|
||||||
|
</SolarEnergyRouteContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -16,12 +16,13 @@ import React from "react";
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { Device, DeviceApi, DeviceRelay, DeviceURL } from "../api/DeviceApi";
|
import { Device, DeviceApi, DeviceRelay, DeviceURL } from "../api/DeviceApi";
|
||||||
import { RelayApi, RelaysStatus } from "../api/RelayApi";
|
import { RelayApi, RelaysStatus } from "../api/RelayApi";
|
||||||
|
import { ServerApi } from "../api/ServerApi";
|
||||||
import { AsyncWidget } from "../widgets/AsyncWidget";
|
import { AsyncWidget } from "../widgets/AsyncWidget";
|
||||||
import { BoolText } from "../widgets/BoolText";
|
import { BoolText } from "../widgets/BoolText";
|
||||||
|
import { CopyToClipboard } from "../widgets/CopyToClipboard";
|
||||||
|
import { RelayForcedState } from "../widgets/RelayForcedState";
|
||||||
import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer";
|
import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer";
|
||||||
import { TimeWidget } from "../widgets/TimeWidget";
|
import { TimeWidget } from "../widgets/TimeWidget";
|
||||||
import { CopyToClipboard } from "../widgets/CopyToClipboard";
|
|
||||||
import { ServerApi } from "../api/ServerApi";
|
|
||||||
|
|
||||||
export function RelaysListRoute(p: {
|
export function RelaysListRoute(p: {
|
||||||
homeWidget?: boolean;
|
homeWidget?: boolean;
|
||||||
@@ -104,6 +105,7 @@ function RelaysList(p: {
|
|||||||
<TableCell>Priority</TableCell>
|
<TableCell>Priority</TableCell>
|
||||||
<TableCell>Consumption</TableCell>
|
<TableCell>Consumption</TableCell>
|
||||||
<TableCell>Status</TableCell>
|
<TableCell>Status</TableCell>
|
||||||
|
<TableCell>Forced state</TableCell>
|
||||||
<TableCell></TableCell>
|
<TableCell></TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
@@ -129,6 +131,13 @@ function RelaysList(p: {
|
|||||||
/>{" "}
|
/>{" "}
|
||||||
for <TimeWidget diff time={p.status.get(row.id)!.for} />
|
for <TimeWidget diff time={p.status.get(row.id)!.for} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<RelayForcedState
|
||||||
|
relay={row}
|
||||||
|
state={p.status.get(row.id)!}
|
||||||
|
onUpdated={p.onReload}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Tooltip title="Copy legacy api status">
|
<Tooltip title="Copy legacy api status">
|
||||||
<CopyToClipboard
|
<CopyToClipboard
|
||||||
|
|||||||
79
central_frontend/src/widgets/RelayForcedState.tsx
Normal file
79
central_frontend/src/widgets/RelayForcedState.tsx
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import { MenuItem, Select, SelectChangeEvent } from "@mui/material";
|
||||||
|
import { DeviceRelay } from "../api/DeviceApi";
|
||||||
|
import { RelayApi, RelayStatus, SetRelayForcedState } from "../api/RelayApi";
|
||||||
|
import { TimeWidget } from "./TimeWidget";
|
||||||
|
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
|
||||||
|
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
|
||||||
|
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
|
||||||
|
import React from "react";
|
||||||
|
import { SelectForcedStateDurationDialog } from "../dialogs/SelectForcedStateDurationDialog";
|
||||||
|
|
||||||
|
export function RelayForcedState(p: {
|
||||||
|
relay: DeviceRelay;
|
||||||
|
state: RelayStatus;
|
||||||
|
onUpdated: () => void;
|
||||||
|
}): React.ReactElement {
|
||||||
|
const loadingMessage = useLoadingMessage();
|
||||||
|
const alert = useAlert();
|
||||||
|
const snackbar = useSnackbar();
|
||||||
|
|
||||||
|
const [futureStateType, setFutureStateType] = React.useState<
|
||||||
|
string | undefined
|
||||||
|
>();
|
||||||
|
|
||||||
|
const handleChange = (event: SelectChangeEvent) => {
|
||||||
|
if (event.target.value == "None") {
|
||||||
|
submitChange({ type: "None" });
|
||||||
|
} else {
|
||||||
|
setFutureStateType(event.target.value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitChange = async (state: SetRelayForcedState) => {
|
||||||
|
try {
|
||||||
|
loadingMessage.show("Setting forced state...");
|
||||||
|
await RelayApi.SetForcedState(p.relay, state);
|
||||||
|
p.onUpdated();
|
||||||
|
snackbar("Forced state successfully updated!");
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Failed to set relay forced state! ${e}`);
|
||||||
|
alert(`Failed to set loading state for relay! ${e}`);
|
||||||
|
} finally {
|
||||||
|
loadingMessage.hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Select
|
||||||
|
value={p.state.forced_state.type}
|
||||||
|
onChange={handleChange}
|
||||||
|
size="small"
|
||||||
|
variant="standard"
|
||||||
|
>
|
||||||
|
<MenuItem value={"None"}>None</MenuItem>
|
||||||
|
<MenuItem value={"Off"}>Off</MenuItem>
|
||||||
|
<MenuItem value={"On"}>On</MenuItem>
|
||||||
|
</Select>
|
||||||
|
{p.state.forced_state.type !== "None" && (
|
||||||
|
<>
|
||||||
|
<TimeWidget future time={p.state.forced_state.until} /> left
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{futureStateType !== undefined && (
|
||||||
|
<SelectForcedStateDurationDialog
|
||||||
|
{...p}
|
||||||
|
forcedState={futureStateType}
|
||||||
|
onCancel={() => setFutureStateType(undefined)}
|
||||||
|
onSubmit={(d) =>
|
||||||
|
submitChange({
|
||||||
|
type: futureStateType as any,
|
||||||
|
for_secs: d,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
mdiChip,
|
mdiChip,
|
||||||
|
mdiCog,
|
||||||
mdiElectricSwitch,
|
mdiElectricSwitch,
|
||||||
mdiHome,
|
mdiHome,
|
||||||
mdiMonitorArrowDown,
|
mdiMonitorArrowDown,
|
||||||
@@ -12,9 +13,11 @@ import {
|
|||||||
ListItemButton,
|
ListItemButton,
|
||||||
ListItemIcon,
|
ListItemIcon,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
|
Typography,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import { RouterLink } from "./RouterLink";
|
import { RouterLink } from "./RouterLink";
|
||||||
|
import { ServerApi } from "../api/ServerApi";
|
||||||
|
|
||||||
export function SolarEnergyNavList(): React.ReactElement {
|
export function SolarEnergyNavList(): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
@@ -52,6 +55,18 @@ export function SolarEnergyNavList(): React.ReactElement {
|
|||||||
uri="/logs"
|
uri="/logs"
|
||||||
icon={<Icon path={mdiNotebookMultiple} size={1} />}
|
icon={<Icon path={mdiNotebookMultiple} size={1} />}
|
||||||
/>
|
/>
|
||||||
|
<NavLink
|
||||||
|
label="Management"
|
||||||
|
uri="/management"
|
||||||
|
icon={<Icon path={mdiCog} size={1} />}
|
||||||
|
/>
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
component="div"
|
||||||
|
style={{ textAlign: "center", width: "100%", marginTop: "30px" }}
|
||||||
|
>
|
||||||
|
Version {ServerApi.Config.backend_version}
|
||||||
|
</Typography>
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ export default function StatCard({
|
|||||||
<Box sx={{ width: "100%", height: 100 }}>
|
<Box sx={{ width: "100%", height: 100 }}>
|
||||||
{data && interval && (
|
{data && interval && (
|
||||||
<SparkLineChart
|
<SparkLineChart
|
||||||
colors={[chartColor]}
|
color={chartColor}
|
||||||
data={data}
|
data={data}
|
||||||
area
|
area
|
||||||
showHighlight
|
showHighlight
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Tooltip } from "@mui/material";
|
import { Tooltip } from "@mui/material";
|
||||||
import date from "date-and-time";
|
import { format } from "date-and-time";
|
||||||
import { time } from "../utils/DateUtils";
|
import { time } from "../utils/DateUtils";
|
||||||
|
|
||||||
export function formatDate(time: number): string {
|
export function formatDate(time: number): string {
|
||||||
const t = new Date();
|
const t = new Date();
|
||||||
t.setTime(1000 * time);
|
t.setTime(1000 * time);
|
||||||
return date.format(t, "DD/MM/YYYY HH:mm:ss");
|
return format(t, "DD/MM/YYYY HH:mm:ss");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function timeDiff(a: number, b: number): string {
|
export function timeDiff(a: number, b: number): string {
|
||||||
@@ -21,7 +21,7 @@ export function timeDiff(a: number, b: number): string {
|
|||||||
diff = Math.floor(diff / 60);
|
diff = Math.floor(diff / 60);
|
||||||
|
|
||||||
if (diff === 1) return "1 minute";
|
if (diff === 1) return "1 minute";
|
||||||
if (diff < 24) {
|
if (diff < 60) {
|
||||||
return `${diff} minutes`;
|
return `${diff} minutes`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,13 +51,14 @@ export function timeDiff(a: number, b: number): string {
|
|||||||
return `${diffYears} years`;
|
return `${diffYears} years`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function timeDiffFromNow(t: number): string {
|
export function timeDiffFromNow(t: number, future?: boolean): string {
|
||||||
return timeDiff(t, time());
|
return future ? timeDiff(time(), t) : timeDiff(t, time());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TimeWidget(p: {
|
export function TimeWidget(p: {
|
||||||
time?: number;
|
time?: number;
|
||||||
diff?: boolean;
|
diff?: boolean;
|
||||||
|
future?: boolean;
|
||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
if (!p.time) return <></>;
|
if (!p.time) return <></>;
|
||||||
return (
|
return (
|
||||||
@@ -65,7 +66,9 @@ export function TimeWidget(p: {
|
|||||||
title={formatDate(p.diff ? new Date().getTime() / 1000 - p.time : p.time)}
|
title={formatDate(p.diff ? new Date().getTime() / 1000 - p.time : p.time)}
|
||||||
arrow
|
arrow
|
||||||
>
|
>
|
||||||
<span>{p.diff ? timeDiff(0, p.time) : timeDiffFromNow(p.time)}</span>
|
<span>
|
||||||
|
{p.diff ? timeDiff(0, p.time) : timeDiffFromNow(p.time, p.future)}
|
||||||
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
|
||||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
@@ -11,7 +10,6 @@
|
|||||||
/* Bundler mode */
|
/* Bundler mode */
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
@@ -21,7 +19,8 @@
|
|||||||
"strict": true,
|
"strict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedSideEffectImports": true
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
{
|
{
|
||||||
"files": [],
|
"files": [],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{ "path": "./tsconfig.app.json" },
|
||||||
"path": "./tsconfig.app.json"
|
{ "path": "./tsconfig.node.json" }
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.node.json"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,24 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
|
||||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||||
"skipLibCheck": true,
|
"target": "ES2022",
|
||||||
|
"lib": ["ES2023"],
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowImportingTsExtensions": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noEmit": true
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedSideEffectImports": true
|
||||||
},
|
},
|
||||||
"include": ["vite.config.ts"]
|
"include": ["vite.config.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react'
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
})
|
})
|
||||||
|
|||||||
2672
custom_consumption/Cargo.lock
generated
2672
custom_consumption/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "custom_consumption"
|
name = "custom_consumption"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
env_logger = "0.11.5"
|
env_logger = "0.11.8"
|
||||||
log = "0.4.22"
|
log = "0.4.28"
|
||||||
clap = { version = "4.5.18", features = ["derive", "env"] }
|
clap = { version = "4.5.50", features = ["derive", "env"] }
|
||||||
egui = "0.28.1"
|
egui = "0.32.3"
|
||||||
eframe = "0.28.1"
|
eframe = "0.32.3"
|
||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
/// Get the current time since epoch
|
/// Get the current time since epoch
|
||||||
|
|
||||||
pub fn time_millis() -> u128 {
|
pub fn time_millis() -> u128 {
|
||||||
SystemTime::now()
|
SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# Configure project for production
|
# Configure project for production
|
||||||
|
|
||||||
|
Note: This guide assumes that you use the default hostname, `central.internal` as hostname for your central system.
|
||||||
|
|
||||||
## Create production build
|
## Create production build
|
||||||
|
|
||||||
### Central
|
### Central
|
||||||
@@ -44,5 +46,146 @@ The OTA update is then located in `build/main.bin`
|
|||||||
* A server running a recent Linux (Debian / Ubuntu preferred) with `central` as hostname
|
* A server running a recent Linux (Debian / Ubuntu preferred) with `central` as hostname
|
||||||
* DHCP configured on the network
|
* DHCP configured on the network
|
||||||
|
|
||||||
|
## Configure DNS server
|
||||||
|
|
||||||
|
If you need to setup a DNS server / proxy to point `central.internal` to the central server IP, you can follow this guide.
|
||||||
|
|
||||||
|
### Retrieve DNS server binary
|
||||||
|
Use [DNSProxy](https://gitlab.com/pierre42100/dnsproxy) as DNS server. Get and compile the sources:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://gitlab.com/pierre42100/dnsproxy
|
||||||
|
cd dnsproxy
|
||||||
|
cargo build --release
|
||||||
|
scp target/release/dns_proxy USER@CENTRAL_IP:/home/USER
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, on the target server, install the binary to its final destination:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo mv dns_proxy /usr/local/bin/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configure DNS server
|
||||||
|
Configure the server as a service `/etc/systemd/system/dns.service`:
|
||||||
|
|
||||||
|
```conf
|
||||||
|
[Unit]
|
||||||
|
Description=DNS server
|
||||||
|
After=syslog.target
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
RestartSec=2s
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
WorkingDirectory=/tmp
|
||||||
|
ExecStart=/usr/local/bin/dns_proxy -l "CENTRAL_IP:53" -c "central.internal. A CENTRAL_IP"
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
Enable and start the new service:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl enable dns
|
||||||
|
sudo systemctl start dns
|
||||||
|
```
|
||||||
|
|
||||||
|
Check that it works correctly:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dig central.internal. @CENTRAL_IP
|
||||||
|
```
|
||||||
|
|
||||||
|
You should get an entry like this if it works:
|
||||||
|
|
||||||
|
```
|
||||||
|
;; ANSWER SECTION:
|
||||||
|
central.internal. 0 IN A CENTRAL_IP
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, in your DHCP service, define the central as the DNS server.
|
||||||
|
|
||||||
## Configure server
|
## Configure server
|
||||||
TODO
|
|
||||||
|
### Create a user dedicated to the central
|
||||||
|
```bash
|
||||||
|
sudo adduser --disabled-login central
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install binary
|
||||||
|
You can use `scp` to copy the binary to the target server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scp central_backend/target/release/central_backend pierre@central:/home/pierre
|
||||||
|
```
|
||||||
|
|
||||||
|
Then the executable must be installed system-wide:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo mv central_backend /usr/local/bin/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create configuration file
|
||||||
|
Create a configuration file in `/home/central/config.yaml`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo touch /home/central/config.yaml
|
||||||
|
sudo chown central:central /home/central/config.yaml
|
||||||
|
sudo chmod 400 /home/central/config.yaml
|
||||||
|
sudo nano /home/central/config.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Sample configuration:
|
||||||
|
|
||||||
|
```conf
|
||||||
|
SECRET=RANDOM_VALUE
|
||||||
|
COOKIE_SECURE=true
|
||||||
|
LISTEN_ADDRESS=0.0.0.0:443
|
||||||
|
ADMIN_USERNAME=admin
|
||||||
|
ADMIN_PASSWORD=FIXME
|
||||||
|
HOSTNAME=central.internal
|
||||||
|
STORAGE=/home/central/storage
|
||||||
|
FRONIUS_ORIG=http://10.0.0.10
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test configuration
|
||||||
|
Run the following command to check if the configuration is working:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo -u central central_backend -c /home/central/config.yaml fronius -c
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create systemd unit file
|
||||||
|
Once you confirmed the configuration is working, you can configure a system service, in `/etc/systemd/system/central.service`:
|
||||||
|
|
||||||
|
```conf
|
||||||
|
[Unit]
|
||||||
|
Description=Central backend server
|
||||||
|
After=syslog.target
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
RestartSec=2s
|
||||||
|
Type=simple
|
||||||
|
User=central
|
||||||
|
Group=central
|
||||||
|
WorkingDirectory=/home/central
|
||||||
|
ExecStart=/usr/local/bin/central_backend -c /home/central/config.yaml fronius -c
|
||||||
|
Restart=always
|
||||||
|
Environment=USER=central
|
||||||
|
HOME=/home/central
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
Enable & start service:
|
||||||
|
```bash
|
||||||
|
sudo systemctl enable central
|
||||||
|
sudo systemctl start central
|
||||||
|
```
|
||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
ESP32 client device, using `W32-ETH01` device
|
ESP32 client device, using `W32-ETH01` device
|
||||||
|
|
||||||
|
## Pins for relays
|
||||||
|
The pins are the following (in the order of definition): 4, 14, 15, 2
|
||||||
|
|
||||||
|
**WARNING!** The Pin 2 MUST be disconnect to reflash the card!
|
||||||
|
|
||||||
## Some commands
|
## Some commands
|
||||||
|
|
||||||
Create a new firmware build:
|
Create a new firmware build:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
/**
|
/**
|
||||||
* Backend unsecure API URL
|
* Backend unsecure API URL
|
||||||
*/
|
*/
|
||||||
#define BACKEND_UNSECURE_URL "http://devweb.internal:8080"
|
#define BACKEND_UNSECURE_URL "http://central.internal:8080"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Device name len
|
* Device name len
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
#define CONFIG_ETH_USE_ESP32_EMAC
|
|
||||||
|
|
||||||
#include "esp_eth.h"
|
#include "esp_eth.h"
|
||||||
#include "esp_eth_mac.h"
|
#include "esp_eth_mac.h"
|
||||||
#include "esp_eth_com.h"
|
#include "esp_eth_com.h"
|
||||||
@@ -84,8 +82,8 @@ void ethernet_init()
|
|||||||
eth_esp32_emac_config_t mac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
|
eth_esp32_emac_config_t mac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
|
||||||
mac_config.clock_config.rmii.clock_mode = EMAC_CLK_EXT_IN;
|
mac_config.clock_config.rmii.clock_mode = EMAC_CLK_EXT_IN;
|
||||||
mac_config.clock_config.rmii.clock_gpio = EMAC_CLK_IN_GPIO;
|
mac_config.clock_config.rmii.clock_gpio = EMAC_CLK_IN_GPIO;
|
||||||
mac_config.smi_mdc_gpio_num = GPIO_NUM_23;
|
mac_config.smi_gpio.mdc_num = GPIO_NUM_23;
|
||||||
mac_config.smi_mdio_gpio_num = GPIO_NUM_18;
|
mac_config.smi_gpio.mdio_num = GPIO_NUM_18;
|
||||||
|
|
||||||
eth_mac_config_t eth_mac_config = ETH_MAC_DEFAULT_CONFIG();
|
eth_mac_config_t eth_mac_config = ETH_MAC_DEFAULT_CONFIG();
|
||||||
eth_mac_config.sw_reset_timeout_ms = 1000;
|
eth_mac_config.sw_reset_timeout_ms = 1000;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ static const char *TAG = "relays";
|
|||||||
/**
|
/**
|
||||||
* Device relays GPIO ids
|
* Device relays GPIO ids
|
||||||
*/
|
*/
|
||||||
static int DEVICE_GPIO_IDS[3] = {4, 14, 15};
|
static int DEVICE_GPIO_IDS[4] = {4, 14, 15, 2};
|
||||||
|
|
||||||
int relays_count()
|
int relays_count()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#
|
#
|
||||||
# Automatically generated file. DO NOT EDIT.
|
# Automatically generated file. DO NOT EDIT.
|
||||||
# Espressif IoT Development Framework (ESP-IDF) 5.2.2 Project Configuration
|
# Espressif IoT Development Framework (ESP-IDF) 5.3.1 Project Configuration
|
||||||
#
|
#
|
||||||
CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined"
|
CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined"
|
||||||
CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined"
|
CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined"
|
||||||
@@ -14,6 +14,7 @@ CONFIG_SOC_GPTIMER_SUPPORTED=y
|
|||||||
CONFIG_SOC_SDMMC_HOST_SUPPORTED=y
|
CONFIG_SOC_SDMMC_HOST_SUPPORTED=y
|
||||||
CONFIG_SOC_BT_SUPPORTED=y
|
CONFIG_SOC_BT_SUPPORTED=y
|
||||||
CONFIG_SOC_PCNT_SUPPORTED=y
|
CONFIG_SOC_PCNT_SUPPORTED=y
|
||||||
|
CONFIG_SOC_PHY_SUPPORTED=y
|
||||||
CONFIG_SOC_WIFI_SUPPORTED=y
|
CONFIG_SOC_WIFI_SUPPORTED=y
|
||||||
CONFIG_SOC_SDIO_SLAVE_SUPPORTED=y
|
CONFIG_SOC_SDIO_SLAVE_SUPPORTED=y
|
||||||
CONFIG_SOC_TWAI_SUPPORTED=y
|
CONFIG_SOC_TWAI_SUPPORTED=y
|
||||||
@@ -43,6 +44,11 @@ CONFIG_SOC_CLK_TREE_SUPPORTED=y
|
|||||||
CONFIG_SOC_MPU_SUPPORTED=y
|
CONFIG_SOC_MPU_SUPPORTED=y
|
||||||
CONFIG_SOC_WDT_SUPPORTED=y
|
CONFIG_SOC_WDT_SUPPORTED=y
|
||||||
CONFIG_SOC_SPI_FLASH_SUPPORTED=y
|
CONFIG_SOC_SPI_FLASH_SUPPORTED=y
|
||||||
|
CONFIG_SOC_RNG_SUPPORTED=y
|
||||||
|
CONFIG_SOC_LIGHT_SLEEP_SUPPORTED=y
|
||||||
|
CONFIG_SOC_DEEP_SLEEP_SUPPORTED=y
|
||||||
|
CONFIG_SOC_LP_PERIPH_SHARE_INTERRUPT=y
|
||||||
|
CONFIG_SOC_PM_SUPPORTED=y
|
||||||
CONFIG_SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL=5
|
CONFIG_SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL=5
|
||||||
CONFIG_SOC_XTAL_SUPPORT_26M=y
|
CONFIG_SOC_XTAL_SUPPORT_26M=y
|
||||||
CONFIG_SOC_XTAL_SUPPORT_40M=y
|
CONFIG_SOC_XTAL_SUPPORT_40M=y
|
||||||
@@ -84,7 +90,9 @@ CONFIG_SOC_GPIO_IN_RANGE_MAX=39
|
|||||||
CONFIG_SOC_GPIO_OUT_RANGE_MAX=33
|
CONFIG_SOC_GPIO_OUT_RANGE_MAX=33
|
||||||
CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA
|
CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA
|
||||||
CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX=y
|
CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX=y
|
||||||
|
CONFIG_SOC_GPIO_CLOCKOUT_CHANNEL_NUM=3
|
||||||
CONFIG_SOC_I2C_NUM=2
|
CONFIG_SOC_I2C_NUM=2
|
||||||
|
CONFIG_SOC_HP_I2C_NUM=2
|
||||||
CONFIG_SOC_I2C_FIFO_LEN=32
|
CONFIG_SOC_I2C_FIFO_LEN=32
|
||||||
CONFIG_SOC_I2C_CMD_REG_NUM=16
|
CONFIG_SOC_I2C_CMD_REG_NUM=16
|
||||||
CONFIG_SOC_I2C_SUPPORT_SLAVE=y
|
CONFIG_SOC_I2C_SUPPORT_SLAVE=y
|
||||||
@@ -164,9 +172,9 @@ CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=2
|
|||||||
CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64
|
CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64
|
||||||
CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4
|
CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4
|
||||||
CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y
|
CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y
|
||||||
CONFIG_SOC_TOUCH_VERSION_1=y
|
CONFIG_SOC_TOUCH_SENSOR_VERSION=1
|
||||||
CONFIG_SOC_TOUCH_SENSOR_NUM=10
|
CONFIG_SOC_TOUCH_SENSOR_NUM=10
|
||||||
CONFIG_SOC_TOUCH_PAD_MEASURE_WAIT_MAX=0xFF
|
CONFIG_SOC_TOUCH_SAMPLE_CFG_NUM=1
|
||||||
CONFIG_SOC_TWAI_CONTROLLER_NUM=1
|
CONFIG_SOC_TWAI_CONTROLLER_NUM=1
|
||||||
CONFIG_SOC_TWAI_BRP_MIN=2
|
CONFIG_SOC_TWAI_BRP_MIN=2
|
||||||
CONFIG_SOC_TWAI_CLK_SUPPORT_APB=y
|
CONFIG_SOC_TWAI_CLK_SUPPORT_APB=y
|
||||||
@@ -222,8 +230,10 @@ CONFIG_SOC_BLE_SUPPORTED=y
|
|||||||
CONFIG_SOC_BLE_MESH_SUPPORTED=y
|
CONFIG_SOC_BLE_MESH_SUPPORTED=y
|
||||||
CONFIG_SOC_BT_CLASSIC_SUPPORTED=y
|
CONFIG_SOC_BT_CLASSIC_SUPPORTED=y
|
||||||
CONFIG_SOC_BLUFI_SUPPORTED=y
|
CONFIG_SOC_BLUFI_SUPPORTED=y
|
||||||
|
CONFIG_SOC_BT_H2C_ENC_KEY_CTRL_ENH_VSC_SUPPORTED=y
|
||||||
CONFIG_SOC_ULP_HAS_ADC=y
|
CONFIG_SOC_ULP_HAS_ADC=y
|
||||||
CONFIG_SOC_PHY_COMBO_MODULE=y
|
CONFIG_SOC_PHY_COMBO_MODULE=y
|
||||||
|
CONFIG_SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK=y
|
||||||
CONFIG_IDF_CMAKE=y
|
CONFIG_IDF_CMAKE=y
|
||||||
CONFIG_IDF_TOOLCHAIN="gcc"
|
CONFIG_IDF_TOOLCHAIN="gcc"
|
||||||
CONFIG_IDF_TARGET_ARCH_XTENSA=y
|
CONFIG_IDF_TARGET_ARCH_XTENSA=y
|
||||||
@@ -319,9 +329,13 @@ CONFIG_ESP_ROM_HAS_MZ_CRC32=y
|
|||||||
CONFIG_ESP_ROM_HAS_JPEG_DECODE=y
|
CONFIG_ESP_ROM_HAS_JPEG_DECODE=y
|
||||||
CONFIG_ESP_ROM_HAS_UART_BUF_SWITCH=y
|
CONFIG_ESP_ROM_HAS_UART_BUF_SWITCH=y
|
||||||
CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y
|
CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y
|
||||||
|
CONFIG_ESP_ROM_HAS_NEWLIB=y
|
||||||
CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT=y
|
CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT=y
|
||||||
|
CONFIG_ESP_ROM_HAS_NEWLIB_32BIT_TIME=y
|
||||||
CONFIG_ESP_ROM_HAS_SW_FLOAT=y
|
CONFIG_ESP_ROM_HAS_SW_FLOAT=y
|
||||||
|
CONFIG_ESP_ROM_USB_OTG_NUM=-1
|
||||||
CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=-1
|
CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=-1
|
||||||
|
CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# Serial flasher config
|
# Serial flasher config
|
||||||
@@ -396,6 +410,8 @@ CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
|
|||||||
# CONFIG_COMPILER_DUMP_RTL_FILES is not set
|
# CONFIG_COMPILER_DUMP_RTL_FILES is not set
|
||||||
CONFIG_COMPILER_RT_LIB_GCCLIB=y
|
CONFIG_COMPILER_RT_LIB_GCCLIB=y
|
||||||
CONFIG_COMPILER_RT_LIB_NAME="gcc"
|
CONFIG_COMPILER_RT_LIB_NAME="gcc"
|
||||||
|
# CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING is not set
|
||||||
|
CONFIG_COMPILER_ORPHAN_SECTIONS_PLACE=y
|
||||||
# end of Compiler options
|
# end of Compiler options
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -421,35 +437,16 @@ CONFIG_APPTRACE_LOCK_ENABLE=y
|
|||||||
CONFIG_BT_ALARM_MAX_NUM=50
|
CONFIG_BT_ALARM_MAX_NUM=50
|
||||||
# end of Bluetooth
|
# end of Bluetooth
|
||||||
|
|
||||||
|
#
|
||||||
|
# Console Library
|
||||||
|
#
|
||||||
|
# CONFIG_CONSOLE_SORTED_HELP is not set
|
||||||
|
# end of Console Library
|
||||||
|
|
||||||
#
|
#
|
||||||
# Driver Configurations
|
# Driver Configurations
|
||||||
#
|
#
|
||||||
|
|
||||||
#
|
|
||||||
# Legacy ADC Configuration
|
|
||||||
#
|
|
||||||
CONFIG_ADC_DISABLE_DAC=y
|
|
||||||
# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set
|
|
||||||
|
|
||||||
#
|
|
||||||
# Legacy ADC Calibration Configuration
|
|
||||||
#
|
|
||||||
CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y
|
|
||||||
CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y
|
|
||||||
CONFIG_ADC_CAL_LUT_ENABLE=y
|
|
||||||
# CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN is not set
|
|
||||||
# end of Legacy ADC Calibration Configuration
|
|
||||||
# end of Legacy ADC Configuration
|
|
||||||
|
|
||||||
#
|
|
||||||
# SPI Configuration
|
|
||||||
#
|
|
||||||
# CONFIG_SPI_MASTER_IN_IRAM is not set
|
|
||||||
CONFIG_SPI_MASTER_ISR_IN_IRAM=y
|
|
||||||
# CONFIG_SPI_SLAVE_IN_IRAM is not set
|
|
||||||
CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
|
|
||||||
# end of SPI Configuration
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# TWAI Configuration
|
# TWAI Configuration
|
||||||
#
|
#
|
||||||
@@ -462,93 +459,62 @@ CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y
|
|||||||
# end of TWAI Configuration
|
# end of TWAI Configuration
|
||||||
|
|
||||||
#
|
#
|
||||||
# UART Configuration
|
# Legacy ADC Driver Configuration
|
||||||
#
|
#
|
||||||
# CONFIG_UART_ISR_IN_IRAM is not set
|
CONFIG_ADC_DISABLE_DAC=y
|
||||||
# end of UART Configuration
|
# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# GPIO Configuration
|
# Legacy ADC Calibration Configuration
|
||||||
#
|
#
|
||||||
# CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL is not set
|
CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y
|
||||||
# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set
|
CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y
|
||||||
# end of GPIO Configuration
|
CONFIG_ADC_CAL_LUT_ENABLE=y
|
||||||
|
# CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN is not set
|
||||||
|
# end of Legacy ADC Calibration Configuration
|
||||||
|
# end of Legacy ADC Driver Configuration
|
||||||
|
|
||||||
#
|
#
|
||||||
# Sigma Delta Modulator Configuration
|
# Legacy DAC Driver Configurations
|
||||||
#
|
#
|
||||||
# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set
|
|
||||||
# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set
|
|
||||||
# CONFIG_SDM_ENABLE_DEBUG_LOG is not set
|
|
||||||
# end of Sigma Delta Modulator Configuration
|
|
||||||
|
|
||||||
#
|
|
||||||
# GPTimer Configuration
|
|
||||||
#
|
|
||||||
CONFIG_GPTIMER_ISR_HANDLER_IN_IRAM=y
|
|
||||||
# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set
|
|
||||||
# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set
|
|
||||||
# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set
|
|
||||||
# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set
|
|
||||||
# end of GPTimer Configuration
|
|
||||||
|
|
||||||
#
|
|
||||||
# PCNT Configuration
|
|
||||||
#
|
|
||||||
# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set
|
|
||||||
# CONFIG_PCNT_ISR_IRAM_SAFE is not set
|
|
||||||
# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set
|
|
||||||
# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set
|
|
||||||
# end of PCNT Configuration
|
|
||||||
|
|
||||||
#
|
|
||||||
# RMT Configuration
|
|
||||||
#
|
|
||||||
# CONFIG_RMT_ISR_IRAM_SAFE is not set
|
|
||||||
# CONFIG_RMT_RECV_FUNC_IN_IRAM is not set
|
|
||||||
# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set
|
|
||||||
# CONFIG_RMT_ENABLE_DEBUG_LOG is not set
|
|
||||||
# end of RMT Configuration
|
|
||||||
|
|
||||||
#
|
|
||||||
# MCPWM Configuration
|
|
||||||
#
|
|
||||||
# CONFIG_MCPWM_ISR_IRAM_SAFE is not set
|
|
||||||
# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set
|
|
||||||
# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set
|
|
||||||
# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set
|
|
||||||
# end of MCPWM Configuration
|
|
||||||
|
|
||||||
#
|
|
||||||
# I2S Configuration
|
|
||||||
#
|
|
||||||
# CONFIG_I2S_ISR_IRAM_SAFE is not set
|
|
||||||
# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set
|
|
||||||
# CONFIG_I2S_ENABLE_DEBUG_LOG is not set
|
|
||||||
# end of I2S Configuration
|
|
||||||
|
|
||||||
#
|
|
||||||
# DAC Configuration
|
|
||||||
#
|
|
||||||
# CONFIG_DAC_CTRL_FUNC_IN_IRAM is not set
|
|
||||||
# CONFIG_DAC_ISR_IRAM_SAFE is not set
|
|
||||||
# CONFIG_DAC_SUPPRESS_DEPRECATE_WARN is not set
|
# CONFIG_DAC_SUPPRESS_DEPRECATE_WARN is not set
|
||||||
# CONFIG_DAC_ENABLE_DEBUG_LOG is not set
|
# end of Legacy DAC Driver Configurations
|
||||||
CONFIG_DAC_DMA_AUTO_16BIT_ALIGN=y
|
|
||||||
# end of DAC Configuration
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# LEDC Configuration
|
# Legacy MCPWM Driver Configurations
|
||||||
#
|
#
|
||||||
# CONFIG_LEDC_CTRL_FUNC_IN_IRAM is not set
|
# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set
|
||||||
# end of LEDC Configuration
|
# end of Legacy MCPWM Driver Configurations
|
||||||
|
|
||||||
#
|
#
|
||||||
# I2C Configuration
|
# Legacy Timer Group Driver Configurations
|
||||||
#
|
#
|
||||||
# CONFIG_I2C_ISR_IRAM_SAFE is not set
|
# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set
|
||||||
# CONFIG_I2C_ENABLE_DEBUG_LOG is not set
|
# end of Legacy Timer Group Driver Configurations
|
||||||
# end of I2C Configuration
|
|
||||||
|
#
|
||||||
|
# Legacy RMT Driver Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set
|
||||||
|
# end of Legacy RMT Driver Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# Legacy I2S Driver Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set
|
||||||
|
# end of Legacy I2S Driver Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# Legacy PCNT Driver Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set
|
||||||
|
# end of Legacy PCNT Driver Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# Legacy SDM Driver Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set
|
||||||
|
# end of Legacy SDM Driver Configurations
|
||||||
# end of Driver Configurations
|
# end of Driver Configurations
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -568,7 +534,9 @@ CONFIG_EFUSE_MAX_BLK_LEN=192
|
|||||||
CONFIG_ESP_TLS_USING_MBEDTLS=y
|
CONFIG_ESP_TLS_USING_MBEDTLS=y
|
||||||
# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set
|
# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set
|
||||||
# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set
|
# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set
|
||||||
# CONFIG_ESP_TLS_SERVER is not set
|
# CONFIG_ESP_TLS_SERVER_SESSION_TICKETS is not set
|
||||||
|
# CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK is not set
|
||||||
|
# CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL is not set
|
||||||
# CONFIG_ESP_TLS_PSK_VERIFICATION is not set
|
# CONFIG_ESP_TLS_PSK_VERIFICATION is not set
|
||||||
# CONFIG_ESP_TLS_INSECURE is not set
|
# CONFIG_ESP_TLS_INSECURE is not set
|
||||||
# end of ESP-TLS
|
# end of ESP-TLS
|
||||||
@@ -588,11 +556,13 @@ CONFIG_ADC_CALI_LUT_ENABLE=y
|
|||||||
# end of ADC Calibration Configurations
|
# end of ADC Calibration Configurations
|
||||||
|
|
||||||
CONFIG_ADC_DISABLE_DAC_OUTPUT=y
|
CONFIG_ADC_DISABLE_DAC_OUTPUT=y
|
||||||
|
# CONFIG_ADC_ENABLE_DEBUG_LOG is not set
|
||||||
# end of ADC and ADC Calibration
|
# end of ADC and ADC Calibration
|
||||||
|
|
||||||
#
|
#
|
||||||
# Wireless Coexistence
|
# Wireless Coexistence
|
||||||
#
|
#
|
||||||
|
CONFIG_ESP_COEX_ENABLED=y
|
||||||
# end of Wireless Coexistence
|
# end of Wireless Coexistence
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -601,6 +571,105 @@ CONFIG_ADC_DISABLE_DAC_OUTPUT=y
|
|||||||
CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
|
CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
|
||||||
# end of Common ESP-related
|
# end of Common ESP-related
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP-Driver:DAC Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_DAC_CTRL_FUNC_IN_IRAM is not set
|
||||||
|
# CONFIG_DAC_ISR_IRAM_SAFE is not set
|
||||||
|
# CONFIG_DAC_ENABLE_DEBUG_LOG is not set
|
||||||
|
CONFIG_DAC_DMA_AUTO_16BIT_ALIGN=y
|
||||||
|
# end of ESP-Driver:DAC Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP-Driver:GPIO Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL is not set
|
||||||
|
# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set
|
||||||
|
# end of ESP-Driver:GPIO Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP-Driver:GPTimer Configurations
|
||||||
|
#
|
||||||
|
CONFIG_GPTIMER_ISR_HANDLER_IN_IRAM=y
|
||||||
|
# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set
|
||||||
|
# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set
|
||||||
|
# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set
|
||||||
|
# end of ESP-Driver:GPTimer Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP-Driver:I2C Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_I2C_ISR_IRAM_SAFE is not set
|
||||||
|
# CONFIG_I2C_ENABLE_DEBUG_LOG is not set
|
||||||
|
# end of ESP-Driver:I2C Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP-Driver:I2S Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_I2S_ISR_IRAM_SAFE is not set
|
||||||
|
# CONFIG_I2S_ENABLE_DEBUG_LOG is not set
|
||||||
|
# end of ESP-Driver:I2S Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP-Driver:LEDC Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_LEDC_CTRL_FUNC_IN_IRAM is not set
|
||||||
|
# end of ESP-Driver:LEDC Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP-Driver:MCPWM Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_MCPWM_ISR_IRAM_SAFE is not set
|
||||||
|
# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set
|
||||||
|
# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set
|
||||||
|
# end of ESP-Driver:MCPWM Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP-Driver:PCNT Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set
|
||||||
|
# CONFIG_PCNT_ISR_IRAM_SAFE is not set
|
||||||
|
# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set
|
||||||
|
# end of ESP-Driver:PCNT Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP-Driver:RMT Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_RMT_ISR_IRAM_SAFE is not set
|
||||||
|
# CONFIG_RMT_RECV_FUNC_IN_IRAM is not set
|
||||||
|
# CONFIG_RMT_ENABLE_DEBUG_LOG is not set
|
||||||
|
# end of ESP-Driver:RMT Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP-Driver:Sigma Delta Modulator Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set
|
||||||
|
# CONFIG_SDM_ENABLE_DEBUG_LOG is not set
|
||||||
|
# end of ESP-Driver:Sigma Delta Modulator Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP-Driver:SPI Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_SPI_MASTER_IN_IRAM is not set
|
||||||
|
CONFIG_SPI_MASTER_ISR_IN_IRAM=y
|
||||||
|
# CONFIG_SPI_SLAVE_IN_IRAM is not set
|
||||||
|
CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
|
||||||
|
# end of ESP-Driver:SPI Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP-Driver:Touch Sensor Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_TOUCH_CTRL_FUNC_IN_IRAM is not set
|
||||||
|
# CONFIG_TOUCH_ISR_IRAM_SAFE is not set
|
||||||
|
# CONFIG_TOUCH_ENABLE_DEBUG_LOG is not set
|
||||||
|
# end of ESP-Driver:Touch Sensor Configurations
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP-Driver:UART Configurations
|
||||||
|
#
|
||||||
|
# CONFIG_UART_ISR_IN_IRAM is not set
|
||||||
|
# end of ESP-Driver:UART Configurations
|
||||||
|
|
||||||
#
|
#
|
||||||
# Ethernet
|
# Ethernet
|
||||||
#
|
#
|
||||||
@@ -645,6 +714,7 @@ CONFIG_ESP_GDBSTUB_MAX_TASKS=32
|
|||||||
CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
|
CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
|
||||||
# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
|
# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
|
||||||
# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set
|
# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set
|
||||||
|
# CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT is not set
|
||||||
# end of ESP HTTP client
|
# end of ESP HTTP client
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -704,6 +774,7 @@ CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y
|
|||||||
CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y
|
CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y
|
||||||
CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y
|
CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y
|
||||||
CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR=y
|
CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR=y
|
||||||
|
CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES=4
|
||||||
# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set
|
# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set
|
||||||
CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y
|
CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y
|
||||||
CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4
|
CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4
|
||||||
@@ -749,6 +820,8 @@ CONFIG_XTAL_FREQ_40=y
|
|||||||
# CONFIG_XTAL_FREQ_AUTO is not set
|
# CONFIG_XTAL_FREQ_AUTO is not set
|
||||||
CONFIG_XTAL_FREQ=40
|
CONFIG_XTAL_FREQ=40
|
||||||
# end of Main XTAL Config
|
# end of Main XTAL Config
|
||||||
|
|
||||||
|
CONFIG_ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM=y
|
||||||
# end of Hardware Settings
|
# end of Hardware Settings
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -787,6 +860,7 @@ CONFIG_ESP_NETIF_USES_TCPIP_WITH_BSD_API=y
|
|||||||
#
|
#
|
||||||
# PHY
|
# PHY
|
||||||
#
|
#
|
||||||
|
CONFIG_ESP_PHY_ENABLED=y
|
||||||
CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
|
CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
|
||||||
# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set
|
# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set
|
||||||
CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20
|
CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20
|
||||||
@@ -868,6 +942,7 @@ CONFIG_ESP_CONSOLE_UART_DEFAULT=y
|
|||||||
# CONFIG_ESP_CONSOLE_NONE is not set
|
# CONFIG_ESP_CONSOLE_NONE is not set
|
||||||
CONFIG_ESP_CONSOLE_UART=y
|
CONFIG_ESP_CONSOLE_UART=y
|
||||||
CONFIG_ESP_CONSOLE_UART_NUM=0
|
CONFIG_ESP_CONSOLE_UART_NUM=0
|
||||||
|
CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=0
|
||||||
CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
|
CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
|
||||||
CONFIG_ESP_INT_WDT=y
|
CONFIG_ESP_INT_WDT=y
|
||||||
CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
|
CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
|
||||||
@@ -912,7 +987,7 @@ CONFIG_ESP_IPC_ISR_ENABLE=y
|
|||||||
# end of IPC (Inter-Processor Call)
|
# end of IPC (Inter-Processor Call)
|
||||||
|
|
||||||
#
|
#
|
||||||
# High resolution timer (esp_timer)
|
# ESP Timer (High Resolution Timer)
|
||||||
#
|
#
|
||||||
# CONFIG_ESP_TIMER_PROFILING is not set
|
# CONFIG_ESP_TIMER_PROFILING is not set
|
||||||
CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y
|
CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y
|
||||||
@@ -922,11 +997,10 @@ CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1
|
|||||||
# CONFIG_ESP_TIMER_SHOW_EXPERIMENTAL is not set
|
# CONFIG_ESP_TIMER_SHOW_EXPERIMENTAL is not set
|
||||||
CONFIG_ESP_TIMER_TASK_AFFINITY=0x0
|
CONFIG_ESP_TIMER_TASK_AFFINITY=0x0
|
||||||
CONFIG_ESP_TIMER_TASK_AFFINITY_CPU0=y
|
CONFIG_ESP_TIMER_TASK_AFFINITY_CPU0=y
|
||||||
CONFIG_ESP_TIMER_ISR_AFFINITY=0x1
|
|
||||||
CONFIG_ESP_TIMER_ISR_AFFINITY_CPU0=y
|
CONFIG_ESP_TIMER_ISR_AFFINITY_CPU0=y
|
||||||
# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set
|
# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set
|
||||||
CONFIG_ESP_TIMER_IMPL_TG0_LAC=y
|
CONFIG_ESP_TIMER_IMPL_TG0_LAC=y
|
||||||
# end of High resolution timer (esp_timer)
|
# end of ESP Timer (High Resolution Timer)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Wi-Fi
|
# Wi-Fi
|
||||||
@@ -960,6 +1034,9 @@ CONFIG_ESP_WIFI_ENABLE_SAE_PK=y
|
|||||||
CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT=y
|
CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT=y
|
||||||
CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA=y
|
CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA=y
|
||||||
# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set
|
# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set
|
||||||
|
CONFIG_ESP_WIFI_SLP_DEFAULT_MIN_ACTIVE_TIME=50
|
||||||
|
CONFIG_ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME=10
|
||||||
|
CONFIG_ESP_WIFI_SLP_DEFAULT_WAIT_BROADCAST_DATA_TIME=15
|
||||||
CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y
|
CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y
|
||||||
# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set
|
# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set
|
||||||
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y
|
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y
|
||||||
@@ -1034,6 +1111,8 @@ CONFIG_FATFS_PER_FILE_CACHE=y
|
|||||||
# CONFIG_FATFS_USE_FASTSEEK is not set
|
# CONFIG_FATFS_USE_FASTSEEK is not set
|
||||||
CONFIG_FATFS_VFS_FSTAT_BLKSIZE=0
|
CONFIG_FATFS_VFS_FSTAT_BLKSIZE=0
|
||||||
# CONFIG_FATFS_IMMEDIATE_FSYNC is not set
|
# CONFIG_FATFS_IMMEDIATE_FSYNC is not set
|
||||||
|
# CONFIG_FATFS_USE_LABEL is not set
|
||||||
|
CONFIG_FATFS_LINK_LOCK=y
|
||||||
# end of FAT Filesystem support
|
# end of FAT Filesystem support
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -1056,12 +1135,17 @@ CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
|
|||||||
CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
|
CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
|
||||||
# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set
|
# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set
|
||||||
CONFIG_FREERTOS_TIMER_SERVICE_TASK_NAME="Tmr Svc"
|
CONFIG_FREERTOS_TIMER_SERVICE_TASK_NAME="Tmr Svc"
|
||||||
|
# CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0 is not set
|
||||||
|
# CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU1 is not set
|
||||||
|
CONFIG_FREERTOS_TIMER_TASK_NO_AFFINITY=y
|
||||||
|
CONFIG_FREERTOS_TIMER_SERVICE_TASK_CORE_AFFINITY=0x7FFFFFFF
|
||||||
CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
|
CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
|
||||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
|
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
|
||||||
CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
|
CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
|
||||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
|
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
|
||||||
CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1
|
CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1
|
||||||
# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set
|
# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set
|
||||||
|
# CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES is not set
|
||||||
# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set
|
# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set
|
||||||
# CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set
|
# CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set
|
||||||
# end of Kernel
|
# end of Kernel
|
||||||
@@ -1092,6 +1176,7 @@ CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
|||||||
CONFIG_FREERTOS_DEBUG_OCDAWARE=y
|
CONFIG_FREERTOS_DEBUG_OCDAWARE=y
|
||||||
CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y
|
CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y
|
||||||
CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH=y
|
CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH=y
|
||||||
|
CONFIG_FREERTOS_NUMBER_OF_CORES=2
|
||||||
# end of FreeRTOS
|
# end of FreeRTOS
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -1218,6 +1303,7 @@ CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000
|
|||||||
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5760
|
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5760
|
||||||
CONFIG_LWIP_TCP_WND_DEFAULT=5760
|
CONFIG_LWIP_TCP_WND_DEFAULT=5760
|
||||||
CONFIG_LWIP_TCP_RECVMBOX_SIZE=6
|
CONFIG_LWIP_TCP_RECVMBOX_SIZE=6
|
||||||
|
CONFIG_LWIP_TCP_ACCEPTMBOX_SIZE=6
|
||||||
CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
|
CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
|
||||||
CONFIG_LWIP_TCP_OOSEQ_TIMEOUT=6
|
CONFIG_LWIP_TCP_OOSEQ_TIMEOUT=6
|
||||||
CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=4
|
CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=4
|
||||||
@@ -1273,6 +1359,8 @@ CONFIG_LWIP_MAX_RAW_PCBS=16
|
|||||||
CONFIG_LWIP_SNTP_MAX_SERVERS=1
|
CONFIG_LWIP_SNTP_MAX_SERVERS=1
|
||||||
# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set
|
# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set
|
||||||
CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
|
CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
|
||||||
|
CONFIG_LWIP_SNTP_STARTUP_DELAY=y
|
||||||
|
CONFIG_LWIP_SNTP_MAXIMUM_STARTUP_DELAY=5000
|
||||||
# end of SNTP
|
# end of SNTP
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -1342,6 +1430,7 @@ CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y
|
|||||||
# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set
|
# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set
|
||||||
# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set
|
# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set
|
||||||
# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set
|
# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set
|
||||||
|
# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEPRECATED_LIST is not set
|
||||||
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200
|
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200
|
||||||
# end of Certificate Bundle
|
# end of Certificate Bundle
|
||||||
|
|
||||||
@@ -1551,6 +1640,7 @@ CONFIG_SPI_FLASH_BROWNOUT_RESET=y
|
|||||||
#
|
#
|
||||||
# Features here require specific hardware (READ DOCS FIRST!)
|
# Features here require specific hardware (READ DOCS FIRST!)
|
||||||
#
|
#
|
||||||
|
CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US=50
|
||||||
# end of Optional and Experimental Features (READ DOCS FIRST)
|
# end of Optional and Experimental Features (READ DOCS FIRST)
|
||||||
# end of Main Flash configuration
|
# end of Main Flash configuration
|
||||||
|
|
||||||
@@ -1645,6 +1735,11 @@ CONFIG_WS_BUFFER_SIZE=1024
|
|||||||
# Ultra Low Power (ULP) Co-processor
|
# Ultra Low Power (ULP) Co-processor
|
||||||
#
|
#
|
||||||
# CONFIG_ULP_COPROC_ENABLED is not set
|
# CONFIG_ULP_COPROC_ENABLED is not set
|
||||||
|
|
||||||
|
#
|
||||||
|
# ULP Debugging Options
|
||||||
|
#
|
||||||
|
# end of ULP Debugging Options
|
||||||
# end of Ultra Low Power (ULP) Co-processor
|
# end of Ultra Low Power (ULP) Co-processor
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.0.0
|
1.0.3
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"extends": ["local>renovate/presets"]
|
||||||
"packageRules": [
|
|
||||||
{
|
|
||||||
"matchUpdateTypes": ["major", "minor", "patch"],
|
|
||||||
"automerge": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user