Compare commits
13 Commits
06659404c1
...
f4dda44d15
| Author | SHA1 | Date | |
|---|---|---|---|
| f4dda44d15 | |||
| 80452e10de | |||
| aa262879f0 | |||
| 37844ae5fa | |||
| d38040cb98 | |||
| 2feb3f6490 | |||
| 2f971c0055 | |||
| e1a94acdcb | |||
| 382c44a18a | |||
| 17f8931f0f | |||
| cc63906ec1 | |||
| 59f8b59efe | |||
| 7f952700ad |
95
central_backend/Cargo.lock
generated
95
central_backend/Cargo.lock
generated
@@ -125,6 +125,44 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-multipart"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5118a26dee7e34e894f7e85aa0ee5080ae4c18bf03c0e30d49a80e418f00a53"
|
||||
dependencies = [
|
||||
"actix-multipart-derive",
|
||||
"actix-utils",
|
||||
"actix-web",
|
||||
"derive_more 0.99.18",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"httparse",
|
||||
"local-waker",
|
||||
"log",
|
||||
"memchr",
|
||||
"mime",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_plain",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-multipart-derive"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e11eb847f49a700678ea2fa73daeb3208061afa2b9d1a8527c03390f4c4a1c6b"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"parse-size",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-remote-ip"
|
||||
version = "0.1.0"
|
||||
@@ -622,6 +660,7 @@ dependencies = [
|
||||
"actix",
|
||||
"actix-cors",
|
||||
"actix-identity",
|
||||
"actix-multipart",
|
||||
"actix-remote-ip",
|
||||
"actix-session",
|
||||
"actix-web",
|
||||
@@ -847,6 +886,41 @@ dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
@@ -1399,6 +1473,12 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.5.0"
|
||||
@@ -1779,6 +1859,12 @@ dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse-size"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "487f2ccd1e17ce8c1bfab3a65c89525af41cfad4c8659021a1e9a2aacd73b89b"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
@@ -2243,6 +2329,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_plain"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
|
||||
@@ -25,6 +25,7 @@ actix = "0.13.5"
|
||||
actix-identity = "0.8.0"
|
||||
actix-session = { version = "0.10.1", features = ["cookie-session"] }
|
||||
actix-cors = "0.7.0"
|
||||
actix-multipart = { version ="0.7.2", features = ["derive"] }
|
||||
actix-remote-ip = "0.1.0"
|
||||
futures-util = "0.3.30"
|
||||
uuid = { version = "1.10.0", features = ["v4", "serde"] }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::devices::device::{DeviceId, DeviceRelayID};
|
||||
use crate::ota::ota_update::OTAPlatform;
|
||||
use clap::{Parser, Subcommand};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
@@ -296,12 +297,17 @@ impl AppConfig {
|
||||
|
||||
/// Get the directory that will store OTA updates
|
||||
pub fn ota_dir(&self) -> PathBuf {
|
||||
self.logs_dir().join("ota")
|
||||
self.storage_path().join("ota")
|
||||
}
|
||||
|
||||
/// Get the directory that will store OTA updates of a given device reference
|
||||
pub fn ota_of_device(&self, dev_ref: &str) -> PathBuf {
|
||||
self.ota_dir().join(dev_ref)
|
||||
/// Get the directory that will store OTA updates for a given platform
|
||||
pub fn ota_platform_dir(&self, platform: OTAPlatform) -> PathBuf {
|
||||
self.ota_dir().join(platform.to_string())
|
||||
}
|
||||
|
||||
/// Get the path to the file that will contain an OTA update
|
||||
pub fn path_ota_update(&self, platform: OTAPlatform, version: &semver::Version) -> PathBuf {
|
||||
self.ota_platform_dir(platform).join(version.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@ pub const MAX_INACTIVITY_DURATION: u64 = 3600;
|
||||
/// Maximum session duration (1 day)
|
||||
pub const MAX_SESSION_DURATION: u64 = 3600 * 24;
|
||||
|
||||
/// Maximum firmware size (in bytes)
|
||||
pub const MAX_FIRMWARE_SIZE: usize = 50 * 1000 * 1000;
|
||||
|
||||
/// List of routes that do not require authentication
|
||||
pub const ROUTES_WITHOUT_AUTH: [&str; 2] =
|
||||
["/web_api/server/config", "/web_api/auth/password_auth"];
|
||||
|
||||
@@ -9,9 +9,9 @@ use std::collections::{HashMap, HashSet};
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct DeviceInfo {
|
||||
/// Device reference
|
||||
reference: String,
|
||||
pub reference: String,
|
||||
/// Device firmware / software version
|
||||
version: semver::Version,
|
||||
pub version: semver::Version,
|
||||
/// Maximum number of relay that the device can support
|
||||
pub max_relays: usize,
|
||||
}
|
||||
@@ -62,6 +62,9 @@ pub struct Device {
|
||||
///
|
||||
/// There cannot be more than [info.max_relays] relays
|
||||
pub relays: Vec<DeviceRelay>,
|
||||
/// Desired version, ie. the version of the software we would to seen run on the device
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub desired_version: Option<semver::Version>,
|
||||
}
|
||||
|
||||
/// Structure that contains information about the minimal expected execution
|
||||
|
||||
@@ -84,6 +84,7 @@ impl DevicesList {
|
||||
validated: false,
|
||||
enabled: false,
|
||||
relays: vec![],
|
||||
desired_version: None,
|
||||
};
|
||||
|
||||
// First, write CSR
|
||||
@@ -186,6 +187,24 @@ impl DevicesList {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set a device desired version
|
||||
pub fn set_desired_version(
|
||||
&mut self,
|
||||
id: &DeviceId,
|
||||
version: Option<semver::Version>,
|
||||
) -> anyhow::Result<()> {
|
||||
let dev = self
|
||||
.0
|
||||
.get_mut(id)
|
||||
.ok_or(DevicesListError::UpdateDeviceFailedDeviceNotFound)?;
|
||||
|
||||
dev.desired_version = version;
|
||||
|
||||
self.persist_dev_config(id)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get single certificate information
|
||||
fn get_cert(&self, id: &DeviceId) -> anyhow::Result<X509> {
|
||||
let dev = self
|
||||
|
||||
@@ -195,6 +195,27 @@ impl Handler<UpdateDeviceGeneralInfo> for EnergyActor {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set device desired version
|
||||
#[derive(Message)]
|
||||
#[rtype(result = "anyhow::Result<()>")]
|
||||
pub struct SetDesiredVersion(pub DeviceId, pub Option<semver::Version>);
|
||||
|
||||
impl Handler<SetDesiredVersion> for EnergyActor {
|
||||
type Result = anyhow::Result<()>;
|
||||
|
||||
fn handle(&mut self, msg: SetDesiredVersion, _ctx: &mut Context<Self>) -> Self::Result {
|
||||
log::info!(
|
||||
"Requested to update device desired version {:?} => {:#?}",
|
||||
&msg.0,
|
||||
&msg.1
|
||||
);
|
||||
|
||||
self.devices.set_desired_version(&msg.0, msg.1)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete a device
|
||||
#[derive(Message)]
|
||||
#[rtype(result = "anyhow::Result<()>")]
|
||||
|
||||
@@ -4,5 +4,6 @@ pub mod crypto;
|
||||
pub mod devices;
|
||||
pub mod energy;
|
||||
pub mod logs;
|
||||
pub mod ota;
|
||||
pub mod server;
|
||||
pub mod utils;
|
||||
|
||||
2
central_backend/src/ota/mod.rs
Normal file
2
central_backend/src/ota/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod ota_manager;
|
||||
pub mod ota_update;
|
||||
51
central_backend/src/ota/ota_manager.rs
Normal file
51
central_backend/src/ota/ota_manager.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use crate::app_config::AppConfig;
|
||||
use crate::ota::ota_update::{OTAPlatform, OTAUpdate};
|
||||
use crate::utils::files_utils;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// Check out whether a given update exists or not
|
||||
pub fn update_exists(platform: OTAPlatform, version: &semver::Version) -> anyhow::Result<bool> {
|
||||
Ok(AppConfig::get()
|
||||
.path_ota_update(platform, version)
|
||||
.is_file())
|
||||
}
|
||||
|
||||
/// Save a new firmware update
|
||||
pub fn save_update(
|
||||
platform: OTAPlatform,
|
||||
version: &semver::Version,
|
||||
update: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let path = AppConfig::get().path_ota_update(platform, version);
|
||||
files_utils::create_directory_if_missing(path.parent().unwrap())?;
|
||||
|
||||
std::fs::write(path, update)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the content of an OTA update
|
||||
pub fn get_ota_update(platform: OTAPlatform, version: &semver::Version) -> anyhow::Result<Vec<u8>> {
|
||||
let path = AppConfig::get().path_ota_update(platform, version);
|
||||
Ok(std::fs::read(path)?)
|
||||
}
|
||||
|
||||
/// Get the list of OTA software updates for a platform
|
||||
pub fn get_ota_updates_for_platform(platform: OTAPlatform) -> anyhow::Result<Vec<OTAUpdate>> {
|
||||
let ota_path = AppConfig::get().ota_platform_dir(platform);
|
||||
|
||||
let mut out = Vec::new();
|
||||
|
||||
for e in std::fs::read_dir(ota_path)? {
|
||||
let e = e?;
|
||||
|
||||
out.push(OTAUpdate {
|
||||
platform,
|
||||
version: semver::Version::from_str(e.file_name().to_str().unwrap_or("bad"))?,
|
||||
file_size: e.metadata()?.size(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
31
central_backend/src/ota/ota_update.rs
Normal file
31
central_backend/src/ota/ota_update.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum OTAPlatform {
|
||||
#[serde(rename = "Wt32-Eth01")]
|
||||
Wt32Eth01,
|
||||
}
|
||||
|
||||
impl Display for OTAPlatform {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let s = serde_json::to_string(&self).unwrap().replace('"', "");
|
||||
write!(f, "{s}")
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for OTAPlatform {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(serde_json::from_str::<Self>(&format!("\"{s}\""))?)
|
||||
}
|
||||
}
|
||||
|
||||
/// Single OTA update information
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||
pub struct OTAUpdate {
|
||||
pub platform: OTAPlatform,
|
||||
pub version: semver::Version,
|
||||
pub file_size: u64,
|
||||
}
|
||||
21
central_backend/src/server/devices_api/devices_ota.rs
Normal file
21
central_backend/src/server/devices_api/devices_ota.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use crate::ota::ota_manager;
|
||||
use crate::ota::ota_update::OTAPlatform;
|
||||
use crate::server::custom_error::HttpResult;
|
||||
use actix_web::{web, HttpResponse};
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct FirmwarePath {
|
||||
platform: OTAPlatform,
|
||||
version: semver::Version,
|
||||
}
|
||||
|
||||
/// Download firmware update
|
||||
pub async fn retrieve_firmware(path: web::Path<FirmwarePath>) -> HttpResult {
|
||||
if !ota_manager::update_exists(path.platform, &path.version)? {
|
||||
return Ok(HttpResponse::NotFound().json("The requested firmware was not found!"));
|
||||
}
|
||||
|
||||
let firmware = ota_manager::get_ota_update(path.platform, &path.version)?;
|
||||
|
||||
Ok(HttpResponse::Ok().body(firmware))
|
||||
}
|
||||
@@ -2,12 +2,15 @@ use crate::app_config::AppConfig;
|
||||
use crate::devices::device::{DeviceId, DeviceInfo};
|
||||
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::custom_error::HttpResult;
|
||||
use crate::server::devices_api::jwt_parser::JWTRequest;
|
||||
use crate::server::WebEnergyActor;
|
||||
use actix_web::{web, HttpResponse};
|
||||
use openssl::nid::Nid;
|
||||
use openssl::x509::X509Req;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct EnrollRequest {
|
||||
@@ -135,6 +138,7 @@ struct Claims {
|
||||
#[derive(serde::Serialize)]
|
||||
struct SyncResult {
|
||||
relays: Vec<RelaySyncStatus>,
|
||||
available_update: Option<semver::Version>,
|
||||
}
|
||||
|
||||
/// Synchronize device
|
||||
@@ -142,8 +146,25 @@ pub async fn sync_device(body: web::Json<JWTRequest>, actor: WebEnergyActor) ->
|
||||
let (device, claims) = body.0.parse_jwt::<Claims>(actor.clone()).await?;
|
||||
|
||||
let relays = actor
|
||||
.send(energy_actor::SynchronizeDevice(device.id, claims.info))
|
||||
.send(energy_actor::SynchronizeDevice(
|
||||
device.id,
|
||||
claims.info.clone(),
|
||||
))
|
||||
.await??;
|
||||
|
||||
Ok(HttpResponse::Ok().json(SyncResult { relays }))
|
||||
let mut available_update = None;
|
||||
|
||||
// Check if the version is available
|
||||
if let Some(desired) = device.desired_version {
|
||||
if claims.info.version < desired
|
||||
&& ota_manager::update_exists(OTAPlatform::from_str(&claims.info.reference)?, &desired)?
|
||||
{
|
||||
available_update = Some(desired);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(HttpResponse::Ok().json(SyncResult {
|
||||
relays,
|
||||
available_update,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod device_logging_controller;
|
||||
pub mod devices_ota;
|
||||
pub mod jwt_parser;
|
||||
pub mod mgmt_controller;
|
||||
pub mod utils_controller;
|
||||
|
||||
@@ -3,7 +3,9 @@ use crate::constants;
|
||||
use crate::crypto::pki;
|
||||
use crate::energy::energy_actor::EnergyActorAddr;
|
||||
use crate::server::auth_middleware::AuthChecker;
|
||||
use crate::server::devices_api::{device_logging_controller, mgmt_controller, utils_controller};
|
||||
use crate::server::devices_api::{
|
||||
device_logging_controller, devices_ota, mgmt_controller, utils_controller,
|
||||
};
|
||||
use crate::server::unsecure_server::*;
|
||||
use crate::server::web_api::*;
|
||||
use crate::server::web_app_controller;
|
||||
@@ -181,12 +183,25 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
|
||||
web::delete().to(devices_controller::delete_device),
|
||||
)
|
||||
// OTA API
|
||||
// TODO : list supported platform references
|
||||
// TODO : upload a new software update
|
||||
// TODO : list ota software update per platform
|
||||
.route(
|
||||
"/web_api/ota/supported_platforms",
|
||||
web::get().to(ota_controller::supported_platforms),
|
||||
)
|
||||
.route(
|
||||
"/web_api/ota/{platform}/{version}",
|
||||
web::post().to(ota_controller::upload_firmware),
|
||||
)
|
||||
// TODO : list all ota software updates
|
||||
.route(
|
||||
"/web_api/ota/{platform}",
|
||||
web::get().to(ota_controller::list_updates_platform),
|
||||
)
|
||||
// TODO : download a OTA file
|
||||
// TODO : delete an OTA file
|
||||
// TODO : deploy an update to a device
|
||||
.route(
|
||||
"/web_api/ota/set_desired_version",
|
||||
web::post().to(ota_controller::set_desired_version),
|
||||
)
|
||||
// Logging controller API
|
||||
.route(
|
||||
"/web_api/logging/logs",
|
||||
@@ -238,6 +253,10 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
|
||||
"/devices_api/mgmt/sync",
|
||||
web::post().to(mgmt_controller::sync_device),
|
||||
)
|
||||
.route(
|
||||
"/devices_api/ota/{platform}/{version}",
|
||||
web::get().to(devices_ota::retrieve_firmware),
|
||||
)
|
||||
.route(
|
||||
"/devices_api/logging/record",
|
||||
web::post().to(device_logging_controller::report_log),
|
||||
|
||||
@@ -2,5 +2,6 @@ pub mod auth_controller;
|
||||
pub mod devices_controller;
|
||||
pub mod energy_controller;
|
||||
pub mod logging_controller;
|
||||
pub mod ota_controller;
|
||||
pub mod relays_controller;
|
||||
pub mod server_controller;
|
||||
|
||||
111
central_backend/src/server/web_api/ota_controller.rs
Normal file
111
central_backend/src/server/web_api/ota_controller.rs
Normal file
@@ -0,0 +1,111 @@
|
||||
use crate::constants;
|
||||
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 actix_multipart::form::MultipartForm;
|
||||
use actix_web::{web, HttpResponse};
|
||||
|
||||
pub async fn supported_platforms() -> HttpResult {
|
||||
Ok(HttpResponse::Ok().json(vec![OTAPlatform::Wt32Eth01]))
|
||||
}
|
||||
|
||||
#[derive(Debug, MultipartForm)]
|
||||
pub struct UploadForm {
|
||||
#[multipart(rename = "firmware")]
|
||||
firmware: Vec<TempFile>,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct UploadPath {
|
||||
platform: OTAPlatform,
|
||||
version: semver::Version,
|
||||
}
|
||||
|
||||
pub async fn upload_firmware(
|
||||
MultipartForm(form): MultipartForm<UploadForm>,
|
||||
path: web::Path<UploadPath>,
|
||||
) -> HttpResult {
|
||||
if ota_manager::update_exists(path.platform, &path.version)? {
|
||||
return Ok(HttpResponse::Conflict()
|
||||
.json("A firmware with the same version has already been uploaded on the platform!"));
|
||||
}
|
||||
|
||||
let Some(file) = form.firmware.first() else {
|
||||
return Ok(HttpResponse::BadRequest().json("No firmware specified!"));
|
||||
};
|
||||
|
||||
if file.size == 0 {
|
||||
return Ok(HttpResponse::BadRequest().json("Uploaded file is empty!"));
|
||||
}
|
||||
|
||||
if file.size > constants::MAX_FIRMWARE_SIZE {
|
||||
return Ok(HttpResponse::BadRequest().json("Uploaded file is too heavy!"));
|
||||
}
|
||||
|
||||
let content = std::fs::read(file.file.path())?;
|
||||
|
||||
ota_manager::save_update(path.platform, &path.version, &content)?;
|
||||
|
||||
Ok(HttpResponse::Accepted().body("OTA update successfully saved."))
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct ListOTAPath {
|
||||
platform: OTAPlatform,
|
||||
}
|
||||
|
||||
/// List OTA software updates for a given platform
|
||||
pub async fn list_updates_platform(path: web::Path<ListOTAPath>) -> HttpResult {
|
||||
let list = ota_manager::get_ota_updates_for_platform(path.platform)?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(list))
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct SetDesiredDeviceVersion {
|
||||
devices: Option<Vec<DeviceId>>,
|
||||
platform: Option<OTAPlatform>,
|
||||
version: semver::Version,
|
||||
}
|
||||
|
||||
pub async fn set_desired_version(
|
||||
actor: WebEnergyActor,
|
||||
body: web::Json<SetDesiredDeviceVersion>,
|
||||
) -> HttpResult {
|
||||
if body.devices.is_none() && body.platform.is_none() {
|
||||
return Ok(
|
||||
HttpResponse::BadRequest().json("Must specify one filter to select target devices!")
|
||||
);
|
||||
}
|
||||
|
||||
let devices = actor.send(energy_actor::GetDeviceLists).await?;
|
||||
|
||||
for d in devices {
|
||||
// Filter per platform
|
||||
if let Some(p) = body.platform {
|
||||
if d.info.reference != p.to_string() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter per device
|
||||
if let Some(ids) = &body.devices {
|
||||
if !ids.contains(&d.id) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
actor
|
||||
.send(energy_actor::SetDesiredVersion(
|
||||
d.id,
|
||||
Some(body.version.clone()),
|
||||
))
|
||||
.await??;
|
||||
}
|
||||
|
||||
Ok(HttpResponse::Ok().finish())
|
||||
}
|
||||
542
central_frontend/package-lock.json
generated
542
central_frontend/package-lock.json
generated
@@ -13,22 +13,22 @@
|
||||
"@fontsource/roboto": "^5.1.0",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@mdi/react": "^1.6.1",
|
||||
"@mui/icons-material": "^6.1.1",
|
||||
"@mui/material": "^6.1.1",
|
||||
"@mui/x-charts": "^7.18.0",
|
||||
"@mui/x-date-pickers": "^7.18.0",
|
||||
"date-and-time": "^3.5.0",
|
||||
"@mui/icons-material": "^6.1.2",
|
||||
"@mui/material": "^6.1.2",
|
||||
"@mui/x-charts": "^7.19.0",
|
||||
"@mui/x-date-pickers": "^7.19.0",
|
||||
"date-and-time": "^3.6.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-router-dom": "^6.26.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.3.10",
|
||||
"@types/react": "^18.3.11",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.7.0",
|
||||
"@typescript-eslint/parser": "^8.7.0",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.8.0",
|
||||
"@typescript-eslint/parser": "^8.8.0",
|
||||
"@vitejs/plugin-react": "^4.3.2",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-react-refresh": "^0.4.12",
|
||||
@@ -50,11 +50,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
|
||||
"integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz",
|
||||
"integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/highlight": "^7.24.7",
|
||||
"@babel/highlight": "^7.25.7",
|
||||
"picocolors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -62,30 +63,32 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/compat-data": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz",
|
||||
"integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.7.tgz",
|
||||
"integrity": "sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz",
|
||||
"integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.7.tgz",
|
||||
"integrity": "sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.24.7",
|
||||
"@babel/generator": "^7.24.7",
|
||||
"@babel/helper-compilation-targets": "^7.24.7",
|
||||
"@babel/helper-module-transforms": "^7.24.7",
|
||||
"@babel/helpers": "^7.24.7",
|
||||
"@babel/parser": "^7.24.7",
|
||||
"@babel/template": "^7.24.7",
|
||||
"@babel/traverse": "^7.24.7",
|
||||
"@babel/types": "^7.24.7",
|
||||
"@babel/code-frame": "^7.25.7",
|
||||
"@babel/generator": "^7.25.7",
|
||||
"@babel/helper-compilation-targets": "^7.25.7",
|
||||
"@babel/helper-module-transforms": "^7.25.7",
|
||||
"@babel/helpers": "^7.25.7",
|
||||
"@babel/parser": "^7.25.7",
|
||||
"@babel/template": "^7.25.7",
|
||||
"@babel/traverse": "^7.25.7",
|
||||
"@babel/types": "^7.25.7",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debug": "^4.1.0",
|
||||
"gensync": "^1.0.0-beta.2",
|
||||
@@ -110,28 +113,30 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz",
|
||||
"integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz",
|
||||
"integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.24.7",
|
||||
"@babel/types": "^7.25.7",
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
"jsesc": "^2.5.1"
|
||||
"jsesc": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-compilation-targets": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz",
|
||||
"integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz",
|
||||
"integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.24.7",
|
||||
"@babel/helper-validator-option": "^7.24.7",
|
||||
"browserslist": "^4.22.2",
|
||||
"@babel/compat-data": "^7.25.7",
|
||||
"@babel/helper-validator-option": "^7.25.7",
|
||||
"browserslist": "^4.24.0",
|
||||
"lru-cache": "^5.1.1",
|
||||
"semver": "^6.3.1"
|
||||
},
|
||||
@@ -144,67 +149,35 @@
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-environment-visitor": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz",
|
||||
"integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-function-name": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz",
|
||||
"integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.24.7",
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-hoist-variables": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz",
|
||||
"integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-imports": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz",
|
||||
"integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz",
|
||||
"integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/traverse": "^7.24.7",
|
||||
"@babel/types": "^7.24.7"
|
||||
"@babel/traverse": "^7.25.7",
|
||||
"@babel/types": "^7.25.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-transforms": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz",
|
||||
"integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz",
|
||||
"integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.24.7",
|
||||
"@babel/helper-module-imports": "^7.24.7",
|
||||
"@babel/helper-simple-access": "^7.24.7",
|
||||
"@babel/helper-split-export-declaration": "^7.24.7",
|
||||
"@babel/helper-validator-identifier": "^7.24.7"
|
||||
"@babel/helper-module-imports": "^7.25.7",
|
||||
"@babel/helper-simple-access": "^7.25.7",
|
||||
"@babel/helper-validator-identifier": "^7.25.7",
|
||||
"@babel/traverse": "^7.25.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -223,73 +196,68 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-simple-access": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz",
|
||||
"integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz",
|
||||
"integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/traverse": "^7.24.7",
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-split-export-declaration": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz",
|
||||
"integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.24.7"
|
||||
"@babel/traverse": "^7.25.7",
|
||||
"@babel/types": "^7.25.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz",
|
||||
"integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz",
|
||||
"integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
|
||||
"integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz",
|
||||
"integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-option": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz",
|
||||
"integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz",
|
||||
"integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz",
|
||||
"integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz",
|
||||
"integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.24.7",
|
||||
"@babel/types": "^7.24.7"
|
||||
"@babel/template": "^7.25.7",
|
||||
"@babel/types": "^7.25.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
|
||||
"integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz",
|
||||
"integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.24.7",
|
||||
"@babel/helper-validator-identifier": "^7.25.7",
|
||||
"chalk": "^2.4.2",
|
||||
"js-tokens": "^4.0.0",
|
||||
"picocolors": "^1.0.0"
|
||||
@@ -299,9 +267,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz",
|
||||
"integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.7.tgz",
|
||||
"integrity": "sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.25.7"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
@@ -352,31 +324,30 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz",
|
||||
"integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz",
|
||||
"integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.24.7",
|
||||
"@babel/parser": "^7.24.7",
|
||||
"@babel/types": "^7.24.7"
|
||||
"@babel/code-frame": "^7.25.7",
|
||||
"@babel/parser": "^7.25.7",
|
||||
"@babel/types": "^7.25.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz",
|
||||
"integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz",
|
||||
"integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.24.7",
|
||||
"@babel/generator": "^7.24.7",
|
||||
"@babel/helper-environment-visitor": "^7.24.7",
|
||||
"@babel/helper-function-name": "^7.24.7",
|
||||
"@babel/helper-hoist-variables": "^7.24.7",
|
||||
"@babel/helper-split-export-declaration": "^7.24.7",
|
||||
"@babel/parser": "^7.24.7",
|
||||
"@babel/types": "^7.24.7",
|
||||
"@babel/code-frame": "^7.25.7",
|
||||
"@babel/generator": "^7.25.7",
|
||||
"@babel/parser": "^7.25.7",
|
||||
"@babel/template": "^7.25.7",
|
||||
"@babel/types": "^7.25.7",
|
||||
"debug": "^4.3.1",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
@@ -385,12 +356,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz",
|
||||
"integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==",
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.7.tgz",
|
||||
"integrity": "sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.24.7",
|
||||
"@babel/helper-validator-identifier": "^7.24.7",
|
||||
"@babel/helper-string-parser": "^7.25.7",
|
||||
"@babel/helper-validator-identifier": "^7.25.7",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1151,9 +1123,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/core-downloads-tracker": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.1.tgz",
|
||||
"integrity": "sha512-VdQC1tPIIcZAnf62L2M1eQif0x2vlKg3YK4kGYbtijSH4niEgI21GnstykW1vQIs+Bc6L+Hua2GATYVjilJ22A==",
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.2.tgz",
|
||||
"integrity": "sha512-1oE4U38/TtzLWRYWEm/m70dUbpcvBx0QvDVg6NtpOmSNQC1Mbx0X/rNvYDdZnn8DIsAiVQ+SZ3am6doSswUQ4g==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -1161,9 +1133,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/icons-material": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.1.tgz",
|
||||
"integrity": "sha512-sy/YKwcLPW8VcacNP2uWMYR9xyWuwO9NN9FXuGEU90bRshBXj8pdKk+joe3TCW7oviVS3zXLHlc94wQ0jNsQRQ==",
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.2.tgz",
|
||||
"integrity": "sha512-7NNcjW5JoT9jHagrVbARA1o41vQY2xezDamtke+mEKKZmsJyejfRBOacSrPDfjZQ//lyhIjNKyzAwisxYJR47w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.25.6"
|
||||
@@ -1176,7 +1148,7 @@
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@mui/material": "^6.1.1",
|
||||
"@mui/material": "^6.1.2",
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
@@ -1187,16 +1159,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/material": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.1.tgz",
|
||||
"integrity": "sha512-b+eULldTqtqTCbN++2BtBWCir/1LwEYw+2mIlOt2GiEUh1EBBw4/wIukGKKNt3xrCZqRA80yLLkV6tF61Lq3cA==",
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.2.tgz",
|
||||
"integrity": "sha512-5TtHeAVX9D5d2LYfB1GAUn29BcVETVsrQ76Dwb2SpAfQGW3JVy4deJCAd0RrIkI3eEUrsl0E4xuBdreszxdTTg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.25.6",
|
||||
"@mui/core-downloads-tracker": "^6.1.1",
|
||||
"@mui/system": "^6.1.1",
|
||||
"@mui/core-downloads-tracker": "^6.1.2",
|
||||
"@mui/system": "^6.1.2",
|
||||
"@mui/types": "^7.2.17",
|
||||
"@mui/utils": "^6.1.1",
|
||||
"@mui/utils": "^6.1.2",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@types/react-transition-group": "^4.4.11",
|
||||
"clsx": "^2.1.1",
|
||||
@@ -1215,7 +1187,7 @@
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.5.0",
|
||||
"@emotion/styled": "^11.3.0",
|
||||
"@mui/material-pigment-css": "^6.1.1",
|
||||
"@mui/material-pigment-css": "^6.1.2",
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
@@ -1236,13 +1208,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/private-theming": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.1.tgz",
|
||||
"integrity": "sha512-JlrjIdhyZUtewtdAuUsvi3ZnO0YS49IW4Mfz19ZWTlQ0sDGga6LNPVwHClWr2/zJK2we2BQx9/i8M32rgKuzrg==",
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.2.tgz",
|
||||
"integrity": "sha512-S8WcjZdNdi++8UhrrY8Lton5h/suRiQexvdTfdcPAlbajlvgM+kx+uJstuVIEyTb3gMkxzIZep87knZ0tqcR0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.25.6",
|
||||
"@mui/utils": "^6.1.1",
|
||||
"@mui/utils": "^6.1.2",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1263,9 +1235,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/styled-engine": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.1.tgz",
|
||||
"integrity": "sha512-HJyIoMpFb11fnHuRtUILOXgq6vj4LhIlE8maG4SwP/W+E5sa7HFexhnB3vOMT7bKys4UKNxhobC8jwWxYilGsA==",
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.2.tgz",
|
||||
"integrity": "sha512-uKOfWkR23X39xj7th2nyTcCHqInTAXtUnqD3T5qRVdJcOPvu1rlgTleTwJC/FJvWZJBU6ieuTWDhbcx5SNViHQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.25.6",
|
||||
@@ -1296,16 +1268,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/system": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.1.tgz",
|
||||
"integrity": "sha512-PaYsCz2tUOcpu3T0okDEsSuP/yCDIj9JZ4Tox1JovRSKIjltHpXPsXZSGr3RiWdtM1MTQMFMCZzu0+CKbyy+Kw==",
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.2.tgz",
|
||||
"integrity": "sha512-mzW7F1ZMIYS1aLON48Nrk9c65OrVEVQ+R4lUcTWs1lCSul0VGK23eo4dmY0NX5PS7Oe4xz3P5B9tQZZ7SYgxcg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.25.6",
|
||||
"@mui/private-theming": "^6.1.1",
|
||||
"@mui/styled-engine": "^6.1.1",
|
||||
"@mui/private-theming": "^6.1.2",
|
||||
"@mui/styled-engine": "^6.1.2",
|
||||
"@mui/types": "^7.2.17",
|
||||
"@mui/utils": "^6.1.1",
|
||||
"@mui/utils": "^6.1.2",
|
||||
"clsx": "^2.1.1",
|
||||
"csstype": "^3.1.3",
|
||||
"prop-types": "^15.8.1"
|
||||
@@ -1350,14 +1322,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/utils": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.1.tgz",
|
||||
"integrity": "sha512-HlRrgdJSPbYDXPpoVMWZV8AE7WcFtAk13rWNWAEVWKSanzBBkymjz3km+Th/Srowsh4pf1fTSP1B0L116wQBYw==",
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.2.tgz",
|
||||
"integrity": "sha512-6+B1YZ8cCBWD1fc3RjqpclF9UA0MLUiuXhyCO+XowD/Z2ku5IlxeEhHHlgglyBWFGMu4kib4YU3CDsG5/zVjJQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.25.6",
|
||||
"@mui/types": "^7.2.17",
|
||||
"@types/prop-types": "^15.7.12",
|
||||
"@types/prop-types": "^15.7.13",
|
||||
"clsx": "^2.1.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-is": "^18.3.1"
|
||||
@@ -1380,14 +1352,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/x-charts": {
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.18.0.tgz",
|
||||
"integrity": "sha512-XvCX6sBj2aRw7MZcOPjKTEIwhj4j+ixw256bArQScSd+Y2BuHxAyfl/L6NPPWamckAPqJwjQ678jFH2s5t1f1w==",
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.19.0.tgz",
|
||||
"integrity": "sha512-gOiSmb+bLIoGOGs+5uzEb7sau7KmjAKJI4+hORCjHUAOefmtHdiw39gZVne1Gcah+h6BIrWMkNJHk5djcCaGsg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.25.6",
|
||||
"@mui/utils": "^5.16.6",
|
||||
"@mui/x-charts-vendor": "7.18.0",
|
||||
"@mui/x-charts-vendor": "7.19.0",
|
||||
"@mui/x-internals": "7.18.0",
|
||||
"@react-spring/rafz": "^9.7.4",
|
||||
"@react-spring/web": "^9.7.4",
|
||||
@@ -1415,9 +1387,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/x-charts-vendor": {
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-charts-vendor/-/x-charts-vendor-7.18.0.tgz",
|
||||
"integrity": "sha512-YPL7SP6W7t9jBIrK8WjmCtW/YoUmgr0BA7j2QE9bKX4VJLEUU498fEKik0ZJZyzyR7ov0MD3m7S+YCw1o5sqkw==",
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-charts-vendor/-/x-charts-vendor-7.19.0.tgz",
|
||||
"integrity": "sha512-idHOi6U8mmX1ezKclv2p4QBrWxQIUSS+bd7rp2PGnf7XAPtUY/X9VTZvU1mDRawtyKjyzQD+vmSbYx9piytqAg==",
|
||||
"license": "MIT AND ISC",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.25.6",
|
||||
@@ -1468,9 +1440,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/x-date-pickers": {
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.18.0.tgz",
|
||||
"integrity": "sha512-12tXIoMj9vpS8fS/bS3kWPCoVrH38vNGCxgplI0vOnUrN9rJuYJz3agLPJe1S0xciTw+9W8ZSe3soaW+owoz1Q==",
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.19.0.tgz",
|
||||
"integrity": "sha512-OIQ+IxgL2Si7DP68sw1ImcHXZtAmklHcyo/oqP4HuJZ2lVnP5sJkoXrksfumL1wjWKJkecONFz3unAqViKXzCQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.25.6",
|
||||
@@ -2068,14 +2040,15 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
|
||||
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
|
||||
"version": "15.7.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
|
||||
"integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.10.tgz",
|
||||
"integrity": "sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg==",
|
||||
"version": "18.3.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz",
|
||||
"integrity": "sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
@@ -2101,17 +2074,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.7.0.tgz",
|
||||
"integrity": "sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A==",
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.0.tgz",
|
||||
"integrity": "sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.7.0",
|
||||
"@typescript-eslint/type-utils": "8.7.0",
|
||||
"@typescript-eslint/utils": "8.7.0",
|
||||
"@typescript-eslint/visitor-keys": "8.7.0",
|
||||
"@typescript-eslint/scope-manager": "8.8.0",
|
||||
"@typescript-eslint/type-utils": "8.8.0",
|
||||
"@typescript-eslint/utils": "8.8.0",
|
||||
"@typescript-eslint/visitor-keys": "8.8.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
@@ -2135,16 +2108,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.7.0.tgz",
|
||||
"integrity": "sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ==",
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.0.tgz",
|
||||
"integrity": "sha512-uEFUsgR+tl8GmzmLjRqz+VrDv4eoaMqMXW7ruXfgThaAShO9JTciKpEsB+TvnfFfbg5IpujgMXVV36gOJRLtZg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.7.0",
|
||||
"@typescript-eslint/types": "8.7.0",
|
||||
"@typescript-eslint/typescript-estree": "8.7.0",
|
||||
"@typescript-eslint/visitor-keys": "8.7.0",
|
||||
"@typescript-eslint/scope-manager": "8.8.0",
|
||||
"@typescript-eslint/types": "8.8.0",
|
||||
"@typescript-eslint/typescript-estree": "8.8.0",
|
||||
"@typescript-eslint/visitor-keys": "8.8.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -2164,14 +2137,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz",
|
||||
"integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==",
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.0.tgz",
|
||||
"integrity": "sha512-EL8eaGC6gx3jDd8GwEFEV091210U97J0jeEHrAYvIYosmEGet4wJ+g0SYmLu+oRiAwbSA5AVrt6DxLHfdd+bUg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.7.0",
|
||||
"@typescript-eslint/visitor-keys": "8.7.0"
|
||||
"@typescript-eslint/types": "8.8.0",
|
||||
"@typescript-eslint/visitor-keys": "8.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -2182,14 +2155,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz",
|
||||
"integrity": "sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ==",
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.0.tgz",
|
||||
"integrity": "sha512-IKwJSS7bCqyCeG4NVGxnOP6lLT9Okc3Zj8hLO96bpMkJab+10HIfJbMouLrlpyOr3yrQ1cA413YPFiGd1mW9/Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.7.0",
|
||||
"@typescript-eslint/utils": "8.7.0",
|
||||
"@typescript-eslint/typescript-estree": "8.8.0",
|
||||
"@typescript-eslint/utils": "8.8.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
@@ -2207,9 +2180,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz",
|
||||
"integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==",
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.0.tgz",
|
||||
"integrity": "sha512-QJwc50hRCgBd/k12sTykOJbESe1RrzmX6COk8Y525C9l7oweZ+1lw9JiU56im7Amm8swlz00DRIlxMYLizr2Vw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2221,14 +2194,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz",
|
||||
"integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==",
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.0.tgz",
|
||||
"integrity": "sha512-ZaMJwc/0ckLz5DaAZ+pNLmHv8AMVGtfWxZe/x2JVEkD5LnmhWiQMMcYT7IY7gkdJuzJ9P14fRy28lUrlDSWYdw==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.7.0",
|
||||
"@typescript-eslint/visitor-keys": "8.7.0",
|
||||
"@typescript-eslint/types": "8.8.0",
|
||||
"@typescript-eslint/visitor-keys": "8.8.0",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -2250,16 +2223,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz",
|
||||
"integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==",
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.0.tgz",
|
||||
"integrity": "sha512-QE2MgfOTem00qrlPgyByaCHay9yb1+9BjnMFnSFkUKQfu7adBXDTnCAivURnuPPAG/qiB+kzKkZKmKfaMT0zVg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@typescript-eslint/scope-manager": "8.7.0",
|
||||
"@typescript-eslint/types": "8.7.0",
|
||||
"@typescript-eslint/typescript-estree": "8.7.0"
|
||||
"@typescript-eslint/scope-manager": "8.8.0",
|
||||
"@typescript-eslint/types": "8.8.0",
|
||||
"@typescript-eslint/typescript-estree": "8.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -2273,13 +2246,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz",
|
||||
"integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==",
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.0.tgz",
|
||||
"integrity": "sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.7.0",
|
||||
"@typescript-eslint/types": "8.8.0",
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -2298,14 +2271,15 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@vitejs/plugin-react": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz",
|
||||
"integrity": "sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==",
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.2.tgz",
|
||||
"integrity": "sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.24.5",
|
||||
"@babel/plugin-transform-react-jsx-self": "^7.24.5",
|
||||
"@babel/plugin-transform-react-jsx-source": "^7.24.1",
|
||||
"@babel/core": "^7.25.2",
|
||||
"@babel/plugin-transform-react-jsx-self": "^7.24.7",
|
||||
"@babel/plugin-transform-react-jsx-source": "^7.24.7",
|
||||
"@types/babel__core": "^7.20.5",
|
||||
"react-refresh": "^0.14.2"
|
||||
},
|
||||
@@ -2369,6 +2343,7 @@
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.0"
|
||||
},
|
||||
@@ -2428,9 +2403,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.23.1",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz",
|
||||
"integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==",
|
||||
"version": "4.24.0",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz",
|
||||
"integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -2446,11 +2421,12 @@
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001629",
|
||||
"electron-to-chromium": "^1.4.796",
|
||||
"node-releases": "^2.0.14",
|
||||
"update-browserslist-db": "^1.0.16"
|
||||
"caniuse-lite": "^1.0.30001663",
|
||||
"electron-to-chromium": "^1.5.28",
|
||||
"node-releases": "^2.0.18",
|
||||
"update-browserslist-db": "^1.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"browserslist": "cli.js"
|
||||
@@ -2468,9 +2444,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001638",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001638.tgz",
|
||||
"integrity": "sha512-5SuJUJ7cZnhPpeLHaH0c/HPAnAHZvS6ElWyHK9GSIbVOQABLzowiI2pjmpvZ1WEbkyz46iFd4UXlOHR5SqgfMQ==",
|
||||
"version": "1.0.30001667",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz",
|
||||
"integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -2485,12 +2461,14 @@
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
]
|
||||
],
|
||||
"license": "CC-BY-4.0"
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
@@ -2512,6 +2490,7 @@
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
@@ -2519,7 +2498,8 @@
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
@@ -2684,9 +2664,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/date-and-time": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-3.5.0.tgz",
|
||||
"integrity": "sha512-JU4y0CIzAU+Cy2GOToby243B54elP8JdPidj4xHJPO4rlResPXKujRJp/MJzFeMWIdTbQ/A0xgd6guipi1mYIw==",
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-3.6.0.tgz",
|
||||
"integrity": "sha512-V99gLaMqNQxPCObBumb31Bfy3OByXnpqUM0yHPi/aBQE61g42A2rGk6Z2CDnpLrWsOFLQwOgl4Vgshw6D44ebw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
@@ -2749,10 +2729,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.815",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.815.tgz",
|
||||
"integrity": "sha512-OvpTT2ItpOXJL7IGcYakRjHCt8L5GrrN/wHCQsRB4PQa1X9fe+X9oen245mIId7s14xvArCGSTIq644yPUKKLg==",
|
||||
"dev": true
|
||||
"version": "1.5.32",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.32.tgz",
|
||||
"integrity": "sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/error-ex": {
|
||||
"version": "1.3.2",
|
||||
@@ -2802,10 +2783,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
|
||||
"integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@@ -2814,6 +2796,7 @@
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
@@ -3352,6 +3335,7 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
@@ -3528,14 +3512,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jsesc": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
|
||||
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
|
||||
"integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"jsesc": "bin/jsesc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/json-buffer": {
|
||||
@@ -3642,6 +3627,7 @@
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"yallist": "^3.0.2"
|
||||
}
|
||||
@@ -3717,10 +3703,11 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
|
||||
"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
|
||||
"dev": true
|
||||
"version": "2.0.18",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
|
||||
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
@@ -4261,6 +4248,7 @@
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
@@ -4360,9 +4348,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.0.16",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz",
|
||||
"integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==",
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz",
|
||||
"integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -4378,9 +4366,10 @@
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"escalade": "^3.1.2",
|
||||
"picocolors": "^1.0.1"
|
||||
"escalade": "^3.2.0",
|
||||
"picocolors": "^1.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"update-browserslist-db": "cli.js"
|
||||
@@ -4494,7 +4483,8 @@
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "1.10.2",
|
||||
|
||||
@@ -15,22 +15,22 @@
|
||||
"@fontsource/roboto": "^5.1.0",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@mdi/react": "^1.6.1",
|
||||
"@mui/icons-material": "^6.1.1",
|
||||
"@mui/material": "^6.1.1",
|
||||
"@mui/x-charts": "^7.18.0",
|
||||
"@mui/x-date-pickers": "^7.18.0",
|
||||
"date-and-time": "^3.5.0",
|
||||
"@mui/icons-material": "^6.1.2",
|
||||
"@mui/material": "^6.1.2",
|
||||
"@mui/x-charts": "^7.19.0",
|
||||
"@mui/x-date-pickers": "^7.19.0",
|
||||
"date-and-time": "^3.6.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-router-dom": "^6.26.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.3.10",
|
||||
"@types/react": "^18.3.11",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.7.0",
|
||||
"@typescript-eslint/parser": "^8.7.0",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.8.0",
|
||||
"@typescript-eslint/parser": "^8.8.0",
|
||||
"@vitejs/plugin-react": "^4.3.2",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-react-refresh": "^0.4.12",
|
||||
|
||||
@@ -37,6 +37,7 @@ export interface Device {
|
||||
validated: boolean;
|
||||
enabled: boolean;
|
||||
relays: DeviceRelay[];
|
||||
desired_version?: string;
|
||||
}
|
||||
|
||||
export interface UpdatedInfo {
|
||||
|
||||
@@ -41,6 +41,10 @@ export function GeneralDeviceInfo(p: {
|
||||
value={p.device.info.reference}
|
||||
/>
|
||||
<DeviceInfoProperty label="Version" value={p.device.info.version} />
|
||||
<DeviceInfoProperty
|
||||
label="Desired version"
|
||||
value={p.device.desired_version ?? "None"}
|
||||
/>
|
||||
<DeviceInfoProperty label="Name" value={p.device.name} />
|
||||
<DeviceInfoProperty
|
||||
label="Description"
|
||||
|
||||
4
esp32_device/.vscode/settings.json
vendored
4
esp32_device/.vscode/settings.json
vendored
@@ -53,6 +53,8 @@
|
||||
"sync_response.h": "c",
|
||||
"gpio.h": "c",
|
||||
"esp_system.h": "c",
|
||||
"relays.h": "c"
|
||||
"relays.h": "c",
|
||||
"esp_app_desc.h": "c",
|
||||
"ota.h": "c"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
# ESP32 device
|
||||
|
||||
ESP32 client device, using `W32-ETH01` device
|
||||
|
||||
## Some commands
|
||||
|
||||
Create a new firmware build:
|
||||
|
||||
```bash
|
||||
idf.py build
|
||||
```
|
||||
|
||||
Upload firmware to central backend, in dev mode:
|
||||
|
||||
```bash
|
||||
curl -k -X POST https://localhost:8443/web_api/ota/Wt32-Eth01/$(cat version.txt) --form firmware="@build/main.bin"
|
||||
curl -k -X POST https://localhost:8443/web_api/ota/set_desired_version --header "Content-Type: application/json" --data "{\"platform\": \"Wt32-Eth01\", \"version\": \"$(cat version.txt)\"}"
|
||||
```
|
||||
5
esp32_device/build_upload_dev.sh
Executable file
5
esp32_device/build_upload_dev.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
idf.py build && \
|
||||
curl -k -X POST https://localhost:8443/web_api/ota/Wt32-Eth01/$(cat version.txt) --form firmware="@build/main.bin" && \
|
||||
curl -k -X POST https://localhost:8443/web_api/ota/set_desired_version --header "Content-Type: application/json" --data "{\"platform\": \"Wt32-Eth01\", \"version\": \"$(cat version.txt)\"}"
|
||||
@@ -1,4 +1,4 @@
|
||||
idf_component_register(SRCS "relays.c" "sync_response.c" "jwt.c" "secure_api.c" "http_client.c" "ethernet.c" "unsecure_api.c" "system.c" "crypto.c" "random.c" "storage.c" "main.c"
|
||||
idf_component_register(SRCS "ota.c" "relays.c" "sync_response.c" "jwt.c" "secure_api.c" "http_client.c" "ethernet.c" "unsecure_api.c" "system.c" "crypto.c" "random.c" "storage.c" "main.c"
|
||||
"dev_name.c"
|
||||
INCLUDE_DIRS ".")
|
||||
|
||||
|
||||
@@ -5,11 +5,6 @@
|
||||
*/
|
||||
#define DEV_REFERENCE "Wt32-Eth01"
|
||||
|
||||
/**
|
||||
* Device version
|
||||
*/
|
||||
#define DEV_VERSION "0.0.1"
|
||||
|
||||
/**
|
||||
* Backend unsecure API URL
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_app_desc.h"
|
||||
|
||||
#include "dev_name.h"
|
||||
#include "storage.h"
|
||||
@@ -11,6 +12,7 @@
|
||||
#include "ethernet.h"
|
||||
#include "constants.h"
|
||||
#include "relays.h"
|
||||
#include "ota.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
@@ -20,7 +22,7 @@ void app_main(void)
|
||||
|
||||
system_show_free_memory();
|
||||
|
||||
ESP_LOGI(TAG, "SolarEnergy WT32-ETH01 device");
|
||||
ESP_LOGI(TAG, "SolarEnergy WT32-ETH01 device version %s", esp_app_get_description()->version);
|
||||
|
||||
// Turn off all relays
|
||||
relays_turn_off_all();
|
||||
@@ -171,6 +173,7 @@ void app_main(void)
|
||||
|
||||
// Main loop
|
||||
ESP_LOGI(TAG, "Starting main loop");
|
||||
secure_api_report_log_message(Info, "Starting program main loop");
|
||||
|
||||
size_t fails = 0;
|
||||
while (true)
|
||||
@@ -204,6 +207,32 @@ void app_main(void)
|
||||
|
||||
sync_response_print(res);
|
||||
|
||||
// Check for firmware update
|
||||
if (res->available_update)
|
||||
{
|
||||
ESP_LOGI(TAG, "Will perform system upgrade to version %s!", res->available_update);
|
||||
relays_turn_off_all();
|
||||
|
||||
secure_api_report_log_message(Info, "Device is starting the OTA procedure...");
|
||||
|
||||
if (ota_perform_update(res->available_update))
|
||||
{
|
||||
ESP_LOGI(TAG, "OTA update succesfully executed, will reboot...");
|
||||
secure_api_report_log_message(Info, "Device successfully updated!");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "OTA update failed! Will reboot...");
|
||||
secure_api_report_log_message(Error, "Device update failed!");
|
||||
}
|
||||
|
||||
secure_api_report_log_message(Info, "Device will restart after OTA procedure...");
|
||||
|
||||
system_sleep(SYNC_TIME_INTERVAL);
|
||||
reboot();
|
||||
}
|
||||
|
||||
// Update relays configuration
|
||||
for (size_t i = 0; i < relays_count(); i++)
|
||||
{
|
||||
relays_set(i, sync_response_is_relay_on(res, i));
|
||||
|
||||
7
esp32_device/main/ota.c
Normal file
7
esp32_device/main/ota.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "ota.h"
|
||||
|
||||
bool ota_perform_update(const char *version)
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
24
esp32_device/main/ota.h
Normal file
24
esp32_device/main/ota.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* OTA functions
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Update device to a desired version
|
||||
*
|
||||
* Returns TRUE in case of success / FALSE otherwise
|
||||
*/
|
||||
bool ota_perform_update(const char *version);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "relays.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_app_desc.h"
|
||||
|
||||
static const char *TAG = "secure_api";
|
||||
|
||||
@@ -118,11 +119,13 @@ fail:
|
||||
*/
|
||||
static cJSON *genDevInfo()
|
||||
{
|
||||
const esp_app_desc_t *desc = esp_app_get_description();
|
||||
|
||||
cJSON *json = cJSON_CreateObject();
|
||||
if (!json)
|
||||
return NULL;
|
||||
cJSON_AddStringToObject(json, "reference", DEV_REFERENCE);
|
||||
cJSON_AddStringToObject(json, "version", DEV_VERSION);
|
||||
cJSON_AddStringToObject(json, "version", desc->version);
|
||||
cJSON_AddNumberToObject(json, "max_relays", relays_count());
|
||||
return json;
|
||||
}
|
||||
@@ -196,6 +199,77 @@ char *secure_api_get_dev_certificate()
|
||||
return res;
|
||||
}
|
||||
|
||||
void secure_api_report_log_message(enum LogMessageSeverity severity, const char *msg)
|
||||
{
|
||||
// Prepare signed payload
|
||||
cJSON *obj = cJSON_CreateObject();
|
||||
if (!obj)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed allocate memory to store JSON object!");
|
||||
return;
|
||||
}
|
||||
|
||||
char *severity_s;
|
||||
switch (severity)
|
||||
{
|
||||
case Info:
|
||||
severity_s = "Info";
|
||||
break;
|
||||
case Warn:
|
||||
severity_s = "Warn";
|
||||
break;
|
||||
case Error:
|
||||
severity_s = "Error";
|
||||
break;
|
||||
default:
|
||||
severity_s = "Debug";
|
||||
break;
|
||||
}
|
||||
|
||||
cJSON_AddStringToObject(obj, "severity", severity_s);
|
||||
cJSON_AddStringToObject(obj, "message", msg);
|
||||
char *payload = jwt_gen(obj);
|
||||
cJSON_Delete(obj);
|
||||
|
||||
if (!payload)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to build log report request!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare request body
|
||||
cJSON *json_body = cJSON_CreateObject();
|
||||
if (!json_body)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to allocated memory to store log report request body!");
|
||||
free(payload);
|
||||
return;
|
||||
}
|
||||
cJSON_AddStringToObject(json_body, "payload", payload);
|
||||
free(payload);
|
||||
|
||||
char *body = cJSON_PrintUnformatted(json_body);
|
||||
cJSON_Delete(json_body);
|
||||
|
||||
if (!body)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to allocated memory to store encoded log report request body!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Send request
|
||||
char *res = process_secure_request("/devices_api/logging/record", body);
|
||||
|
||||
free(body);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
ESP_LOGE(TAG, "Log reporting failed!");
|
||||
}
|
||||
|
||||
free(res);
|
||||
}
|
||||
|
||||
sync_response *secure_api_sync_device()
|
||||
{
|
||||
cJSON *obj = cJSON_CreateObject();
|
||||
|
||||
@@ -29,6 +29,17 @@ extern "C"
|
||||
DevEnrollValidated = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* Log message severity
|
||||
*/
|
||||
enum LogMessageSeverity
|
||||
{
|
||||
Debug = 0,
|
||||
Info,
|
||||
Warn,
|
||||
Error
|
||||
};
|
||||
|
||||
/**
|
||||
* Get current device enrollment status
|
||||
*/
|
||||
@@ -45,6 +56,11 @@ extern "C"
|
||||
*/
|
||||
char *secure_api_get_dev_certificate();
|
||||
|
||||
/**
|
||||
* Report log message to backend
|
||||
*/
|
||||
void secure_api_report_log_message(enum LogMessageSeverity severity, const char *msg);
|
||||
|
||||
/**
|
||||
* Synchronise device with central backend
|
||||
*
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#include "sync_response.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
const static char *TAG = "sync_response";
|
||||
|
||||
sync_response *sync_response_parse(cJSON *res)
|
||||
{
|
||||
// Parse relays information
|
||||
cJSON *relays_json = cJSON_GetObjectItem(res, "relays");
|
||||
if (relays_json == NULL)
|
||||
{
|
||||
@@ -45,12 +47,26 @@ sync_response *sync_response_parse(cJSON *res)
|
||||
}
|
||||
}
|
||||
|
||||
// Parse firmware update information
|
||||
cJSON *update = cJSON_GetObjectItem(res, "available_update");
|
||||
if (update != NULL)
|
||||
{
|
||||
char *val = cJSON_GetStringValue(update);
|
||||
sync_res->available_update = val != NULL ? strdup(val) : NULL;
|
||||
}
|
||||
|
||||
return sync_res;
|
||||
}
|
||||
|
||||
void sync_response_print(sync_response *res)
|
||||
{
|
||||
ESP_LOGI(TAG, " === sync response begin === ");
|
||||
|
||||
if (res->available_update != NULL)
|
||||
{
|
||||
ESP_LOGI(TAG, "> AVAILABLE UPDATE! Version %s", res->available_update);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "# of relays: %d", res->len);
|
||||
for (size_t i = 0; i < res->len; i++)
|
||||
ESP_LOGI(TAG, "Relay[%d]=%s", i, res->relays[i] ? "ON" : "off");
|
||||
@@ -59,8 +75,13 @@ void sync_response_print(sync_response *res)
|
||||
|
||||
void sync_response_free(sync_response *res)
|
||||
{
|
||||
if (res != NULL)
|
||||
free(res);
|
||||
if (res == NULL)
|
||||
return;
|
||||
|
||||
if (res->available_update != NULL)
|
||||
free(res->available_update);
|
||||
|
||||
free(res);
|
||||
}
|
||||
|
||||
bool sync_response_is_relay_on(sync_response *res, int relay_number)
|
||||
|
||||
@@ -16,6 +16,7 @@ extern "C"
|
||||
typedef struct sync_response
|
||||
{
|
||||
size_t len;
|
||||
char *available_update;
|
||||
bool relays[];
|
||||
} sync_response;
|
||||
|
||||
|
||||
@@ -339,14 +339,14 @@ CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
|
||||
# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ="40m"
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="2MB"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
|
||||
# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set
|
||||
CONFIG_ESPTOOLPY_BEFORE_RESET=y
|
||||
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
|
||||
@@ -360,12 +360,12 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
|
||||
#
|
||||
# Partition Table
|
||||
#
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP=y
|
||||
# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
|
||||
# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set
|
||||
# CONFIG_PARTITION_TABLE_TWO_OTA is not set
|
||||
CONFIG_PARTITION_TABLE_TWO_OTA=y
|
||||
# CONFIG_PARTITION_TABLE_CUSTOM is not set
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions_two_ota.csv"
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x8000
|
||||
CONFIG_PARTITION_TABLE_MD5=y
|
||||
# end of Partition Table
|
||||
|
||||
@@ -229,7 +229,7 @@ CONFIG_IDF_TOOLCHAIN="gcc"
|
||||
CONFIG_IDF_TARGET_ARCH_XTENSA=y
|
||||
CONFIG_IDF_TARGET_ARCH="xtensa"
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_IDF_INIT_VERSION="5.2.2"
|
||||
CONFIG_IDF_INIT_VERSION="$IDF_INIT_VERSION"
|
||||
CONFIG_IDF_TARGET_ESP32=y
|
||||
CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
|
||||
|
||||
@@ -339,14 +339,14 @@ CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
|
||||
# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ="40m"
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="2MB"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
|
||||
# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set
|
||||
CONFIG_ESPTOOLPY_BEFORE_RESET=y
|
||||
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
|
||||
@@ -360,12 +360,12 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
|
||||
#
|
||||
# Partition Table
|
||||
#
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP=y
|
||||
# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
|
||||
# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set
|
||||
# CONFIG_PARTITION_TABLE_TWO_OTA is not set
|
||||
CONFIG_PARTITION_TABLE_TWO_OTA=y
|
||||
# CONFIG_PARTITION_TABLE_CUSTOM is not set
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions_two_ota.csv"
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x8000
|
||||
CONFIG_PARTITION_TABLE_MD5=y
|
||||
# end of Partition Table
|
||||
@@ -1127,14 +1127,13 @@ CONFIG_HEAP_TRACING_OFF=y
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
|
||||
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
|
||||
CONFIG_LOG_DEFAULT_LEVEL=3
|
||||
CONFIG_LOG_DEFAULT_LEVEL=4
|
||||
CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y
|
||||
# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set
|
||||
# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set
|
||||
CONFIG_LOG_MAXIMUM_LEVEL=3
|
||||
CONFIG_LOG_MAXIMUM_LEVEL=4
|
||||
# CONFIG_LOG_MASTER_LEVEL is not set
|
||||
CONFIG_LOG_COLORS=y
|
||||
CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y
|
||||
|
||||
1
esp32_device/version.txt
Normal file
1
esp32_device/version.txt
Normal file
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
Reference in New Issue
Block a user