diff --git a/rust/src/main.rs b/rust/src/main.rs index 27a752f..f29c654 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -258,7 +258,7 @@ fn safe_main() -> anyhow::Result<()> { Err(err) => { println!("Missing normal config, entering config mode {}", err); //config upload will trigger reboot! - let _ = board.wifi_ap(); + let _ = board.wifi_ap(Option::None); drop(board); let reboot_now = Arc::new(AtomicBool::new(false)); let _webserver = httpd(reboot_now.clone()); @@ -293,13 +293,15 @@ fn safe_main() -> anyhow::Result<()> { board.general_fault(true); } } - match board.mqtt(&config) { - Ok(_) => { - println!("Mqtt connection ready"); - mqtt = true; - } - Err(err) => { - println!("Could not connect mqtt due to {}", err); + if (config.network.mqtt_url.is_some()){ + match board.mqtt(&config) { + Ok(_) => { + println!("Mqtt connection ready"); + mqtt = true; + } + Err(err) => { + println!("Could not connect mqtt due to {}", err); + } } } } @@ -312,6 +314,16 @@ fn safe_main() -> anyhow::Result<()> { 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); println!( "Running logic at utc {} and {} {}", diff --git a/rust/src/plant_hal.rs b/rust/src/plant_hal.rs index a0cb12c..221ac7a 100644 --- a/rust/src/plant_hal.rs +++ b/rust/src/plant_hal.rs @@ -514,9 +514,10 @@ impl PlantCtrlBoard<'_> { unsafe { gpio_hold_en(self.general_fault.pin()) }; } - pub fn wifi_ap(&mut self) -> Result<()> { + pub fn wifi_ap(&mut self, ap_ssid: Option>) -> Result<()> { + let ssid = ap_ssid.unwrap_or(heapless::String::from_str("PlantCtrl Emergency Mode").unwrap()); let apconfig = AccessPointConfiguration { - ssid: heapless::String::from_str("PlantCtrl").unwrap(), + ssid, auth_method: AuthMethod::None, ssid_hidden: false, ..Default::default() @@ -643,6 +644,7 @@ impl PlantCtrlBoard<'_> { } pub fn get_rtc_time(&mut self) -> Result> { + match self.rtc.datetime() { OkStd(rtc_time) => { return Ok(rtc_time.and_utc()); @@ -743,11 +745,18 @@ impl PlantCtrlBoard<'_> { .base_topic .as_ref() .context("missing base topic")?; + if base_topic.is_empty() { + bail!("Mqtt base_topic was empty") + } let mqtt_url = config .network .mqtt_url .as_ref() .context("missing mqtt url")?; + if mqtt_url.is_empty() { + bail!("Mqtt url was empty") + } + let last_will_topic = format!("{}/state", base_topic); 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 .store(true, std::sync::atomic::Ordering::Relaxed); mqtt_connected_event_ok_copy.store(true, std::sync::atomic::Ordering::Relaxed); println!("Mqtt connected"); } - embedded_svc::mqtt::client::EventPayload::Disconnected => { + esp_idf_svc::mqtt::client::EventPayload::Disconnected => { mqtt_connected_event_received_copy .store(true, std::sync::atomic::Ordering::Relaxed); mqtt_connected_event_ok_copy.store(false, std::sync::atomic::Ordering::Relaxed); 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); mqtt_connected_event_received_copy .store(true, std::sync::atomic::Ordering::Relaxed); mqtt_connected_event_ok_copy.store(false, std::sync::atomic::Ordering::Relaxed); 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") + }, + } })?; diff --git a/rust/src_webpack/src/api.ts b/rust/src_webpack/src/api.ts index 303883c..4984f1a 100644 --- a/rust/src_webpack/src/api.ts +++ b/rust/src_webpack/src/api.ts @@ -24,7 +24,7 @@ interface TankConfig { interface PlantControllerConfig { network: NetworkConfig, tank: TankConfig, - nightLamp: NightLampConfig, + night_lamp: NightLampConfig, plants: PlantConfig[] } diff --git a/rust/src_webpack/src/index.html b/rust/src_webpack/src/index.html index bf1494e..90fe598 100644 --- a/rust/src_webpack/src/index.html +++ b/rust/src_webpack/src/index.html @@ -31,6 +31,7 @@
+
remote ip

WIFI


@@ -52,12 +53,12 @@

Mqtt:

- MQTT Url +
- Base Topic +
@@ -114,13 +115,6 @@

Plants:

- - -
- - Max consecutive pump count: -
-
diff --git a/rust/src_webpack/src/index.ts b/rust/src_webpack/src/index.ts index 1bf1a2b..9fae4dd 100644 --- a/rust/src_webpack/src/index.ts +++ b/rust/src_webpack/src/index.ts @@ -10,18 +10,59 @@ import { NightLampView } from "./nightmode"; 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 { + 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 plantViews: PlantViews; readonly networkView: NetworkConfigView; readonly tankView: TankConfigView; readonly nightLampView: NightLampView; + readonly submitView: SubmitView; constructor() { this.timeView = new TimeView(this) this.plantViews = new PlantViews(this) - this.networkView = new NetworkConfigView(this) + this.networkView = new NetworkConfigView(this, PUBLIC_URL) this.tankView = new TankConfigView(this) this.nightLampView = new NightLampView(this) + this.submitView = new SubmitView(this) } syncRTCFromBrowser(){ @@ -36,7 +77,10 @@ export class Controller { } configChanged() { - updateJson() + const current = controller.getConfig(); + var pretty = JSON.stringify(current, undefined, 1); + console.log(pretty) + controller.submitView.setJson(pretty); } testPlant(plantId: number) { @@ -72,7 +116,7 @@ export class Controller { return { network: controller.networkView.getConfig(), tank: controller.tankView.getConfig(), - nightLamp: controller.nightLampView.getConfig(), + night_lamp: controller.nightLampView.getConfig(), plants: controller.plantViews.getConfig() } } @@ -95,60 +139,13 @@ export class Controller { setConfig(current: PlantControllerConfig) { this.tankView.setConfig(current.tank); this.networkView.setConfig(current.network); - this.nightLampView.setConfig(current.nightLamp); + this.nightLampView.setConfig(current.night_lamp); this.plantViews.setConfig(current.plants); } } - const controller = new Controller(); setTimeout(controller.updateRealTimeData, 1000); - - - - - - -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() +controller.downloadConfig(); diff --git a/rust/src_webpack/src/network.ts b/rust/src_webpack/src/network.ts index e3e693f..da7ef7b 100644 --- a/rust/src_webpack/src/network.ts +++ b/rust/src_webpack/src/network.ts @@ -16,7 +16,9 @@ export class NetworkConfigView { private readonly base_topic: HTMLInputElement; 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.onchange = controller.configChanged @@ -48,10 +50,10 @@ export class NetworkConfigView { getConfig(): NetworkConfig { return { ap_ssid: this.ap_ssid.value, - ssid: this.ssid.value, - password: this.password.value, - mqtt_url: this.mqtt_url.value, - base_topic: this.base_topic.value + ssid: this.ssid.value ?? null, + password: this.password.value ?? null, + mqtt_url: this.mqtt_url.value ?? null, + base_topic: this.base_topic.value ?? null } } } \ No newline at end of file diff --git a/rust/src_webpack/src/plant.ts b/rust/src_webpack/src/plant.ts index 4d7115f..43a0989 100644 --- a/rust/src_webpack/src/plant.ts +++ b/rust/src_webpack/src/plant.ts @@ -1,5 +1,5 @@ -declare const PLANT_COUNT = 8; +const PLANT_COUNT = 8; import { Controller } from "."; diff --git a/rust/src_webpack/src/tanks.ts b/rust/src_webpack/src/tanks.ts index 196bfa9..7400c9b 100644 --- a/rust/src_webpack/src/tanks.ts +++ b/rust/src_webpack/src/tanks.ts @@ -1,7 +1,6 @@ import { Controller } from "."; export class TankConfigView { - private readonly max_consecutive_pump_count: HTMLInputElement; private readonly tank_useable_ml: HTMLInputElement; private readonly tank_empty_percent: HTMLInputElement; private readonly tank_full_percent: HTMLInputElement; @@ -10,8 +9,6 @@ export class TankConfigView { private readonly tank_allow_pumping_if_sensor_error: HTMLInputElement; 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.onchange = controller.configChanged this.tank_empty_percent = document.getElementById("tank_empty_percent") as HTMLInputElement; diff --git a/rust/src_webpack/webpack.config.js b/rust/src_webpack/webpack.config.js index ad95f57..1fd1936 100644 --- a/rust/src_webpack/webpack.config.js +++ b/rust/src_webpack/webpack.config.js @@ -6,7 +6,7 @@ const isDevServer = process.env.WEBPACK_SERVE; console.log("Dev server is " + isDevServer); var host; if (isDevServer){ - host = 'http://10.23.43.24'; + host = 'http://192.168.1.172'; } else { host = ''; } @@ -36,7 +36,7 @@ module.exports = { rules: [ { test: /\.html$/, - type: 'asset/source' + type: 'asset/source', }, { test: /\.tsx?$/,