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) => {
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 {} {}",

View File

@ -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<heapless::String<32>>) -> 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<DateTime<Utc>> {
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")
},
}
})?;

View File

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

View File

@ -31,6 +31,7 @@
</form>
<div>
<div id="remote_ip">remote ip</div>
<h2>WIFI</h2>
<input type="button" id="scan" value="Scan">
<br>
@ -52,12 +53,12 @@
<div id="configform">
<h3>Mqtt:</h3>
<div>
<input type="text" id="mqtt_url">
MQTT Url
<input type="text" id="mqtt_url" placeholder="mqtt://192.168.1.1:1883">
</div>
<div>
<input type="text" id="base_topic">
Base Topic
<input type="text" id="base_topic" placeholder="plants/one">
</div>
@ -114,13 +115,6 @@
</form>
<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>
<button id="submit">Submit</button>

View File

@ -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();

View File

@ -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
}
}
}

View File

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

View File

@ -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;

View File

@ -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?$/,