adust pcb to new 3.3 software improvements

This commit is contained in:
Empire 2024-12-30 20:19:37 +01:00
parent 58b63fc8ee
commit 1927449c1d
22 changed files with 16833 additions and 13984 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"board": { "board": {
"active_layer": 1, "active_layer": 0,
"active_layer_preset": "", "active_layer_preset": "",
"auto_track_width": false, "auto_track_width": false,
"hidden_netclasses": [], "hidden_netclasses": [],
@ -68,7 +68,7 @@
39, 39,
40 40
], ],
"visible_layers": "ffc7fff_ffffffff", "visible_layers": "ffc35ba_ffffffff",
"zone_display_mode": 1 "zone_display_mode": 1
}, },
"git": { "git": {

File diff suppressed because it is too large Load Diff

View File

@ -10,11 +10,7 @@ use chrono_tz::{Europe::Berlin, Tz};
use config::Mode; use config::Mode;
use esp_idf_hal::delay::Delay; use esp_idf_hal::delay::Delay;
use esp_idf_sys::{ use esp_idf_sys::{
esp_deep_sleep, esp_ota_get_app_partition_count, esp_ota_get_running_partition, esp_deep_sleep, esp_ota_get_app_partition_count, esp_ota_get_running_partition, esp_ota_get_state_partition, esp_ota_img_states_t, esp_ota_img_states_t_ESP_OTA_IMG_ABORTED, esp_ota_img_states_t_ESP_OTA_IMG_INVALID, esp_ota_img_states_t_ESP_OTA_IMG_NEW, esp_ota_img_states_t_ESP_OTA_IMG_PENDING_VERIFY, esp_ota_img_states_t_ESP_OTA_IMG_UNDEFINED, esp_ota_img_states_t_ESP_OTA_IMG_VALID, esp_restart, esp_sleep_enable_ext1_wakeup, esp_sleep_ext1_wakeup_mode_t_ESP_EXT1_WAKEUP_ANY_LOW, vTaskDelay, CONFIG_FREERTOS_HZ
esp_ota_get_state_partition, esp_ota_img_states_t, esp_ota_img_states_t_ESP_OTA_IMG_ABORTED,
esp_ota_img_states_t_ESP_OTA_IMG_INVALID, esp_ota_img_states_t_ESP_OTA_IMG_NEW,
esp_ota_img_states_t_ESP_OTA_IMG_PENDING_VERIFY, esp_ota_img_states_t_ESP_OTA_IMG_UNDEFINED,
esp_ota_img_states_t_ESP_OTA_IMG_VALID, esp_restart, vTaskDelay, CONFIG_FREERTOS_HZ,
}; };
use log::error; use log::error;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@ -126,16 +122,6 @@ struct PlantStateMQTT<'a> {
last_pump: &'a str, last_pump: &'a str,
next_pump: &'a str, next_pump: &'a str,
} }
#[derive(Serialize)]
struct BatteryState<'a> {
voltage_milli_volt: &'a str,
current_milli_ampere: &'a str,
cycle_count: &'a str,
design_milli_ampere: &'a str,
remaining_milli_ampere: &'a str,
state_of_charge: &'a str,
state_of_health: &'a str,
}
fn safe_main() -> anyhow::Result<()> { fn safe_main() -> anyhow::Result<()> {
// It is necessary to call this function once. Otherwise some patches to the runtime // It is necessary to call this function once. Otherwise some patches to the runtime
@ -155,15 +141,16 @@ fn safe_main() -> anyhow::Result<()> {
log::info!("Startup Rust"); log::info!("Startup Rust");
let git_hash = env!("VERGEN_GIT_DESCRIBE"); let mut to_config = false;
let build_timestamp = env!("VERGEN_BUILD_TIMESTAMP");
let version = get_version();
println!( println!(
"Version useing git has {} build on {}", "Version useing git has {} build on {}",
git_hash, build_timestamp version.git_hash, version.build_time
); );
let count = unsafe { esp_ota_get_app_partition_count() }; let count = unsafe { esp_ota_get_app_partition_count() };
println!("Partit ion count is {}", count); println!("Partition count is {}", count);
let mut ota_state: esp_ota_img_states_t = 0; let mut ota_state: esp_ota_img_states_t = 0;
let running_partition = unsafe { esp_ota_get_running_partition() }; let running_partition = unsafe { esp_ota_get_running_partition() };
let address = unsafe { (*running_partition).address }; let address = unsafe { (*running_partition).address };
@ -192,6 +179,7 @@ fn safe_main() -> anyhow::Result<()> {
println!("Board hal init"); println!("Board hal init");
let mut board: std::sync::MutexGuard<'_, PlantCtrlBoard<'_>> = BOARD_ACCESS.lock().unwrap(); let mut board: std::sync::MutexGuard<'_, PlantCtrlBoard<'_>> = BOARD_ACCESS.lock().unwrap();
board.general_fault(false); board.general_fault(false);
println!("Mounting filesystem"); println!("Mounting filesystem");
board.mount_file_system()?; board.mount_file_system()?;
let free_space = board.file_system_size()?; let free_space = board.file_system_size()?;
@ -232,8 +220,18 @@ fn safe_main() -> anyhow::Result<()> {
println!("cur is {}", cur); println!("cur is {}", cur);
let mut to_config = false; if board.get_restart_to_conf() {
if board.is_mode_override() { println!("config mode software override");
for _i in 0..2 {
board.general_fault(true);
Delay::new_default().delay_ms(100);
board.general_fault(false);
Delay::new_default().delay_ms(100);
}
to_config = true;
board.general_fault(true);
board.set_restart_to_conf(false);
} else if board.is_mode_override() {
board.general_fault(true); board.general_fault(true);
println!("config mode override is pressed, waiting 5s"); println!("config mode override is pressed, waiting 5s");
for _i in 0..5 { for _i in 0..5 {
@ -244,12 +242,16 @@ fn safe_main() -> anyhow::Result<()> {
} }
if board.is_mode_override() { if board.is_mode_override() {
board.general_fault(true);
to_config = true; to_config = true;
} else { } else {
board.general_fault(false); board.general_fault(false);
} }
} else {
println!("No config override start detected");
} }
let config: PlantControllerConfig; let config: PlantControllerConfig;
match board.get_config() { match board.get_config() {
Ok(valid) => { Ok(valid) => {
@ -293,7 +295,7 @@ fn safe_main() -> anyhow::Result<()> {
board.general_fault(true); board.general_fault(true);
} }
} }
if (config.network.mqtt_url.is_some()) { if config.network.mqtt_url.is_some() {
match board.mqtt(&config) { match board.mqtt(&config) {
Ok(_) => { Ok(_) => {
println!("Mqtt connection ready"); println!("Mqtt connection ready");
@ -338,8 +340,12 @@ fn safe_main() -> anyhow::Result<()> {
if mqtt { if mqtt {
let ip_string = ip_address.unwrap_or("N/A".to_owned()); let ip_string = ip_address.unwrap_or("N/A".to_owned());
let _ = board.mqtt_publish(&config, "/firmware/address", ip_string.as_bytes()); let _ = board.mqtt_publish(&config, "/firmware/address", ip_string.as_bytes());
let _ = board.mqtt_publish(&config, "/firmware/githash", git_hash.as_bytes()); let _ = board.mqtt_publish(&config, "/firmware/githash", version.git_hash.as_bytes());
let _ = board.mqtt_publish(&config, "/firmware/buildtime", build_timestamp.as_bytes()); let _ = board.mqtt_publish(
&config,
"/firmware/buildtime",
version.build_time.as_bytes(),
);
let _ = board.mqtt_publish( let _ = board.mqtt_publish(
&config, &config,
"/firmware/last_online", "/firmware/last_online",
@ -425,6 +431,7 @@ fn safe_main() -> anyhow::Result<()> {
); );
let stay_alive_mqtt = STAY_ALIVE.load(std::sync::atomic::Ordering::Relaxed); let stay_alive_mqtt = STAY_ALIVE.load(std::sync::atomic::Ordering::Relaxed);
let stay_alive = stay_alive_mqtt; let stay_alive = stay_alive_mqtt;
println!("Check stay alive, current state is {}", stay_alive); println!("Check stay alive, current state is {}", stay_alive);
@ -550,23 +557,17 @@ fn safe_main() -> anyhow::Result<()> {
let _webserver = httpd(reboot_now.clone()); let _webserver = httpd(reboot_now.clone());
wait_infinity(WaitType::MqttConfig, reboot_now.clone()); wait_infinity(WaitType::MqttConfig, reboot_now.clone());
} }
unsafe {
unsafe { esp_deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64) }; esp_sleep_enable_ext1_wakeup(0b10u64, esp_sleep_ext1_wakeup_mode_t_ESP_EXT1_WAKEUP_ANY_LOW);
esp_deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64)
};
} }
fn publish_battery_state( fn publish_battery_state(
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>, board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
config: &PlantControllerConfig, config: &PlantControllerConfig,
) { ) {
let bat = BatteryState { let bat = board.get_battery_state();
voltage_milli_volt: &to_string(&board.voltage_milli_volt()),
current_milli_ampere: &to_string(&board.average_current_milli_ampere()),
cycle_count: &to_string(&board.cycle_count()),
design_milli_ampere: &to_string(&board.design_milli_ampere_hour()),
remaining_milli_ampere: &to_string(&board.remaining_milli_ampere_hour()),
state_of_charge: &to_string(&board.state_charge_percent()),
state_of_health: &to_string(&board.state_health_percent()),
};
match serde_json::to_string(&bat) { match serde_json::to_string(&bat) {
Ok(state) => { Ok(state) => {
let _ = board.mqtt_publish(&config, "/battery", state.as_bytes()); let _ = board.mqtt_publish(&config, "/battery", state.as_bytes());
@ -1005,7 +1006,7 @@ fn sensor_to_string(value: &Option<u8>, error: &Option<SensorError>, enabled: bo
}; };
} }
fn to_string<T: Display>(value: &Result<T>) -> String { fn to_string<T: Display>(value: Result<T>) -> String {
return match value { return match value {
Ok(v) => v.to_string(), Ok(v) => v.to_string(),
Err(err) => { Err(err) => {
@ -1054,3 +1055,19 @@ fn in_time_range(cur: &DateTime<Tz>, start: u8, end: u8) -> bool {
return curhour > start || curhour < end; return curhour > start || curhour < end;
} }
} }
fn get_version() -> VersionInfo {
let branch = env!("VERGEN_GIT_BRANCH").to_owned();
let hash = &env!("VERGEN_GIT_SHA")[0..8];
return VersionInfo {
git_hash: (branch + "@" + hash),
build_time: env!("VERGEN_BUILD_TIMESTAMP").to_owned(),
};
}
#[derive(Serialize, Debug)]
struct VersionInfo {
git_hash: String,
build_time: String,
}

View File

@ -53,7 +53,7 @@ use esp_idf_sys::{esp, esp_spiffs_check, gpio_hold_dis, gpio_hold_en, vTaskDelay
use one_wire_bus::OneWire; use one_wire_bus::OneWire;
use crate::config::{self, PlantControllerConfig}; use crate::config::{self, PlantControllerConfig};
use crate::{plant_hal, STAY_ALIVE}; use crate::{plant_hal, to_string, STAY_ALIVE};
//Only support for 8 right now! //Only support for 8 right now!
pub const PLANT_COUNT: usize = 8; pub const PLANT_COUNT: usize = 8;
@ -117,6 +117,9 @@ static mut CONSECUTIVE_WATERING_PLANT: [u32; PLANT_COUNT] = [0; PLANT_COUNT];
#[link_section = ".rtc.data"] #[link_section = ".rtc.data"]
static mut LOW_VOLTAGE_DETECTED: bool = false; static mut LOW_VOLTAGE_DETECTED: bool = false;
#[link_section = ".rtc.data"]
static mut RESTART_TO_CONF: bool = false;
pub struct FileSystemSizeInfo { pub struct FileSystemSizeInfo {
pub total_size: usize, pub total_size: usize,
pub used_size: usize, pub used_size: usize,
@ -180,7 +183,33 @@ pub struct FileList {
iter_error: Option<String>, iter_error: Option<String>,
} }
#[derive(Serialize)]
pub struct BatteryState {
voltage_milli_volt: String,
current_milli_ampere: String,
cycle_count: String,
design_milli_ampere: String,
remaining_milli_ampere: String,
state_of_charge: String,
state_of_health: String,
temperature: String,
}
impl PlantCtrlBoard<'_> { impl PlantCtrlBoard<'_> {
pub fn get_battery_state(&mut self) -> BatteryState {
let bat = BatteryState {
voltage_milli_volt: to_string(self.voltage_milli_volt()),
current_milli_ampere: to_string(self.average_current_milli_ampere()),
cycle_count: to_string(self.cycle_count()),
design_milli_ampere: to_string(self.design_milli_ampere_hour()),
remaining_milli_ampere: to_string(self.remaining_milli_ampere_hour()),
state_of_charge: to_string(self.state_charge_percent()),
state_of_health: to_string(self.state_health_percent()),
temperature: to_string(self.bat_temperature()),
};
return bat;
}
pub fn list_files(&self, filename: &str) -> FileList { pub fn list_files(&self, filename: &str) -> FileList {
let storage = CString::new(SPIFFS_PARTITION_NAME).unwrap(); let storage = CString::new(SPIFFS_PARTITION_NAME).unwrap();
let error = unsafe { let error = unsafe {
@ -956,6 +985,16 @@ impl PlantCtrlBoard<'_> {
}; };
} }
pub fn get_restart_to_conf(&mut self) -> bool {
return unsafe { RESTART_TO_CONF };
}
pub fn set_restart_to_conf(&mut self, to_conf: bool) {
unsafe {
RESTART_TO_CONF = to_conf;
}
}
pub fn state_charge_percent(&mut self) -> Result<u8> { pub fn state_charge_percent(&mut self) -> Result<u8> {
match self.battery_driver.state_of_charge() { match self.battery_driver.state_of_charge() {
OkStd(r) => Ok(r), OkStd(r) => Ok(r),
@ -1012,6 +1051,13 @@ impl PlantCtrlBoard<'_> {
} }
} }
pub fn bat_temperature(&mut self) -> Result<u16> {
match self.battery_driver.temperature() {
OkStd(r) => Ok(r as u16),
Err(err) => bail!("Error reading Temperature {:?}", err),
}
}
pub fn flash_bq34_z100(&mut self, line: &str, dryrun: bool) -> Result<()> { pub fn flash_bq34_z100(&mut self, line: &str, dryrun: bool) -> Result<()> {
match self.battery_driver.write_flash_stream_i2c(line, dryrun) { match self.battery_driver.write_flash_stream_i2c(line, dryrun) {
OkStd(r) => Ok(r), OkStd(r) => Ok(r),
@ -1193,32 +1239,60 @@ impl PlantHal {
ms4.set_high()?; ms4.set_high()?;
//init,reset rtc memory depending on cause //init,reset rtc memory depending on cause
let mut init_rtc_store: bool = false;
let mut to_config_mode: bool = false;
let reasons = ResetReason::get(); let reasons = ResetReason::get();
let reset_store = match reasons { match reasons {
ResetReason::Software => false, ResetReason::Software => {},
ResetReason::ExternalPin => false, ResetReason::ExternalPin => {},
ResetReason::Watchdog => true, ResetReason::Watchdog => {
ResetReason::Sdio => true, init_rtc_store = true;
ResetReason::Panic => true, },
ResetReason::InterruptWatchdog => true, ResetReason::Sdio => {
ResetReason::PowerOn => true, init_rtc_store = true
ResetReason::Unknown => true, },
ResetReason::Brownout => true, ResetReason::Panic => {
ResetReason::TaskWatchdog => true, init_rtc_store = true
ResetReason::DeepSleep => false, },
ResetReason::USBPeripheral => true, ResetReason::InterruptWatchdog => {
ResetReason::JTAG => true, init_rtc_store = true
},
ResetReason::PowerOn => {
init_rtc_store = true
},
ResetReason::Unknown => {
init_rtc_store = true
},
ResetReason::Brownout => {
init_rtc_store = true
},
ResetReason::TaskWatchdog => {
init_rtc_store = true
},
ResetReason::DeepSleep => {},
ResetReason::USBPeripheral => {
init_rtc_store = true;
to_config_mode = true;
},
ResetReason::JTAG => {
init_rtc_store = true
},
}; };
if reset_store { println!("Reset due to {:?} requires rtc clear {} and force config mode {}", reasons, init_rtc_store, to_config_mode);
println!("Clear and reinit RTC store"); if init_rtc_store {
unsafe { unsafe {
LAST_WATERING_TIMESTAMP = [0; PLANT_COUNT]; LAST_WATERING_TIMESTAMP = [0; PLANT_COUNT];
CONSECUTIVE_WATERING_PLANT = [0; PLANT_COUNT]; CONSECUTIVE_WATERING_PLANT = [0; PLANT_COUNT];
LOW_VOLTAGE_DETECTED = false; LOW_VOLTAGE_DETECTED = false;
RESTART_TO_CONF = to_config_mode;
}; };
} else { } else {
println!("Keeping RTC store");
unsafe { unsafe {
if to_config_mode{
RESTART_TO_CONF = true;
}
println!("Current restart to conf mode{:?}", RESTART_TO_CONF);
println!( println!(
"Current low voltage detection is {:?}", "Current low voltage detection is {:?}",
LOW_VOLTAGE_DETECTED LOW_VOLTAGE_DETECTED

2050
rust/src/webserver/bootstrap-grid.css vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,9 @@ use std::{
sync::{atomic::AtomicBool, Arc}, sync::{atomic::AtomicBool, Arc},
}; };
use crate::{espota::OtaUpdate, map_range_moisture, plant_hal::FileInfo, BOARD_ACCESS}; use crate::{
espota::OtaUpdate, get_version, map_range_moisture, plant_hal::FileInfo, BOARD_ACCESS,
};
use anyhow::bail; use anyhow::bail;
use chrono::DateTime; use chrono::DateTime;
use core::result::Result::Ok; use core::result::Result::Ok;
@ -29,12 +31,6 @@ struct FileList {
file: Vec<FileInfo>, file: Vec<FileInfo>,
} }
#[derive(Serialize, Debug)]
struct VersionInfo<'a> {
git_hash: &'a str,
build_time: &'a str,
}
#[derive(Serialize, Debug)] #[derive(Serialize, Debug)]
struct LoadData<'a> { struct LoadData<'a> {
rtc: &'a str, rtc: &'a str,
@ -158,17 +154,19 @@ fn set_config(
anyhow::Ok(Some("saved".to_owned())) anyhow::Ok(Some("saved".to_owned()))
} }
fn get_version( fn get_battery_state(
_request: &mut Request<&mut EspHttpConnection>, _request: &mut Request<&mut EspHttpConnection>,
) -> Result<Option<std::string::String>, anyhow::Error> { ) -> Result<Option<std::string::String>, anyhow::Error> {
let branch = env!("VERGEN_GIT_BRANCH").to_owned(); let mut board = BOARD_ACCESS.lock().unwrap();
let hash = &env!("VERGEN_GIT_SHA")[0..8]; let battery_state = board.get_battery_state();
let battery_json = serde_json::to_string(&battery_state)?;
anyhow::Ok(Some(battery_json))
}
let version_info: VersionInfo<'_> = VersionInfo { fn get_version_web(
git_hash: &(branch + "@" + hash), _request: &mut Request<&mut EspHttpConnection>,
build_time: env!("VERGEN_BUILD_TIMESTAMP"), ) -> Result<Option<std::string::String>, anyhow::Error> {
}; anyhow::Ok(Some(serde_json::to_string(&get_version())?))
anyhow::Ok(Some(serde_json::to_string(&version_info)?))
} }
fn pump_test( fn pump_test(
@ -296,10 +294,14 @@ pub fn httpd(_reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
Box::new(EspHttpServer::new(&server_config).unwrap()); Box::new(EspHttpServer::new(&server_config).unwrap());
server server
.fn_handler("/version", Method::Get, |request| { .fn_handler("/version", Method::Get, |request| {
handle_error_to500(request, get_version) handle_error_to500(request, get_version_web)
})
.unwrap();
server
.fn_handler("/battery", Method::Get, |request| {
handle_error_to500(request, get_battery_state)
}) })
.unwrap(); .unwrap();
server server
.fn_handler("/time", Method::Get, |request| { .fn_handler("/time", Method::Get, |request| {
handle_error_to500(request, get_data) handle_error_to500(request, get_data)
@ -522,7 +524,7 @@ fn cors_response(
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
let headers = [ let headers = [
("Access-Control-Allow-Origin", "*"), ("Access-Control-Allow-Origin", "*"),
("Access-Control-Allow-Headers", "*") ("Access-Control-Allow-Headers", "*"),
]; ];
let mut response = request.into_response(status, None, &headers)?; let mut response = request.into_response(status, None, &headers)?;
response.write(body.as_bytes())?; response.write(body.as_bytes())?;

View File

@ -5,11 +5,10 @@
"packages": { "packages": {
"": { "": {
"dependencies": { "dependencies": {
"copy-webpack-plugin": "^12.0.2",
"source-map-loader": "^4.0.1" "source-map-loader": "^4.0.1"
}, },
"devDependencies": { "devDependencies": {
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^7.1.2",
"html-webpack-harddisk-plugin": "^2.0.0", "html-webpack-harddisk-plugin": "^2.0.0",
"html-webpack-plugin": "^5.6.3", "html-webpack-plugin": "^5.6.3",
"raw-loader": "^4.0.2", "raw-loader": "^4.0.2",
@ -155,7 +154,6 @@
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@nodelib/fs.stat": "2.0.5", "@nodelib/fs.stat": "2.0.5",
@ -169,7 +167,6 @@
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 8" "node": ">= 8"
@ -179,7 +176,6 @@
"version": "1.2.8", "version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@nodelib/fs.scandir": "2.1.5", "@nodelib/fs.scandir": "2.1.5",
@ -193,7 +189,6 @@
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz",
"integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@ -698,7 +693,6 @@
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ajv": "^8.0.0" "ajv": "^8.0.0"
@ -716,7 +710,6 @@
"version": "8.17.1", "version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
@ -733,7 +726,6 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/ajv-keywords": { "node_modules/ajv-keywords": {
@ -894,7 +886,6 @@
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"dependencies": { "dependencies": {
"fill-range": "^7.0.1" "fill-range": "^7.0.1"
}, },
@ -1222,7 +1213,6 @@
"version": "12.0.2", "version": "12.0.2",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz",
"integrity": "sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA==", "integrity": "sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
@ -1247,7 +1237,6 @@
"version": "8.17.1", "version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
@ -1264,7 +1253,6 @@
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.3" "fast-deep-equal": "^3.1.3"
@ -1277,7 +1265,6 @@
"version": "6.0.2", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"is-glob": "^4.0.3" "is-glob": "^4.0.3"
@ -1290,14 +1277,12 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/copy-webpack-plugin/node_modules/schema-utils": { "node_modules/copy-webpack-plugin/node_modules/schema-utils": {
"version": "4.2.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
"integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/json-schema": "^7.0.9", "@types/json-schema": "^7.0.9",
@ -1306,7 +1291,7 @@
"ajv-keywords": "^5.1.0" "ajv-keywords": "^5.1.0"
}, },
"engines": { "engines": {
"node": ">= 12.13.0" "node": ">= 10.13.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@ -1334,42 +1319,6 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/css-loader": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz",
"integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==",
"dev": true,
"license": "MIT",
"dependencies": {
"icss-utils": "^5.1.0",
"postcss": "^8.4.33",
"postcss-modules-extract-imports": "^3.1.0",
"postcss-modules-local-by-default": "^4.0.5",
"postcss-modules-scope": "^3.2.0",
"postcss-modules-values": "^4.0.0",
"postcss-value-parser": "^4.2.0",
"semver": "^7.5.4"
},
"engines": {
"node": ">= 18.12.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"@rspack/core": "0.x || 1.x",
"webpack": "^5.27.0"
},
"peerDependenciesMeta": {
"@rspack/core": {
"optional": true
},
"webpack": {
"optional": true
}
}
},
"node_modules/css-select": { "node_modules/css-select": {
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
@ -1400,19 +1349,6 @@
"url": "https://github.com/sponsors/fb55" "url": "https://github.com/sponsors/fb55"
} }
}, },
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true,
"license": "MIT",
"bin": {
"cssesc": "bin/cssesc"
},
"engines": {
"node": ">=4"
}
},
"node_modules/debug": { "node_modules/debug": {
"version": "2.6.9", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@ -1833,7 +1769,6 @@
"version": "3.3.2", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.stat": "^2.0.2",
@ -1855,7 +1790,6 @@
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz",
"integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==",
"dev": true,
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/fastest-levenshtein": { "node_modules/fastest-levenshtein": {
@ -1871,7 +1805,6 @@
"version": "1.17.1", "version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
"dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"reusify": "^1.0.4" "reusify": "^1.0.4"
@ -1894,7 +1827,6 @@
"version": "7.0.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"dependencies": { "dependencies": {
"to-regex-range": "^5.0.1" "to-regex-range": "^5.0.1"
}, },
@ -2017,7 +1949,6 @@
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"is-glob": "^4.0.1" "is-glob": "^4.0.1"
@ -2036,7 +1967,6 @@
"version": "14.0.2", "version": "14.0.2",
"resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz",
"integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@sindresorhus/merge-streams": "^2.1.0", "@sindresorhus/merge-streams": "^2.1.0",
@ -2404,24 +2334,10 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/icss-utils": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
"dev": true,
"license": "ISC",
"engines": {
"node": "^10 || ^12 || >= 14"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.3.2", "version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 4" "node": ">= 4"
@ -2517,7 +2433,6 @@
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@ -2527,7 +2442,6 @@
"version": "4.0.3", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"is-extglob": "^2.1.1" "is-extglob": "^2.1.1"
@ -2572,7 +2486,6 @@
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"engines": { "engines": {
"node": ">=0.12.0" "node": ">=0.12.0"
} }
@ -2814,7 +2727,6 @@
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 8" "node": ">= 8"
@ -2834,7 +2746,6 @@
"version": "4.0.5", "version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"dev": true,
"dependencies": { "dependencies": {
"braces": "^3.0.2", "braces": "^3.0.2",
"picomatch": "^2.3.1" "picomatch": "^2.3.1"
@ -2903,25 +2814,6 @@
"multicast-dns": "cli.js" "multicast-dns": "cli.js"
} }
}, },
"node_modules/nanoid": {
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/negotiator": { "node_modules/negotiator": {
"version": "0.6.4", "version": "0.6.4",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz",
@ -2968,7 +2860,6 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@ -3170,7 +3061,6 @@
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz",
"integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=12" "node": ">=12"
@ -3189,7 +3079,6 @@
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"engines": { "engines": {
"node": ">=8.6" "node": ">=8.6"
}, },
@ -3209,119 +3098,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/postcss": {
"version": "8.4.49",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.7",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/postcss-modules-extract-imports": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz",
"integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==",
"dev": true,
"license": "ISC",
"engines": {
"node": "^10 || ^12 || >= 14"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/postcss-modules-local-by-default": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz",
"integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==",
"dev": true,
"license": "MIT",
"dependencies": {
"icss-utils": "^5.0.0",
"postcss-selector-parser": "^7.0.0",
"postcss-value-parser": "^4.1.0"
},
"engines": {
"node": "^10 || ^12 || >= 14"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/postcss-modules-scope": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz",
"integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==",
"dev": true,
"license": "ISC",
"dependencies": {
"postcss-selector-parser": "^7.0.0"
},
"engines": {
"node": "^10 || ^12 || >= 14"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/postcss-modules-values": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
"integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
"dev": true,
"license": "ISC",
"dependencies": {
"icss-utils": "^5.0.0"
},
"engines": {
"node": "^10 || ^12 || >= 14"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/postcss-selector-parser": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz",
"integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
},
"engines": {
"node": ">=4"
}
},
"node_modules/postcss-value-parser": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true,
"license": "MIT"
},
"node_modules/pretty-error": { "node_modules/pretty-error": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz",
@ -3392,7 +3168,6 @@
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true,
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@ -3545,7 +3320,6 @@
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@ -3610,7 +3384,6 @@
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"iojs": ">=1.0.0", "iojs": ">=1.0.0",
@ -3634,7 +3407,6 @@
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
"dev": true,
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@ -3959,7 +3731,6 @@
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
"integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=14.16" "node": ">=14.16"
@ -4262,7 +4033,6 @@
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"dependencies": { "dependencies": {
"is-number": "^7.0.0" "is-number": "^7.0.0"
}, },
@ -4361,7 +4131,6 @@
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz",
"integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=18" "node": ">=18"

View File

@ -10,6 +10,7 @@
"webpack-dev-server": "^5.1.0" "webpack-dev-server": "^5.1.0"
}, },
"dependencies": { "dependencies": {
"copy-webpack-plugin": "^12.0.2",
"source-map-loader": "^4.0.1" "source-map-loader": "^4.0.1"
} }
} }

View File

@ -66,3 +66,14 @@ interface VersionInfo {
git_hash: string, git_hash: string,
build_time: string build_time: string
} }
interface BatteryState {
temperature: string
voltage_milli_volt: string,
current_milli_ampere: string,
cycle_count: string,
design_milli_ampere: string,
remaining_milli_ampere: string,
state_of_charge: string,
state_of_health: string
}

View File

@ -0,0 +1,46 @@
<div class="container col-sm-6 col-md-5" style="border-style: solid; border-width: 1px; padding: 8px; margin: 8px;" >
<div class="row">
<div class="col-7">
</div>
<div class="col-7" style="text-align: center; font-weight: bold;">
Time:
</div>
<div style="display: block; right: 8px; position: absolute;">
<input id="battery_auto_refresh" type="checkbox">
</div>
</div>
<div class="row">
<span class="col-7">V:</span>
<div class="col-5" id="battery_voltage_milli_volt" style="text-wrap: nowrap"></div>
</div>
<div class="row">
<span class="col-7">mA:</span>
<div class="col-5" id="battery_current_milli_ampere" style="text-wrap: nowrap"></div>
</div>
<div class="row">
<span class="col-7">Cycles:</span>
<div class="col-5" id="battery_cycle_count" style="text-wrap: nowrap"></div>
</div>
<div class="row">
<span class="col-7">design mA:</span>
<div class="col-5" id="battery_design_milli_ampere" style="text-wrap: nowrap"></div>
</div>
<div class="row">
<span class="col-7">remaining mA:</span>
<div class="col-5" id="battery_remaining_milli_ampere" style="text-wrap: nowrap"></div>
</div>
<div class="row">
<span class="col-7">charge %:</span>
<div class="col-5" id="battery_state_of_charge" style="text-wrap: nowrap"></div>
</div>
<div class="row">
<span class="col-7">health %:</span>
<div class="col-5" id="battery_state_of_health" style="text-wrap: nowrap"></div>
</div>
<div class="row">
<span class="col-7">Temp °C:</span>
<div class="col-5" id="battery_temperature" style="text-wrap: nowrap"></div>
</div>
</div>

View File

@ -0,0 +1,69 @@
import { Controller } from "./main";
export class BatteryView{
voltage_milli_volt: HTMLSpanElement;
current_milli_ampere: HTMLSpanElement;
cycle_count: HTMLSpanElement;
design_milli_ampere: HTMLSpanElement;
remaining_milli_ampere: HTMLSpanElement;
state_of_charge: HTMLSpanElement;
state_of_health: HTMLSpanElement;
temperature: HTMLSpanElement;
auto_refresh: HTMLInputElement;
timer: NodeJS.Timeout | undefined;
controller: Controller;
constructor (controller:Controller) {
(document.getElementById("batteryview") as HTMLElement).innerHTML = require("./batteryview.html")
this.voltage_milli_volt = document.getElementById("battery_voltage_milli_volt") as HTMLSpanElement;
this.current_milli_ampere = document.getElementById("battery_current_milli_ampere") as HTMLSpanElement;
this.cycle_count = document.getElementById("battery_cycle_count") as HTMLSpanElement;
this.design_milli_ampere = document.getElementById("battery_design_milli_ampere") as HTMLSpanElement;
this.remaining_milli_ampere = document.getElementById("battery_remaining_milli_ampere") as HTMLSpanElement;
this.state_of_charge = document.getElementById("battery_state_of_charge") as HTMLSpanElement;
this.state_of_health = document.getElementById("battery_state_of_health") as HTMLSpanElement;
this.temperature = document.getElementById("battery_temperature") as HTMLSpanElement;
this.auto_refresh = document.getElementById("battery_auto_refresh") as HTMLInputElement;
this.controller = controller
this.auto_refresh.onchange = () => {
if(this.timer){
clearTimeout(this.timer)
}
if(this.auto_refresh.checked){
controller.updateBatteryData()
}
}
}
update(batterystate: BatteryState|null){
if (batterystate == null) {
this.voltage_milli_volt.innerText = "N/A"
this.current_milli_ampere.innerText = "N/A"
this.cycle_count.innerText = "N/A"
this.design_milli_ampere.innerText = "N/A"
this.remaining_milli_ampere.innerText = "N/A"
this.state_of_charge.innerText = "N/A"
this.state_of_health.innerText = "N/A"
this.temperature.innerText = "N/A"
} else {
this.voltage_milli_volt.innerText = String(+batterystate.voltage_milli_volt/1000)
this.current_milli_ampere.innerText = batterystate.current_milli_ampere
this.cycle_count.innerText = batterystate.cycle_count
this.design_milli_ampere.innerText = batterystate.design_milli_ampere
this.remaining_milli_ampere.innerText = batterystate.remaining_milli_ampere
this.state_of_charge.innerText = batterystate.state_of_charge
this.state_of_health.innerText = batterystate.state_of_health
this.temperature.innerText = String(+batterystate.temperature / 100)
}
if(this.auto_refresh.checked){
this.timer = setTimeout(this.controller.updateBatteryData, 1000);
} else {
if(this.timer){
clearTimeout(this.timer)
}
}
}
}

View File

@ -1,4 +1,3 @@
<div class="container-xxl">
<link rel="stylesheet" href="bootstrap-grid.css"> <link rel="stylesheet" href="bootstrap-grid.css">
<style> <style>
.progressPane{ .progressPane{
@ -66,70 +65,30 @@
</style> </style>
<div id="progressPane" class="progressPane">
<div class="progressPaneCenter">
<div id="progressPaneBar" class="progress" data-label="50% Complete">
<span id="progressPaneSpan" class="value" style="width:100%;"></span>
</div>
</div>
</div>
<div class="container-xxl">
<input type="button" id="test" value="Test"> <input type="button" id="test" value="Test">
<h2>Current Firmware</h2>
<div> <div id="firmwareview">
<div id="firmware_buildtime">Buildtime loading</div>
<div id="firmware_githash">Build githash loading</div>
</div> </div>
<h2>firmeware OTA v3</h2>
<form id="upload_form" method="post">
<input type="file" name="file1" id="firmware_file"><br>
<progress id="firmware_progressBar" value="0" max="100" style="width:300px;"></progress>
<h3 id="firmware_status"></h3>
<h3 id="firmware_answer"></h3>
<p id="firmware_loaded_n_total"></p>
</form>
<div id="timeview"> <div id="timeview">
</div> </div>
<div id="network_view"> <div id="network_view">
</div> </div>
<div id="tankview"></div>
<div id="batteryview"></div>
<h2>config</h2> <h2>config</h2>
<div id="configform"> <div id="configform">
<h3>Tank:</h3>
<div>
<input type="checkbox" id="tank_sensor_enabled">
Enable Tank Sensor
</div>
<div>
<input type="checkbox" id="tank_allow_pumping_if_sensor_error">
Allow Pumping if Sensor Error
</div>
<div>
<input type="number" min="2" max="500000" id="tank_useable_ml">
Tank Size mL
</div>
<div>
<input type="number" min="1" max="500000" id="tank_warn_percent">
Tank Warn Percent (mapped in relation to empty and full)
</div>
<div>
<input type="number" min="0" max="100" id="tank_empty_percent">
Tank Empty Percent (% max move)
</div>
<div>
<input type="number" min="0" max="100" id="tank_full_percent">
Tank Full Percent (% max move)
</div>
<h3>Light:</h3> <h3>Light:</h3>
<input type="checkbox" id="night_lamp_enabled" checked="false"> Enable Nightlight <input type="checkbox" id="night_lamp_enabled" checked="false"> Enable Nightlight
<div> <div>
@ -155,3 +114,11 @@
<textarea id="json" cols=50 rows=10></textarea> <textarea id="json" cols=50 rows=10></textarea>
<script src="bundle.js"></script> <script src="bundle.js"></script>
</div> </div>
<div id="progressPane" class="progressPane">
<div class="progressPaneCenter">
<div id="progressPaneBar" class="progress" data-label="50% Complete">
<span id="progressPaneSpan" class="value" style="width:100%;"></span>
</div>
</div>
</div>

View File

@ -9,10 +9,11 @@ import { TimeView } from "./timeview";
import { PlantView, PlantViews } from "./plant"; import { PlantView, PlantViews } from "./plant";
import { NetworkConfigView } from "./network"; import { NetworkConfigView } from "./network";
import { NightLampView } from "./nightmode"; import { NightLampView } from "./nightmode";
import { TankConfigView } from "./tanks"; import { TankConfigView } from "./tankview";
import { SubmitView } from "./submitView"; import { SubmitView } from "./submitView";
import { ProgressView } from "./progress"; import { ProgressView } from "./progress";
import { OTAView } from "./ota"; import { OTAView } from "./ota";
import { BatteryView } from "./batteryview";
export class Controller { export class Controller {
updateRTCData() { updateRTCData() {
@ -27,6 +28,18 @@ export class Controller {
console.log(error); console.log(error);
}); });
} }
updateBatteryData() {
fetch(PUBLIC_URL + "/battery")
.then(response => response.json())
.then(json => json as BatteryState)
.then(battery => {
controller.batteryView.update(battery)
})
.catch(error => {
controller.batteryView.update(null)
console.log(error);
});
}
uploadNewFirmware(file: File) { uploadNewFirmware(file: File) {
var current = 0; var current = 0;
var max = 100; var max = 100;
@ -226,11 +239,13 @@ export class Controller {
readonly submitView: SubmitView; readonly submitView: SubmitView;
readonly firmWareView : OTAView; readonly firmWareView : OTAView;
readonly progressview: ProgressView; readonly progressview: ProgressView;
readonly batteryView: BatteryView;
constructor() { constructor() {
this.timeView = new TimeView(this) this.timeView = new TimeView(this)
this.plantViews = new PlantViews(this) this.plantViews = new PlantViews(this)
this.networkView = new NetworkConfigView(this, PUBLIC_URL) this.networkView = new NetworkConfigView(this, PUBLIC_URL)
this.tankView = new TankConfigView(this) this.tankView = new TankConfigView(this)
this.batteryView = new BatteryView(this)
this.nightLampView = new NightLampView(this) this.nightLampView = new NightLampView(this)
this.submitView = new SubmitView(this) this.submitView = new SubmitView(this)
this.firmWareView = new OTAView(this) this.firmWareView = new OTAView(this)
@ -239,6 +254,8 @@ export class Controller {
} }
const controller = new Controller(); const controller = new Controller();
controller.updateRTCData(); controller.updateRTCData();
controller.updateBatteryData();
controller.downloadConfig(); controller.downloadConfig();
controller.measure_moisture(); n controller.measure_moisture();
controller.version(); controller.version();

View File

@ -0,0 +1,22 @@
<div class="container col-12 col-sm-7 col-md-7" style="border-width: 1px; border-style: solid; padding: 8px; margin: 8px;">
<div class="row">
<div class="col-12" style="text-align: center; font-weight: bold;">
Current Firmware
</div>
</div>
<div class="row">
<div class="col-6">
<span>Buildtime:</span>
<span id="firmware_buildtime" style="text-wrap: nowrap"></span>
</div>
<div class="col-md-6">
<span>Buildhash:</span>
<span id="firmware_githash" style="text-wrap: nowrap"></span>
</div>
</div>
<div class="row">
<form class="col-12" id="upload_form" method="post">
<input type="file" name="file1" id="firmware_file"><br>
</form>
</div>
</div>

View File

@ -6,6 +6,8 @@ export class OTAView {
firmware_githash: HTMLDivElement; firmware_githash: HTMLDivElement;
constructor(controller: Controller) { constructor(controller: Controller) {
(document.getElementById("firmwareview") as HTMLElement).innerHTML = require("./ota.html")
this.firmware_buildtime = document.getElementById("firmware_buildtime") as HTMLDivElement; this.firmware_buildtime = document.getElementById("firmware_buildtime") as HTMLDivElement;
this.firmware_githash = document.getElementById("firmware_githash") as HTMLDivElement; this.firmware_githash = document.getElementById("firmware_githash") as HTMLDivElement;

View File

@ -1,35 +1,59 @@
<h4 id="plant_${plantId}_header">Plant ${plantId}</h4> <div class="container" style="border-style: solid; border-width: 1px; margin: 8px; padding: 8px;">
<div> <span class="row col-12" style="font-weight: bold; display: block; text-align: center;" id="plant_${plantId}_header">Plant ${plantId}</span>
<button id="plant_${plantId}_test">Test</button>
<div class="row">
<div class="col-1"></div>
<button class="col-10" id="plant_${plantId}_test">Test</button>
<div class="col-1"></div>
</div> </div>
<div> <div class="row">
Current: <div class="col-12">Live:</div>
<br>
Sensor A:<span id="plant_${plantId}_moisture_a">loading</span>
<br>
Sensor b:<span id="plant_${plantId}_moisture_b">loading</span>
</div> </div>
Mode: <select id="plant_${plantId}_mode"> <div class="row">
<div class="col-7">Sensor A:</div>
<span class="col-4" id="plant_${plantId}_moisture_a">loading</span>
<div class="col-7">Sensor B:</div>
<span class="col-4" id="plant_${plantId}_moisture_b">loading</span>
</div>
<div class="row">
<div class="col-7">
Mode:
</div>
<select class="col-4" id="plant_${plantId}_mode">
<option value="OFF">Off</option> <option value="OFF">Off</option>
<option value="TargetMoisture">Target Moisture</option> <option value="TargetMoisture">Target</option>
<option value="TimerOnly">Timer Only</option> <option value="TimerOnly">Timer</option>
</select> </select>
<div> </div>
Target Moisture: <input id="plant_${plantId}_target_moisture" type="number" min="0" max="100" placeholder="0"> <div class="row">
<br> <div class="col-7">Target Moisture:</div>
Pump Time (s): <input id="plant_${plantId}_pump_time_s" type="number" min="0" max="600" placeholder="30"> <input class="col-4" id="plant_${plantId}_target_moisture" type="number" min="0" max="100" placeholder="0">
<br> </div>
Pump Cooldown (m): <input id="plant_${plantId}_pump_cooldown_min" type="number" min="0" max="600" placeholder="30"> <div class="row">
<br> <div class="col-7">Pump Time (s):</div>
"Pump Hour Start": <select id="plant_${plantId}_pump_hour_start">10</select> <input class="col-4" id="plant_${plantId}_pump_time_s" type="number" min="0" max="600" placeholder="30">
<br> </div>
"Pump Hour End": <select id="plant_${plantId}_pump_hour_end">19</select>
<br> <div class="row">
Sensor B installed: <input id="plant_${plantId}_sensor_b" type="checkbox"> <div class="col-7">Pump Cooldown (m):</div>
<br> <input class="col-4" id="plant_${plantId}_pump_cooldown_min" type="number" min="0" max="600" placeholder="30">
Max Consecutive Pump Count: <input id="plant_${plantId}_max_consecutive_pump_count" type="number" min="1", max="50", placeholder="10"> </div>
<div class="row">
<div class="col-7">"Pump Hour Start":</div>
<select class="col-4" id="plant_${plantId}_pump_hour_start">10</select>
</div>
<div class="row">
<div class="col-7">"Pump Hour End":</div>
<select class="col-4" id="plant_${plantId}_pump_hour_end">19</select>
</div>
<div class="row">
<div class="col-7">Sensor B installed:</div>
<input class="col-4" id="plant_${plantId}_sensor_b" type="checkbox">
</div>
<div class="row">
<div class="col-7">Max Consecutive Pump Count:</div>
<input class="col-4" id="plant_${plantId}_max_consecutive_pump_count" type="number" min="1", max="50", placeholder="10">
</div>
</div> </div>

View File

@ -135,7 +135,6 @@ export class PlantView {
this.maxConsecutivePumpCount.onchange = function(){ this.maxConsecutivePumpCount.onchange = function(){
controller.configChanged() controller.configChanged()
} }
console.log(this)
} }
update(a: number, b: number) { update(a: number, b: number) {

View File

@ -0,0 +1,27 @@
<h3>Tank:</h3>
<div>
<input type="checkbox" id="tank_sensor_enabled">
Enable Tank Sensor
</div>
<div>
<input type="checkbox" id="tank_allow_pumping_if_sensor_error">
Allow Pumping if Sensor Error
</div>
<div>
<input type="number" min="2" max="500000" id="tank_useable_ml">
Tank Size mL
</div>
<div>
<input type="number" min="1" max="500000" id="tank_warn_percent">
Tank Warn Percent (mapped in relation to empty and full)
</div>
<div>
<input type="number" min="0" max="100" id="tank_empty_percent">
Tank Empty Percent (% max move)
</div>
<div>
<input type="number" min="0" max="100" id="tank_full_percent">
Tank Full Percent (% max move)
</div>

View File

@ -9,6 +9,9 @@ export class TankConfigView {
private readonly tank_allow_pumping_if_sensor_error: HTMLInputElement; private readonly tank_allow_pumping_if_sensor_error: HTMLInputElement;
constructor(controller:Controller){ constructor(controller:Controller){
(document.getElementById("tankview") as HTMLElement).innerHTML = require("./tankview.html")
this.tank_useable_ml = document.getElementById("tank_useable_ml") as HTMLInputElement; this.tank_useable_ml = document.getElementById("tank_useable_ml") as HTMLInputElement;
this.tank_useable_ml.onchange = controller.configChanged this.tank_useable_ml.onchange = controller.configChanged
this.tank_empty_percent = document.getElementById("tank_empty_percent") as HTMLInputElement; this.tank_empty_percent = document.getElementById("tank_empty_percent") as HTMLInputElement;

View File

@ -1,7 +1,28 @@
<h2>Time</h2> <div class="container col-sm-6 col-md-5" style="border-style: solid; border-width: 1px; padding: 8px; margin: 8px;" >
AutoRefresh:<input id="timeview_auto_refresh" type="checkbox"> <div class="row">
<div id="timeview_esp_time">Esp time</div> <div class="col-4">
<div id="timeview_rtc_time">Rtc time</div> </div>
<div id="timeview_browser_time">Rtc time</div> <div class="col-4" style="text-align: center; font-weight: bold;">
<div></div> Time:
<button id="timeview_time_upload">Store Browser time into esp and rtc</button> </div>
<div style="display: block; right: 8px; position: absolute;">
<input id="timeview_auto_refresh" type="checkbox">
</div>
</div>
<div class="row">
<span class="col-2">MCU:</span>
<div class="col-9" id="timeview_esp_time" style="text-wrap: nowrap">Esp time</div>
</div>
<div class="row">
<span class="col-2">RTC:</span>
<div class="col-9" id="timeview_rtc_time" style="text-wrap: nowrap">Rtc time</div>
</div>
<div class="row">
<span class="col-2">Local:</span>
<div class="col-9" id="timeview_browser_time" style="text-wrap: nowrap">Local time</div>
</div>
<button id="timeview_time_upload">Store Browser time into esp and rtc</button>
</div>

View File

@ -8,7 +8,7 @@ const isDevServer = process.env.WEBPACK_SERVE;
console.log("Dev server is " + isDevServer); console.log("Dev server is " + isDevServer);
var host; var host;
if (isDevServer){ if (isDevServer){
host = 'http://192.168.1.172'; host = 'http://192.168.0.103';
} else { } else {
host = ''; host = '';
} }