progress new ui

This commit is contained in:
Empire Phoenix 2024-12-17 01:39:47 +01:00
parent 74f9c17461
commit 5fedbec433
9 changed files with 113 additions and 87 deletions

View File

@ -258,7 +258,7 @@ fn safe_main() -> anyhow::Result<()> {
Err(err) => { Err(err) => {
println!("Missing normal config, entering config mode {}", err); println!("Missing normal config, entering config mode {}", err);
//config upload will trigger reboot! //config upload will trigger reboot!
let _ = board.wifi_ap(); let _ = board.wifi_ap(Option::None);
drop(board); drop(board);
let reboot_now = Arc::new(AtomicBool::new(false)); let reboot_now = Arc::new(AtomicBool::new(false));
let _webserver = httpd(reboot_now.clone()); let _webserver = httpd(reboot_now.clone());
@ -293,6 +293,7 @@ fn safe_main() -> anyhow::Result<()> {
board.general_fault(true); board.general_fault(true);
} }
} }
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");
@ -303,6 +304,7 @@ fn safe_main() -> anyhow::Result<()> {
} }
} }
} }
}
Err(_) => { Err(_) => {
println!("Offline mode"); println!("Offline mode");
board.general_fault(true); board.general_fault(true);
@ -312,6 +314,16 @@ fn safe_main() -> anyhow::Result<()> {
println!("No wifi configured"); println!("No wifi configured");
} }
if !wifi && to_config {
println!("Could not connect to station and config mode forced, switching to ap mode!");
match board.wifi_ap(Some(config.network.ap_ssid.clone())) {
Ok(_) => {
println!("Started ap, continuing")
},
Err(err) => println!("Could not start config override ap mode due to {}", err.to_string()),
}
}
let timezone_time = cur.with_timezone(&TIME_ZONE); let timezone_time = cur.with_timezone(&TIME_ZONE);
println!( println!(
"Running logic at utc {} and {} {}", "Running logic at utc {} and {} {}",

View File

@ -514,9 +514,10 @@ impl PlantCtrlBoard<'_> {
unsafe { gpio_hold_en(self.general_fault.pin()) }; unsafe { gpio_hold_en(self.general_fault.pin()) };
} }
pub fn wifi_ap(&mut self) -> Result<()> { pub fn wifi_ap(&mut self, ap_ssid: Option<heapless::String<32>>) -> Result<()> {
let ssid = ap_ssid.unwrap_or(heapless::String::from_str("PlantCtrl Emergency Mode").unwrap());
let apconfig = AccessPointConfiguration { let apconfig = AccessPointConfiguration {
ssid: heapless::String::from_str("PlantCtrl").unwrap(), ssid,
auth_method: AuthMethod::None, auth_method: AuthMethod::None,
ssid_hidden: false, ssid_hidden: false,
..Default::default() ..Default::default()
@ -643,6 +644,7 @@ impl PlantCtrlBoard<'_> {
} }
pub fn get_rtc_time(&mut self) -> Result<DateTime<Utc>> { pub fn get_rtc_time(&mut self) -> Result<DateTime<Utc>> {
match self.rtc.datetime() { match self.rtc.datetime() {
OkStd(rtc_time) => { OkStd(rtc_time) => {
return Ok(rtc_time.and_utc()); return Ok(rtc_time.and_utc());
@ -743,11 +745,18 @@ impl PlantCtrlBoard<'_> {
.base_topic .base_topic
.as_ref() .as_ref()
.context("missing base topic")?; .context("missing base topic")?;
if base_topic.is_empty() {
bail!("Mqtt base_topic was empty")
}
let mqtt_url = config let mqtt_url = config
.network .network
.mqtt_url .mqtt_url
.as_ref() .as_ref()
.context("missing mqtt url")?; .context("missing mqtt url")?;
if mqtt_url.is_empty() {
bail!("Mqtt url was empty")
}
let last_will_topic = format!("{}/state", base_topic); let last_will_topic = format!("{}/state", base_topic);
let mqtt_client_config = MqttClientConfiguration { let mqtt_client_config = MqttClientConfiguration {
@ -805,26 +814,41 @@ impl PlantCtrlBoard<'_> {
} }
} }
} }
embedded_svc::mqtt::client::EventPayload::Connected(_) => { esp_idf_svc::mqtt::client::EventPayload::Connected(_) => {
mqtt_connected_event_received_copy mqtt_connected_event_received_copy
.store(true, std::sync::atomic::Ordering::Relaxed); .store(true, std::sync::atomic::Ordering::Relaxed);
mqtt_connected_event_ok_copy.store(true, std::sync::atomic::Ordering::Relaxed); mqtt_connected_event_ok_copy.store(true, std::sync::atomic::Ordering::Relaxed);
println!("Mqtt connected"); println!("Mqtt connected");
} }
embedded_svc::mqtt::client::EventPayload::Disconnected => { esp_idf_svc::mqtt::client::EventPayload::Disconnected => {
mqtt_connected_event_received_copy mqtt_connected_event_received_copy
.store(true, std::sync::atomic::Ordering::Relaxed); .store(true, std::sync::atomic::Ordering::Relaxed);
mqtt_connected_event_ok_copy.store(false, std::sync::atomic::Ordering::Relaxed); mqtt_connected_event_ok_copy.store(false, std::sync::atomic::Ordering::Relaxed);
println!("Mqtt disconnected"); println!("Mqtt disconnected");
} }
embedded_svc::mqtt::client::EventPayload::Error(esp_error) => { esp_idf_svc::mqtt::client::EventPayload::Error(esp_error) => {
println!("EspMqttError reported {:?}", esp_error); println!("EspMqttError reported {:?}", esp_error);
mqtt_connected_event_received_copy mqtt_connected_event_received_copy
.store(true, std::sync::atomic::Ordering::Relaxed); .store(true, std::sync::atomic::Ordering::Relaxed);
mqtt_connected_event_ok_copy.store(false, std::sync::atomic::Ordering::Relaxed); mqtt_connected_event_ok_copy.store(false, std::sync::atomic::Ordering::Relaxed);
println!("Mqtt error"); println!("Mqtt error");
} }
_ => {} esp_idf_svc::mqtt::client::EventPayload::BeforeConnect => {
println!("Mqtt before connect")
},
esp_idf_svc::mqtt::client::EventPayload::Subscribed(_) => {
println!("Mqtt subscribed")
},
esp_idf_svc::mqtt::client::EventPayload::Unsubscribed(_) => {
println!("Mqtt unsubscribed")
},
esp_idf_svc::mqtt::client::EventPayload::Published(_) => {
println!("Mqtt published")
},
esp_idf_svc::mqtt::client::EventPayload::Deleted(_) => {
println!("Mqtt deleted")
},
} }
})?; })?;

View File

@ -24,7 +24,7 @@ interface TankConfig {
interface PlantControllerConfig { interface PlantControllerConfig {
network: NetworkConfig, network: NetworkConfig,
tank: TankConfig, tank: TankConfig,
nightLamp: NightLampConfig, night_lamp: NightLampConfig,
plants: PlantConfig[] plants: PlantConfig[]
} }

View File

@ -31,6 +31,7 @@
</form> </form>
<div> <div>
<div id="remote_ip">remote ip</div>
<h2>WIFI</h2> <h2>WIFI</h2>
<input type="button" id="scan" value="Scan"> <input type="button" id="scan" value="Scan">
<br> <br>
@ -52,12 +53,12 @@
<div id="configform"> <div id="configform">
<h3>Mqtt:</h3> <h3>Mqtt:</h3>
<div> <div>
<input type="text" id="mqtt_url">
MQTT Url MQTT Url
<input type="text" id="mqtt_url" placeholder="mqtt://192.168.1.1:1883">
</div> </div>
<div> <div>
<input type="text" id="base_topic">
Base Topic Base Topic
<input type="text" id="base_topic" placeholder="plants/one">
</div> </div>
@ -114,13 +115,6 @@
</form> </form>
<h3>Plants:</h3> <h3>Plants:</h3>
<div>
<input type="number" min="2" max="100" id="max_consecutive_pump_count">
Max consecutive pump count:
</div>
<div id="plants"></div> <div id="plants"></div>
</div> </div>
<button id="submit">Submit</button> <button id="submit">Submit</button>

View File

@ -10,18 +10,59 @@ import { NightLampView } from "./nightmode";
import { TankConfigView } from "./tanks"; import { TankConfigView } from "./tanks";
export class SubmitView{
json: HTMLInputElement;
submitFormBtn: HTMLButtonElement;
submit_status: HTMLElement;
constructor(controller: Controller){
this.json = document.getElementById('json') as HTMLInputElement
this.submitFormBtn = document.getElementById("submit") as HTMLButtonElement
this.submit_status = document.getElementById("submit_status") as HTMLElement
this.submitFormBtn.onclick = () => {
controller.uploadConfig(this.json.value, (status:string) => {
this.submit_status.innerHTML = status;
});
}
}
setJson(pretty: string) {
this.json.value = pretty
}
}
export class Controller { export class Controller {
downloadConfig() {
fetch(PUBLIC_URL + "/get_config")
.then(response => response.json())
.then(loaded => {
var currentConfig = loaded as PlantControllerConfig;
this.setConfig(currentConfig);
//sync json view initially
this.configChanged();
})
}
uploadConfig(json: string, statusCallback: (status: string) => void) {
fetch(PUBLIC_URL + "/set_config", {
method: "POST",
body: json,
})
.then(response => response.text())
.then(text => statusCallback(text))
}
readonly timeView: TimeView; readonly timeView: TimeView;
readonly plantViews: PlantViews; readonly plantViews: PlantViews;
readonly networkView: NetworkConfigView; readonly networkView: NetworkConfigView;
readonly tankView: TankConfigView; readonly tankView: TankConfigView;
readonly nightLampView: NightLampView; readonly nightLampView: NightLampView;
readonly submitView: SubmitView;
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) this.networkView = new NetworkConfigView(this, PUBLIC_URL)
this.tankView = new TankConfigView(this) this.tankView = new TankConfigView(this)
this.nightLampView = new NightLampView(this) this.nightLampView = new NightLampView(this)
this.submitView = new SubmitView(this)
} }
syncRTCFromBrowser(){ syncRTCFromBrowser(){
@ -36,7 +77,10 @@ export class Controller {
} }
configChanged() { configChanged() {
updateJson() const current = controller.getConfig();
var pretty = JSON.stringify(current, undefined, 1);
console.log(pretty)
controller.submitView.setJson(pretty);
} }
testPlant(plantId: number) { testPlant(plantId: number) {
@ -72,7 +116,7 @@ export class Controller {
return { return {
network: controller.networkView.getConfig(), network: controller.networkView.getConfig(),
tank: controller.tankView.getConfig(), tank: controller.tankView.getConfig(),
nightLamp: controller.nightLampView.getConfig(), night_lamp: controller.nightLampView.getConfig(),
plants: controller.plantViews.getConfig() plants: controller.plantViews.getConfig()
} }
} }
@ -95,60 +139,13 @@ export class Controller {
setConfig(current: PlantControllerConfig) { setConfig(current: PlantControllerConfig) {
this.tankView.setConfig(current.tank); this.tankView.setConfig(current.tank);
this.networkView.setConfig(current.network); this.networkView.setConfig(current.network);
this.nightLampView.setConfig(current.nightLamp); this.nightLampView.setConfig(current.night_lamp);
this.plantViews.setConfig(current.plants); this.plantViews.setConfig(current.plants);
} }
} }
const controller = new Controller(); const controller = new Controller();
setTimeout(controller.updateRealTimeData, 1000); setTimeout(controller.updateRealTimeData, 1000);
controller.downloadConfig();
function updateJson() {
const current = controller.getConfig();
console.log(current);
var pretty = JSON.stringify(current, undefined, 1);
console.log(pretty)
}
let fromWrapper = (() => {
let json = document.getElementById('json') as HTMLInputElement
let submitFormBtn = document.getElementById("submit") as HTMLButtonElement
let submit_status = document.getElementById("submit_status") as HTMLElement
if (submitFormBtn) {
submitFormBtn.onclick = function () {
updateJson()
fetch(PUBLIC_URL + "/set_config", {
method: "POST",
body: json.value,
})
.then(response => response.text())
.then(text => submit_status.innerText = text)
};
}
fetch(PUBLIC_URL + "/get_config")
.then(response => response.json())
.then(loaded => {
var currentConfig = loaded as PlantControllerConfig;
controller.setConfig(currentConfig);
var pretty = JSON.stringify(currentConfig, undefined, 1);
json.value = pretty;
}
)
})
fromWrapper()

View File

@ -16,7 +16,9 @@ export class NetworkConfigView {
private readonly base_topic: HTMLInputElement; private readonly base_topic: HTMLInputElement;
private readonly ssidlist: HTMLElement; private readonly ssidlist: HTMLElement;
constructor(controller: Controller) { constructor(controller: Controller, publicIp: string) {
(document.getElementById("remote_ip") as HTMLElement).innerText = publicIp;
this.ap_ssid = (document.getElementById("ap_ssid") as HTMLInputElement); this.ap_ssid = (document.getElementById("ap_ssid") as HTMLInputElement);
this.ap_ssid.onchange = controller.configChanged this.ap_ssid.onchange = controller.configChanged
@ -48,10 +50,10 @@ export class NetworkConfigView {
getConfig(): NetworkConfig { getConfig(): NetworkConfig {
return { return {
ap_ssid: this.ap_ssid.value, ap_ssid: this.ap_ssid.value,
ssid: this.ssid.value, ssid: this.ssid.value ?? null,
password: this.password.value, password: this.password.value ?? null,
mqtt_url: this.mqtt_url.value, mqtt_url: this.mqtt_url.value ?? null,
base_topic: this.base_topic.value base_topic: this.base_topic.value ?? null
} }
} }
} }

View File

@ -1,5 +1,5 @@
declare const PLANT_COUNT = 8; const PLANT_COUNT = 8;
import { Controller } from "."; import { Controller } from ".";

View File

@ -1,7 +1,6 @@
import { Controller } from "."; import { Controller } from ".";
export class TankConfigView { export class TankConfigView {
private readonly max_consecutive_pump_count: HTMLInputElement;
private readonly tank_useable_ml: HTMLInputElement; private readonly tank_useable_ml: HTMLInputElement;
private readonly tank_empty_percent: HTMLInputElement; private readonly tank_empty_percent: HTMLInputElement;
private readonly tank_full_percent: HTMLInputElement; private readonly tank_full_percent: HTMLInputElement;
@ -10,8 +9,6 @@ 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){
this.max_consecutive_pump_count = document.getElementById("max_consecutive_pump_count") as HTMLInputElement;
this.max_consecutive_pump_count.onchange = controller.configChanged
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

@ -6,7 +6,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://10.23.43.24'; host = 'http://192.168.1.172';
} else { } else {
host = ''; host = '';
} }
@ -36,7 +36,7 @@ module.exports = {
rules: [ rules: [
{ {
test: /\.html$/, test: /\.html$/,
type: 'asset/source' type: 'asset/source',
}, },
{ {
test: /\.tsx?$/, test: /\.tsx?$/,