add pump current configuration

This commit is contained in:
2025-06-26 02:39:32 +02:00
parent 577c38d026
commit 5d91daf23d
12 changed files with 492 additions and 275 deletions

View File

@@ -1,174 +1,185 @@
export interface LogArray extends Array<LogEntry>{}
export interface LogEntry {
timestamp: string,
message_id: number,
a: number,
b: number,
txt_short: string,
txt_long: string
export interface LogArray extends Array<LogEntry> {
}
export interface LogLocalisation extends Array<LogLocalisationEntry>{}
export interface LogEntry {
timestamp: string,
message_id: number,
a: number,
b: number,
txt_short: string,
txt_long: string
}
export interface LogLocalisation extends Array<LogLocalisationEntry> {
}
export interface LogLocalisationEntry {
msg_type: string,
message: string
msg_type: string,
message: string
}
export interface BackupHeader {
timestamp: string,
size: number
timestamp: string,
size: number
}
export interface NetworkConfig {
ap_ssid: string,
ssid: string,
password: string,
mqtt_url: string,
base_topic: string,
max_wait: number
ap_ssid: string,
ssid: string,
password: string,
mqtt_url: string,
base_topic: string,
max_wait: number
}
export interface FileList {
total: number,
used: number,
files: FileInfo[],
file_system_corrupt: string,
iter_error: string,
total: number,
used: number,
files: FileInfo[],
file_system_corrupt: string,
iter_error: string,
}
export interface SolarState{
mppt_voltage: number,
mppt_current: number,
is_day: boolean
export interface SolarState {
mppt_voltage: number,
mppt_current: number,
is_day: boolean
}
export interface FileInfo{
filename: string,
size: number,
export interface FileInfo {
filename: string,
size: number,
}
export interface NightLampConfig {
enabled: boolean,
night_lamp_hour_start: number,
night_lamp_hour_end: number,
night_lamp_only_when_dark: boolean,
low_soc_cutoff: number,
low_soc_restore: number
enabled: boolean,
night_lamp_hour_start: number,
night_lamp_hour_end: number,
night_lamp_only_when_dark: boolean,
low_soc_cutoff: number,
low_soc_restore: number
}
export interface NightLampCommand {
active: boolean
active: boolean
}
export interface TankConfig {
tank_sensor_enabled: boolean,
tank_allow_pumping_if_sensor_error: boolean,
tank_useable_ml: number,
tank_warn_percent: number,
tank_empty_percent: number,
tank_full_percent: number,
tank_sensor_enabled: boolean,
tank_allow_pumping_if_sensor_error: boolean,
tank_useable_ml: number,
tank_warn_percent: number,
tank_empty_percent: number,
tank_full_percent: number,
}
export enum BatteryBoardVersion {
Disabled = "Disabled",
BQ34Z100G1 = "BQ34Z100G1",
WchI2cSlave = "WchI2cSlave"
Disabled = "Disabled",
BQ34Z100G1 = "BQ34Z100G1",
WchI2cSlave = "WchI2cSlave"
}
export enum BoardVersion{
export enum BoardVersion {
INITIAL = "INITIAL",
V3 = "V3",
V4 = "V4"
}
export interface BoardHardware {
board: BoardVersion,
battery: BatteryBoardVersion,
board: BoardVersion,
battery: BatteryBoardVersion,
}
export interface PlantControllerConfig {
hardware: BoardHardware,
hardware: BoardHardware,
network: NetworkConfig,
tank: TankConfig,
night_lamp: NightLampConfig,
plants: PlantConfig[]
timezone?: string,
network: NetworkConfig,
tank: TankConfig,
night_lamp: NightLampConfig,
plants: PlantConfig[]
timezone?: string,
}
export interface PlantConfig {
mode: string,
target_moisture: number,
pump_time_s: number,
pump_cooldown_min: number,
pump_hour_start: number,
pump_hour_end: number,
sensor_a: boolean,
sensor_b: boolean,
max_consecutive_pump_count: number,
moisture_sensor_min_frequency: number | null;
moisture_sensor_max_frequency: number | null;
mode: string,
target_moisture: number,
pump_time_s: number,
pump_cooldown_min: number,
pump_hour_start: number,
pump_hour_end: number,
sensor_a: boolean,
sensor_b: boolean,
max_consecutive_pump_count: number,
moisture_sensor_min_frequency: number | null;
moisture_sensor_max_frequency: number | null;
min_pump_current_ma: number,
max_pump_current_ma: number,
ignore_current_error: boolean,
}
export interface PumpTestResult {
median_current_ma: number,
max_current_ma: number,
min_current_ma: number,
error: boolean,
}
export interface SSIDList {
ssids: [string]
ssids: [string]
}
export interface TestPump {
pump: number
pump: number
}
export interface SetTime {
time: string
time: string
}
export interface GetTime {
rtc: string,
native: string
rtc: string,
native: string
}
export interface Moistures {
moisture_a: [string],
moisture_b: [string],
moisture_a: [string],
moisture_b: [string],
}
export interface VersionInfo {
git_hash: string,
build_time: string,
partition: string
git_hash: string,
build_time: string,
partition: string
}
export 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
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
}
export interface TankInfo {
/// is there enough water in the tank
enough_water: boolean,
/// warning that water needs to be refilled soon
warn_level: boolean,
/// estimation how many ml are still in tank
left_ml: number | null,
/// if there is was an issue with the water level sensor
sensor_error: string | null,
/// raw water sensor value
raw: number | null,
/// percent value
percent: number | null,
/// water in tank might be frozen
water_frozen: boolean,
/// water temperature
water_temp: number | null,
temp_sensor_error: string | null
/// is there enough water in the tank
enough_water: boolean,
/// warning that water needs to be refilled soon
warn_level: boolean,
/// estimation how many ml are still in tank
left_ml: number | null,
/// if there is was an issue with the water level sensor
sensor_error: string | null,
/// raw water sensor value
raw: number | null,
/// percent value
percent: number | null,
/// water in tank might be frozen
water_frozen: boolean,
/// water temperature
water_temp: number | null,
temp_sensor_error: string | null
}

View File

@@ -28,7 +28,7 @@ import {
SetTime, SSIDList, TankInfo,
TestPump,
VersionInfo,
FileList, SolarState
FileList, SolarState, PumpTestResult
} from "./api";
import {SolarView} from "./solarview";
@@ -345,9 +345,10 @@ export class Controller {
method: "POST",
body: pretty
})
.then(response => response.text())
.then(response => response.json() as Promise<PumpTestResult>)
.then(
_ => {
response => {
controller.plantViews.setPumpTestCurrent(plantId, response);
clearTimeout(timerId);
controller.progressview.removeProgress("test_pump");
}

View File

@@ -1,27 +1,30 @@
<style>
.plantsensorkey{
min-width: 100px;
}
.plantsensorvalue{
flex-grow: 1;
}
.plantsensorkey {
min-width: 100px;
}
.plantkey{
min-width: 175px;
}
.plantvalue{
flex-grow: 1;
}
.plantcheckbox{
min-width: 20px;
margin: 0;
}
.plantsensorvalue {
flex-grow: 1;
}
.plantkey {
min-width: 175px;
}
.plantvalue {
flex-grow: 1;
}
.plantcheckbox {
min-width: 20px;
margin: 0;
}
</style>
<div>
<div class="subtitle"
id="plant_${plantId}_header">
id="plant_${plantId}_header">
Plant ${plantId}
</div>
@@ -47,7 +50,8 @@
<div class="flexcontainer">
<div class="plantkey">Pump Cooldown (m):</div>
<input class="plantvalue" id="plant_${plantId}_pump_cooldown_min" type="number" min="0" max="600" placeholder="30">
<input class="plantvalue" id="plant_${plantId}_pump_cooldown_min" type="number" min="0" max="600"
placeholder="30">
</div>
<div class="flexcontainer">
<div class="plantkey">"Pump Hour Start":</div>
@@ -59,8 +63,8 @@
</div>
<div class="flexcontainer">
<div class="plantkey">Warn Pump Count:</div>
<input class="plantvalue" id="plant_${plantId}_max_consecutive_pump_count" type="number" min="1" max="50"
placeholder="10">
<input class="plantvalue" id="plant_${plantId}_max_consecutive_pump_count" type="number" min="1" max="50"
placeholder="10">
</div>
<div class="flexcontainer">
<div class="plantkey">Min Frequency Override</div>
@@ -68,7 +72,7 @@
</div>
<div class="flexcontainer">
<div class="plantkey">Max Frequency Override</div>
<input class="plantvalue" id="plant_${plantId}_max_frequency" type="number" min="1000" max="25000" >
<input class="plantvalue" id="plant_${plantId}_max_frequency" type="number" min="1000" max="25000">
</div>
<div class="flexcontainer">
@@ -79,6 +83,22 @@
<div class="plantkey">Sensor B installed:</div>
<input class="plantcheckbox" id="plant_${plantId}_sensor_b" type="checkbox">
</div>
<div class="flexcontainer">
<h2 class="plantkey">Current config:</h2>
</div>
<div class="flexcontainer">
<div class="plantkey">Min current</div>
<input class="plantvalue" id="plant_${plantId}_min_pump_current_ma" type="number" min="0" max="4500">
</div>
<div class="flexcontainer">
<div class="plantkey">Max current</div>
<input class="plantvalue" id="plant_${plantId}_max_pump_current_ma" type="number" min="0" max="4500">
</div>
<div class="flexcontainer">
<div class="plantkey">Ignore current sensor error</div>
<input class="plantcheckbox" id="plant_${plantId}_ignore_current_error" type="checkbox">
</div>
<div class="flexcontainer">
<button class="subtitle" id="plant_${plantId}_test">Test Pump</button>
@@ -89,11 +109,15 @@
</div>
<div class="flexcontainer">
<span class="plantsensorkey">Sensor A:</span>
<span class="plantsensorvalue" id="plant_${plantId}_moisture_a">loading</span>
<span class="plantsensorvalue" id="plant_${plantId}_moisture_a">not measured</span>
</div>
<div class="flexcontainer">
<div class="plantsensorkey">Sensor B:</div>
<span class="plantsensorvalue" id="plant_${plantId}_moisture_b">loading</span>
<span class="plantsensorvalue" id="plant_${plantId}_moisture_b">not measured</span>
</div>
<div class="flexcontainer">
<div class="plantsensorkey">Test Current</div>
<span class="plantsensorvalue" id="plant_${plantId}_pump_current_result">not_tested</span>
</div>

View File

@@ -1,4 +1,4 @@
import {PlantConfig} from "./api";
import {PlantConfig, PumpTestResult} from "./api";
const PLANT_COUNT = 8;
@@ -9,39 +9,45 @@ export class PlantViews {
private readonly measure_moisture: HTMLButtonElement;
private readonly plants: PlantView[] = []
private readonly plantsDiv: HTMLDivElement
constructor(syncConfig:Controller) {
this.measure_moisture = document.getElementById("measure_moisture") as HTMLButtonElement
this.measure_moisture.onclick = syncConfig.measure_moisture
this.plantsDiv = document.getElementById("plants") as HTMLDivElement;
for (let plantId = 0; plantId < PLANT_COUNT; plantId++) {
this.plants[plantId] = new PlantView(plantId, this.plantsDiv, syncConfig);
}
constructor(syncConfig: Controller) {
this.measure_moisture = document.getElementById("measure_moisture") as HTMLButtonElement
this.measure_moisture.onclick = syncConfig.measure_moisture
this.plantsDiv = document.getElementById("plants") as HTMLDivElement;
for (let plantId = 0; plantId < PLANT_COUNT; plantId++) {
this.plants[plantId] = new PlantView(plantId, this.plantsDiv, syncConfig);
}
}
getConfig(): PlantConfig[] {
const rv: PlantConfig[] = [];
for (let i = 0; i < PLANT_COUNT; i++) {
rv[i] = this.plants[i].getConfig();
}
return rv
const rv: PlantConfig[] = [];
for (let i = 0; i < PLANT_COUNT; i++) {
rv[i] = this.plants[i].getConfig();
}
return rv
}
update(moisture_a: [string], moisture_b: [string]) {
for (let plantId = 0; plantId < PLANT_COUNT; plantId++) {
const a = moisture_a[plantId]
const b = moisture_b[plantId]
this.plants[plantId].update(a,b)
}
for (let plantId = 0; plantId < PLANT_COUNT; plantId++) {
const a = moisture_a[plantId]
const b = moisture_b[plantId]
this.plants[plantId].setMeasurementResult(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)
}
for (let plantId = 0; plantId < PLANT_COUNT; plantId++) {
const plantConfig = plants[plantId];
const plantView = this.plants[plantId];
plantView.setConfig(plantConfig)
}
}
}
setPumpTestCurrent(plantId: number, response: PumpTestResult) {
const plantView = this.plants[plantId];
plantView.setTestResult(response)
}
}
export class PlantView {
private readonly moistureSensorMinFrequency: HTMLInputElement;
@@ -60,109 +66,135 @@ export class PlantView {
private readonly mode: HTMLSelectElement;
private readonly moistureA: HTMLElement;
private readonly moistureB: HTMLElement;
private readonly pump_current_result: HTMLElement
private readonly maxConsecutivePumpCount: HTMLInputElement;
constructor(plantId: number, parent:HTMLDivElement, controller:Controller) {
private readonly minPumpCurrentMa: HTMLInputElement;
private readonly maxPumpCurrentMa: HTMLInputElement;
private readonly ignoreCurrentError: HTMLInputElement;
constructor(plantId: number, parent: HTMLDivElement, controller: Controller) {
this.plantId = plantId;
this.plantDiv = document.createElement("div")! as HTMLDivElement
const template = require('./plant.html') as string;
this.plantDiv = document.createElement("div")! as HTMLDivElement
const template = require('./plant.html') as string;
this.plantDiv.innerHTML = template.replaceAll("${plantId}", String(plantId))
this.plantDiv.classList.add("plantcontainer")
parent.appendChild(this.plantDiv)
this.header = document.getElementById("plant_"+plantId+"_header")!
this.header.innerText = "Plant "+ (this.plantId+1)
this.moistureA = document.getElementById("plant_"+plantId+"_moisture_a")! as HTMLElement;
this.moistureB = document.getElementById("plant_"+plantId+"_moisture_b")! as HTMLElement;
this.testButton = document.getElementById("plant_"+plantId+"_test")! as HTMLButtonElement;
this.testButton.onclick = function(){
controller.testPlant(plantId)
}
this.plantDiv.classList.add("plantcontainer")
parent.appendChild(this.plantDiv)
this.mode = document.getElementById("plant_"+plantId+"_mode") as HTMLSelectElement
this.mode.onchange = function(){
controller.configChanged()
}
this.header = document.getElementById("plant_" + plantId + "_header")!
this.header.innerText = "Plant " + (this.plantId + 1)
this.targetMoisture = document.getElementById("plant_"+plantId+"_target_moisture")! as HTMLInputElement;
this.targetMoisture.onchange = function(){
controller.configChanged()
}
this.moistureA = document.getElementById("plant_" + plantId + "_moisture_a")! as HTMLElement;
this.moistureB = document.getElementById("plant_" + plantId + "_moisture_b")! as HTMLElement;
this.pump_current_result = document.getElementById("plant_" + plantId + "_pump_current_result")! as HTMLElement;
this.pumpTimeS = document.getElementById("plant_"+plantId+"_pump_time_s") as HTMLInputElement;
this.pumpTimeS.onchange = function(){
controller.configChanged()
}
this.pumpCooldown = document.getElementById("plant_"+plantId+"_pump_cooldown_min") as HTMLInputElement;
this.pumpCooldown.onchange = function(){
controller.configChanged()
}
this.pumpHourStart = document.getElementById("plant_"+plantId+"_pump_hour_start") as HTMLSelectElement;
this.pumpHourStart.onchange = function(){
controller.configChanged()
}
for (let i = 0; i < 24; i++) {
let option = document.createElement("option");
if (i == 10){
option.selected = true
this.testButton = document.getElementById("plant_" + plantId + "_test")! as HTMLButtonElement;
this.testButton.onclick = function () {
controller.testPlant(plantId)
}
option.innerText = i.toString();
this.pumpHourStart.appendChild(option);
}
this.pumpHourEnd = document.getElementById("plant_"+plantId+"_pump_hour_end") as HTMLSelectElement;
this.pumpHourEnd.onchange = function(){
controller.configChanged()
}
for (let i = 0; i < 24; i++) {
let option = document.createElement("option");
if (i == 19){
option.selected = true
this.mode = document.getElementById("plant_" + plantId + "_mode") as HTMLSelectElement
this.mode.onchange = function () {
controller.configChanged()
}
option.innerText = i.toString();
this.pumpHourEnd.appendChild(option);
}
this.sensorAInstalled = document.getElementById("plant_"+plantId+"_sensor_a") as HTMLInputElement;
this.sensorAInstalled.onchange = function(){
controller.configChanged()
}
this.targetMoisture = document.getElementById("plant_" + plantId + "_target_moisture")! as HTMLInputElement;
this.targetMoisture.onchange = function () {
controller.configChanged()
}
this.sensorBInstalled = document.getElementById("plant_"+plantId+"_sensor_b") as HTMLInputElement;
this.sensorBInstalled.onchange = function(){
controller.configChanged()
}
this.pumpTimeS = document.getElementById("plant_" + plantId + "_pump_time_s") as HTMLInputElement;
this.pumpTimeS.onchange = function () {
controller.configChanged()
}
this.maxConsecutivePumpCount = document.getElementById("plant_"+plantId+"_max_consecutive_pump_count") as HTMLInputElement;
this.maxConsecutivePumpCount.onchange = function(){
controller.configChanged()
}
this.pumpCooldown = document.getElementById("plant_" + plantId + "_pump_cooldown_min") as HTMLInputElement;
this.pumpCooldown.onchange = function () {
controller.configChanged()
}
this.moistureSensorMinFrequency = document.getElementById("plant_"+plantId+"_min_frequency") as HTMLInputElement;
this.moistureSensorMinFrequency.onchange = function(){
this.pumpHourStart = document.getElementById("plant_" + plantId + "_pump_hour_start") as HTMLSelectElement;
this.pumpHourStart.onchange = function () {
controller.configChanged()
}
for (let i = 0; i < 24; i++) {
let option = document.createElement("option");
if (i == 10) {
option.selected = true
}
option.innerText = i.toString();
this.pumpHourStart.appendChild(option);
}
this.pumpHourEnd = document.getElementById("plant_" + plantId + "_pump_hour_end") as HTMLSelectElement;
this.pumpHourEnd.onchange = function () {
controller.configChanged()
}
for (let i = 0; i < 24; i++) {
let option = document.createElement("option");
if (i == 19) {
option.selected = true
}
option.innerText = i.toString();
this.pumpHourEnd.appendChild(option);
}
this.sensorAInstalled = document.getElementById("plant_" + plantId + "_sensor_a") as HTMLInputElement;
this.sensorAInstalled.onchange = function () {
controller.configChanged()
}
this.sensorBInstalled = document.getElementById("plant_" + plantId + "_sensor_b") as HTMLInputElement;
this.sensorBInstalled.onchange = function () {
controller.configChanged()
}
this.minPumpCurrentMa = document.getElementById("plant_" + plantId + "_min_pump_current_ma") as HTMLInputElement;
this.minPumpCurrentMa.onchange = function () {
controller.configChanged()
}
this.maxPumpCurrentMa = document.getElementById("plant_" + plantId + "_max_pump_current_ma") as HTMLInputElement;
this.maxPumpCurrentMa.onchange = function () {
controller.configChanged()
}
this.ignoreCurrentError = document.getElementById("plant_" + plantId + "_ignore_current_error") as HTMLInputElement;
this.ignoreCurrentError.onchange = function () {
controller.configChanged()
}
this.maxConsecutivePumpCount = document.getElementById("plant_" + plantId + "_max_consecutive_pump_count") as HTMLInputElement;
this.maxConsecutivePumpCount.onchange = function () {
controller.configChanged()
}
this.moistureSensorMinFrequency = document.getElementById("plant_" + plantId + "_min_frequency") as HTMLInputElement;
this.moistureSensorMinFrequency.onchange = function () {
controller.configChanged()
}
this.moistureSensorMinFrequency.onchange = () => {
controller.configChanged();
};
this.moistureSensorMaxFrequency = document.getElementById("plant_"+plantId+"_max_frequency") as HTMLInputElement;
this.moistureSensorMaxFrequency = document.getElementById("plant_" + plantId + "_max_frequency") as HTMLInputElement;
this.moistureSensorMaxFrequency.onchange = () => {
controller.configChanged();
};
}
update(a: string, b: string) {
setTestResult(result: PumpTestResult) {
this.pump_current_result.innerText = "Did abort " + result.error + " median current " + result.median_current_ma + " max current " + result.max_current_ma + " min current " + result.min_current_ma
}
setMeasurementResult(a: string, b: string) {
this.moistureA.innerText = a
this.moistureB.innerText = b
}
setConfig(plantConfig: PlantConfig) {
this.mode.value = plantConfig.mode;
this.targetMoisture.value = plantConfig.target_moisture.toString();
@@ -173,6 +205,9 @@ export class PlantView {
this.sensorBInstalled.checked = plantConfig.sensor_b;
this.sensorAInstalled.checked = plantConfig.sensor_a;
this.maxConsecutivePumpCount.value = plantConfig.max_consecutive_pump_count.toString();
this.minPumpCurrentMa.value = plantConfig.min_pump_current_ma.toString();
this.maxPumpCurrentMa.value = plantConfig.max_pump_current_ma.toString();
this.ignoreCurrentError.checked = plantConfig.ignore_current_error;
// Set new fields
this.moistureSensorMinFrequency.value =
@@ -193,7 +228,10 @@ export class PlantView {
sensor_a: this.sensorAInstalled.checked,
max_consecutive_pump_count: this.maxConsecutivePumpCount.valueAsNumber,
moisture_sensor_min_frequency: this.moistureSensorMinFrequency.valueAsNumber || null,
moisture_sensor_max_frequency: this.moistureSensorMaxFrequency.valueAsNumber || null
moisture_sensor_max_frequency: this.moistureSensorMaxFrequency.valueAsNumber || null,
min_pump_current_ma: this.minPumpCurrentMa.valueAsNumber,
max_pump_current_ma: this.maxPumpCurrentMa.valueAsNumber,
ignore_current_error: this.ignoreCurrentError.checked,
};
}
}
}