Compare commits
	
		
			126 Commits
		
	
	
		
			1.0.2
			...
			15526a0278
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 15526a0278 | |||
| 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 | |||
| 541f7cbe95 | |||
| fc5f9735bf | |||
| ffbbd14ac3 | |||
| 4330e64489 | 
.drone.yml
central_backend
Cargo.lockCargo.toml
src
crypto
devices
energy
logs
main.rsserver
auth_middleware.rscustom_error.rs
devices_api
servers.rsunsecure_server
web_api
auth_controller.rsdevices_controller.rsenergy_controller.rslogging_controller.rsota_controller.rsrelays_controller.rs
web_app_controller.rsutils
central_frontend
eslint.config.jspackage-lock.jsonpackage.json
src
tsconfig.app.jsontsconfig.jsontsconfig.node.jsonvite.config.tscustom_consumption
renovate.json@@ -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
 | 
				
			||||||
@@ -56,7 +56,7 @@ steps:
 | 
				
			|||||||
      - ls -lah target/release/central_backend
 | 
					      - ls -lah target/release/central_backend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - name: esp32_compile
 | 
					  - name: esp32_compile
 | 
				
			||||||
    image: espressif/idf:v5.3.1
 | 
					    image: espressif/idf:v5.4.1
 | 
				
			||||||
    commands:
 | 
					    commands:
 | 
				
			||||||
      - cd esp32_device
 | 
					      - cd esp32_device
 | 
				
			||||||
      - /opt/esp/entrypoint.sh idf.py build
 | 
					      - /opt/esp/entrypoint.sh idf.py build
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1301
									
								
								central_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1301
									
								
								central_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,46 +1,46 @@
 | 
				
			|||||||
[package]
 | 
					[package]
 | 
				
			||||||
name = "central_backend"
 | 
					name = "central_backend"
 | 
				
			||||||
version = "1.0.2"
 | 
					version = "1.0.2"
 | 
				
			||||||
edition = "2021"
 | 
					edition = "2024"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
log = "0.4.22"
 | 
					log = "0.4.27"
 | 
				
			||||||
env_logger = "0.11.5"
 | 
					env_logger = "0.11.8"
 | 
				
			||||||
lazy_static = "1.5.0"
 | 
					lazy_static = "1.5.0"
 | 
				
			||||||
dotenvy = "0.15.7"
 | 
					dotenvy = "0.15.7"
 | 
				
			||||||
clap = { version = "4.5.20", features = ["derive", "env"] }
 | 
					clap = { version = "4.5.38", features = ["derive", "env"] }
 | 
				
			||||||
anyhow = "1.0.89"
 | 
					anyhow = "1.0.98"
 | 
				
			||||||
thiserror = "2.0.3"
 | 
					thiserror = "2.0.12"
 | 
				
			||||||
openssl = { version = "0.10.66" }
 | 
					openssl = { version = "0.10.72" }
 | 
				
			||||||
openssl-sys = "0.9.102"
 | 
					openssl-sys = "0.9.108"
 | 
				
			||||||
libc = "0.2.159"
 | 
					libc = "0.2.172"
 | 
				
			||||||
foreign-types-shared = "0.1.1"
 | 
					foreign-types-shared = "0.1.1"
 | 
				
			||||||
asn1 = "0.20"
 | 
					asn1 = "0.21.3"
 | 
				
			||||||
actix-web = { version = "4", features = ["openssl"] }
 | 
					actix-web = { version = "4.10.2", features = ["openssl"] }
 | 
				
			||||||
futures = "0.3.31"
 | 
					futures = "0.3.31"
 | 
				
			||||||
serde = { version = "1.0.215", features = ["derive"] }
 | 
					serde = { version = "1.0.219", features = ["derive"] }
 | 
				
			||||||
reqwest = { version = "0.12.7", features = ["json"] }
 | 
					reqwest = { version = "0.12.15", features = ["json"] }
 | 
				
			||||||
serde_json = "1.0.131"
 | 
					serde_json = "1.0.140"
 | 
				
			||||||
rand = "0.8.5"
 | 
					rand = "0.9.1"
 | 
				
			||||||
actix = "0.13.5"
 | 
					actix = "0.13.5"
 | 
				
			||||||
actix-identity = "0.8.0"
 | 
					actix-identity = "0.8.0"
 | 
				
			||||||
actix-session = { version = "0.10.1", features = ["cookie-session"] }
 | 
					actix-session = { version = "0.10.1", 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.11.0", features = ["v4", "serde"] }
 | 
					uuid = { version = "1.16.0", features = ["v4", "serde"] }
 | 
				
			||||||
semver = { version = "1.0.23", features = ["serde"] }
 | 
					semver = { version = "1.0.26", features = ["serde"] }
 | 
				
			||||||
lazy-regex = "3.3.0"
 | 
					lazy-regex = "3.4.1"
 | 
				
			||||||
tokio = { version = "1.40.0", features = ["full"] }
 | 
					tokio = { version = "1.44.2", 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.6.0"
 | 
				
			||||||
jsonwebtoken = { version = "9.3.0", features = ["use_pem"] }
 | 
					jsonwebtoken = { version = "9.3.1", features = ["use_pem"] }
 | 
				
			||||||
prettytable-rs = "0.10.0"
 | 
					prettytable-rs = "0.10.0"
 | 
				
			||||||
chrono = "0.4.38"
 | 
					chrono = "0.4.41"
 | 
				
			||||||
serde_yml = "0.0.12"
 | 
					serde_yml = "0.0.12"
 | 
				
			||||||
bincode = "=2.0.0-rc.3"
 | 
					bincode = "2.0.1"
 | 
				
			||||||
fs4 = { version = "0.12.0", features = ["sync"] }
 | 
					fs4 = { version = "0.13.1", features = ["sync"] }
 | 
				
			||||||
zip = { version = "2.2.0", features = ["bzip2"] }
 | 
					zip = { version = "2.2.0", features = ["bzip2"] }
 | 
				
			||||||
walkdir = "2.5.0"
 | 
					walkdir = "2.5.0"
 | 
				
			||||||
@@ -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,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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!(
 | 
				
			||||||
 | 
					            dep_cycle_1
 | 
				
			||||||
                .error(&[dep_cycle_2.clone(), dep_cycle_3.clone()])
 | 
					                .error(&[dep_cycle_2.clone(), dep_cycle_3.clone()])
 | 
				
			||||||
            .is_some());
 | 
					                .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!(
 | 
				
			||||||
 | 
					            target_relay
 | 
				
			||||||
                .error(&[other_dep.clone(), second_dep.clone()])
 | 
					                .error(&[other_dep.clone(), second_dep.clone()])
 | 
				
			||||||
            .is_some());
 | 
					                .is_some()
 | 
				
			||||||
        assert!(target_relay
 | 
					        );
 | 
				
			||||||
 | 
					        assert!(
 | 
				
			||||||
 | 
					            target_relay
 | 
				
			||||||
                .error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()])
 | 
					                .error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()])
 | 
				
			||||||
            .is_some());
 | 
					                .is_some()
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        second_dep.conflicts_with = vec![];
 | 
					        second_dep.conflicts_with = vec![];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert!(target_relay
 | 
					        assert!(
 | 
				
			||||||
 | 
					            target_relay
 | 
				
			||||||
                .error(&[other_dep.clone(), second_dep.clone()])
 | 
					                .error(&[other_dep.clone(), second_dep.clone()])
 | 
				
			||||||
            .is_none());
 | 
					                .is_none()
 | 
				
			||||||
        assert!(target_relay
 | 
					        );
 | 
				
			||||||
 | 
					        assert!(
 | 
				
			||||||
 | 
					            target_relay
 | 
				
			||||||
                .error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()])
 | 
					                .error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()])
 | 
				
			||||||
            .is_none());
 | 
					                .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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -49,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);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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};
 | 
				
			||||||
@@ -289,7 +289,11 @@ 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;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check if we have reached reset_time today yet or not
 | 
				
			||||||
 | 
					    if time_start_day + reset_time as u64 <= time_secs() {
 | 
				
			||||||
        let start_time = time_start_day + reset_time as u64;
 | 
					        let start_time = time_start_day + reset_time as u64;
 | 
				
			||||||
        let end_time = time_start_day + 3600 * 24 + 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)
 | 
					        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,7 +5,7 @@ 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<()> {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,8 @@
 | 
				
			|||||||
 | 
					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;
 | 
					use zip::result::ZipError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Custom error to ease controller writing
 | 
					/// Custom error to ease controller writing
 | 
				
			||||||
@@ -52,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())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -82,43 +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 {
 | 
					impl From<ZipError> for HttpErr {
 | 
				
			||||||
    fn from(value: ZipError) -> Self {
 | 
					    fn from(value: ZipError) -> 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<walkdir::Error> for HttpErr {
 | 
					impl From<walkdir::Error> for HttpErr {
 | 
				
			||||||
    fn from(value: walkdir::Error) -> Self {
 | 
					    fn from(value: walkdir::Error) -> Self {
 | 
				
			||||||
        HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
 | 
					        HttpErr::Err(std::io::Error::other(value.to_string()).into())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
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)]
 | 
				
			||||||
pub struct LogRequest {
 | 
					pub struct LogRequest {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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::LogoutBehaviour;
 | 
				
			||||||
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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,8 +2,8 @@ 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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()))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
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::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 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										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 },
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										2816
									
								
								central_frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2816
									
								
								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.0",
 | 
				
			||||||
    "@fontsource/roboto": "^5.1.0",
 | 
					    "@fontsource/roboto": "^5.2.6",
 | 
				
			||||||
    "@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.4",
 | 
					    "@mui/icons-material": "^7.0.2",
 | 
				
			||||||
    "@mui/material": "^6.1.4",
 | 
					    "@mui/material": "^7.0.2",
 | 
				
			||||||
    "@mui/x-charts": "^7.21.0",
 | 
					    "@mui/x-charts": "^7.29.1",
 | 
				
			||||||
    "@mui/x-date-pickers": "^7.21.0",
 | 
					    "@mui/x-date-pickers": "^7.29.4",
 | 
				
			||||||
    "@types/semver": "^7.5.8",
 | 
					 | 
				
			||||||
    "date-and-time": "^3.6.0",
 | 
					    "date-and-time": "^3.6.0",
 | 
				
			||||||
    "dayjs": "^1.11.13",
 | 
					    "dayjs": "^1.11.13",
 | 
				
			||||||
    "filesize": "^10.1.6",
 | 
					    "filesize": "^10.1.6",
 | 
				
			||||||
    "react": "^18.3.1",
 | 
					    "react": "^19.0.0",
 | 
				
			||||||
    "react-dom": "^18.3.1",
 | 
					    "react-dom": "^19.0.0",
 | 
				
			||||||
    "react-router-dom": "^7.0.0",
 | 
					    "react-router-dom": "^7.6.2",
 | 
				
			||||||
    "semver": "^7.6.3"
 | 
					    "semver": "^7.7.2"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@types/react": "^18.3.11",
 | 
					    "@types/react": "^19.0.0",
 | 
				
			||||||
    "@types/react-dom": "^18.3.1",
 | 
					    "@types/react-dom": "^19.0.4",
 | 
				
			||||||
    "@typescript-eslint/eslint-plugin": "^8.15.0",
 | 
					    "@types/semver": "^7.7.0",
 | 
				
			||||||
    "@typescript-eslint/parser": "^8.10.0",
 | 
					    "@typescript-eslint/eslint-plugin": "^8.32.1",
 | 
				
			||||||
    "@vitejs/plugin-react": "^4.3.2",
 | 
					    "@typescript-eslint/parser": "^8.32.1",
 | 
				
			||||||
    "eslint": "^9.0.0",
 | 
					    "@vitejs/plugin-react": "^4.4.1",
 | 
				
			||||||
    "eslint-plugin-react-hooks": "^5.0.0",
 | 
					    "eslint": "^9.26.0",
 | 
				
			||||||
    "eslint-plugin-react-refresh": "^0.4.12",
 | 
					    "eslint-plugin-react-hooks": "^5.2.0",
 | 
				
			||||||
    "typescript": "^5.6.3",
 | 
					    "eslint-plugin-react-refresh": "^0.4.20",
 | 
				
			||||||
    "vite": "^5.4.9"
 | 
					    "globals": "^16.1.0",
 | 
				
			||||||
 | 
					    "typescript": "^5.8.3",
 | 
				
			||||||
 | 
					    "typescript-eslint": "^8.34.0",
 | 
				
			||||||
 | 
					    "vite": "^6.2.3"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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()],
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1502
									
								
								custom_consumption/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1502
									
								
								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.27"
 | 
				
			||||||
clap = { version = "4.5.18", features = ["derive", "env"] }
 | 
					clap = { version = "4.5.38", features = ["derive", "env"] }
 | 
				
			||||||
egui = "0.29.1"
 | 
					egui = "0.31.1"
 | 
				
			||||||
eframe = "0.29.1"
 | 
					eframe = "0.31.1"
 | 
				
			||||||
lazy_static = "1.5.0"
 | 
					lazy_static = "1.5.0"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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