Compare commits
	
		
			78 Commits
		
	
	
		
			1.0.2
			...
			da60a57f53
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | 
| @@ -5,7 +5,7 @@ name: default | ||||
|  | ||||
| steps: | ||||
|   - name: web_build | ||||
|     image: node:21 | ||||
|     image: node:23 | ||||
|     volumes: | ||||
|       - name: web_app | ||||
|         path: /tmp/web_build | ||||
| @@ -56,7 +56,7 @@ steps: | ||||
|       - ls -lah target/release/central_backend | ||||
|  | ||||
|   - name: esp32_compile | ||||
|     image: espressif/idf:v5.3.1 | ||||
|     image: espressif/idf:v5.4.1 | ||||
|     commands: | ||||
|       - cd esp32_device | ||||
|       - /opt/esp/entrypoint.sh idf.py build | ||||
|   | ||||
							
								
								
									
										1302
									
								
								central_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1302
									
								
								central_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,46 +1,46 @@ | ||||
| [package] | ||||
| name = "central_backend" | ||||
| version = "1.0.2" | ||||
| edition = "2021" | ||||
| edition = "2024" | ||||
|  | ||||
| [dependencies] | ||||
| log = "0.4.22" | ||||
| env_logger = "0.11.5" | ||||
| log = "0.4.27" | ||||
| env_logger = "0.11.7" | ||||
| lazy_static = "1.5.0" | ||||
| dotenvy = "0.15.7" | ||||
| clap = { version = "4.5.20", features = ["derive", "env"] } | ||||
| anyhow = "1.0.89" | ||||
| clap = { version = "4.5.34", features = ["derive", "env"] } | ||||
| anyhow = "1.0.97" | ||||
| thiserror = "2.0.3" | ||||
| openssl = { version = "0.10.66" } | ||||
| openssl-sys = "0.9.102" | ||||
| libc = "0.2.159" | ||||
| openssl = { version = "0.10.71" } | ||||
| openssl-sys = "0.9.106" | ||||
| libc = "0.2.171" | ||||
| foreign-types-shared = "0.1.1" | ||||
| asn1 = "0.20" | ||||
| actix-web = { version = "4", features = ["openssl"] } | ||||
| asn1 = "0.21" | ||||
| actix-web = { version = "4.10.2", features = ["openssl"] } | ||||
| futures = "0.3.31" | ||||
| serde = { version = "1.0.215", features = ["derive"] } | ||||
| reqwest = { version = "0.12.7", features = ["json"] } | ||||
| serde_json = "1.0.131" | ||||
| rand = "0.8.5" | ||||
| rand = "0.9.0" | ||||
| actix = "0.13.5" | ||||
| actix-identity = "0.8.0" | ||||
| 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-remote-ip = "0.1.0" | ||||
| futures-util = "0.3.31" | ||||
| uuid = { version = "1.11.0", features = ["v4", "serde"] } | ||||
| semver = { version = "1.0.23", features = ["serde"] } | ||||
| lazy-regex = "3.3.0" | ||||
| lazy-regex = "3.4.1" | ||||
| tokio = { version = "1.40.0", features = ["full"] } | ||||
| tokio_schedule = "0.3.2" | ||||
| mime_guess = "2.0.5" | ||||
| rust-embed = "8.5.0" | ||||
| jsonwebtoken = { version = "9.3.0", features = ["use_pem"] } | ||||
| jsonwebtoken = { version = "9.3.1", features = ["use_pem"] } | ||||
| prettytable-rs = "0.10.0" | ||||
| chrono = "0.4.38" | ||||
| chrono = "0.4.40" | ||||
| serde_yml = "0.0.12" | ||||
| bincode = "=2.0.0-rc.3" | ||||
| fs4 = { version = "0.12.0", features = ["sync"] } | ||||
| bincode = "2.0.1" | ||||
| fs4 = { version = "0.13.1", features = ["sync"] } | ||||
| 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::{ | ||||
|     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::{ | ||||
|     X509_CRL_add0_revoked, X509_CRL_new, X509_CRL_set1_lastUpdate, X509_CRL_set1_nextUpdate, | ||||
|     X509_CRL_set_issuer_name, X509_CRL_set_version, X509_CRL_sign, X509_REVOKED_dup, | ||||
|     X509_CRL_add0_revoked, X509_CRL_new, X509_CRL_set_issuer_name, X509_CRL_set_version, | ||||
|     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, | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -325,9 +325,11 @@ mod tests { | ||||
|             ..Default::default() | ||||
|         }; | ||||
|         dep_cycle_1.depends_on = vec![dep_cycle_3.id]; | ||||
|         assert!(dep_cycle_1 | ||||
|             .error(&[dep_cycle_2.clone(), dep_cycle_3.clone()]) | ||||
|             .is_some()); | ||||
|         assert!( | ||||
|             dep_cycle_1 | ||||
|                 .error(&[dep_cycle_2.clone(), dep_cycle_3.clone()]) | ||||
|                 .is_some() | ||||
|         ); | ||||
|  | ||||
|         dep_cycle_1.depends_on = vec![]; | ||||
|         assert!(dep_cycle_1.error(&[dep_cycle_2, dep_cycle_3]).is_none()); | ||||
| @@ -351,21 +353,29 @@ mod tests { | ||||
|             ..Default::default() | ||||
|         }; | ||||
|  | ||||
|         assert!(target_relay | ||||
|             .error(&[other_dep.clone(), second_dep.clone()]) | ||||
|             .is_some()); | ||||
|         assert!(target_relay | ||||
|             .error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()]) | ||||
|             .is_some()); | ||||
|         assert!( | ||||
|             target_relay | ||||
|                 .error(&[other_dep.clone(), second_dep.clone()]) | ||||
|                 .is_some() | ||||
|         ); | ||||
|         assert!( | ||||
|             target_relay | ||||
|                 .error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()]) | ||||
|                 .is_some() | ||||
|         ); | ||||
|  | ||||
|         second_dep.conflicts_with = vec![]; | ||||
|  | ||||
|         assert!(target_relay | ||||
|             .error(&[other_dep.clone(), second_dep.clone()]) | ||||
|             .is_none()); | ||||
|         assert!(target_relay | ||||
|             .error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()]) | ||||
|             .is_none()); | ||||
|         assert!( | ||||
|             target_relay | ||||
|                 .error(&[other_dep.clone(), second_dep.clone()]) | ||||
|                 .is_none() | ||||
|         ); | ||||
|         assert!( | ||||
|             target_relay | ||||
|                 .error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()]) | ||||
|                 .is_none() | ||||
|         ); | ||||
|  | ||||
|         // self loop | ||||
|         let mut self_loop = DeviceRelay { | ||||
|   | ||||
| @@ -4,7 +4,7 @@ use crate::devices::device::{ | ||||
|     Device, DeviceGeneralInfo, DeviceId, DeviceInfo, DeviceRelay, DeviceRelayID, | ||||
| }; | ||||
| use crate::utils::time_utils::time_secs; | ||||
| use openssl::x509::{X509Req, X509}; | ||||
| use openssl::x509::{X509, X509Req}; | ||||
| use std::collections::HashMap; | ||||
|  | ||||
| #[derive(thiserror::Error, Debug)] | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| use crate::app_config::{AppConfig, ConsumptionBackend}; | ||||
| use rand::{thread_rng, Rng}; | ||||
| use rand::{Rng, rng}; | ||||
| use std::num::ParseIntError; | ||||
| use std::path::Path; | ||||
|  | ||||
| @@ -49,7 +49,7 @@ pub async fn get_curr_consumption() -> anyhow::Result<EnergyConsumption> { | ||||
|     match backend { | ||||
|         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 } => { | ||||
|             let path = Path::new(path); | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| use std::collections::HashMap; | ||||
|  | ||||
| use crate::app_config::AppConfig; | ||||
| use prettytable::{row, Table}; | ||||
| use prettytable::{Table, row}; | ||||
|  | ||||
| use crate::constants; | ||||
| use crate::devices::device::{Device, DeviceId, DeviceRelay, DeviceRelayID}; | ||||
| @@ -289,7 +289,11 @@ impl EnergyEngine { | ||||
|                     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; | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| use crate::app_config::AppConfig; | ||||
| use crate::devices::device::{DeviceRelay, DeviceRelayID}; | ||||
| 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; | ||||
|  | ||||
| @@ -128,15 +128,26 @@ pub fn relay_total_runtime_adjusted(relay: &DeviceRelay) -> usize { | ||||
|         .unwrap_or(0); | ||||
|  | ||||
|     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; | ||||
|     relay_total_runtime(relay.id, start_time, end_time).unwrap_or(3600 * 24) | ||||
|  | ||||
|     // 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 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)] | ||||
| mod tests { | ||||
|     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] | ||||
|     fn test_relay_state_history() { | ||||
|   | ||||
| @@ -35,7 +35,7 @@ pub fn save_log( | ||||
|         .as_bytes(), | ||||
|     )?; | ||||
|     file.flush()?; | ||||
|     file.unlock()?; | ||||
|     fs4::fs_std::FileExt::unlock(&file)?; | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|   | ||||
| @@ -5,7 +5,7 @@ use central_backend::energy::energy_actor::EnergyActor; | ||||
| use central_backend::server::servers; | ||||
| use central_backend::utils::files_utils::create_directory_if_missing; | ||||
| use futures::future; | ||||
| use tokio_schedule::{every, Job}; | ||||
| use tokio_schedule::{Job, every}; | ||||
|  | ||||
| #[actix_web::main] | ||||
| async fn main() -> std::io::Result<()> { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| use actix_identity::Identity; | ||||
| use std::future::{ready, Ready}; | ||||
| use std::future::{Ready, ready}; | ||||
| use std::rc::Rc; | ||||
|  | ||||
| use crate::app_config::AppConfig; | ||||
| @@ -7,8 +7,8 @@ use crate::constants; | ||||
| use actix_web::body::EitherBody; | ||||
| use actix_web::dev::Payload; | ||||
| use actix_web::{ | ||||
|     dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform}, | ||||
|     Error, FromRequest, HttpResponse, | ||||
|     dev::{Service, ServiceRequest, ServiceResponse, Transform, forward_ready}, | ||||
| }; | ||||
| use futures_util::future::LocalBoxFuture; | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| use actix_web::HttpResponse; | ||||
| use actix_web::body::BoxBody; | ||||
| use actix_web::http::StatusCode; | ||||
| use actix_web::HttpResponse; | ||||
| use std::error::Error; | ||||
| use std::fmt::{Display, Formatter}; | ||||
| use std::io::ErrorKind; | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| use crate::logs::logs_manager; | ||||
| use crate::logs::severity::LogSeverity; | ||||
| use crate::server::WebEnergyActor; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| use crate::server::devices_api::jwt_parser::JWTRequest; | ||||
| use crate::server::WebEnergyActor; | ||||
| use actix_web::{web, HttpResponse}; | ||||
| use actix_web::{HttpResponse, web}; | ||||
|  | ||||
| #[derive(Debug, serde::Deserialize)] | ||||
| pub struct LogRequest { | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| use crate::ota::ota_manager; | ||||
| use crate::ota::ota_update::OTAPlatform; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| use actix_web::{web, HttpResponse}; | ||||
| use actix_web::{HttpResponse, web}; | ||||
|  | ||||
| #[derive(serde::Deserialize)] | ||||
| pub struct FirmwarePath { | ||||
|   | ||||
| @@ -4,10 +4,10 @@ use crate::energy::energy_actor; | ||||
| use crate::energy::energy_actor::RelaySyncStatus; | ||||
| use crate::ota::ota_manager; | ||||
| use crate::ota::ota_update::OTAPlatform; | ||||
| use crate::server::WebEnergyActor; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| use crate::server::devices_api::jwt_parser::JWTRequest; | ||||
| use crate::server::WebEnergyActor; | ||||
| use actix_web::{web, HttpResponse}; | ||||
| use actix_web::{HttpResponse, web}; | ||||
| use openssl::nid::Nid; | ||||
| use openssl::x509::X509Req; | ||||
| use std::str::FromStr; | ||||
|   | ||||
| @@ -10,14 +10,14 @@ use crate::server::unsecure_server::*; | ||||
| use crate::server::web_api::*; | ||||
| use crate::server::web_app_controller; | ||||
| use actix_cors::Cors; | ||||
| use actix_identity::config::LogoutBehaviour; | ||||
| use actix_identity::IdentityMiddleware; | ||||
| use actix_identity::config::LogoutBehaviour; | ||||
| use actix_remote_ip::RemoteIPConfig; | ||||
| use actix_session::storage::CookieSessionStore; | ||||
| use actix_session::SessionMiddleware; | ||||
| use actix_session::storage::CookieSessionStore; | ||||
| use actix_web::cookie::{Key, SameSite}; | ||||
| use actix_web::middleware::Logger; | ||||
| use actix_web::{web, App, HttpServer}; | ||||
| use actix_web::{App, HttpServer, web}; | ||||
| use openssl::ssl::{SslAcceptor, SslMethod}; | ||||
| use std::time::Duration; | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| use crate::app_config::AppConfig; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| use actix_web::{web, HttpResponse}; | ||||
| use actix_web::{HttpResponse, web}; | ||||
|  | ||||
| #[derive(serde::Deserialize)] | ||||
| pub struct ServeCRLPath { | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| use crate::devices::device::DeviceRelayID; | ||||
| use crate::energy::{energy_actor, relay_state_history}; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| use crate::server::WebEnergyActor; | ||||
| use actix_web::{web, HttpResponse}; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| use actix_web::{HttpResponse, web}; | ||||
|  | ||||
| #[derive(serde::Deserialize)] | ||||
| pub struct LegacyStateRelay { | ||||
|   | ||||
| @@ -2,7 +2,7 @@ use crate::app_config::AppConfig; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| use actix_identity::Identity; | ||||
| use actix_remote_ip::RemoteIP; | ||||
| use actix_web::{web, HttpMessage, HttpRequest, HttpResponse}; | ||||
| use actix_web::{HttpMessage, HttpRequest, HttpResponse, web}; | ||||
|  | ||||
| #[derive(serde::Deserialize)] | ||||
| pub struct AuthRequest { | ||||
| @@ -17,11 +17,11 @@ pub async fn password_auth( | ||||
|     remote_ip: RemoteIP, | ||||
| ) -> HttpResult { | ||||
|     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!")); | ||||
|     } | ||||
|  | ||||
|     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())?; | ||||
|     Ok(HttpResponse::Ok().finish()) | ||||
| } | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| use crate::devices::device::{DeviceGeneralInfo, DeviceId}; | ||||
| use crate::energy::energy_actor; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| 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 | ||||
| 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_history_file::ConsumptionHistoryFile; | ||||
| use crate::energy::{consumption, energy_actor}; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| use crate::server::WebEnergyActor; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| use crate::utils::time_utils::time_secs; | ||||
| use actix_web::HttpResponse; | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,7 @@ use crate::logs::logs_manager; | ||||
| use crate::logs::severity::LogSeverity; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| use crate::utils::time_utils::curr_day_number; | ||||
| use actix_web::{web, HttpResponse}; | ||||
| use actix_web::{HttpResponse, web}; | ||||
|  | ||||
| #[derive(serde::Deserialize)] | ||||
| pub struct LogRequest { | ||||
|   | ||||
| @@ -3,11 +3,11 @@ use crate::devices::device::DeviceId; | ||||
| use crate::energy::energy_actor; | ||||
| use crate::ota::ota_manager; | ||||
| use crate::ota::ota_update::OTAPlatform; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| use crate::server::WebEnergyActor; | ||||
| use actix_multipart::form::tempfile::TempFile; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| 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 { | ||||
|     Ok(HttpResponse::Ok().json(OTAPlatform::supported_platforms())) | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| use crate::devices::device::{DeviceId, DeviceRelay, DeviceRelayID}; | ||||
| use crate::energy::energy_actor; | ||||
| use crate::server::custom_error::HttpResult; | ||||
| 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 | ||||
| pub async fn get_list(actor: WebEnergyActor) -> HttpResult { | ||||
|   | ||||
| @@ -19,7 +19,7 @@ mod serve_static_debug { | ||||
|  | ||||
| #[cfg(not(debug_assertions))] | ||||
| mod serve_static_release { | ||||
|     use actix_web::{web, HttpResponse, Responder}; | ||||
|     use actix_web::{HttpResponse, Responder, web}; | ||||
|     use rust_embed::RustEmbed; | ||||
|  | ||||
|     #[derive(RustEmbed)] | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| use chrono::prelude::*; | ||||
| 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 { | ||||
|     SystemTime::now() | ||||
|         .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 }, | ||||
|       ], | ||||
|     }, | ||||
|   }, | ||||
| ) | ||||
							
								
								
									
										1808
									
								
								central_frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1808
									
								
								central_frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -6,38 +6,40 @@ | ||||
|   "scripts": { | ||||
|     "dev": "vite", | ||||
|     "build": "tsc -b && vite build", | ||||
|     "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", | ||||
|     "lint": "eslint .", | ||||
|     "preview": "vite preview" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@emotion/react": "^11.13.3", | ||||
|     "@emotion/react": "^11.14.0", | ||||
|     "@emotion/styled": "^11.13.0", | ||||
|     "@fontsource/roboto": "^5.1.0", | ||||
|     "@fontsource/roboto": "^5.2.5", | ||||
|     "@mdi/js": "^7.4.47", | ||||
|     "@mdi/react": "^1.6.1", | ||||
|     "@mui/icons-material": "^6.1.4", | ||||
|     "@mui/material": "^6.1.4", | ||||
|     "@mui/icons-material": "^7.0.0", | ||||
|     "@mui/material": "^7.0.0", | ||||
|     "@mui/x-charts": "^7.21.0", | ||||
|     "@mui/x-date-pickers": "^7.21.0", | ||||
|     "@types/semver": "^7.5.8", | ||||
|     "@mui/x-date-pickers": "^7.28.2", | ||||
|     "date-and-time": "^3.6.0", | ||||
|     "dayjs": "^1.11.13", | ||||
|     "filesize": "^10.1.6", | ||||
|     "react": "^18.3.1", | ||||
|     "react-dom": "^18.3.1", | ||||
|     "react-router-dom": "^7.0.0", | ||||
|     "semver": "^7.6.3" | ||||
|     "react": "^19.0.0", | ||||
|     "react-dom": "^19.0.0", | ||||
|     "react-router-dom": "^7.4.0", | ||||
|     "semver": "^7.7.1" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/react": "^18.3.11", | ||||
|     "@types/react-dom": "^18.3.1", | ||||
|     "@typescript-eslint/eslint-plugin": "^8.15.0", | ||||
|     "@typescript-eslint/parser": "^8.10.0", | ||||
|     "@vitejs/plugin-react": "^4.3.2", | ||||
|     "eslint": "^9.0.0", | ||||
|     "@types/react": "^19.0.0", | ||||
|     "@types/react-dom": "^19.0.4", | ||||
|     "@types/semver": "^7.7.0", | ||||
|     "@typescript-eslint/eslint-plugin": "^8.18.2", | ||||
|     "@typescript-eslint/parser": "^8.28.0", | ||||
|     "@vitejs/plugin-react": "^4.3.4", | ||||
|     "eslint": "^9.23.0", | ||||
|     "eslint-plugin-react-hooks": "^5.0.0", | ||||
|     "eslint-plugin-react-refresh": "^0.4.12", | ||||
|     "typescript": "^5.6.3", | ||||
|     "vite": "^5.4.9" | ||||
|     "eslint-plugin-react-refresh": "^0.4.19", | ||||
|     "globals": "^16.0.0", | ||||
|     "typescript": "^5.8.2", | ||||
|     "typescript-eslint": "^8.24.1", | ||||
|     "vite": "^6.2.3" | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -6,7 +6,7 @@ import { | ||||
|   DialogTitle, | ||||
|   Typography, | ||||
| } from "@mui/material"; | ||||
| import Grid from "@mui/material/Grid2"; | ||||
| import Grid from "@mui/material/Grid"; | ||||
| import { TimePicker } from "@mui/x-date-pickers"; | ||||
| import React from "react"; | ||||
| import { Device, DeviceRelay } from "../api/DeviceApi"; | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import DeleteIcon from "@mui/icons-material/Delete"; | ||||
| import RefreshIcon from "@mui/icons-material/Refresh"; | ||||
| import { IconButton, Tooltip } from "@mui/material"; | ||||
| import Grid from "@mui/material/Grid2"; | ||||
| import Grid from "@mui/material/Grid"; | ||||
| import React from "react"; | ||||
| import { useNavigate, useParams } from "react-router-dom"; | ||||
| import { Device, DeviceApi } from "../../api/DeviceApi"; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { Typography } from "@mui/material"; | ||||
| import { CurrConsumptionWidget } from "./HomeRoute/CurrConsumptionWidget"; | ||||
| import Grid from "@mui/material/Grid2"; | ||||
| import Grid from "@mui/material/Grid"; | ||||
| import { CachedConsumptionWidget } from "./HomeRoute/CachedConsumptionWidget"; | ||||
| import { RelayConsumptionWidget } from "./HomeRoute/RelayConsumptionWidget"; | ||||
| import { RelaysListRoute } from "./RelaysListRoute"; | ||||
|   | ||||
| @@ -11,7 +11,7 @@ import Typography from "@mui/material/Typography"; | ||||
| import * as React from "react"; | ||||
| import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider"; | ||||
| import { AuthApi } from "../api/AuthApi"; | ||||
| import Grid from "@mui/material/Grid2"; | ||||
| import Grid from "@mui/material/Grid"; | ||||
|  | ||||
| function Copyright(props: any) { | ||||
|   return ( | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| { | ||||
|   "compilerOptions": { | ||||
|     "composite": true, | ||||
|     "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", | ||||
|     "target": "ES2020", | ||||
|     "useDefineForClassFields": true, | ||||
| @@ -11,7 +10,6 @@ | ||||
|     /* Bundler mode */ | ||||
|     "moduleResolution": "bundler", | ||||
|     "allowImportingTsExtensions": true, | ||||
|     "resolveJsonModule": true, | ||||
|     "isolatedModules": true, | ||||
|     "moduleDetection": "force", | ||||
|     "noEmit": true, | ||||
| @@ -21,7 +19,8 @@ | ||||
|     "strict": true, | ||||
|     "noUnusedLocals": true, | ||||
|     "noUnusedParameters": true, | ||||
|     "noFallthroughCasesInSwitch": true | ||||
|     "noFallthroughCasesInSwitch": true, | ||||
|     "noUncheckedSideEffectImports": true | ||||
|   }, | ||||
|   "include": ["src"] | ||||
| } | ||||
|   | ||||
| @@ -1,11 +1,7 @@ | ||||
| { | ||||
|   "files": [], | ||||
|   "references": [ | ||||
|     { | ||||
|       "path": "./tsconfig.app.json" | ||||
|     }, | ||||
|     { | ||||
|       "path": "./tsconfig.node.json" | ||||
|     } | ||||
|     { "path": "./tsconfig.app.json" }, | ||||
|     { "path": "./tsconfig.node.json" } | ||||
|   ] | ||||
| } | ||||
|   | ||||
| @@ -1,13 +1,24 @@ | ||||
| { | ||||
|   "compilerOptions": { | ||||
|     "composite": true, | ||||
|     "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", | ||||
|     "skipLibCheck": true, | ||||
|     "target": "ES2022", | ||||
|     "lib": ["ES2023"], | ||||
|     "module": "ESNext", | ||||
|     "skipLibCheck": true, | ||||
|  | ||||
|     /* Bundler mode */ | ||||
|     "moduleResolution": "bundler", | ||||
|     "allowSyntheticDefaultImports": true, | ||||
|     "allowImportingTsExtensions": true, | ||||
|     "isolatedModules": true, | ||||
|     "moduleDetection": "force", | ||||
|     "noEmit": true, | ||||
|  | ||||
|     /* Linting */ | ||||
|     "strict": true, | ||||
|     "noEmit": true | ||||
|     "noUnusedLocals": true, | ||||
|     "noUnusedParameters": true, | ||||
|     "noFallthroughCasesInSwitch": true, | ||||
|     "noUncheckedSideEffectImports": true | ||||
|   }, | ||||
|   "include": ["vite.config.ts"] | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { defineConfig } from 'vite' | ||||
| import react from '@vitejs/plugin-react' | ||||
|  | ||||
| // https://vitejs.dev/config/ | ||||
| // https://vite.dev/config/ | ||||
| export default defineConfig({ | ||||
|   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] | ||||
| name = "custom_consumption" | ||||
| version = "0.1.0" | ||||
| edition = "2021" | ||||
| edition = "2024" | ||||
|  | ||||
| [dependencies] | ||||
| env_logger = "0.11.5" | ||||
| log = "0.4.22" | ||||
| clap = { version = "4.5.18", features = ["derive", "env"] } | ||||
| egui = "0.29.1" | ||||
| eframe = "0.29.1" | ||||
| env_logger = "0.11.7" | ||||
| log = "0.4.27" | ||||
| clap = { version = "4.5.34", features = ["derive", "env"] } | ||||
| egui = "0.31.1" | ||||
| eframe = "0.31.1" | ||||
| lazy_static = "1.5.0" | ||||
|   | ||||
| @@ -1,9 +1,3 @@ | ||||
| { | ||||
|   "$schema": "https://docs.renovatebot.com/renovate-schema.json", | ||||
|   "packageRules": [ | ||||
|     { | ||||
|       "matchUpdateTypes": ["major", "minor", "patch"], | ||||
|       "automerge": true | ||||
|     } | ||||
|   ] | ||||
|   "extends": ["local>renovate/presets"] | ||||
| } | ||||
		Reference in New Issue
	
	Block a user