1 Commits

Author SHA1 Message Date
e25ddaca6d Update Rust crate serde_json to v1.0.129
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-10-18 00:29:00 +00:00
74 changed files with 3324 additions and 5752 deletions

View File

@@ -5,7 +5,7 @@ name: default
steps: steps:
- name: web_build - name: web_build
image: node:23 image: node:21
volumes: volumes:
- name: web_app - name: web_app
path: /tmp/web_build path: /tmp/web_build
@@ -46,11 +46,6 @@ steps:
path: /usr/local/cargo/registry path: /usr/local/cargo/registry
- name: web_app - name: web_app
path: /tmp/web_build path: /tmp/web_build
- name: releases
path: /tmp/releases
when:
event:
- tag
depends_on: depends_on:
- backend_check - backend_check
- web_build - web_build
@@ -59,41 +54,13 @@ steps:
- mv /tmp/web_build/dist static - mv /tmp/web_build/dist static
- cargo build --release - cargo build --release
- ls -lah target/release/central_backend - ls -lah target/release/central_backend
- mv target/release/central_backend /tmp/releases/central_backend
# Build ESP32 program
- name: esp32_compile - name: esp32_compile
image: espressif/idf:v5.5.1 image: espressif/idf:v5.2.2 # FIXME : upgrade to 5.3.1
volumes:
- name: releases
path: /tmp/releases
commands: commands:
- cd esp32_device - cd esp32_device
- /opt/esp/entrypoint.sh idf.py build - /opt/esp/entrypoint.sh idf.py build
- ls -lah build/main.bin - ls -lah build/main.bin
- cp build/main.bin /tmp/releases/wt32-eth01.bin
# Auto-release to Gitea
- name: gitea_release
image: plugins/gitea-release
depends_on:
- backend_compile
- esp32_compile
when:
event:
- tag
volumes:
- name: releases
path: /tmp/releases
environment:
PLUGIN_API_KEY:
from_secret: GITEA_API_KEY # needs permission write:repository
settings:
base_url: https://gitea.communiquons.org
files:
- /tmp/releases/central_backend
- /tmp/releases/wt32-eth01.bin
checksum: sha512
volumes: volumes:
@@ -101,5 +68,3 @@ volumes:
temp: {} temp: {}
- name: web_app - name: web_app
temp: {} temp: {}
- name: releases
temp: {}

File diff suppressed because it is too large Load Diff

View File

@@ -1,46 +1,43 @@
[package] [package]
name = "central_backend" name = "central_backend"
version = "1.0.3" version = "0.1.0"
edition = "2024" edition = "2021"
[dependencies] [dependencies]
log = "0.4.28" log = "0.4.22"
env_logger = "0.11.8" env_logger = "0.11.5"
lazy_static = "1.5.0" lazy_static = "1.5.0"
dotenvy = "0.15.7" clap = { version = "4.5.20", features = ["derive", "env"] }
clap = { version = "4.5.50", features = ["derive", "env"] } anyhow = "1.0.89"
anyhow = "1.0.100" thiserror = "1.0.64"
thiserror = "2.0.17" openssl = { version = "0.10.66" }
openssl = { version = "0.10.74" } openssl-sys = "0.9.102"
openssl-sys = "0.9.110" libc = "0.2.159"
libc = "0.2.177"
foreign-types-shared = "0.1.1" foreign-types-shared = "0.1.1"
asn1 = "0.23.0" asn1 = "0.17"
actix-web = { version = "4.11.0", features = ["openssl"] } actix-web = { version = "4", features = ["openssl"] }
futures = "0.3.31" futures = "0.3.31"
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.210", features = ["derive"] }
reqwest = { version = "0.12.24", features = ["json"] } reqwest = { version = "0.12.7", features = ["json"] }
serde_json = "1.0.145" serde_json = "1.0.128"
rand = "0.10.0-rc.0" rand = "0.8.5"
actix = "0.13.5" actix = "0.13.5"
actix-identity = "0.9.0" actix-identity = "0.8.0"
actix-session = { version = "0.11.0", features = ["cookie-session"] } actix-session = { version = "0.10.1", features = ["cookie-session"] }
actix-cors = "0.7.1" actix-cors = "0.7.0"
actix-multipart = { version = "0.7.2", features = ["derive"] } actix-multipart = { version ="0.7.2", features = ["derive"] }
actix-remote-ip = "0.1.0" actix-remote-ip = "0.1.0"
futures-util = "0.3.31" futures-util = "0.3.31"
uuid = { version = "1.18.1", features = ["v4", "serde"] } uuid = { version = "1.10.0", features = ["v4", "serde"] }
semver = { version = "1.0.27", features = ["serde"] } semver = { version = "1.0.23", features = ["serde"] }
lazy-regex = "3.4.1" lazy-regex = "3.3.0"
tokio = { version = "1.48.0", features = ["full"] } tokio = { version = "1.40.0", features = ["full"] }
tokio_schedule = "0.3.2" tokio_schedule = "0.3.2"
mime_guess = "2.0.5" mime_guess = "2.0.5"
rust-embed = "8.8.0" rust-embed = "8.5.0"
jsonwebtoken = { version = "10.1.0", features = ["use_pem", "rust_crypto"] } jsonwebtoken = { version = "9.3.0", features = ["use_pem"] }
prettytable-rs = "0.10.0" prettytable-rs = "0.10.0"
chrono = "0.4.42" chrono = "0.4.38"
serde_yml = "0.0.12" serde_yml = "0.0.12"
bincode = "2.0.1" bincode = "=2.0.0-rc.3"
fs4 = { version = "0.13.1", features = ["sync"] } fs4 = { version = "0.10.0", features = ["sync"] }
zip = { version = "6.0.0", features = ["bzip2"] }
walkdir = "2.5.0"

View File

@@ -1,33 +0,0 @@
devices:
- id: dev1
info:
reference: A
version: 0.0.1
max_relays: 1
time_create: 1
time_update: 1
name: Dev1
description: Day1
validated: true
enabled: true
relays:
- id: dcb3fd91-bf9b-4de3-99e5-92c1c7dd72e9
name: R1
enabled: true
priority: 1
consumption: 100
minimal_uptime: 10
minimal_downtime: 10
depends_on: []
conflicts_with: []
on: false
for: 5000
forced_state:
type: Off
for_secs: 500
should_be_on: false
online: true
curr_consumption: -10000

View File

@@ -1,49 +0,0 @@
devices:
- id: dev1
info:
reference: A
version: 0.0.1
max_relays: 1
time_create: 1
time_update: 1
name: Dev1
description: Day1
validated: true
enabled: true
relays:
- id: dcb3fd91-bf9b-4de3-99e5-92c1c7dd72e9
name: R1
enabled: true
priority: 1
consumption: 100
minimal_uptime: 10
minimal_downtime: 10
depends_on: []
conflicts_with: []
on: false
for: 500
forced_state:
type: On
for_secs: 500
should_be_on: true
- id: dcb3fd91-bf9b-4de3-99e5-92c1c7dd72f0
name: R2
enabled: true
priority: 1
consumption: 100
minimal_uptime: 10
minimal_downtime: 10
depends_on: [ ]
conflicts_with: [ ]
on: false
for: 500
forced_state:
type: None
should_be_on: false
online: true
curr_consumption: 10000

View File

@@ -10,7 +10,7 @@ pub enum ConsumptionHistoryType {
} }
/// Electrical consumption fetcher backend /// Electrical consumption fetcher backend
#[derive(Subcommand, Debug, Clone, serde::Serialize)] #[derive(Subcommand, Debug, Clone)]
pub enum ConsumptionBackend { pub enum ConsumptionBackend {
/// Constant consumption value /// Constant consumption value
Constant { Constant {
@@ -38,24 +38,16 @@ pub enum ConsumptionBackend {
/// Fronius inverter consumption /// Fronius inverter consumption
Fronius { Fronius {
/// The origin of the domain where the webserver of the Fronius Symo can be reached /// The origin of the domain where the webserver of the Fronius Symo can be reacher
#[clap(short, long, env)]
fronius_orig: String,
/// Use cURL instead of reqwest to perform request
#[clap(short, long)] #[clap(short, long)]
curl: bool, origin: String,
}, },
} }
/// Solar system central backend /// Solar system central backend
#[derive(Parser, Debug, serde::Serialize)] #[derive(Parser, Debug)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
pub struct AppConfig { pub struct AppConfig {
/// Read arguments from env file
#[clap(short, long, env)]
pub config: Option<String>,
/// Proxy IP, might end with a star "*" /// Proxy IP, might end with a star "*"
#[clap(short, long, env)] #[clap(short, long, env)]
pub proxy_ip: Option<String>, pub proxy_ip: Option<String>,
@@ -110,18 +102,6 @@ pub struct AppConfig {
#[arg(short('f'), long, env, default_value_t = 5)] #[arg(short('f'), long, env, default_value_t = 5)]
pub energy_fetch_interval: u64, pub energy_fetch_interval: u64,
/// Custom current consumption title in dashboard
#[arg(long, env)]
pub dashboard_custom_current_consumption_title: Option<String>,
/// Custom relays consumption title in dashboard
#[arg(long, env)]
pub dashboard_custom_relays_consumption_title: Option<String>,
/// Custom cached consumption title in dashboard
#[arg(long, env)]
pub dashboard_custom_cached_consumption_title: Option<String>,
/// Consumption backend provider /// Consumption backend provider
#[clap(subcommand)] #[clap(subcommand)]
pub consumption_backend: Option<ConsumptionBackend>, pub consumption_backend: Option<ConsumptionBackend>,
@@ -134,21 +114,6 @@ lazy_static::lazy_static! {
} }
impl AppConfig { impl AppConfig {
/// Parse environment variables from file, if requedst
pub fn parse_env_file() -> anyhow::Result<()> {
if let Some(c) = Self::parse().config {
log::info!("Load additional environment variables from {c}");
let conf_file = Path::new(&c);
if !conf_file.is_file() {
panic!("Specified configuration is not a file!");
}
dotenvy::from_path(conf_file)?;
}
Ok(())
}
/// Get parsed command line arguments /// Get parsed command line arguments
pub fn get() -> &'static AppConfig { pub fn get() -> &'static AppConfig {
&ARGS &ARGS

View File

@@ -16,13 +16,11 @@ impl CRLDistributionPointExt {
let crl_bytes = asn1::write(|w| { let crl_bytes = asn1::write(|w| {
w.write_element(&asn1::SequenceWriter::new(&|w| { w.write_element(&asn1::SequenceWriter::new(&|w| {
w.write_element(&asn1::SequenceWriter::new(&|w| { w.write_element(&asn1::SequenceWriter::new(&|w| {
w.write_tlv(tag_a0, None, |w: &mut asn1::WriteBuf| { w.write_tlv(tag_a0, |w| {
w.push_slice(&asn1::write(|w| { w.push_slice(&asn1::write(|w| {
w.write_tlv(tag_a0, None, |w: &mut asn1::WriteBuf| { w.write_tlv(tag_a0, |w| {
w.push_slice(&asn1::write(|w| { w.push_slice(&asn1::write(|w| {
w.write_tlv(tag_86, None, |b| { w.write_tlv(tag_86, |b| b.push_slice(self.url.as_bytes()))?;
b.push_slice(self.url.as_bytes())
})?;
Ok(()) Ok(())
})?) })?)
})?; })?;

View File

@@ -13,10 +13,10 @@ use openssl::pkey::{PKey, Private};
use openssl::x509::extension::{ use openssl::x509::extension::{
BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, SubjectKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, SubjectKeyIdentifier,
}; };
use openssl::x509::{CrlStatus, X509, X509Crl, X509Name, X509NameBuilder, X509Req}; use openssl::x509::{CrlStatus, X509Crl, X509Name, X509NameBuilder, X509Req, X509};
use openssl_sys::{ use openssl_sys::{
X509_CRL_add0_revoked, X509_CRL_new, X509_CRL_set_issuer_name, X509_CRL_set_version, X509_CRL_add0_revoked, X509_CRL_new, X509_CRL_set1_lastUpdate, X509_CRL_set1_nextUpdate,
X509_CRL_set1_lastUpdate, X509_CRL_set1_nextUpdate, X509_CRL_sign, X509_REVOKED_dup, X509_CRL_set_issuer_name, X509_CRL_set_version, X509_CRL_sign, X509_REVOKED_dup,
X509_REVOKED_new, X509_REVOKED_set_revocationDate, X509_REVOKED_set_serialNumber, X509_REVOKED_new, X509_REVOKED_set_revocationDate, X509_REVOKED_set_serialNumber,
}; };
@@ -120,7 +120,7 @@ enum GenCertificatSubjectReq<'a> {
CSR { csr: &'a X509Req }, CSR { csr: &'a X509Req },
} }
impl Default for GenCertificatSubjectReq<'_> { impl<'a> Default for GenCertificatSubjectReq<'a> {
fn default() -> Self { fn default() -> Self {
Self::Subject { cn: "" } Self::Subject { cn: "" }
} }
@@ -174,16 +174,17 @@ fn gen_certificate(req: GenCertificateReq) -> anyhow::Result<(Option<Vec<u8>>, V
cert_builder.set_not_after(&not_after)?; cert_builder.set_not_after(&not_after)?;
// Specify CRL URL // Specify CRL URL
if let Some(issuer) = req.issuer if let Some(issuer) = req.issuer {
&& let Some(crl) = &issuer.crl if let Some(crl) = &issuer.crl {
{ let crl_url = format!(
let crl_url = format!( "{}/pki/{}",
"{}/pki/{}", AppConfig::get().unsecure_origin(),
AppConfig::get().unsecure_origin(), crl.file_name().unwrap().to_string_lossy()
crl.file_name().unwrap().to_string_lossy() );
);
cert_builder.append_extension(CRLDistributionPointExt { url: crl_url }.as_extension()?)?; cert_builder
.append_extension(CRLDistributionPointExt { url: crl_url }.as_extension()?)?;
}
} }
// If cert is a CA or not // If cert is a CA or not
@@ -423,12 +424,12 @@ fn refresh_crl(d: &CertData, new_cert: Option<&X509>) -> anyhow::Result<()> {
} }
// Add old entries // Add old entries
if let Some(old_crl) = old_crl if let Some(old_crl) = old_crl {
&& let Some(entries) = old_crl.get_revoked() if let Some(entries) = old_crl.get_revoked() {
{ for entry in entries {
for entry in entries { if X509_CRL_add0_revoked(crl, X509_REVOKED_dup(entry.as_ptr())) == 0 {
if X509_CRL_add0_revoked(crl, X509_REVOKED_dup(entry.as_ptr())) == 0 { return Err(PKIError::GenCRLError("X509_CRL_add0_revoked").into());
return Err(PKIError::GenCRLError("X509_CRL_add0_revoked").into()); }
} }
} }
} }

View File

@@ -325,11 +325,9 @@ mod tests {
..Default::default() ..Default::default()
}; };
dep_cycle_1.depends_on = vec![dep_cycle_3.id]; dep_cycle_1.depends_on = vec![dep_cycle_3.id];
assert!( assert!(dep_cycle_1
dep_cycle_1 .error(&[dep_cycle_2.clone(), dep_cycle_3.clone()])
.error(&[dep_cycle_2.clone(), dep_cycle_3.clone()]) .is_some());
.is_some()
);
dep_cycle_1.depends_on = vec![]; dep_cycle_1.depends_on = vec![];
assert!(dep_cycle_1.error(&[dep_cycle_2, dep_cycle_3]).is_none()); assert!(dep_cycle_1.error(&[dep_cycle_2, dep_cycle_3]).is_none());
@@ -353,29 +351,21 @@ mod tests {
..Default::default() ..Default::default()
}; };
assert!( assert!(target_relay
target_relay .error(&[other_dep.clone(), second_dep.clone()])
.error(&[other_dep.clone(), second_dep.clone()]) .is_some());
.is_some() assert!(target_relay
); .error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()])
assert!( .is_some());
target_relay
.error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()])
.is_some()
);
second_dep.conflicts_with = vec![]; second_dep.conflicts_with = vec![];
assert!( assert!(target_relay
target_relay .error(&[other_dep.clone(), second_dep.clone()])
.error(&[other_dep.clone(), second_dep.clone()]) .is_none());
.is_none() assert!(target_relay
); .error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()])
assert!( .is_none());
target_relay
.error(&[other_dep.clone(), second_dep.clone(), target_relay.clone()])
.is_none()
);
// self loop // self loop
let mut self_loop = DeviceRelay { let mut self_loop = DeviceRelay {

View File

@@ -4,7 +4,7 @@ use crate::devices::device::{
Device, DeviceGeneralInfo, DeviceId, DeviceInfo, DeviceRelay, DeviceRelayID, Device, DeviceGeneralInfo, DeviceId, DeviceInfo, DeviceRelay, DeviceRelayID,
}; };
use crate::utils::time_utils::time_secs; use crate::utils::time_utils::time_secs;
use openssl::x509::{X509, X509Req}; use openssl::x509::{X509Req, X509};
use std::collections::HashMap; use std::collections::HashMap;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]

View File

@@ -1,5 +1,5 @@
use crate::app_config::{AppConfig, ConsumptionBackend}; use crate::app_config::{AppConfig, ConsumptionBackend};
use rand::{Rng, rng}; use rand::{thread_rng, Rng};
use std::num::ParseIntError; use std::num::ParseIntError;
use std::path::Path; use std::path::Path;
@@ -9,8 +9,6 @@ pub enum ConsumptionError {
NonExistentFile, NonExistentFile,
#[error("The file that should contain the consumption has an invalid content!")] #[error("The file that should contain the consumption has an invalid content!")]
FileInvalidContent(#[source] ParseIntError), FileInvalidContent(#[source] ParseIntError),
#[error("Failed to execute cURL request!")]
CurlReqFailed,
} }
pub type EnergyConsumption = i32; pub type EnergyConsumption = i32;
@@ -49,7 +47,7 @@ pub async fn get_curr_consumption() -> anyhow::Result<EnergyConsumption> {
match backend { match backend {
ConsumptionBackend::Constant { value } => Ok(*value), ConsumptionBackend::Constant { value } => Ok(*value),
ConsumptionBackend::Random { min, max } => Ok(rng().random_range(*min..*max)), ConsumptionBackend::Random { min, max } => Ok(thread_rng().gen_range(*min..*max)),
ConsumptionBackend::File { path } => { ConsumptionBackend::File { path } => {
let path = Path::new(path); let path = Path::new(path);
@@ -65,25 +63,9 @@ pub async fn get_curr_consumption() -> anyhow::Result<EnergyConsumption> {
.map_err(ConsumptionError::FileInvalidContent)?) .map_err(ConsumptionError::FileInvalidContent)?)
} }
ConsumptionBackend::Fronius { fronius_orig, curl } => { ConsumptionBackend::Fronius { origin } => {
let url = format!("{fronius_orig}/solar_api/v1/GetPowerFlowRealtimeData.fcgi"); let url = format!("{origin}/solar_api/v1/GetPowerFlowRealtimeData.fcgi");
let response = reqwest::get(url).await?.json::<FroniusResponse>().await?;
let response = match curl {
false => reqwest::get(url).await?.json::<FroniusResponse>().await?,
true => {
let res = std::process::Command::new("curl")
.arg("--connect-timeout")
.arg("1.5")
.arg(url)
.output()?;
if !res.status.success() {
return Err(ConsumptionError::CurlReqFailed.into());
}
serde_json::from_slice::<FroniusResponse>(&res.stdout)?
}
};
Ok(response.body.data.site.grid_production as i32) Ok(response.body.data.site.grid_production as i32)
} }

View File

@@ -8,7 +8,7 @@ use crate::energy::consumption;
use crate::energy::consumption::EnergyConsumption; use crate::energy::consumption::EnergyConsumption;
use crate::energy::consumption_cache::ConsumptionCache; use crate::energy::consumption_cache::ConsumptionCache;
use crate::energy::consumption_history_file::ConsumptionHistoryFile; use crate::energy::consumption_history_file::ConsumptionHistoryFile;
use crate::energy::engine::{EnergyEngine, RelayForcedState}; use crate::energy::engine::EnergyEngine;
use crate::utils::time_utils::time_secs; use crate::utils::time_utils::time_secs;
use actix::prelude::*; use actix::prelude::*;
use openssl::x509::X509Req; use openssl::x509::X509Req;
@@ -25,14 +25,7 @@ impl EnergyActor {
pub async fn new() -> anyhow::Result<Self> { pub async fn new() -> anyhow::Result<Self> {
let consumption_cache_size = let consumption_cache_size =
AppConfig::get().refresh_interval / AppConfig::get().energy_fetch_interval; AppConfig::get().refresh_interval / AppConfig::get().energy_fetch_interval;
let curr_consumption = match consumption::get_curr_consumption().await { let curr_consumption = consumption::get_curr_consumption().await?;
Ok(v) => v,
Err(e) => {
log::warn!("Failed to fetch consumption, using default value! {e}");
constants::FALLBACK_PRODUCTION_VALUE
}
};
log::info!("Initial consumption value: {curr_consumption}");
let mut consumption_cache = ConsumptionCache::new(consumption_cache_size as usize); let mut consumption_cache = ConsumptionCache::new(consumption_cache_size as usize);
consumption_cache.add_value(curr_consumption); consumption_cache.add_value(curr_consumption);
@@ -328,19 +321,6 @@ impl Handler<UpdateDeviceRelay> for EnergyActor {
} }
} }
#[derive(Message)]
#[rtype(result = "anyhow::Result<()>")]
pub struct SetRelayForcedState(pub DeviceRelayID, pub RelayForcedState);
impl Handler<SetRelayForcedState> for EnergyActor {
type Result = anyhow::Result<()>;
fn handle(&mut self, msg: SetRelayForcedState, _ctx: &mut Context<Self>) -> Self::Result {
self.engine.relay_state(msg.0).set_forced(msg.1);
Ok(())
}
}
/// Delete a device relay /// Delete a device relay
#[derive(Message)] #[derive(Message)]
#[rtype(result = "anyhow::Result<()>")] #[rtype(result = "anyhow::Result<()>")]
@@ -421,7 +401,6 @@ pub struct ResRelayState {
pub id: DeviceRelayID, pub id: DeviceRelayID,
pub on: bool, pub on: bool,
pub r#for: usize, pub r#for: usize,
pub forced_state: RelayForcedState,
} }
/// Get the state of all relays /// Get the state of all relays
@@ -441,7 +420,6 @@ impl Handler<GetAllRelaysState> for EnergyActor {
id: d.id, id: d.id,
on: state.is_on(), on: state.is_on(),
r#for: state.state_for(), r#for: state.state_for(),
forced_state: state.actual_forced_state(),
}) })
} }

View File

@@ -1,7 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::app_config::AppConfig; use crate::app_config::AppConfig;
use prettytable::{Table, row}; use prettytable::{row, Table};
use crate::constants; use crate::constants;
use crate::devices::device::{Device, DeviceId, DeviceRelay, DeviceRelayID}; use crate::devices::device::{Device, DeviceId, DeviceRelay, DeviceRelayID};
@@ -25,83 +25,19 @@ impl DeviceState {
} }
} }
#[derive(Default, Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type")]
pub enum SetRelayForcedStateReq {
#[default]
None,
Off {
for_secs: u64,
},
On {
for_secs: u64,
},
}
impl SetRelayForcedStateReq {
pub fn to_forced_state(&self) -> RelayForcedState {
match &self {
SetRelayForcedStateReq::None => RelayForcedState::None,
SetRelayForcedStateReq::Off { for_secs } => RelayForcedState::Off {
until: time_secs() + for_secs,
},
SetRelayForcedStateReq::On { for_secs } => RelayForcedState::On {
until: time_secs() + for_secs,
},
}
}
}
#[derive(Default, Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type")]
pub enum RelayForcedState {
#[default]
None,
Off {
until: u64,
},
On {
until: u64,
},
}
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct RelayState { pub struct RelayState {
on: bool, on: bool,
since: usize, since: usize,
forced_state: RelayForcedState,
} }
impl RelayState { impl RelayState {
/// Get actual forced state (returns None if state is expired)
pub fn actual_forced_state(&self) -> RelayForcedState {
match self.forced_state {
RelayForcedState::Off { until } if until > time_secs() => {
RelayForcedState::Off { until }
}
RelayForcedState::On { until } if until > time_secs() => RelayForcedState::On { until },
_ => RelayForcedState::None,
}
}
pub fn is_on(&self) -> bool { pub fn is_on(&self) -> bool {
let forced_state = self.actual_forced_state(); self.on
(self.on || matches!(forced_state, RelayForcedState::On { .. }))
&& !matches!(forced_state, RelayForcedState::Off { .. })
} }
fn is_off(&self) -> bool { fn is_off(&self) -> bool {
!self.is_on() !self.on
}
/// Check if relay state is enforced
pub fn is_forced(&self) -> bool {
self.actual_forced_state() != RelayForcedState::None
}
pub fn set_forced(&mut self, s: RelayForcedState) {
self.since = time_secs() as usize;
self.forced_state = s;
} }
pub fn state_for(&self) -> usize { pub fn state_for(&self) -> usize {
@@ -210,11 +146,7 @@ impl EnergyEngine {
r.name, r.name,
r.consumption, r.consumption,
format!("{} / {}", r.minimal_downtime, r.minimal_uptime), format!("{} / {}", r.minimal_downtime, r.minimal_uptime),
status.is_on().to_string() status.is_on().to_string(),
+ match status.is_forced() {
true => " (Forced)",
false => "",
},
status.since, status.since,
match dev_online { match dev_online {
true => "Online", true => "Online",
@@ -260,28 +192,19 @@ impl EnergyEngine {
let mut new_relays_state = self.relays_state.clone(); let mut new_relays_state = self.relays_state.clone();
// Forcefully turn off disabled relays // Forcefully turn off relays that belongs to offline devices
for d in devices { for d in devices {
for r in &d.relays { if !self.device_state(&d.id).is_online() {
if !r.enabled || !d.enabled { for r in &d.relays {
new_relays_state.get_mut(&r.id).unwrap().on = false; new_relays_state.get_mut(&r.id).unwrap().on = false;
} }
} }
} }
// Apply forced relays state // Forcefully turn off disabled relays
for d in devices { for d in devices {
for r in &d.relays { for r in &d.relays {
if self.relay_state(r.id).is_forced() { if !r.enabled || !d.enabled {
new_relays_state.get_mut(&r.id).unwrap().on = self.relay_state(r.id).is_on();
}
}
}
// Forcefully turn off relays that belongs to offline devices
for d in devices {
if !self.device_state(&d.id).is_online() {
for r in &d.relays {
new_relays_state.get_mut(&r.id).unwrap().on = false; new_relays_state.get_mut(&r.id).unwrap().on = false;
} }
} }
@@ -293,9 +216,7 @@ impl EnergyEngine {
for d in devices { for d in devices {
for r in &d.relays { for r in &d.relays {
if new_relays_state.get(&r.id).unwrap().is_off() if new_relays_state.get(&r.id).unwrap().is_off() {
|| new_relays_state.get(&r.id).unwrap().is_forced()
{
continue; continue;
} }
@@ -319,7 +240,7 @@ impl EnergyEngine {
for d in devices { for d in devices {
for r in &d.relays { for r in &d.relays {
let state = new_relays_state.get(&r.id).unwrap(); let state = new_relays_state.get(&r.id).unwrap();
if state.is_off() || state.is_forced() { if state.is_off() {
continue; continue;
} }
@@ -350,9 +271,7 @@ impl EnergyEngine {
continue; continue;
} }
if new_relays_state.get(&r.id).unwrap().is_on() if new_relays_state.get(&r.id).unwrap().is_on() {
|| new_relays_state.get(&r.id).unwrap().is_forced()
{
continue; continue;
} }
@@ -370,16 +289,12 @@ impl EnergyEngine {
continue; continue;
} }
log::info!( log::info!("Forcefully turn on relay {} to catch up running constraints (only {}s this day)", r.name, total_runtime);
"Forcefully turn on relay {} to catch up running constraints (only {}s this day)",
r.name,
total_runtime
);
new_relays_state.get_mut(&r.id).unwrap().on = true; new_relays_state.get_mut(&r.id).unwrap().on = true;
} }
} }
// Order relays to select the ones with the most elevated priorities // Order relays
let mut ordered_relays = devices let mut ordered_relays = devices
.iter() .iter()
.filter(|d| self.device_state(&d.id).is_online() && d.enabled) .filter(|d| self.device_state(&d.id).is_online() && d.enabled)
@@ -389,13 +304,10 @@ impl EnergyEngine {
ordered_relays.sort_by_key(|r| r.priority); ordered_relays.sort_by_key(|r| r.priority);
ordered_relays.reverse(); ordered_relays.reverse();
// Select relays to start, starting with those with highest priorities
loop { loop {
let mut changed = false; let mut changed = false;
for relay in &ordered_relays { for relay in &ordered_relays {
if new_relays_state.get(&relay.id).unwrap().is_on() if new_relays_state.get(&relay.id).unwrap().is_on() {
|| new_relays_state.get(&relay.id).unwrap().is_forced()
{
continue; continue;
} }
@@ -467,7 +379,7 @@ impl EnergyEngine {
mod test { mod test {
use crate::devices::device::{Device, DeviceId, DeviceRelayID}; use crate::devices::device::{Device, DeviceId, DeviceRelayID};
use crate::energy::consumption::EnergyConsumption; use crate::energy::consumption::EnergyConsumption;
use crate::energy::engine::{EnergyEngine, SetRelayForcedStateReq}; use crate::energy::engine::EnergyEngine;
use crate::utils::time_utils::time_secs; use crate::utils::time_utils::time_secs;
use rust_embed::Embed; use rust_embed::Embed;
@@ -476,8 +388,6 @@ mod test {
id: DeviceRelayID, id: DeviceRelayID,
on: bool, on: bool,
r#for: usize, r#for: usize,
#[serde(default)]
forced_state: SetRelayForcedStateReq,
should_be_on: bool, should_be_on: bool,
} }
@@ -525,7 +435,6 @@ mod test {
let s = engine.relay_state(r.id); let s = engine.relay_state(r.id);
s.on = r.on; s.on = r.on;
s.since = time_secs() as usize - r.r#for; s.since = time_secs() as usize - r.r#for;
s.forced_state = r.forced_state.to_forced_state()
} }
} }

View File

@@ -1,7 +1,7 @@
use crate::app_config::AppConfig; use crate::app_config::AppConfig;
use crate::devices::device::{DeviceRelay, DeviceRelayID}; use crate::devices::device::{DeviceRelay, DeviceRelayID};
use crate::utils::files_utils; use crate::utils::files_utils;
use crate::utils::time_utils::{day_number, time_secs, time_start_of_day}; use crate::utils::time_utils::{day_number, time_start_of_day};
const TIME_INTERVAL: usize = 30; const TIME_INTERVAL: usize = 30;
@@ -128,26 +128,15 @@ pub fn relay_total_runtime_adjusted(relay: &DeviceRelay) -> usize {
.unwrap_or(0); .unwrap_or(0);
let time_start_day = time_start_of_day().unwrap_or(1726696800); let time_start_day = time_start_of_day().unwrap_or(1726696800);
let start_time = time_start_day + reset_time as u64;
// Check if we have reached reset_time today yet or not let end_time = time_start_day + 3600 * 24 + reset_time as u64;
if time_start_day + reset_time as u64 <= time_secs() { relay_total_runtime(relay.id, start_time, end_time).unwrap_or(3600 * 24)
let start_time = time_start_day + reset_time as u64;
let end_time = time_start_day + 3600 * 24 + reset_time as u64;
relay_total_runtime(relay.id, start_time, end_time).unwrap_or(3600 * 24)
}
// If we have not reached reset time yet, we need to focus on previous day
else {
let time_start_yesterday = time_start_day - 3600 * 24;
let start_time = time_start_yesterday + reset_time as u64;
let end_time = time_start_day + reset_time as u64;
relay_total_runtime(relay.id, start_time, end_time).unwrap_or(3600 * 24)
}
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::devices::device::DeviceRelayID; use crate::devices::device::DeviceRelayID;
use crate::energy::relay_state_history::{RelayStateHistory, relay_total_runtime}; use crate::energy::relay_state_history::{relay_total_runtime, RelayStateHistory};
#[test] #[test]
fn test_relay_state_history() { fn test_relay_state_history() {

View File

@@ -35,7 +35,7 @@ pub fn save_log(
.as_bytes(), .as_bytes(),
)?; )?;
file.flush()?; file.flush()?;
fs4::fs_std::FileExt::unlock(&file)?; file.unlock()?;
Ok(()) Ok(())
} }

View File

@@ -5,13 +5,10 @@ use central_backend::energy::energy_actor::EnergyActor;
use central_backend::server::servers; use central_backend::server::servers;
use central_backend::utils::files_utils::create_directory_if_missing; use central_backend::utils::files_utils::create_directory_if_missing;
use futures::future; use futures::future;
use tokio_schedule::{Job, every}; use tokio_schedule::{every, Job};
#[actix_web::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
// Load additional config from file, if requested
AppConfig::parse_env_file().expect("Failed to parse environment file!");
// Initialize OpenSSL // Initialize OpenSSL
openssl_sys::init(); openssl_sys::init();

View File

@@ -1,5 +1,5 @@
use actix_identity::Identity; use actix_identity::Identity;
use std::future::{Ready, ready}; use std::future::{ready, Ready};
use std::rc::Rc; use std::rc::Rc;
use crate::app_config::AppConfig; use crate::app_config::AppConfig;
@@ -7,8 +7,8 @@ use crate::constants;
use actix_web::body::EitherBody; use actix_web::body::EitherBody;
use actix_web::dev::Payload; use actix_web::dev::Payload;
use actix_web::{ use actix_web::{
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
Error, FromRequest, HttpResponse, Error, FromRequest, HttpResponse,
dev::{Service, ServiceRequest, ServiceResponse, Transform, forward_ready},
}; };
use futures_util::future::LocalBoxFuture; use futures_util::future::LocalBoxFuture;

View File

@@ -1,9 +1,9 @@
use actix_web::HttpResponse;
use actix_web::body::BoxBody; use actix_web::body::BoxBody;
use actix_web::http::StatusCode; use actix_web::http::StatusCode;
use actix_web::HttpResponse;
use std::error::Error; use std::error::Error;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use zip::result::ZipError; use std::io::ErrorKind;
/// Custom error to ease controller writing /// Custom error to ease controller writing
#[derive(Debug)] #[derive(Debug)]
@@ -31,7 +31,7 @@ impl actix_web::error::ResponseError for HttpErr {
} }
} }
fn error_response(&self) -> HttpResponse<BoxBody> { fn error_response(&self) -> HttpResponse<BoxBody> {
log::error!("Error while processing request! {self}"); log::error!("Error while processing request! {}", self);
HttpResponse::InternalServerError().body("Failed to execute request!") HttpResponse::InternalServerError().body("Failed to execute request!")
} }
@@ -51,7 +51,7 @@ impl From<serde_json::Error> for HttpErr {
impl From<Box<dyn Error>> for HttpErr { impl From<Box<dyn Error>> for HttpErr {
fn from(value: Box<dyn Error>) -> Self { fn from(value: Box<dyn Error>) -> Self {
HttpErr::Err(std::io::Error::other(value.to_string()).into()) HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
} }
} }
@@ -81,43 +81,31 @@ impl From<reqwest::header::ToStrError> for HttpErr {
impl From<actix_web::Error> for HttpErr { impl From<actix_web::Error> for HttpErr {
fn from(value: actix_web::Error) -> Self { fn from(value: actix_web::Error) -> Self {
HttpErr::Err(std::io::Error::other(value.to_string()).into()) HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
} }
} }
impl From<actix::MailboxError> for HttpErr { impl From<actix::MailboxError> for HttpErr {
fn from(value: actix::MailboxError) -> Self { fn from(value: actix::MailboxError) -> Self {
HttpErr::Err(std::io::Error::other(value.to_string()).into()) HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
} }
} }
impl From<actix_identity::error::GetIdentityError> for HttpErr { impl From<actix_identity::error::GetIdentityError> for HttpErr {
fn from(value: actix_identity::error::GetIdentityError) -> Self { fn from(value: actix_identity::error::GetIdentityError) -> Self {
HttpErr::Err(std::io::Error::other(value.to_string()).into()) HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
} }
} }
impl From<actix_identity::error::LoginError> for HttpErr { impl From<actix_identity::error::LoginError> for HttpErr {
fn from(value: actix_identity::error::LoginError) -> Self { fn from(value: actix_identity::error::LoginError) -> Self {
HttpErr::Err(std::io::Error::other(value.to_string()).into()) HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
} }
} }
impl From<openssl::error::ErrorStack> for HttpErr { impl From<openssl::error::ErrorStack> for HttpErr {
fn from(value: openssl::error::ErrorStack) -> Self { fn from(value: openssl::error::ErrorStack) -> Self {
HttpErr::Err(std::io::Error::other(value.to_string()).into()) HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
}
}
impl From<ZipError> for HttpErr {
fn from(value: ZipError) -> Self {
HttpErr::Err(std::io::Error::other(value.to_string()).into())
}
}
impl From<walkdir::Error> for HttpErr {
fn from(value: walkdir::Error) -> Self {
HttpErr::Err(std::io::Error::other(value.to_string()).into())
} }
} }

View File

@@ -1,11 +1,11 @@
use crate::logs::logs_manager; use crate::logs::logs_manager;
use crate::logs::severity::LogSeverity; use crate::logs::severity::LogSeverity;
use crate::server::WebEnergyActor;
use crate::server::custom_error::HttpResult; use crate::server::custom_error::HttpResult;
use crate::server::devices_api::jwt_parser::JWTRequest; use crate::server::devices_api::jwt_parser::JWTRequest;
use actix_web::{HttpResponse, web}; use crate::server::WebEnergyActor;
use actix_web::{web, HttpResponse};
#[derive(Debug, serde::Deserialize, Clone)] #[derive(Debug, serde::Deserialize)]
pub struct LogRequest { pub struct LogRequest {
severity: LogSeverity, severity: LogSeverity,
message: String, message: String,

View File

@@ -1,7 +1,7 @@
use crate::ota::ota_manager; use crate::ota::ota_manager;
use crate::ota::ota_update::OTAPlatform; use crate::ota::ota_update::OTAPlatform;
use crate::server::custom_error::HttpResult; use crate::server::custom_error::HttpResult;
use actix_web::{HttpResponse, web}; use actix_web::{web, HttpResponse};
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct FirmwarePath { pub struct FirmwarePath {

View File

@@ -30,7 +30,7 @@ pub struct JWTRequest {
} }
impl JWTRequest { impl JWTRequest {
pub async fn parse_jwt<E: DeserializeOwned + std::clone::Clone>( pub async fn parse_jwt<E: DeserializeOwned>(
&self, &self,
actor: WebEnergyActor, actor: WebEnergyActor,
) -> anyhow::Result<(Device, E)> { ) -> anyhow::Result<(Device, E)> {

View File

@@ -4,10 +4,10 @@ use crate::energy::energy_actor;
use crate::energy::energy_actor::RelaySyncStatus; use crate::energy::energy_actor::RelaySyncStatus;
use crate::ota::ota_manager; use crate::ota::ota_manager;
use crate::ota::ota_update::OTAPlatform; use crate::ota::ota_update::OTAPlatform;
use crate::server::WebEnergyActor;
use crate::server::custom_error::HttpResult; use crate::server::custom_error::HttpResult;
use crate::server::devices_api::jwt_parser::JWTRequest; use crate::server::devices_api::jwt_parser::JWTRequest;
use actix_web::{HttpResponse, web}; use crate::server::WebEnergyActor;
use actix_web::{web, HttpResponse};
use openssl::nid::Nid; use openssl::nid::Nid;
use openssl::x509::X509Req; use openssl::x509::X509Req;
use std::str::FromStr; use std::str::FromStr;
@@ -130,7 +130,7 @@ pub async fn get_certificate(query: web::Query<ReqWithDevID>, actor: WebEnergyAc
.body(cert)) .body(cert))
} }
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[derive(Debug, serde::Serialize, serde::Deserialize)]
struct Claims { struct Claims {
info: DeviceInfo, info: DeviceInfo,
} }
@@ -155,11 +155,12 @@ pub async fn sync_device(body: web::Json<JWTRequest>, actor: WebEnergyActor) ->
let mut available_update = None; let mut available_update = None;
// Check if the version is available // Check if the version is available
if let Some(desired) = device.desired_version if let Some(desired) = device.desired_version {
&& claims.info.version < desired if claims.info.version < desired
&& ota_manager::update_exists(OTAPlatform::from_str(&claims.info.reference)?, &desired)? && ota_manager::update_exists(OTAPlatform::from_str(&claims.info.reference)?, &desired)?
{ {
available_update = Some(desired); available_update = Some(desired);
}
} }
Ok(HttpResponse::Ok().json(SyncResult { Ok(HttpResponse::Ok().json(SyncResult {

View File

@@ -10,14 +10,14 @@ use crate::server::unsecure_server::*;
use crate::server::web_api::*; use crate::server::web_api::*;
use crate::server::web_app_controller; use crate::server::web_app_controller;
use actix_cors::Cors; use actix_cors::Cors;
use actix_identity::config::LogoutBehaviour;
use actix_identity::IdentityMiddleware; use actix_identity::IdentityMiddleware;
use actix_identity::config::LogoutBehavior;
use actix_remote_ip::RemoteIPConfig; use actix_remote_ip::RemoteIPConfig;
use actix_session::SessionMiddleware;
use actix_session::storage::CookieSessionStore; use actix_session::storage::CookieSessionStore;
use actix_session::SessionMiddleware;
use actix_web::cookie::{Key, SameSite}; use actix_web::cookie::{Key, SameSite};
use actix_web::middleware::Logger; use actix_web::middleware::Logger;
use actix_web::{App, HttpServer, web}; use actix_web::{web, App, HttpServer};
use openssl::ssl::{SslAcceptor, SslMethod}; use openssl::ssl::{SslAcceptor, SslMethod};
use std::time::Duration; use std::time::Duration;
@@ -84,7 +84,7 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
.build(); .build();
let identity_middleware = IdentityMiddleware::builder() let identity_middleware = IdentityMiddleware::builder()
.logout_behavior(LogoutBehavior::PurgeSession) .logout_behaviour(LogoutBehaviour::PurgeSession)
.visit_deadline(Some(Duration::from_secs( .visit_deadline(Some(Duration::from_secs(
constants::MAX_INACTIVITY_DURATION, constants::MAX_INACTIVITY_DURATION,
))) )))
@@ -231,10 +231,6 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
"/web_api/relay/{id}", "/web_api/relay/{id}",
web::put().to(relays_controller::update), web::put().to(relays_controller::update),
) )
.route(
"/web_api/relay/{id}/forced_state",
web::put().to(relays_controller::set_forced_state),
)
.route( .route(
"/web_api/relay/{id}", "/web_api/relay/{id}",
web::delete().to(relays_controller::delete), web::delete().to(relays_controller::delete),
@@ -247,11 +243,6 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
"/web_api/relay/{id}/status", "/web_api/relay/{id}/status",
web::get().to(relays_controller::status_single), web::get().to(relays_controller::status_single),
) )
// Management API
.route(
"/web_api/management/download_storage",
web::get().to(management_controller::download_storage),
)
// Devices API // Devices API
.route( .route(
"/devices_api/utils/time", "/devices_api/utils/time",

View File

@@ -1,6 +1,6 @@
use crate::app_config::AppConfig; use crate::app_config::AppConfig;
use crate::server::custom_error::HttpResult; use crate::server::custom_error::HttpResult;
use actix_web::{HttpResponse, web}; use actix_web::{web, HttpResponse};
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct ServeCRLPath { pub struct ServeCRLPath {

View File

@@ -1,8 +1,8 @@
use crate::devices::device::DeviceRelayID; use crate::devices::device::DeviceRelayID;
use crate::energy::{energy_actor, relay_state_history}; use crate::energy::{energy_actor, relay_state_history};
use crate::server::WebEnergyActor;
use crate::server::custom_error::HttpResult; use crate::server::custom_error::HttpResult;
use actix_web::{HttpResponse, web}; use crate::server::WebEnergyActor;
use actix_web::{web, HttpResponse};
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct LegacyStateRelay { pub struct LegacyStateRelay {

View File

@@ -2,7 +2,7 @@ use crate::app_config::AppConfig;
use crate::server::custom_error::HttpResult; use crate::server::custom_error::HttpResult;
use actix_identity::Identity; use actix_identity::Identity;
use actix_remote_ip::RemoteIP; use actix_remote_ip::RemoteIP;
use actix_web::{HttpMessage, HttpRequest, HttpResponse, web}; use actix_web::{web, HttpMessage, HttpRequest, HttpResponse};
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct AuthRequest { pub struct AuthRequest {
@@ -17,11 +17,11 @@ pub async fn password_auth(
remote_ip: RemoteIP, remote_ip: RemoteIP,
) -> HttpResult { ) -> HttpResult {
if r.user != AppConfig::get().admin_username || r.password != AppConfig::get().admin_password { if r.user != AppConfig::get().admin_username || r.password != AppConfig::get().admin_password {
log::error!("Failed login attempt from {}!", remote_ip.0); log::error!("Failed login attempt from {}!", remote_ip.0.to_string());
return Ok(HttpResponse::Unauthorized().json("Invalid credentials!")); return Ok(HttpResponse::Unauthorized().json("Invalid credentials!"));
} }
log::info!("Successful login attempt from {}!", remote_ip.0); log::info!("Successful login attempt from {}!", remote_ip.0.to_string());
Identity::login(&request.extensions(), r.user.to_string())?; Identity::login(&request.extensions(), r.user.to_string())?;
Ok(HttpResponse::Ok().finish()) Ok(HttpResponse::Ok().finish())
} }

View File

@@ -1,8 +1,8 @@
use crate::devices::device::{DeviceGeneralInfo, DeviceId}; use crate::devices::device::{DeviceGeneralInfo, DeviceId};
use crate::energy::energy_actor; use crate::energy::energy_actor;
use crate::server::WebEnergyActor;
use crate::server::custom_error::HttpResult; use crate::server::custom_error::HttpResult;
use actix_web::{HttpResponse, web}; use crate::server::WebEnergyActor;
use actix_web::{web, HttpResponse};
/// Get the list of pending (not accepted yet) devices /// Get the list of pending (not accepted yet) devices
pub async fn list_pending(actor: WebEnergyActor) -> HttpResult { pub async fn list_pending(actor: WebEnergyActor) -> HttpResult {

View File

@@ -2,27 +2,21 @@ use crate::app_config::ConsumptionHistoryType;
use crate::energy::consumption::EnergyConsumption; use crate::energy::consumption::EnergyConsumption;
use crate::energy::consumption_history_file::ConsumptionHistoryFile; use crate::energy::consumption_history_file::ConsumptionHistoryFile;
use crate::energy::{consumption, energy_actor}; use crate::energy::{consumption, energy_actor};
use crate::server::WebEnergyActor;
use crate::server::custom_error::HttpResult; use crate::server::custom_error::HttpResult;
use crate::server::WebEnergyActor;
use crate::utils::time_utils::time_secs; use crate::utils::time_utils::time_secs;
use actix_web::HttpResponse; use actix_web::HttpResponse;
#[derive(serde::Serialize)] #[derive(serde::Serialize)]
struct Consumption { struct Consumption {
consumption: Option<i32>, consumption: i32,
} }
/// Get current energy consumption /// Get current energy consumption
pub async fn curr_consumption() -> HttpResult { pub async fn curr_consumption() -> HttpResult {
Ok(match consumption::get_curr_consumption().await { let consumption = consumption::get_curr_consumption().await?;
Ok(v) => HttpResponse::Ok().json(Consumption {
consumption: Some(v), Ok(HttpResponse::Ok().json(Consumption { consumption }))
}),
Err(e) => {
log::error!("Failed to fetch current consumption! {e}");
HttpResponse::Ok().json(Consumption { consumption: None })
}
})
} }
/// Get curr consumption history /// Get curr consumption history
@@ -40,9 +34,7 @@ pub async fn curr_consumption_history() -> HttpResult {
pub async fn cached_consumption(energy_actor: WebEnergyActor) -> HttpResult { pub async fn cached_consumption(energy_actor: WebEnergyActor) -> HttpResult {
let consumption = energy_actor.send(energy_actor::GetCurrConsumption).await?; let consumption = energy_actor.send(energy_actor::GetCurrConsumption).await?;
Ok(HttpResponse::Ok().json(Consumption { Ok(HttpResponse::Ok().json(Consumption { consumption }))
consumption: Some(consumption),
}))
} }
/// Get current relays consumption /// Get current relays consumption
@@ -50,9 +42,7 @@ pub async fn relays_consumption(energy_actor: WebEnergyActor) -> HttpResult {
let consumption = let consumption =
energy_actor.send(energy_actor::RelaysConsumption).await? as EnergyConsumption; energy_actor.send(energy_actor::RelaysConsumption).await? as EnergyConsumption;
Ok(HttpResponse::Ok().json(Consumption { Ok(HttpResponse::Ok().json(Consumption { consumption }))
consumption: Some(consumption),
}))
} }
pub async fn relays_consumption_history() -> HttpResult { pub async fn relays_consumption_history() -> HttpResult {

View File

@@ -3,7 +3,7 @@ use crate::logs::logs_manager;
use crate::logs::severity::LogSeverity; use crate::logs::severity::LogSeverity;
use crate::server::custom_error::HttpResult; use crate::server::custom_error::HttpResult;
use crate::utils::time_utils::curr_day_number; use crate::utils::time_utils::curr_day_number;
use actix_web::{HttpResponse, web}; use actix_web::{web, HttpResponse};
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct LogRequest { pub struct LogRequest {

View File

@@ -1,66 +0,0 @@
use crate::app_config::AppConfig;
use crate::server::custom_error::HttpResult;
use crate::utils::time_utils::current_day;
use actix_web::HttpResponse;
use anyhow::Context;
use std::fs::File;
use std::io::{Cursor, Read, Write};
use walkdir::WalkDir;
use zip::write::SimpleFileOptions;
/// Download a full copy of the storage data
pub async fn download_storage() -> HttpResult {
let mut zip_buff = Cursor::new(Vec::new());
let mut zip = zip::ZipWriter::new(&mut zip_buff);
let options = SimpleFileOptions::default()
.compression_method(zip::CompressionMethod::Bzip2)
.unix_permissions(0o700);
let storage = AppConfig::get().storage_path();
let mut file_buff = Vec::new();
for entry in WalkDir::new(&storage) {
let entry = entry?;
let path = entry.path();
let name = path.strip_prefix(&storage).unwrap();
let path_as_string = name
.to_str()
.map(str::to_owned)
.with_context(|| format!("{name:?} Is a Non UTF-8 Path"))?;
// Write file or directory explicitly
// Some unzip tools unzip files with directory paths correctly, some do not!
if path.is_file() {
log::debug!("adding file {path:?} as {name:?} ...");
zip.start_file(path_as_string, options)?;
let mut f = File::open(path)?;
f.read_to_end(&mut file_buff)?;
zip.write_all(&file_buff)?;
file_buff.clear();
} else if !name.as_os_str().is_empty() {
// Only if not root! Avoids path spec / warning
// and mapname conversion failed error on unzip
log::debug!("adding dir {path_as_string:?} as {name:?} ...");
zip.add_directory(path_as_string, options)?;
}
}
// Inject runtime configuration
zip.start_file("/app_config.json", options)?;
zip.write_all(&serde_json::to_vec_pretty(&AppConfig::get())?)?;
zip.finish()?;
let filename = format!("storage-{}.zip", current_day());
Ok(HttpResponse::Ok()
.content_type("application/zip")
.insert_header((
"content-disposition",
format!("attachment; filename=\"{filename}\""),
))
.body(zip_buff.into_inner()))
}

View File

@@ -2,7 +2,6 @@ pub mod auth_controller;
pub mod devices_controller; pub mod devices_controller;
pub mod energy_controller; pub mod energy_controller;
pub mod logging_controller; pub mod logging_controller;
pub mod management_controller;
pub mod ota_controller; pub mod ota_controller;
pub mod relays_controller; pub mod relays_controller;
pub mod server_controller; pub mod server_controller;

View File

@@ -3,11 +3,11 @@ use crate::devices::device::DeviceId;
use crate::energy::energy_actor; use crate::energy::energy_actor;
use crate::ota::ota_manager; use crate::ota::ota_manager;
use crate::ota::ota_update::OTAPlatform; use crate::ota::ota_update::OTAPlatform;
use crate::server::WebEnergyActor;
use crate::server::custom_error::HttpResult; use crate::server::custom_error::HttpResult;
use actix_multipart::form::MultipartForm; use crate::server::WebEnergyActor;
use actix_multipart::form::tempfile::TempFile; use actix_multipart::form::tempfile::TempFile;
use actix_web::{HttpResponse, web}; use actix_multipart::form::MultipartForm;
use actix_web::{web, HttpResponse};
pub async fn supported_platforms() -> HttpResult { pub async fn supported_platforms() -> HttpResult {
Ok(HttpResponse::Ok().json(OTAPlatform::supported_platforms())) Ok(HttpResponse::Ok().json(OTAPlatform::supported_platforms()))
@@ -123,17 +123,17 @@ pub async fn set_desired_version(
for d in devices { for d in devices {
// Filter per platform // Filter per platform
if let Some(p) = body.platform if let Some(p) = body.platform {
&& d.info.reference != p.to_string() if d.info.reference != p.to_string() {
{ continue;
continue; }
} }
// Filter per device // Filter per device
if let Some(ids) = &body.devices if let Some(ids) = &body.devices {
&& !ids.contains(&d.id) if !ids.contains(&d.id) {
{ continue;
continue; }
} }
actor actor

View File

@@ -1,9 +1,8 @@
use crate::devices::device::{DeviceId, DeviceRelay, DeviceRelayID}; use crate::devices::device::{DeviceId, DeviceRelay, DeviceRelayID};
use crate::energy::energy_actor; use crate::energy::energy_actor;
use crate::energy::engine::SetRelayForcedStateReq;
use crate::server::WebEnergyActor;
use crate::server::custom_error::HttpResult; use crate::server::custom_error::HttpResult;
use actix_web::{HttpResponse, web}; use crate::server::WebEnergyActor;
use actix_web::{web, HttpResponse};
/// Get the full list of relays /// Get the full list of relays
pub async fn get_list(actor: WebEnergyActor) -> HttpResult { pub async fn get_list(actor: WebEnergyActor) -> HttpResult {
@@ -86,29 +85,6 @@ pub async fn update(
Ok(HttpResponse::Accepted().finish()) Ok(HttpResponse::Accepted().finish())
} }
/// Set relay forced status
pub async fn set_forced_state(
actor: WebEnergyActor,
req: web::Json<SetRelayForcedStateReq>,
path: web::Path<RelayIDInPath>,
) -> HttpResult {
// Check if relay exists first
let list = actor.send(energy_actor::GetAllRelaysState).await?;
if !list.into_iter().any(|r| r.id == path.id) {
return Ok(HttpResponse::NotFound().json("Relay not found!"));
};
// Update relay forced state
actor
.send(energy_actor::SetRelayForcedState(
path.id,
req.to_forced_state(),
))
.await??;
Ok(HttpResponse::Accepted().finish())
}
/// Delete an existing relay /// Delete an existing relay
pub async fn delete(actor: WebEnergyActor, path: web::Path<RelayIDInPath>) -> HttpResult { pub async fn delete(actor: WebEnergyActor, path: web::Path<RelayIDInPath>) -> HttpResult {
actor actor

View File

@@ -13,10 +13,6 @@ struct ServerConfig {
auth_disabled: bool, auth_disabled: bool,
constraints: StaticConstraints, constraints: StaticConstraints,
unsecure_origin: String, unsecure_origin: String,
backend_version: &'static str,
dashboard_custom_current_consumption_title: Option<&'static str>,
dashboard_custom_relays_consumption_title: Option<&'static str>,
dashboard_custom_cached_consumption_title: Option<&'static str>,
} }
impl Default for ServerConfig { impl Default for ServerConfig {
@@ -25,16 +21,6 @@ impl Default for ServerConfig {
auth_disabled: AppConfig::get().unsecure_disable_login, auth_disabled: AppConfig::get().unsecure_disable_login,
constraints: Default::default(), constraints: Default::default(),
unsecure_origin: AppConfig::get().unsecure_origin(), unsecure_origin: AppConfig::get().unsecure_origin(),
backend_version: env!("CARGO_PKG_VERSION"),
dashboard_custom_current_consumption_title: AppConfig::get()
.dashboard_custom_current_consumption_title
.as_deref(),
dashboard_custom_relays_consumption_title: AppConfig::get()
.dashboard_custom_relays_consumption_title
.as_deref(),
dashboard_custom_cached_consumption_title: AppConfig::get()
.dashboard_custom_cached_consumption_title
.as_deref(),
} }
} }
} }

View File

@@ -19,7 +19,7 @@ mod serve_static_debug {
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
mod serve_static_release { mod serve_static_release {
use actix_web::{HttpResponse, Responder, web}; use actix_web::{web, HttpResponse, Responder};
use rust_embed::RustEmbed; use rust_embed::RustEmbed;
#[derive(RustEmbed)] #[derive(RustEmbed)]

View File

@@ -1,7 +1,7 @@
use chrono::prelude::*; use chrono::prelude::*;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
/// Get the current time since epoch, in seconds /// Get the current time since epoch
pub fn time_secs() -> u64 { pub fn time_secs() -> u64 {
SystemTime::now() SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
@@ -41,12 +41,6 @@ pub fn time_start_of_day() -> anyhow::Result<u64> {
Ok(local.timestamp() as u64) Ok(local.timestamp() as u64)
} }
/// Get formatted string containing current day information
pub fn current_day() -> String {
let dt = Local::now();
format!("{}-{:0>2}-{:0>2}", dt.year(), dt.month(), dt.day())
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::utils::time_utils::day_number; use crate::utils::time_utils::day_number;

View File

@@ -1,28 +0,0 @@
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 },
],
},
},
)

File diff suppressed because it is too large Load Diff

View File

@@ -6,40 +6,38 @@
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "tsc -b && vite build", "build": "tsc -b && vite build",
"lint": "eslint .", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.14.0", "@emotion/react": "^11.13.3",
"@emotion/styled": "^11.14.1", "@emotion/styled": "^11.13.0",
"@fontsource/roboto": "^5.2.8", "@fontsource/roboto": "^5.1.0",
"@mdi/js": "^7.4.47", "@mdi/js": "^7.4.47",
"@mdi/react": "^1.6.1", "@mdi/react": "^1.6.1",
"@mui/icons-material": "^7.3.4", "@mui/icons-material": "^6.1.3",
"@mui/material": "^7.3.4", "@mui/material": "^6.1.3",
"@mui/x-charts": "^8.15.0", "@mui/x-charts": "^7.20.0",
"@mui/x-date-pickers": "^8.15.0", "@mui/x-date-pickers": "^7.20.0",
"date-and-time": "^4.1.0", "@types/semver": "^7.5.8",
"dayjs": "^1.11.18", "date-and-time": "^3.6.0",
"filesize": "^11.0.13", "dayjs": "^1.11.13",
"react": "^19.2.0", "filesize": "^10.1.6",
"react-dom": "^19.2.0", "react": "^18.3.1",
"react-router-dom": "^7.9.4", "react-dom": "^18.3.1",
"semver": "^7.7.3" "react-router-dom": "^6.27.0",
"semver": "^7.6.3"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^19.2.2", "@types/react": "^18.3.11",
"@types/react-dom": "^19.2.2", "@types/react-dom": "^18.3.1",
"@types/semver": "^7.7.1", "@typescript-eslint/eslint-plugin": "^8.8.0",
"@typescript-eslint/eslint-plugin": "^8.46.2", "@typescript-eslint/parser": "^8.8.0",
"@typescript-eslint/parser": "^8.46.2", "@vitejs/plugin-react": "^4.3.2",
"@vitejs/plugin-react": "^5.1.0", "eslint": "^8.57.1",
"eslint": "^9.38.0", "eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.12",
"eslint-plugin-react-refresh": "^0.4.24", "typescript": "^5.6.3",
"globals": "^16.4.0", "vite": "^5.4.8"
"typescript": "^5.9.3",
"typescript-eslint": "^8.46.2",
"vite": "^7.1.12"
} }
} }

View File

@@ -16,7 +16,6 @@ import { PendingDevicesRoute } from "./routes/PendingDevicesRoute";
import { RelaysListRoute } from "./routes/RelaysListRoute"; import { RelaysListRoute } from "./routes/RelaysListRoute";
import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage"; import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage";
import { OTARoute } from "./routes/OTARoute"; import { OTARoute } from "./routes/OTARoute";
import { ManagementRoute } from "./routes/ManagementRoute";
export function App() { export function App() {
if (!AuthApi.SignedIn && !ServerApi.Config.auth_disabled) if (!AuthApi.SignedIn && !ServerApi.Config.auth_disabled)
@@ -32,7 +31,6 @@ export function App() {
<Route path="relays" element={<RelaysListRoute />} /> <Route path="relays" element={<RelaysListRoute />} />
<Route path="ota" element={<OTARoute />} /> <Route path="ota" element={<OTARoute />} />
<Route path="logs" element={<LogsRoute />} /> <Route path="logs" element={<LogsRoute />} />
<Route path="management" element={<ManagementRoute />} />
<Route path="*" element={<NotFoundRoute />} /> <Route path="*" element={<NotFoundRoute />} />
</Route> </Route>
) )

View File

@@ -1,19 +1,10 @@
import { APIClient } from "./ApiClient"; import { APIClient } from "./ApiClient";
import { Device, DeviceRelay } from "./DeviceApi"; import { Device, DeviceRelay } from "./DeviceApi";
export type RelayForcedState =
| { type: "None" }
| { type: "Off" | "On"; until: number };
export type SetRelayForcedState =
| { type: "None" }
| { type: "Off" | "On"; for_secs: number };
export interface RelayStatus { export interface RelayStatus {
id: string; id: string;
on: boolean; on: boolean;
for: number; for: number;
forced_state: RelayForcedState;
} }
export type RelaysStatus = Map<string, RelayStatus>; export type RelaysStatus = Map<string, RelayStatus>;
@@ -57,20 +48,6 @@ export class RelayApi {
}); });
} }
/**
* Set relay forced state
*/
static async SetForcedState(
relay: DeviceRelay,
forced: SetRelayForcedState
): Promise<void> {
await APIClient.exec({
method: "PUT",
uri: `/relay/${relay.id}/forced_state`,
jsonData: forced,
});
}
/** /**
* Delete a relay configuration * Delete a relay configuration
*/ */

View File

@@ -4,10 +4,6 @@ export interface ServerConfig {
auth_disabled: boolean; auth_disabled: boolean;
constraints: ServerConstraint; constraints: ServerConstraint;
unsecure_origin: string; unsecure_origin: string;
backend_version: string;
dashboard_custom_current_consumption_title?: string;
dashboard_custom_relays_consumption_title?: string;
dashboard_custom_cached_consumption_title?: string;
} }
export interface ServerConstraint { export interface ServerConstraint {

View File

@@ -84,7 +84,7 @@ export function DeployOTAUpdateDialogProvider(p: {
</DialogContentText> </DialogContentText>
<FormControl> <FormControl>
<FormLabel>Deployment target</FormLabel> <FormLabel>Gender</FormLabel>
<RadioGroup <RadioGroup
name="radio-buttons-group" name="radio-buttons-group"
value={allDevices} value={allDevices}

View File

@@ -6,7 +6,7 @@ import {
DialogTitle, DialogTitle,
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import Grid from "@mui/material/Grid"; import Grid from "@mui/material/Grid2";
import { TimePicker } from "@mui/x-date-pickers"; import { TimePicker } from "@mui/x-date-pickers";
import React from "react"; import React from "react";
import { Device, DeviceRelay } from "../api/DeviceApi"; import { Device, DeviceRelay } from "../api/DeviceApi";

View File

@@ -1,53 +0,0 @@
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
TextField,
} from "@mui/material";
import { DeviceRelay } from "../api/DeviceApi";
import React from "react";
export function SelectForcedStateDurationDialog(p: {
relay: DeviceRelay;
forcedState: string;
onCancel: () => void;
onSubmit: (duration: number) => void;
}): React.ReactElement {
const [duration, setDuration] = React.useState(60);
return (
<Dialog open onClose={p.onCancel}>
<DialogTitle>Set forced relay state</DialogTitle>
<DialogContent>
<DialogContentText>
Please specify the number of minutes the relay <i>{p.relay.name}</i>{" "}
will remain in forced state <i>{p.forcedState}</i>:
</DialogContentText>
<TextField
label="Duration (min)"
variant="standard"
value={Math.floor(duration / 60)}
onChange={(e) => {
const val = Number.parseInt(e.target.value);
setDuration((Number.isNaN(val) ? 1 : val) * 60);
}}
fullWidth
style={{ marginTop: "5px" }}
/>
<p>Equivalent in seconds: {duration} secs</p>
<p>Equivalent in hours: {duration / 3600} hours</p>
</DialogContent>
<DialogActions>
<Button onClick={p.onCancel}>Cancel</Button>
<Button onClick={() => p.onSubmit(duration)} autoFocus>
Start timer
</Button>
</DialogActions>
</Dialog>
);
}

View File

@@ -10,16 +10,16 @@ import {
} from "@mui/material"; } from "@mui/material";
import React from "react"; import React from "react";
import { Device, DeviceRelay } from "../../api/DeviceApi"; import { Device, DeviceRelay } from "../../api/DeviceApi";
import { RelayApi, RelayStatus } from "../../api/RelayApi";
import { EditDeviceRelaysDialog } from "../../dialogs/EditDeviceRelaysDialog"; import { EditDeviceRelaysDialog } from "../../dialogs/EditDeviceRelaysDialog";
import { useAlert } from "../../hooks/context_providers/AlertDialogProvider"; import { DeviceRouteCard } from "./DeviceRouteCard";
import { useConfirm } from "../../hooks/context_providers/ConfirmDialogProvider"; import { useConfirm } from "../../hooks/context_providers/ConfirmDialogProvider";
import { useLoadingMessage } from "../../hooks/context_providers/LoadingMessageProvider"; import { useLoadingMessage } from "../../hooks/context_providers/LoadingMessageProvider";
import { RelayApi, RelayStatus } from "../../api/RelayApi";
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider"; import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
import { useAlert } from "../../hooks/context_providers/AlertDialogProvider";
import { AsyncWidget } from "../../widgets/AsyncWidget"; import { AsyncWidget } from "../../widgets/AsyncWidget";
import { BoolText } from "../../widgets/BoolText";
import { TimeWidget } from "../../widgets/TimeWidget"; import { TimeWidget } from "../../widgets/TimeWidget";
import { DeviceRouteCard } from "./DeviceRouteCard"; import { BoolText } from "../../widgets/BoolText";
export function DeviceRelays(p: { export function DeviceRelays(p: {
device: Device; device: Device;
@@ -145,8 +145,7 @@ function RelayEntryStatus(
errMsg="Failed to load relay status!" errMsg="Failed to load relay status!"
build={() => ( build={() => (
<> <>
<BoolText val={state!.on} positive="ON" negative="OFF" />{" "} <BoolText val={state!.on} positive="ON" negative="OFF" /> for{" "}
{state?.forced_state.type !== "None" && <b>Forced</b>} for{" "}
<TimeWidget diff time={state!.for} /> <TimeWidget diff time={state!.for} />
</> </>
)} )}

View File

@@ -1,7 +1,7 @@
import DeleteIcon from "@mui/icons-material/Delete"; import DeleteIcon from "@mui/icons-material/Delete";
import RefreshIcon from "@mui/icons-material/Refresh"; import RefreshIcon from "@mui/icons-material/Refresh";
import { IconButton, Tooltip } from "@mui/material"; import { IconButton, Tooltip } from "@mui/material";
import Grid from "@mui/material/Grid"; import Grid from "@mui/material/Grid2";
import React from "react"; import React from "react";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import { Device, DeviceApi } from "../../api/DeviceApi"; import { Device, DeviceApi } from "../../api/DeviceApi";

View File

@@ -81,7 +81,7 @@ function ValidatedDevicesList(p: {
<Table sx={{ minWidth: 650 }} aria-label="simple table"> <Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell>Name</TableCell> <TableCell>#</TableCell>
<TableCell align="center">Model</TableCell> <TableCell align="center">Model</TableCell>
<TableCell align="center">Version</TableCell> <TableCell align="center">Version</TableCell>
<TableCell align="center">Max relays</TableCell> <TableCell align="center">Max relays</TableCell>
@@ -99,7 +99,7 @@ function ValidatedDevicesList(p: {
onDoubleClick={() => navigate(DeviceURL(dev))} onDoubleClick={() => navigate(DeviceURL(dev))}
> >
<TableCell component="th" scope="row"> <TableCell component="th" scope="row">
{dev.name} {dev.id}
</TableCell> </TableCell>
<TableCell align="center">{dev.info.reference}</TableCell> <TableCell align="center">{dev.info.reference}</TableCell>
<TableCell align="center">{dev.info.version}</TableCell> <TableCell align="center">{dev.info.version}</TableCell>

View File

@@ -1,6 +1,6 @@
import { Typography } from "@mui/material"; import { Typography } from "@mui/material";
import { CurrConsumptionWidget } from "./HomeRoute/CurrConsumptionWidget"; import { CurrConsumptionWidget } from "./HomeRoute/CurrConsumptionWidget";
import Grid from "@mui/material/Grid"; import Grid from "@mui/material/Grid2";
import { CachedConsumptionWidget } from "./HomeRoute/CachedConsumptionWidget"; import { CachedConsumptionWidget } from "./HomeRoute/CachedConsumptionWidget";
import { RelayConsumptionWidget } from "./HomeRoute/RelayConsumptionWidget"; import { RelayConsumptionWidget } from "./HomeRoute/RelayConsumptionWidget";
import { RelaysListRoute } from "./RelaysListRoute"; import { RelaysListRoute } from "./RelaysListRoute";

View File

@@ -2,7 +2,6 @@ import React from "react";
import { EnergyApi } from "../../api/EnergyApi"; import { EnergyApi } from "../../api/EnergyApi";
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider"; import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
import StatCard from "../../widgets/StatCard"; import StatCard from "../../widgets/StatCard";
import { ServerApi } from "../../api/ServerApi";
export function CachedConsumptionWidget(): React.ReactElement { export function CachedConsumptionWidget(): React.ReactElement {
const snackbar = useSnackbar(); const snackbar = useSnackbar();
@@ -27,12 +26,6 @@ export function CachedConsumptionWidget(): React.ReactElement {
}); });
return ( return (
<StatCard <StatCard title="Cached consumption" value={val?.toString() ?? "Loading"} />
title={
ServerApi.Config.dashboard_custom_cached_consumption_title ??
"Cached consumption"
}
value={val?.toString() ?? "Loading"}
/>
); );
} }

View File

@@ -2,7 +2,6 @@ import React from "react";
import { EnergyApi } from "../../api/EnergyApi"; import { EnergyApi } from "../../api/EnergyApi";
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider"; import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
import StatCard from "../../widgets/StatCard"; import StatCard from "../../widgets/StatCard";
import { ServerApi } from "../../api/ServerApi";
export function CurrConsumptionWidget(): React.ReactElement { export function CurrConsumptionWidget(): React.ReactElement {
const snackbar = useSnackbar(); const snackbar = useSnackbar();
@@ -30,10 +29,7 @@ export function CurrConsumptionWidget(): React.ReactElement {
return ( return (
<StatCard <StatCard
title={ title="Current consumption"
ServerApi.Config.dashboard_custom_current_consumption_title ??
"Current consumption"
}
data={history ?? []} data={history ?? []}
interval="Last day" interval="Last day"
value={val?.toString() ?? "Loading"} value={val?.toString() ?? "Loading"}

View File

@@ -2,7 +2,6 @@ import React from "react";
import { EnergyApi } from "../../api/EnergyApi"; import { EnergyApi } from "../../api/EnergyApi";
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider"; import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
import StatCard from "../../widgets/StatCard"; import StatCard from "../../widgets/StatCard";
import { ServerApi } from "../../api/ServerApi";
export function RelayConsumptionWidget(): React.ReactElement { export function RelayConsumptionWidget(): React.ReactElement {
const snackbar = useSnackbar(); const snackbar = useSnackbar();
@@ -30,10 +29,7 @@ export function RelayConsumptionWidget(): React.ReactElement {
return ( return (
<StatCard <StatCard
title={ title="Relays consumption"
ServerApi.Config.dashboard_custom_relays_consumption_title ??
"Relays consumption"
}
data={history ?? []} data={history ?? []}
interval="Last day" interval="Last day"
value={val?.toString() ?? "Loading"} value={val?.toString() ?? "Loading"}

View File

@@ -11,7 +11,7 @@ import Typography from "@mui/material/Typography";
import * as React from "react"; import * as React from "react";
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider"; import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
import { AuthApi } from "../api/AuthApi"; import { AuthApi } from "../api/AuthApi";
import Grid from "@mui/material/Grid"; import Grid from "@mui/material/Grid2";
function Copyright(props: any) { function Copyright(props: any) {
return ( return (

View File

@@ -1,31 +0,0 @@
import { Button } from "@mui/material";
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer";
import { APIClient } from "../api/ApiClient";
export function ManagementRoute(): React.ReactElement {
const confirm = useConfirm();
const downloadBackup = async () => {
try {
if (
!(await confirm(
`Do you really want to download a copy of the storage? It will contain sensitive information!`
))
)
return;
location.href = APIClient.backendURL() + "/management/download_storage";
} catch (e) {
console.error(`Failed to donwload a backup of the storage! Error: ${e}`);
}
};
return (
<SolarEnergyRouteContainer label="Management">
<Button variant="outlined" onClick={downloadBackup}>
Download a backup of storage
</Button>
</SolarEnergyRouteContainer>
);
}

View File

@@ -16,13 +16,12 @@ import React from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { Device, DeviceApi, DeviceRelay, DeviceURL } from "../api/DeviceApi"; import { Device, DeviceApi, DeviceRelay, DeviceURL } from "../api/DeviceApi";
import { RelayApi, RelaysStatus } from "../api/RelayApi"; import { RelayApi, RelaysStatus } from "../api/RelayApi";
import { ServerApi } from "../api/ServerApi";
import { AsyncWidget } from "../widgets/AsyncWidget"; import { AsyncWidget } from "../widgets/AsyncWidget";
import { BoolText } from "../widgets/BoolText"; import { BoolText } from "../widgets/BoolText";
import { CopyToClipboard } from "../widgets/CopyToClipboard";
import { RelayForcedState } from "../widgets/RelayForcedState";
import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer"; import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer";
import { TimeWidget } from "../widgets/TimeWidget"; import { TimeWidget } from "../widgets/TimeWidget";
import { CopyToClipboard } from "../widgets/CopyToClipboard";
import { ServerApi } from "../api/ServerApi";
export function RelaysListRoute(p: { export function RelaysListRoute(p: {
homeWidget?: boolean; homeWidget?: boolean;
@@ -105,7 +104,6 @@ function RelaysList(p: {
<TableCell>Priority</TableCell> <TableCell>Priority</TableCell>
<TableCell>Consumption</TableCell> <TableCell>Consumption</TableCell>
<TableCell>Status</TableCell> <TableCell>Status</TableCell>
<TableCell>Forced state</TableCell>
<TableCell></TableCell> <TableCell></TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
@@ -131,13 +129,6 @@ function RelaysList(p: {
/>{" "} />{" "}
for <TimeWidget diff time={p.status.get(row.id)!.for} /> for <TimeWidget diff time={p.status.get(row.id)!.for} />
</TableCell> </TableCell>
<TableCell>
<RelayForcedState
relay={row}
state={p.status.get(row.id)!}
onUpdated={p.onReload}
/>
</TableCell>
<TableCell> <TableCell>
<Tooltip title="Copy legacy api status"> <Tooltip title="Copy legacy api status">
<CopyToClipboard <CopyToClipboard

View File

@@ -1,79 +0,0 @@
import { MenuItem, Select, SelectChangeEvent } from "@mui/material";
import { DeviceRelay } from "../api/DeviceApi";
import { RelayApi, RelayStatus, SetRelayForcedState } from "../api/RelayApi";
import { TimeWidget } from "./TimeWidget";
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
import React from "react";
import { SelectForcedStateDurationDialog } from "../dialogs/SelectForcedStateDurationDialog";
export function RelayForcedState(p: {
relay: DeviceRelay;
state: RelayStatus;
onUpdated: () => void;
}): React.ReactElement {
const loadingMessage = useLoadingMessage();
const alert = useAlert();
const snackbar = useSnackbar();
const [futureStateType, setFutureStateType] = React.useState<
string | undefined
>();
const handleChange = (event: SelectChangeEvent) => {
if (event.target.value == "None") {
submitChange({ type: "None" });
} else {
setFutureStateType(event.target.value);
}
};
const submitChange = async (state: SetRelayForcedState) => {
try {
loadingMessage.show("Setting forced state...");
await RelayApi.SetForcedState(p.relay, state);
p.onUpdated();
snackbar("Forced state successfully updated!");
} catch (e) {
console.error(`Failed to set relay forced state! ${e}`);
alert(`Failed to set loading state for relay! ${e}`);
} finally {
loadingMessage.hide();
}
};
return (
<>
<Select
value={p.state.forced_state.type}
onChange={handleChange}
size="small"
variant="standard"
>
<MenuItem value={"None"}>None</MenuItem>
<MenuItem value={"Off"}>Off</MenuItem>
<MenuItem value={"On"}>On</MenuItem>
</Select>
{p.state.forced_state.type !== "None" && (
<>
<TimeWidget future time={p.state.forced_state.until} /> left
</>
)}
{futureStateType !== undefined && (
<SelectForcedStateDurationDialog
{...p}
forcedState={futureStateType}
onCancel={() => setFutureStateType(undefined)}
onSubmit={(d) =>
submitChange({
type: futureStateType as any,
for_secs: d,
})
}
/>
)}
</>
);
}

View File

@@ -1,6 +1,5 @@
import { import {
mdiChip, mdiChip,
mdiCog,
mdiElectricSwitch, mdiElectricSwitch,
mdiHome, mdiHome,
mdiMonitorArrowDown, mdiMonitorArrowDown,
@@ -13,11 +12,9 @@ import {
ListItemButton, ListItemButton,
ListItemIcon, ListItemIcon,
ListItemText, ListItemText,
Typography,
} from "@mui/material"; } from "@mui/material";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { RouterLink } from "./RouterLink"; import { RouterLink } from "./RouterLink";
import { ServerApi } from "../api/ServerApi";
export function SolarEnergyNavList(): React.ReactElement { export function SolarEnergyNavList(): React.ReactElement {
return ( return (
@@ -55,18 +52,6 @@ export function SolarEnergyNavList(): React.ReactElement {
uri="/logs" uri="/logs"
icon={<Icon path={mdiNotebookMultiple} size={1} />} icon={<Icon path={mdiNotebookMultiple} size={1} />}
/> />
<NavLink
label="Management"
uri="/management"
icon={<Icon path={mdiCog} size={1} />}
/>
<Typography
variant="caption"
component="div"
style={{ textAlign: "center", width: "100%", marginTop: "30px" }}
>
Version {ServerApi.Config.backend_version}
</Typography>
</List> </List>
); );
} }

View File

@@ -106,7 +106,7 @@ export default function StatCard({
<Box sx={{ width: "100%", height: 100 }}> <Box sx={{ width: "100%", height: 100 }}>
{data && interval && ( {data && interval && (
<SparkLineChart <SparkLineChart
color={chartColor} colors={[chartColor]}
data={data} data={data}
area area
showHighlight showHighlight

View File

@@ -1,11 +1,11 @@
import { Tooltip } from "@mui/material"; import { Tooltip } from "@mui/material";
import { format } from "date-and-time"; import date from "date-and-time";
import { time } from "../utils/DateUtils"; import { time } from "../utils/DateUtils";
export function formatDate(time: number): string { export function formatDate(time: number): string {
const t = new Date(); const t = new Date();
t.setTime(1000 * time); t.setTime(1000 * time);
return format(t, "DD/MM/YYYY HH:mm:ss"); return date.format(t, "DD/MM/YYYY HH:mm:ss");
} }
export function timeDiff(a: number, b: number): string { export function timeDiff(a: number, b: number): string {
@@ -21,7 +21,7 @@ export function timeDiff(a: number, b: number): string {
diff = Math.floor(diff / 60); diff = Math.floor(diff / 60);
if (diff === 1) return "1 minute"; if (diff === 1) return "1 minute";
if (diff < 60) { if (diff < 24) {
return `${diff} minutes`; return `${diff} minutes`;
} }
@@ -51,14 +51,13 @@ export function timeDiff(a: number, b: number): string {
return `${diffYears} years`; return `${diffYears} years`;
} }
export function timeDiffFromNow(t: number, future?: boolean): string { export function timeDiffFromNow(t: number): string {
return future ? timeDiff(time(), t) : timeDiff(t, time()); return timeDiff(t, time());
} }
export function TimeWidget(p: { export function TimeWidget(p: {
time?: number; time?: number;
diff?: boolean; diff?: boolean;
future?: boolean;
}): React.ReactElement { }): React.ReactElement {
if (!p.time) return <></>; if (!p.time) return <></>;
return ( return (
@@ -66,9 +65,7 @@ export function TimeWidget(p: {
title={formatDate(p.diff ? new Date().getTime() / 1000 - p.time : p.time)} title={formatDate(p.diff ? new Date().getTime() / 1000 - p.time : p.time)}
arrow arrow
> >
<span> <span>{p.diff ? timeDiff(0, p.time) : timeDiffFromNow(p.time)}</span>
{p.diff ? timeDiff(0, p.time) : timeDiffFromNow(p.time, p.future)}
</span>
</Tooltip> </Tooltip>
); );
} }

View File

@@ -1,5 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020", "target": "ES2020",
"useDefineForClassFields": true, "useDefineForClassFields": true,
@@ -10,6 +11,7 @@
/* Bundler mode */ /* Bundler mode */
"moduleResolution": "bundler", "moduleResolution": "bundler",
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"moduleDetection": "force", "moduleDetection": "force",
"noEmit": true, "noEmit": true,
@@ -19,8 +21,7 @@
"strict": true, "strict": true,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true
"noUncheckedSideEffectImports": true
}, },
"include": ["src"] "include": ["src"]
} }

View File

@@ -1,7 +1,11 @@
{ {
"files": [], "files": [],
"references": [ "references": [
{ "path": "./tsconfig.app.json" }, {
{ "path": "./tsconfig.node.json" } "path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.node.json"
}
] ]
} }

View File

@@ -1,24 +1,13 @@
{ {
"compilerOptions": { "compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true, "skipLibCheck": true,
"module": "ESNext",
/* Bundler mode */
"moduleResolution": "bundler", "moduleResolution": "bundler",
"allowImportingTsExtensions": true, "allowSyntheticDefaultImports": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true, "strict": true,
"noUnusedLocals": true, "noEmit": true
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
}, },
"include": ["vite.config.ts"] "include": ["vite.config.ts"]
} }

View File

@@ -1,7 +1,7 @@
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react' import react from '@vitejs/plugin-react'
// https://vite.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
}) })

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,12 @@
[package] [package]
name = "custom_consumption" name = "custom_consumption"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2021"
[dependencies] [dependencies]
env_logger = "0.11.8" env_logger = "0.11.5"
log = "0.4.28" log = "0.4.22"
clap = { version = "4.5.50", features = ["derive", "env"] } clap = { version = "4.5.18", features = ["derive", "env"] }
egui = "0.32.3" egui = "0.28.1"
eframe = "0.32.3" eframe = "0.28.1"
lazy_static = "1.5.0" lazy_static = "1.5.0"

View File

@@ -1,6 +1,7 @@
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
/// Get the current time since epoch /// Get the current time since epoch
pub fn time_millis() -> u128 { pub fn time_millis() -> u128 {
SystemTime::now() SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)

View File

@@ -1,7 +1,5 @@
# Configure project for production # Configure project for production
Note: This guide assumes that you use the default hostname, `central.internal` as hostname for your central system.
## Create production build ## Create production build
### Central ### Central
@@ -46,146 +44,5 @@ The OTA update is then located in `build/main.bin`
* A server running a recent Linux (Debian / Ubuntu preferred) with `central` as hostname * A server running a recent Linux (Debian / Ubuntu preferred) with `central` as hostname
* DHCP configured on the network * DHCP configured on the network
## Configure DNS server
If you need to setup a DNS server / proxy to point `central.internal` to the central server IP, you can follow this guide.
### Retrieve DNS server binary
Use [DNSProxy](https://gitlab.com/pierre42100/dnsproxy) as DNS server. Get and compile the sources:
```bash
git clone https://gitlab.com/pierre42100/dnsproxy
cd dnsproxy
cargo build --release
scp target/release/dns_proxy USER@CENTRAL_IP:/home/USER
```
Then, on the target server, install the binary to its final destination:
```bash
sudo mv dns_proxy /usr/local/bin/
```
### Configure DNS server
Configure the server as a service `/etc/systemd/system/dns.service`:
```conf
[Unit]
Description=DNS server
After=syslog.target
After=network.target
[Service]
RestartSec=2s
Type=simple
User=root
Group=root
WorkingDirectory=/tmp
ExecStart=/usr/local/bin/dns_proxy -l "CENTRAL_IP:53" -c "central.internal. A CENTRAL_IP"
Restart=always
[Install]
WantedBy=multi-user.target
```
Enable and start the new service:
```bash
sudo systemctl enable dns
sudo systemctl start dns
```
Check that it works correctly:
```bash
dig central.internal. @CENTRAL_IP
```
You should get an entry like this if it works:
```
;; ANSWER SECTION:
central.internal. 0 IN A CENTRAL_IP
```
Then, in your DHCP service, define the central as the DNS server.
## Configure server ## Configure server
TODO
### Create a user dedicated to the central
```bash
sudo adduser --disabled-login central
```
### Install binary
You can use `scp` to copy the binary to the target server:
```bash
scp central_backend/target/release/central_backend pierre@central:/home/pierre
```
Then the executable must be installed system-wide:
```bash
sudo mv central_backend /usr/local/bin/
```
### Create configuration file
Create a configuration file in `/home/central/config.yaml`:
```bash
sudo touch /home/central/config.yaml
sudo chown central:central /home/central/config.yaml
sudo chmod 400 /home/central/config.yaml
sudo nano /home/central/config.yaml
```
Sample configuration:
```conf
SECRET=RANDOM_VALUE
COOKIE_SECURE=true
LISTEN_ADDRESS=0.0.0.0:443
ADMIN_USERNAME=admin
ADMIN_PASSWORD=FIXME
HOSTNAME=central.internal
STORAGE=/home/central/storage
FRONIUS_ORIG=http://10.0.0.10
```
### Test configuration
Run the following command to check if the configuration is working:
```bash
sudo -u central central_backend -c /home/central/config.yaml fronius -c
```
### Create systemd unit file
Once you confirmed the configuration is working, you can configure a system service, in `/etc/systemd/system/central.service`:
```conf
[Unit]
Description=Central backend server
After=syslog.target
After=network.target
[Service]
RestartSec=2s
Type=simple
User=central
Group=central
WorkingDirectory=/home/central
ExecStart=/usr/local/bin/central_backend -c /home/central/config.yaml fronius -c
Restart=always
Environment=USER=central
HOME=/home/central
[Install]
WantedBy=multi-user.target
```
Enable & start service:
```bash
sudo systemctl enable central
sudo systemctl start central
```

View File

@@ -2,11 +2,6 @@
ESP32 client device, using `W32-ETH01` device ESP32 client device, using `W32-ETH01` device
## Pins for relays
The pins are the following (in the order of definition): 4, 14, 15, 2
**WARNING!** The Pin 2 MUST be disconnect to reflash the card!
## Some commands ## Some commands
Create a new firmware build: Create a new firmware build:

View File

@@ -8,7 +8,7 @@
/** /**
* Backend unsecure API URL * Backend unsecure API URL
*/ */
#define BACKEND_UNSECURE_URL "http://central.internal:8080" #define BACKEND_UNSECURE_URL "http://devweb.internal:8080"
/** /**
* Device name len * Device name len

View File

@@ -1,3 +1,5 @@
#define CONFIG_ETH_USE_ESP32_EMAC
#include "esp_eth.h" #include "esp_eth.h"
#include "esp_eth_mac.h" #include "esp_eth_mac.h"
#include "esp_eth_com.h" #include "esp_eth_com.h"
@@ -82,8 +84,8 @@ void ethernet_init()
eth_esp32_emac_config_t mac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); eth_esp32_emac_config_t mac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
mac_config.clock_config.rmii.clock_mode = EMAC_CLK_EXT_IN; mac_config.clock_config.rmii.clock_mode = EMAC_CLK_EXT_IN;
mac_config.clock_config.rmii.clock_gpio = EMAC_CLK_IN_GPIO; mac_config.clock_config.rmii.clock_gpio = EMAC_CLK_IN_GPIO;
mac_config.smi_gpio.mdc_num = GPIO_NUM_23; mac_config.smi_mdc_gpio_num = GPIO_NUM_23;
mac_config.smi_gpio.mdio_num = GPIO_NUM_18; mac_config.smi_mdio_gpio_num = GPIO_NUM_18;
eth_mac_config_t eth_mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_mac_config_t eth_mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_mac_config.sw_reset_timeout_ms = 1000; eth_mac_config.sw_reset_timeout_ms = 1000;

View File

@@ -9,7 +9,7 @@ static const char *TAG = "relays";
/** /**
* Device relays GPIO ids * Device relays GPIO ids
*/ */
static int DEVICE_GPIO_IDS[4] = {4, 14, 15, 2}; static int DEVICE_GPIO_IDS[3] = {4, 14, 15};
int relays_count() int relays_count()
{ {

View File

@@ -1,6 +1,6 @@
# #
# Automatically generated file. DO NOT EDIT. # Automatically generated file. DO NOT EDIT.
# Espressif IoT Development Framework (ESP-IDF) 5.3.1 Project Configuration # Espressif IoT Development Framework (ESP-IDF) 5.2.2 Project Configuration
# #
CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined" CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined"
CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined" CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined"
@@ -14,7 +14,6 @@ CONFIG_SOC_GPTIMER_SUPPORTED=y
CONFIG_SOC_SDMMC_HOST_SUPPORTED=y CONFIG_SOC_SDMMC_HOST_SUPPORTED=y
CONFIG_SOC_BT_SUPPORTED=y CONFIG_SOC_BT_SUPPORTED=y
CONFIG_SOC_PCNT_SUPPORTED=y CONFIG_SOC_PCNT_SUPPORTED=y
CONFIG_SOC_PHY_SUPPORTED=y
CONFIG_SOC_WIFI_SUPPORTED=y CONFIG_SOC_WIFI_SUPPORTED=y
CONFIG_SOC_SDIO_SLAVE_SUPPORTED=y CONFIG_SOC_SDIO_SLAVE_SUPPORTED=y
CONFIG_SOC_TWAI_SUPPORTED=y CONFIG_SOC_TWAI_SUPPORTED=y
@@ -44,11 +43,6 @@ CONFIG_SOC_CLK_TREE_SUPPORTED=y
CONFIG_SOC_MPU_SUPPORTED=y CONFIG_SOC_MPU_SUPPORTED=y
CONFIG_SOC_WDT_SUPPORTED=y CONFIG_SOC_WDT_SUPPORTED=y
CONFIG_SOC_SPI_FLASH_SUPPORTED=y CONFIG_SOC_SPI_FLASH_SUPPORTED=y
CONFIG_SOC_RNG_SUPPORTED=y
CONFIG_SOC_LIGHT_SLEEP_SUPPORTED=y
CONFIG_SOC_DEEP_SLEEP_SUPPORTED=y
CONFIG_SOC_LP_PERIPH_SHARE_INTERRUPT=y
CONFIG_SOC_PM_SUPPORTED=y
CONFIG_SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL=5 CONFIG_SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL=5
CONFIG_SOC_XTAL_SUPPORT_26M=y CONFIG_SOC_XTAL_SUPPORT_26M=y
CONFIG_SOC_XTAL_SUPPORT_40M=y CONFIG_SOC_XTAL_SUPPORT_40M=y
@@ -90,9 +84,7 @@ CONFIG_SOC_GPIO_IN_RANGE_MAX=39
CONFIG_SOC_GPIO_OUT_RANGE_MAX=33 CONFIG_SOC_GPIO_OUT_RANGE_MAX=33
CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA
CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX=y CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX=y
CONFIG_SOC_GPIO_CLOCKOUT_CHANNEL_NUM=3
CONFIG_SOC_I2C_NUM=2 CONFIG_SOC_I2C_NUM=2
CONFIG_SOC_HP_I2C_NUM=2
CONFIG_SOC_I2C_FIFO_LEN=32 CONFIG_SOC_I2C_FIFO_LEN=32
CONFIG_SOC_I2C_CMD_REG_NUM=16 CONFIG_SOC_I2C_CMD_REG_NUM=16
CONFIG_SOC_I2C_SUPPORT_SLAVE=y CONFIG_SOC_I2C_SUPPORT_SLAVE=y
@@ -172,9 +164,9 @@ CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=2
CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64 CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64
CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4 CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4
CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y
CONFIG_SOC_TOUCH_SENSOR_VERSION=1 CONFIG_SOC_TOUCH_VERSION_1=y
CONFIG_SOC_TOUCH_SENSOR_NUM=10 CONFIG_SOC_TOUCH_SENSOR_NUM=10
CONFIG_SOC_TOUCH_SAMPLE_CFG_NUM=1 CONFIG_SOC_TOUCH_PAD_MEASURE_WAIT_MAX=0xFF
CONFIG_SOC_TWAI_CONTROLLER_NUM=1 CONFIG_SOC_TWAI_CONTROLLER_NUM=1
CONFIG_SOC_TWAI_BRP_MIN=2 CONFIG_SOC_TWAI_BRP_MIN=2
CONFIG_SOC_TWAI_CLK_SUPPORT_APB=y CONFIG_SOC_TWAI_CLK_SUPPORT_APB=y
@@ -230,10 +222,8 @@ CONFIG_SOC_BLE_SUPPORTED=y
CONFIG_SOC_BLE_MESH_SUPPORTED=y CONFIG_SOC_BLE_MESH_SUPPORTED=y
CONFIG_SOC_BT_CLASSIC_SUPPORTED=y CONFIG_SOC_BT_CLASSIC_SUPPORTED=y
CONFIG_SOC_BLUFI_SUPPORTED=y CONFIG_SOC_BLUFI_SUPPORTED=y
CONFIG_SOC_BT_H2C_ENC_KEY_CTRL_ENH_VSC_SUPPORTED=y
CONFIG_SOC_ULP_HAS_ADC=y CONFIG_SOC_ULP_HAS_ADC=y
CONFIG_SOC_PHY_COMBO_MODULE=y CONFIG_SOC_PHY_COMBO_MODULE=y
CONFIG_SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK=y
CONFIG_IDF_CMAKE=y CONFIG_IDF_CMAKE=y
CONFIG_IDF_TOOLCHAIN="gcc" CONFIG_IDF_TOOLCHAIN="gcc"
CONFIG_IDF_TARGET_ARCH_XTENSA=y CONFIG_IDF_TARGET_ARCH_XTENSA=y
@@ -329,13 +319,9 @@ CONFIG_ESP_ROM_HAS_MZ_CRC32=y
CONFIG_ESP_ROM_HAS_JPEG_DECODE=y CONFIG_ESP_ROM_HAS_JPEG_DECODE=y
CONFIG_ESP_ROM_HAS_UART_BUF_SWITCH=y CONFIG_ESP_ROM_HAS_UART_BUF_SWITCH=y
CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y
CONFIG_ESP_ROM_HAS_NEWLIB=y
CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT=y CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT=y
CONFIG_ESP_ROM_HAS_NEWLIB_32BIT_TIME=y
CONFIG_ESP_ROM_HAS_SW_FLOAT=y CONFIG_ESP_ROM_HAS_SW_FLOAT=y
CONFIG_ESP_ROM_USB_OTG_NUM=-1
CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=-1 CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=-1
CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB=y
# #
# Serial flasher config # Serial flasher config
@@ -410,8 +396,6 @@ CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
# CONFIG_COMPILER_DUMP_RTL_FILES is not set # CONFIG_COMPILER_DUMP_RTL_FILES is not set
CONFIG_COMPILER_RT_LIB_GCCLIB=y CONFIG_COMPILER_RT_LIB_GCCLIB=y
CONFIG_COMPILER_RT_LIB_NAME="gcc" CONFIG_COMPILER_RT_LIB_NAME="gcc"
# CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING is not set
CONFIG_COMPILER_ORPHAN_SECTIONS_PLACE=y
# end of Compiler options # end of Compiler options
# #
@@ -437,16 +421,35 @@ CONFIG_APPTRACE_LOCK_ENABLE=y
CONFIG_BT_ALARM_MAX_NUM=50 CONFIG_BT_ALARM_MAX_NUM=50
# end of Bluetooth # end of Bluetooth
#
# Console Library
#
# CONFIG_CONSOLE_SORTED_HELP is not set
# end of Console Library
# #
# Driver Configurations # Driver Configurations
# #
#
# Legacy ADC Configuration
#
CONFIG_ADC_DISABLE_DAC=y
# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set
#
# Legacy ADC Calibration Configuration
#
CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y
CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y
CONFIG_ADC_CAL_LUT_ENABLE=y
# CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN is not set
# end of Legacy ADC Calibration Configuration
# end of Legacy ADC Configuration
#
# SPI Configuration
#
# CONFIG_SPI_MASTER_IN_IRAM is not set
CONFIG_SPI_MASTER_ISR_IN_IRAM=y
# CONFIG_SPI_SLAVE_IN_IRAM is not set
CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
# end of SPI Configuration
# #
# TWAI Configuration # TWAI Configuration
# #
@@ -459,62 +462,93 @@ CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y
# end of TWAI Configuration # end of TWAI Configuration
# #
# Legacy ADC Driver Configuration # UART Configuration
# #
CONFIG_ADC_DISABLE_DAC=y # CONFIG_UART_ISR_IN_IRAM is not set
# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set # end of UART Configuration
# #
# Legacy ADC Calibration Configuration # GPIO Configuration
# #
CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y # CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL is not set
CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y # CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set
CONFIG_ADC_CAL_LUT_ENABLE=y # end of GPIO Configuration
# CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN is not set
# end of Legacy ADC Calibration Configuration
# end of Legacy ADC Driver Configuration
# #
# Legacy DAC Driver Configurations # Sigma Delta Modulator Configuration
#
# CONFIG_DAC_SUPPRESS_DEPRECATE_WARN is not set
# end of Legacy DAC Driver Configurations
#
# Legacy MCPWM Driver Configurations
#
# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set
# end of Legacy MCPWM Driver Configurations
#
# Legacy Timer Group Driver Configurations
#
# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set
# end of Legacy Timer Group Driver Configurations
#
# Legacy RMT Driver Configurations
#
# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set
# end of Legacy RMT Driver Configurations
#
# Legacy I2S Driver Configurations
#
# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set
# end of Legacy I2S Driver Configurations
#
# Legacy PCNT Driver Configurations
#
# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set
# end of Legacy PCNT Driver Configurations
#
# Legacy SDM Driver Configurations
# #
# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set
# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set # CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set
# end of Legacy SDM Driver Configurations # CONFIG_SDM_ENABLE_DEBUG_LOG is not set
# end of Sigma Delta Modulator Configuration
#
# GPTimer Configuration
#
CONFIG_GPTIMER_ISR_HANDLER_IN_IRAM=y
# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set
# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set
# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set
# end of GPTimer Configuration
#
# PCNT Configuration
#
# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set
# CONFIG_PCNT_ISR_IRAM_SAFE is not set
# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set
# end of PCNT Configuration
#
# RMT Configuration
#
# CONFIG_RMT_ISR_IRAM_SAFE is not set
# CONFIG_RMT_RECV_FUNC_IN_IRAM is not set
# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_RMT_ENABLE_DEBUG_LOG is not set
# end of RMT Configuration
#
# MCPWM Configuration
#
# CONFIG_MCPWM_ISR_IRAM_SAFE is not set
# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set
# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set
# end of MCPWM Configuration
#
# I2S Configuration
#
# CONFIG_I2S_ISR_IRAM_SAFE is not set
# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_I2S_ENABLE_DEBUG_LOG is not set
# end of I2S Configuration
#
# DAC Configuration
#
# CONFIG_DAC_CTRL_FUNC_IN_IRAM is not set
# CONFIG_DAC_ISR_IRAM_SAFE is not set
# CONFIG_DAC_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_DAC_ENABLE_DEBUG_LOG is not set
CONFIG_DAC_DMA_AUTO_16BIT_ALIGN=y
# end of DAC Configuration
#
# LEDC Configuration
#
# CONFIG_LEDC_CTRL_FUNC_IN_IRAM is not set
# end of LEDC Configuration
#
# I2C Configuration
#
# CONFIG_I2C_ISR_IRAM_SAFE is not set
# CONFIG_I2C_ENABLE_DEBUG_LOG is not set
# end of I2C Configuration
# end of Driver Configurations # end of Driver Configurations
# #
@@ -534,9 +568,7 @@ CONFIG_EFUSE_MAX_BLK_LEN=192
CONFIG_ESP_TLS_USING_MBEDTLS=y CONFIG_ESP_TLS_USING_MBEDTLS=y
# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set # CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set
# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set # CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set
# CONFIG_ESP_TLS_SERVER_SESSION_TICKETS is not set # CONFIG_ESP_TLS_SERVER is not set
# CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK is not set
# CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL is not set
# CONFIG_ESP_TLS_PSK_VERIFICATION is not set # CONFIG_ESP_TLS_PSK_VERIFICATION is not set
# CONFIG_ESP_TLS_INSECURE is not set # CONFIG_ESP_TLS_INSECURE is not set
# end of ESP-TLS # end of ESP-TLS
@@ -556,13 +588,11 @@ CONFIG_ADC_CALI_LUT_ENABLE=y
# end of ADC Calibration Configurations # end of ADC Calibration Configurations
CONFIG_ADC_DISABLE_DAC_OUTPUT=y CONFIG_ADC_DISABLE_DAC_OUTPUT=y
# CONFIG_ADC_ENABLE_DEBUG_LOG is not set
# end of ADC and ADC Calibration # end of ADC and ADC Calibration
# #
# Wireless Coexistence # Wireless Coexistence
# #
CONFIG_ESP_COEX_ENABLED=y
# end of Wireless Coexistence # end of Wireless Coexistence
# #
@@ -571,105 +601,6 @@ CONFIG_ESP_COEX_ENABLED=y
CONFIG_ESP_ERR_TO_NAME_LOOKUP=y CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
# end of Common ESP-related # end of Common ESP-related
#
# ESP-Driver:DAC Configurations
#
# CONFIG_DAC_CTRL_FUNC_IN_IRAM is not set
# CONFIG_DAC_ISR_IRAM_SAFE is not set
# CONFIG_DAC_ENABLE_DEBUG_LOG is not set
CONFIG_DAC_DMA_AUTO_16BIT_ALIGN=y
# end of ESP-Driver:DAC Configurations
#
# ESP-Driver:GPIO Configurations
#
# CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL is not set
# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set
# end of ESP-Driver:GPIO Configurations
#
# ESP-Driver:GPTimer Configurations
#
CONFIG_GPTIMER_ISR_HANDLER_IN_IRAM=y
# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set
# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set
# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set
# end of ESP-Driver:GPTimer Configurations
#
# ESP-Driver:I2C Configurations
#
# CONFIG_I2C_ISR_IRAM_SAFE is not set
# CONFIG_I2C_ENABLE_DEBUG_LOG is not set
# end of ESP-Driver:I2C Configurations
#
# ESP-Driver:I2S Configurations
#
# CONFIG_I2S_ISR_IRAM_SAFE is not set
# CONFIG_I2S_ENABLE_DEBUG_LOG is not set
# end of ESP-Driver:I2S Configurations
#
# ESP-Driver:LEDC Configurations
#
# CONFIG_LEDC_CTRL_FUNC_IN_IRAM is not set
# end of ESP-Driver:LEDC Configurations
#
# ESP-Driver:MCPWM Configurations
#
# CONFIG_MCPWM_ISR_IRAM_SAFE is not set
# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set
# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set
# end of ESP-Driver:MCPWM Configurations
#
# ESP-Driver:PCNT Configurations
#
# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set
# CONFIG_PCNT_ISR_IRAM_SAFE is not set
# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set
# end of ESP-Driver:PCNT Configurations
#
# ESP-Driver:RMT Configurations
#
# CONFIG_RMT_ISR_IRAM_SAFE is not set
# CONFIG_RMT_RECV_FUNC_IN_IRAM is not set
# CONFIG_RMT_ENABLE_DEBUG_LOG is not set
# end of ESP-Driver:RMT Configurations
#
# ESP-Driver:Sigma Delta Modulator Configurations
#
# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set
# CONFIG_SDM_ENABLE_DEBUG_LOG is not set
# end of ESP-Driver:Sigma Delta Modulator Configurations
#
# ESP-Driver:SPI Configurations
#
# CONFIG_SPI_MASTER_IN_IRAM is not set
CONFIG_SPI_MASTER_ISR_IN_IRAM=y
# CONFIG_SPI_SLAVE_IN_IRAM is not set
CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
# end of ESP-Driver:SPI Configurations
#
# ESP-Driver:Touch Sensor Configurations
#
# CONFIG_TOUCH_CTRL_FUNC_IN_IRAM is not set
# CONFIG_TOUCH_ISR_IRAM_SAFE is not set
# CONFIG_TOUCH_ENABLE_DEBUG_LOG is not set
# end of ESP-Driver:Touch Sensor Configurations
#
# ESP-Driver:UART Configurations
#
# CONFIG_UART_ISR_IN_IRAM is not set
# end of ESP-Driver:UART Configurations
# #
# Ethernet # Ethernet
# #
@@ -714,7 +645,6 @@ CONFIG_ESP_GDBSTUB_MAX_TASKS=32
CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set # CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set # CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set
# CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT is not set
# end of ESP HTTP client # end of ESP HTTP client
# #
@@ -774,7 +704,6 @@ CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y
CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y
CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y
CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR=y CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR=y
CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES=4
# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set # CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set
CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y
CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4 CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4
@@ -820,8 +749,6 @@ CONFIG_XTAL_FREQ_40=y
# CONFIG_XTAL_FREQ_AUTO is not set # CONFIG_XTAL_FREQ_AUTO is not set
CONFIG_XTAL_FREQ=40 CONFIG_XTAL_FREQ=40
# end of Main XTAL Config # end of Main XTAL Config
CONFIG_ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM=y
# end of Hardware Settings # end of Hardware Settings
# #
@@ -860,7 +787,6 @@ CONFIG_ESP_NETIF_USES_TCPIP_WITH_BSD_API=y
# #
# PHY # PHY
# #
CONFIG_ESP_PHY_ENABLED=y
CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set # CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set
CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20
@@ -942,7 +868,6 @@ CONFIG_ESP_CONSOLE_UART_DEFAULT=y
# CONFIG_ESP_CONSOLE_NONE is not set # CONFIG_ESP_CONSOLE_NONE is not set
CONFIG_ESP_CONSOLE_UART=y CONFIG_ESP_CONSOLE_UART=y
CONFIG_ESP_CONSOLE_UART_NUM=0 CONFIG_ESP_CONSOLE_UART_NUM=0
CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=0
CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
CONFIG_ESP_INT_WDT=y CONFIG_ESP_INT_WDT=y
CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
@@ -987,7 +912,7 @@ CONFIG_ESP_IPC_ISR_ENABLE=y
# end of IPC (Inter-Processor Call) # end of IPC (Inter-Processor Call)
# #
# ESP Timer (High Resolution Timer) # High resolution timer (esp_timer)
# #
# CONFIG_ESP_TIMER_PROFILING is not set # CONFIG_ESP_TIMER_PROFILING is not set
CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y
@@ -997,10 +922,11 @@ CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1
# CONFIG_ESP_TIMER_SHOW_EXPERIMENTAL is not set # CONFIG_ESP_TIMER_SHOW_EXPERIMENTAL is not set
CONFIG_ESP_TIMER_TASK_AFFINITY=0x0 CONFIG_ESP_TIMER_TASK_AFFINITY=0x0
CONFIG_ESP_TIMER_TASK_AFFINITY_CPU0=y CONFIG_ESP_TIMER_TASK_AFFINITY_CPU0=y
CONFIG_ESP_TIMER_ISR_AFFINITY=0x1
CONFIG_ESP_TIMER_ISR_AFFINITY_CPU0=y CONFIG_ESP_TIMER_ISR_AFFINITY_CPU0=y
# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set # CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set
CONFIG_ESP_TIMER_IMPL_TG0_LAC=y CONFIG_ESP_TIMER_IMPL_TG0_LAC=y
# end of ESP Timer (High Resolution Timer) # end of High resolution timer (esp_timer)
# #
# Wi-Fi # Wi-Fi
@@ -1034,9 +960,6 @@ CONFIG_ESP_WIFI_ENABLE_SAE_PK=y
CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT=y CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT=y
CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA=y CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA=y
# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set # CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set
CONFIG_ESP_WIFI_SLP_DEFAULT_MIN_ACTIVE_TIME=50
CONFIG_ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME=10
CONFIG_ESP_WIFI_SLP_DEFAULT_WAIT_BROADCAST_DATA_TIME=15
CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y
# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set # CONFIG_ESP_WIFI_GMAC_SUPPORT is not set
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y
@@ -1111,8 +1034,6 @@ CONFIG_FATFS_PER_FILE_CACHE=y
# CONFIG_FATFS_USE_FASTSEEK is not set # CONFIG_FATFS_USE_FASTSEEK is not set
CONFIG_FATFS_VFS_FSTAT_BLKSIZE=0 CONFIG_FATFS_VFS_FSTAT_BLKSIZE=0
# CONFIG_FATFS_IMMEDIATE_FSYNC is not set # CONFIG_FATFS_IMMEDIATE_FSYNC is not set
# CONFIG_FATFS_USE_LABEL is not set
CONFIG_FATFS_LINK_LOCK=y
# end of FAT Filesystem support # end of FAT Filesystem support
# #
@@ -1135,17 +1056,12 @@ CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set # CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set
CONFIG_FREERTOS_TIMER_SERVICE_TASK_NAME="Tmr Svc" CONFIG_FREERTOS_TIMER_SERVICE_TASK_NAME="Tmr Svc"
# CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0 is not set
# CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU1 is not set
CONFIG_FREERTOS_TIMER_TASK_NO_AFFINITY=y
CONFIG_FREERTOS_TIMER_SERVICE_TASK_CORE_AFFINITY=0x7FFFFFFF
CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048 CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1 CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1
# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set # CONFIG_FREERTOS_USE_TRACE_FACILITY is not set
# CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES is not set
# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set # CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set
# CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set # CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set
# end of Kernel # end of Kernel
@@ -1176,7 +1092,6 @@ CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
CONFIG_FREERTOS_DEBUG_OCDAWARE=y CONFIG_FREERTOS_DEBUG_OCDAWARE=y
CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y
CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH=y CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH=y
CONFIG_FREERTOS_NUMBER_OF_CORES=2
# end of FreeRTOS # end of FreeRTOS
# #
@@ -1303,7 +1218,6 @@ CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5760 CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5760
CONFIG_LWIP_TCP_WND_DEFAULT=5760 CONFIG_LWIP_TCP_WND_DEFAULT=5760
CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 CONFIG_LWIP_TCP_RECVMBOX_SIZE=6
CONFIG_LWIP_TCP_ACCEPTMBOX_SIZE=6
CONFIG_LWIP_TCP_QUEUE_OOSEQ=y CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
CONFIG_LWIP_TCP_OOSEQ_TIMEOUT=6 CONFIG_LWIP_TCP_OOSEQ_TIMEOUT=6
CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=4 CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=4
@@ -1359,8 +1273,6 @@ CONFIG_LWIP_MAX_RAW_PCBS=16
CONFIG_LWIP_SNTP_MAX_SERVERS=1 CONFIG_LWIP_SNTP_MAX_SERVERS=1
# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set # CONFIG_LWIP_DHCP_GET_NTP_SRV is not set
CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
CONFIG_LWIP_SNTP_STARTUP_DELAY=y
CONFIG_LWIP_SNTP_MAXIMUM_STARTUP_DELAY=5000
# end of SNTP # end of SNTP
# #
@@ -1430,7 +1342,6 @@ CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y
# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set # CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set
# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set # CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set
# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set # CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set
# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEPRECATED_LIST is not set
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200
# end of Certificate Bundle # end of Certificate Bundle
@@ -1640,7 +1551,6 @@ CONFIG_SPI_FLASH_BROWNOUT_RESET=y
# #
# Features here require specific hardware (READ DOCS FIRST!) # Features here require specific hardware (READ DOCS FIRST!)
# #
CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US=50
# end of Optional and Experimental Features (READ DOCS FIRST) # end of Optional and Experimental Features (READ DOCS FIRST)
# end of Main Flash configuration # end of Main Flash configuration
@@ -1735,11 +1645,6 @@ CONFIG_WS_BUFFER_SIZE=1024
# Ultra Low Power (ULP) Co-processor # Ultra Low Power (ULP) Co-processor
# #
# CONFIG_ULP_COPROC_ENABLED is not set # CONFIG_ULP_COPROC_ENABLED is not set
#
# ULP Debugging Options
#
# end of ULP Debugging Options
# end of Ultra Low Power (ULP) Co-processor # end of Ultra Low Power (ULP) Co-processor
# #

View File

@@ -1 +1 @@
1.0.3 1.0.0

View File

@@ -1,3 +1,9 @@
{ {
"extends": ["local>renovate/presets"] "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"packageRules": [
{
"matchUpdateTypes": ["major", "minor", "patch"],
"automerge": true
}
]
} }