diff --git a/rust/src_webpack/src/index.html b/rust/src_webpack/src/index.html index c78c784..bf1494e 100644 --- a/rust/src_webpack/src/index.html +++ b/rust/src_webpack/src/index.html @@ -1,7 +1,9 @@ - - - + + + + +

Current Firmware

@@ -10,12 +12,12 @@
Build githash loading

Time

-
-
Esp time
-
Rtc time
-
Rtc time
+
+
Esp time
+
Rtc time
+
Rtc time
Store Browser time into esp and rtc
- +

firmeware OTA v3

@@ -38,13 +40,13 @@ - -
+ + -

config

@@ -69,7 +71,7 @@ Allow Pumping if Sensor Error
- +
Tank Size mL @@ -108,9 +110,9 @@

-
+
- +

Plants:

@@ -118,7 +120,7 @@ Max consecutive pump count:
- +
@@ -128,4 +130,4 @@ - + \ No newline at end of file diff --git a/rust/src_webpack/src/index.ts b/rust/src_webpack/src/index.ts index e45faf0..1bf1a2b 100644 --- a/rust/src_webpack/src/index.ts +++ b/rust/src_webpack/src/index.ts @@ -6,16 +6,33 @@ console.log("Url is " + PUBLIC_URL); import { TimeView } from "./timeview"; import { PlantView, PlantViews } from "./plant"; import { NetworkConfigView } from "./network"; +import { NightLampView } from "./nightmode"; +import { TankConfigView } from "./tanks"; export class Controller { - readonly timeView: TimeView - readonly plantViews: PlantViews + readonly timeView: TimeView; + readonly plantViews: PlantViews; readonly networkView: NetworkConfigView; + readonly tankView: TankConfigView; + readonly nightLampView: NightLampView; constructor() { - this.timeView = new TimeView() + this.timeView = new TimeView(this) this.plantViews = new PlantViews(this) this.networkView = new NetworkConfigView(this) + this.tankView = new TankConfigView(this) + this.nightLampView = new NightLampView(this) + } + + syncRTCFromBrowser(){ + var value: SetTime = { + time: new Date().toISOString() + } + var pretty = JSON.stringify(value, undefined, 1); + fetch(PUBLIC_URL + "/time", { + method: "POST", + body: pretty + }) } configChanged() { @@ -40,15 +57,9 @@ export class Controller { .then(response => response.json()) .then(json => json as GetData) .then(time => { + controller.timeView.update(time.native, time.rtc) - - time.moisture_a.forEach((a, index) => { - controller.plantViews.getPlant(index).setMoistureA(a); - }) - time.moisture_b.forEach((b, index) => { - controller.plantViews.getPlant(index).setMoistureB(b); - }) - + controller.plantViews.update(time.moisture_a, time.moisture_b) setTimeout(controller.updateRealTimeData, 1000); }) .catch(error => { @@ -57,6 +68,36 @@ export class Controller { }); } + getConfig(): PlantControllerConfig{ + return { + network: controller.networkView.getConfig(), + tank: controller.tankView.getConfig(), + nightLamp: controller.nightLampView.getConfig(), + plants: controller.plantViews.getConfig() + } + } + + scanWifi() { + var ajax = new XMLHttpRequest(); + ajax.responseType = 'json'; + ajax.onreadystatechange = () => { + if (ajax.readyState === 4) { + this.networkView.setScanResult(ajax.response as SSIDList) + } + }; + ajax.onerror = (evt) => { + alert("Failed to start see console") + } + ajax.open("POST", PUBLIC_URL + "/wifiscan"); + ajax.send(); + } + + setConfig(current: PlantControllerConfig) { + this.tankView.setConfig(current.tank); + this.networkView.setConfig(current.network); + this.nightLampView.setConfig(current.nightLamp); + this.plantViews.setConfig(current.plants); + } } const controller = new Controller(); @@ -66,178 +107,18 @@ setTimeout(controller.updateRealTimeData, 1000); -let scanWifiBtn = document.getElementById("scan") as HTMLButtonElement; -if (scanWifiBtn) { - scanWifiBtn.onclick = scanWifi; -} - - -export function scanWifi() { - var scanButton = (document.getElementById("scan") as HTMLButtonElement); - scanButton.disabled = true; - - var ajax = new XMLHttpRequest(); - ajax.responseType = 'json'; - ajax.onreadystatechange = () => { - if (ajax.readyState === 4) { - callback(ajax.response); - } - }; - ajax.onerror = (evt) => { - console.log(evt) - scanButton.disabled = false; - alert("Failed to start see console") - } - ajax.open("POST", PUBLIC_URL + "/wifiscan"); - ajax.send(); -} - -function callback(data: SSIDList) { - var ssidlist = document.getElementById("ssidlist") as HTMLElement - ssidlist.innerHTML = '' - - for (var ssid of data.ssids) { - var wi = document.createElement("option"); - wi.value = ssid; - ssidlist.appendChild(wi); - } -} - -function addTimeOptions(select: HTMLSelectElement) { - for (let i = 0; i < 24; i++) { - let option = document.createElement("option"); - option.innerText = i.toString(); - select.appendChild(option); - } -} - -class TankConfigView { - max_consecutive_pump_count: HTMLInputElement; - tank_useable_ml: HTMLInputElement; - tank_empty_percent: HTMLInputElement; - tank_full_percent: HTMLInputElement; - tank_warn_percent: HTMLInputElement; - tank_sensor_enabled: HTMLInputElement; - 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; - this.tank_empty_percent.onchange = controller.configChanged - this.tank_full_percent = document.getElementById("tank_full_percent") as HTMLInputElement; - this.tank_full_percent.onchange = controller.configChanged - this.tank_warn_percent = document.getElementById("tank_warn_percent") as HTMLInputElement; - this.tank_warn_percent.onchange = controller.configChanged - this.tank_sensor_enabled = document.getElementById("tank_sensor_enabled") as HTMLInputElement; - this.tank_sensor_enabled.onchange = controller.configChanged - this.tank_allow_pumping_if_sensor_error = document.getElementById("tank_allow_pumping_if_sensor_error") as HTMLInputElement; - this.tank_allow_pumping_if_sensor_error.onchange = controller.configChanged - } -} - -class NightLampView { - night_lamp_only_when_dark: HTMLInputElement; - night_lamp_time_start: HTMLSelectElement; - night_lamp_time_end: HTMLSelectElement; - constructor(){ - this.night_lamp_only_when_dark = document.getElementById("night_lamp_only_when_dark") as HTMLInputElement; - this.night_lamp_only_when_dark.onchange = updateJson - this.night_lamp_time_start = document.getElementById("night_lamp_time_start") as HTMLSelectElement; - this.night_lamp_time_start.onchange = updateJson - for (let i = 0; i < 24; i++) { - let option = document.createElement("option"); - if (i == 20){ - option.selected = true - } - option.innerText = i.toString(); - this.night_lamp_time_start.appendChild(option); - } - this.night_lamp_time_end = document.getElementById("night_lamp_time_end") as HTMLSelectElement; - this.night_lamp_time_end.onchange = updateJson - - - for (let i = 0; i < 24; i++) { - let option = document.createElement("option"); - if (i == 1){ - option.selected = true - } - option.innerText = i.toString(); - this.night_lamp_time_end.appendChild(option); - } - } -} - - function updateJson() { - var current: PlantControllerConfig = { - network: controller.networkView.getConfig(), - tank_sensor_enabled: tank_sensor_enabled.checked, - tank_useable_ml: +tank_useable_ml.value, - tank_warn_percent: +tank_warn_percent.value, - tank_empty_percent: +tank_empty_percent.value, - tank_full_percent: +tank_full_percent.value, - night_lamp_hour_start: +night_lamp_time_start.value, - night_lamp_hour_end: +night_lamp_time_end.value, - night_lamp_only_when_dark: night_lamp_only_when_dark.checked, - plants: [] - } + const current = controller.getConfig(); - for (let i = 0; i < 8; i++) { - current.plants[i] = controller.plantViews.getPlant(i).getConfig(); - } - //sync(current); console.log(current); var pretty = JSON.stringify(current, undefined, 1); console.log(pretty) - //json.value = pretty; } let fromWrapper = (() => { - - let plantcount = 0; - - - - let json = document.getElementById('json') as HTMLInputElement - - - function sync(current: PlantControllerConfig) { - plantcount = current.plants.length - - ap_ssid.value = current.ap_ssid; - ssid.value = current.ssid; - password.value = current.password; - - mqtt_url.value = current.mqtt_url; - base_topic.value = current.base_topic; - max_consecutive_pump_count.value = current.max_consecutive_pump_count.toString(); - - tank_useable_ml.disabled = !current.tank_sensor_enabled; - tank_warn_percent.disabled = !current.tank_sensor_enabled; - tank_sensor_enabled.checked = current.tank_sensor_enabled; - tank_allow_pumping_if_sensor_error.checked = current.tank_allow_pumping_if_sensor_error; - tank_useable_ml.value = current.tank_useable_ml.toString(); - tank_warn_percent.value = current.tank_warn_percent.toString(); - tank_empty_percent.value = current.tank_empty_percent.toString(); - tank_full_percent.value = current.tank_full_percent.toString(); - - night_lamp_time_start.value = current.night_lamp_hour_start.toString(); - night_lamp_time_end.value = current.night_lamp_hour_end.toString(); - - for (let i = 0; i < current.plants.length; i++) { - const plantConfig = current.plants[i]; - const plantView = controller.plantViews.getPlant(i); - plantView.setConfig(plantConfig) - } - } - - let submitFormBtn = document.getElementById("submit") as HTMLButtonElement let submit_status = document.getElementById("submit_status") as HTMLElement @@ -261,7 +142,7 @@ let fromWrapper = (() => { .then(response => response.json()) .then(loaded => { var currentConfig = loaded as PlantControllerConfig; - sync(currentConfig); + controller.setConfig(currentConfig); var pretty = JSON.stringify(currentConfig, undefined, 1); json.value = pretty; } diff --git a/rust/src_webpack/src/network.ts b/rust/src_webpack/src/network.ts index 1b7f423..e3e693f 100644 --- a/rust/src_webpack/src/network.ts +++ b/rust/src_webpack/src/network.ts @@ -1,13 +1,12 @@ import { Controller } from "."; 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 + setScanResult(ssidList: SSIDList) { + this.ssidlist.innerHTML = '' + for (var ssid of ssidList.ssids) { + var wi = document.createElement("option"); + wi.value = ssid; + this.ssidlist.appendChild(wi); } } private readonly ap_ssid: HTMLInputElement; @@ -15,7 +14,8 @@ export class NetworkConfigView { private readonly password: HTMLInputElement; private readonly mqtt_url: HTMLInputElement; private readonly base_topic: HTMLInputElement; - + private readonly ssidlist: HTMLElement; + constructor(controller: Controller) { this.ap_ssid = (document.getElementById("ap_ssid") as HTMLInputElement); this.ap_ssid.onchange = controller.configChanged @@ -28,5 +28,30 @@ export class NetworkConfigView { this.mqtt_url.onchange = controller.configChanged this.base_topic = document.getElementById("base_topic") as HTMLInputElement; this.base_topic.onchange = controller.configChanged + + this.ssidlist = document.getElementById("ssidlist") as HTMLElement + + let scanWifiBtn = document.getElementById("scan") as HTMLButtonElement; + scanWifiBtn.onclick = function (){ + controller.scanWifi(); + } + } + + setConfig(network: NetworkConfig) { + this.ap_ssid.value = network.ap_ssid; + this.ssid.value = network.ssid; + this.password.value = network.password; + this.mqtt_url.value = network.mqtt_url; + this.base_topic.value = network.base_topic; + } + + 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 + } } } \ No newline at end of file diff --git a/rust/src_webpack/src/nightmode.ts b/rust/src_webpack/src/nightmode.ts new file mode 100644 index 0000000..10105d0 --- /dev/null +++ b/rust/src_webpack/src/nightmode.ts @@ -0,0 +1,46 @@ +import { Controller } from "."; + +export class NightLampView { + private readonly night_lamp_only_when_dark: HTMLInputElement; + private readonly night_lamp_time_start: HTMLSelectElement; + private readonly night_lamp_time_end: HTMLSelectElement; + constructor(controller:Controller){ + this.night_lamp_only_when_dark = document.getElementById("night_lamp_only_when_dark") as HTMLInputElement; + this.night_lamp_only_when_dark.onchange = controller.configChanged + this.night_lamp_time_start = document.getElementById("night_lamp_time_start") as HTMLSelectElement; + this.night_lamp_time_start.onchange = controller.configChanged + for (let i = 0; i < 24; i++) { + let option = document.createElement("option"); + if (i == 20){ + option.selected = true + } + option.innerText = i.toString(); + this.night_lamp_time_start.appendChild(option); + } + this.night_lamp_time_end = document.getElementById("night_lamp_time_end") as HTMLSelectElement; + this.night_lamp_time_end.onchange = controller.configChanged + + for (let i = 0; i < 24; i++) { + let option = document.createElement("option"); + if (i == 1){ + option.selected = true + } + option.innerText = i.toString(); + this.night_lamp_time_end.appendChild(option); + } + } + + setConfig(nightLamp: NightLampConfig) { + this.night_lamp_only_when_dark.checked = nightLamp.night_lamp_only_when_dark + this.night_lamp_time_start.value = nightLamp.night_lamp_hour_start.toString(); + this.night_lamp_time_end.value = nightLamp.night_lamp_hour_end.toString(); + } + + getConfig(): NightLampConfig { + return { + night_lamp_hour_start: +this.night_lamp_time_start.value, + night_lamp_hour_end: +this.night_lamp_time_end.value, + night_lamp_only_when_dark: this.night_lamp_only_when_dark.checked, + } + } + } \ No newline at end of file diff --git a/rust/src_webpack/src/plant.ts b/rust/src_webpack/src/plant.ts index f10e692..4d7115f 100644 --- a/rust/src_webpack/src/plant.ts +++ b/rust/src_webpack/src/plant.ts @@ -1,22 +1,41 @@ -declare var PUBLIC_URL: string; +declare const PLANT_COUNT = 8; + import { Controller } from "."; export class PlantViews { + getConfig(): PlantConfig[] { + const rv: PlantConfig[] = []; + for (let i = 0; i < PLANT_COUNT; i++) { + rv[i] = this.plants[i].getConfig(); + } + return rv + } + update(moisture_a: [number], moisture_b: [number]) { + for (let plantId = 0; plantId < PLANT_COUNT; plantId++) { + const a = moisture_a[plantId] + const b = moisture_b[plantId] + this.plants[plantId].update(a,b) + } + } + + setConfig(plants: PlantConfig[]) { + for (let plantId = 0; plantId < PLANT_COUNT; plantId++) { + const plantConfig = plants[plantId]; + const plantView = this.plants[plantId]; + plantView.setConfig(plantConfig) + } + } private readonly plants: PlantView[] = [] private readonly plantsDiv: HTMLDivElement constructor(syncConfig:Controller) { this.plantsDiv = document.getElementById("plants") as HTMLDivElement; - for (let plantId = 0; plantId < 8; plantId++) { + for (let plantId = 0; plantId < PLANT_COUNT; plantId++) { this.plants[plantId] = new PlantView(plantId, this.plantsDiv, syncConfig); } } - - getPlant(plantId: number) { - return this.plants[plantId] - } } export class PlantView { @@ -113,6 +132,11 @@ export class PlantView { } console.log(this) } + + update(a: number, b: number) { + this.moistureA.innerText = String(a) + this.moistureB.innerText = String(b) + } setConfig(plantConfig: PlantConfig) { console.log("apply config to ui plant " + this.plantId + " config: " + JSON.stringify(plantConfig)) diff --git a/rust/src_webpack/src/tanks.ts b/rust/src_webpack/src/tanks.ts new file mode 100644 index 0000000..196bfa9 --- /dev/null +++ b/rust/src_webpack/src/tanks.ts @@ -0,0 +1,47 @@ +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; + private readonly tank_warn_percent: HTMLInputElement; + private readonly tank_sensor_enabled: HTMLInputElement; + 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; + this.tank_empty_percent.onchange = controller.configChanged + this.tank_full_percent = document.getElementById("tank_full_percent") as HTMLInputElement; + this.tank_full_percent.onchange = controller.configChanged + this.tank_warn_percent = document.getElementById("tank_warn_percent") as HTMLInputElement; + this.tank_warn_percent.onchange = controller.configChanged + this.tank_sensor_enabled = document.getElementById("tank_sensor_enabled") as HTMLInputElement; + this.tank_sensor_enabled.onchange = controller.configChanged + this.tank_allow_pumping_if_sensor_error = document.getElementById("tank_allow_pumping_if_sensor_error") as HTMLInputElement; + this.tank_allow_pumping_if_sensor_error.onchange = controller.configChanged + } + + setConfig(tank: TankConfig) { + this.tank_allow_pumping_if_sensor_error.checked = tank.tank_allow_pumping_if_sensor_error; + this.tank_empty_percent.value = String(tank.tank_empty_percent) + this.tank_warn_percent.value = String(tank.tank_warn_percent) + this.tank_full_percent.value = String(tank.tank_full_percent) + this.tank_sensor_enabled.checked = tank.tank_sensor_enabled + this.tank_useable_ml.value = String(tank.tank_useable_ml) + } + getConfig(): TankConfig { + return { + tank_allow_pumping_if_sensor_error: this.tank_allow_pumping_if_sensor_error.checked, + tank_empty_percent : this.tank_empty_percent.valueAsNumber, + tank_full_percent: this.tank_full_percent.valueAsNumber, + tank_sensor_enabled: this.tank_sensor_enabled.checked, + tank_useable_ml: this.tank_useable_ml.valueAsNumber, + tank_warn_percent: this.tank_warn_percent.valueAsNumber + } + } + } \ No newline at end of file diff --git a/rust/src_webpack/src/timeview.ts b/rust/src_webpack/src/timeview.ts index 6dfe1f4..91ff24a 100644 --- a/rust/src_webpack/src/timeview.ts +++ b/rust/src_webpack/src/timeview.ts @@ -1,34 +1,23 @@ -declare var PUBLIC_URL: string; +import { Controller } from "."; - export class TimeView { - esp_time: HTMLDivElement - rtc_time: HTMLDivElement - browser_time: HTMLDivElement - sync: HTMLButtonElement - - constructor() { - this.esp_time = document.getElementById("esp_time") as HTMLDivElement; - this.rtc_time = document.getElementById("rtc_time") as HTMLDivElement; - this.browser_time = document.getElementById("browser_time") as HTMLDivElement; - this.sync = document.getElementById("time_upload") as HTMLButtonElement; - this.sync.onclick = this.syncTimeFromBrowser; - } - - update(native: string, rtc: string) { - this.esp_time.innerText = native; - this.rtc_time.innerText = rtc; - var date = new Date(); - this.browser_time.innerText = date.toISOString(); - } - - syncTimeFromBrowser() { - var value: SetTime = { - time: new Date().toISOString() - } - var pretty = JSON.stringify(value, undefined, 1); - fetch(PUBLIC_URL + "/time", { - method: "POST", - body: pretty - }) - } - } \ No newline at end of file +export class TimeView { + esp_time: HTMLDivElement + rtc_time: HTMLDivElement + browser_time: HTMLDivElement + sync: HTMLButtonElement + + constructor(controller:Controller) { + this.esp_time = document.getElementById("timeview_esp_time") as HTMLDivElement; + this.rtc_time = document.getElementById("timeview_rtc_time") as HTMLDivElement; + this.browser_time = document.getElementById("timeview_browser_time") as HTMLDivElement; + this.sync = document.getElementById("timeview_time_upload") as HTMLButtonElement; + this.sync.onclick = controller.syncRTCFromBrowser; + } + + update(native: string, rtc: string) { + this.esp_time.innerText = native; + this.rtc_time.innerText = rtc; + var date = new Date(); + this.browser_time.innerText = date.toISOString(); + } + } \ No newline at end of file