Javascript cleanup

This commit is contained in:
2026-03-04 12:03:39 +01:00
parent 56b9d04cf8
commit 627790b5fc
7 changed files with 31 additions and 303 deletions

8
README
View File

@@ -149,16 +149,16 @@ Bill of materials (WIP)
1x buzzer 12V, passive 1x buzzer 12V, passive
1x MOSFET 2N7000 1x MOSFET 2N7000
1x resistor 150 Ω 1x resistor 150 Ω
1x wiring set for buttons, 0.25 mm², 15cm each 1x wiring set for buttons, 0.25 mm²
8x black (GND) 7x black (GND), 10cm each
7x colored (signal) 7x colored (signal), 15cm each
1x screw terminal block 2pol. 2.54mm 1x screw terminal block 2pol. 2.54mm
1x 3D enclosure consisting of front and back 1x 3D enclosure consisting of front and back
1x nut tool, 3D-printed 1x nut tool, 3D-printed
4x mounting screws M4 countersunk 4x mounting screws M4 countersunk
4x enclosure screws M2.5, long 4x enclosure screws M2.5, long
8x PCB screws M2.5, short 8x PCB screws M2.5, short
1x silicone sealing cord 2 mm 1x silicone sealing cord 2 mm, l=380mm
1x SHT31 I²C module 1x SHT31 I²C module
1x female header 2.54 mm 1x female header 2.54 mm
1x pin header 2.54mm 1x pin header 2.54mm

View File

@@ -157,16 +157,16 @@ Bauteilliste (WIP)
1x Buzzer 12V, passiv 1x Buzzer 12V, passiv
1x MOSFET 2N7000 1x MOSFET 2N7000
1x Widerstand 150 Ω 1x Widerstand 150 Ω
1x Kabelsatz für Tasten, 0,25 mm², je 15cm lang 1x Kabelsatz für Tasten, 0,25 mm²
8x schwarz (GND) 7x schwarz (GND), je 10cm lang
7x farbig (Signal) 7x farbig (Signal), je 15cm lang
1x Terminalblock 2pol. 2,54mm schraubbar 1x Terminalblock 2pol. 2,54mm schraubbar
1x 3D-Gehäuse bestehend auf Front- und Rückseite 1x 3D-Gehäuse bestehend auf Front- und Rückseite
1x Mutternwerkzeug 3D-Druck 1x Mutternwerkzeug 3D-Druck
4x Befestigungsschraube M4 Senkkopf 4x Befestigungsschraube M4 Senkkopf
4x Gehäuseschraube M2,5, lang 4x Gehäuseschraube M2,5, lang
8x Platinenschraube M2,5, kurz 8x Platinenschraube M2,5, kurz
1x Silikondichtschnur 2mm 1x Silikondichtschnur 2mm, l=380mm
1x SHT31 I²C-Modul 1x SHT31 I²C-Modul
1x Buchsenleiste 2,54 mm 1x Buchsenleiste 2,54 mm
1x Stiftleiste 2,54mm 1x Stiftleiste 2,54mm

View File

@@ -53,6 +53,15 @@ def postbuild(source, target, env):
firmware = env.subst("$BUILD_DIR/${PROGNAME}.bin") firmware = env.subst("$BUILD_DIR/${PROGNAME}.bin")
(fwname, fwversion) = getFirmwareInfo(firmware) (fwname, fwversion) = getFirmwareInfo(firmware)
pcbvers = "unknown"
for x in env["BUILD_FLAGS"]:
if not x.startswith('-D'):
continue
opt = x[2:].strip()
if opt.startswith("HARDWARE_"):
pcbvers = x.split('_')[1].lower()
print(f"compiled for pcb version {pcbvers}")
esptool = env.get('UPLOADER') esptool = env.get('UPLOADER')
uploaderflags = env.subst("${UPLOADERFLAGS}") uploaderflags = env.subst("${UPLOADERFLAGS}")
base = env.subst("$PIOENV") base = env.subst("$PIOENV")
@@ -91,9 +100,9 @@ def postbuild(source, target, env):
env.Execute(' '.join(cmd), "#merging bin files") env.Execute(' '.join(cmd), "#merging bin files")
# Create symlinks to better identify firmware # Create symlinks to better identify firmware
fw_update = os.path.join(outdir, f"{base}-{fwversion}-update.bin") fw_update = os.path.join(outdir, f"{base}_{pcbvers}-{fwversion}-update.bin")
os.symlink(firmware, fw_update) os.symlink(firmware, fw_update)
fw_full = os.path.join(outdir, f"{base}-{fwversion}-all.bin") fw_full = os.path.join(outdir, f"{base}_{pcbvers}-{fwversion}-all.bin")
os.symlink(outfile, fw_full) os.symlink(outfile, fw_full)
env.AddPostAction( env.AddPostAction(

View File

@@ -29,7 +29,6 @@ extra_scripts =
post:extra_post.py post:extra_post.py
lib_ldf_mode = chain lib_ldf_mode = chain
monitor_speed = 115200 monitor_speed = 115200
# monitor_raw = yes
build_flags = build_flags =
-DPIO_ENV_BUILD=$PIOENV -DPIO_ENV_BUILD=$PIOENV
-DBOARD_HAS_PSRAM -DBOARD_HAS_PSRAM
@@ -43,13 +42,12 @@ build_flags =
build_unflags = build_unflags =
-std=gnu++11 -std=gnu++11
custom_version = 0.1.1 custom_version = 0.2.0
custom_versionformat = DEVELOP # Version format switch: e.g.DEVELOP=dev<yyyymmdd>|RELEASE=1.0.0 custom_versionformat = DEVELOP # Version format switch: e.g.DEVELOP=dev<yyyymmdd>|RELEASE=1.0.0
[env:obpkp61] [env:obpkp61]
build_type = release # debug | release build_type = release # debug | release
board = esp32_s3_nano board = esp32_s3_nano
#board = arduino_nano_esp32 # ATTENTION! Pin numbering scheme changes
board_upload.flash_size = 16MB board_upload.flash_size = 16MB
board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
upload_port = /dev/ttyACM0 upload_port = /dev/ttyACM0

View File

@@ -282,8 +282,10 @@ void setup() {
pinMode(KEY_6, INPUT_PULLUP); pinMode(KEY_6, INPUT_PULLUP);
pinMode(KEY_DST, INPUT_PULLUP); pinMode(KEY_DST, INPUT_PULLUP);
#ifdef HARDWARE_V2
// Light sensor input // Light sensor input
pinMode(LDR, INPUT); pinMode(LDR, INPUT);
#endif
// Early signal system activity, red while booting // Early signal system activity, red while booting
digitalWrite(RGBLED_R, HIGH); digitalWrite(RGBLED_R, HIGH);
@@ -738,6 +740,7 @@ void loop() {
case BUTTON_5: // reset case BUTTON_5: // reset
LOGI(TAG, "Device reset"); LOGI(TAG, "Device reset");
esp_rom_uart_tx_wait_idle(0); esp_rom_uart_tx_wait_idle(0);
ledcWrite(LEDC_RGBLED_B, 0); // blue config light off
led_blink(LEDC_RGBLED_G, 3, 4095, 500); led_blink(LEDC_RGBLED_G, 3, 4095, 500);
ESP.restart(); ESP.restart();
break; break;

View File

@@ -164,6 +164,7 @@ void webserver_init() {
String out; String out;
serializeJson(doc, out); serializeJson(doc, out);
request->send(200, "application/json", out); request->send(200, "application/json", out);
ledcWrite(LEDC_RGBLED_B, 0); // blue config light off
led_blink(LEDC_RGBLED_G, 3, 4095, 500); led_blink(LEDC_RGBLED_G, 3, 4095, 500);
esp_rom_uart_tx_wait_idle(0); esp_rom_uart_tx_wait_idle(0);
ESP.restart(); ESP.restart();

View File

@@ -95,29 +95,6 @@
let even = true; //first counter let even = true; //first counter
if (statusPage){ if (statusPage){
for (let k in jsonData) { for (let k in jsonData) {
if (typeof (jsonData[k]) === 'object') {
if (k.indexOf('count') == 0) {
createCounterDisplay(statusPage, k.replace("count", "").replace(/in$/, " in").replace(/out$/, " out"), k, even);
even = !even;
for (let sk in jsonData[k]) {
let key = k + "." + sk;
if (typeof (jsonData[k][sk]) === 'object') {
//msg details
updateMsgDetails(key, jsonData[k][sk]);
}
else {
let el = document.getElementById(key);
if (el) el.textContent = jsonData[k][sk];
}
}
}
if (k.indexOf("ch") == 0) {
//channel def
let name = k.substring(2);
channelList[name] = jsonData[k];
}
}
else {
let el = document.getElementById(k); let el = document.getElementById(k);
if (el) el.textContent = jsonData[k]; if (el) el.textContent = jsonData[k];
forEl('.status-' + k, function (el) { forEl('.status-' + k, function (el) {
@@ -125,7 +102,6 @@
}); });
} }
} }
}
lastUpdate = (new Date()).getTime(); lastUpdate = (new Date()).getTime();
if (reloadConfig) { if (reloadConfig) {
reloadConfig = false; reloadConfig = false;
@@ -341,33 +317,6 @@
}) })
.catch(function (e) { }); .catch(function (e) { });
} }
function createCounterDisplay(parent, label, key, isEven) {
if (parent.querySelector("#" + key)) {
return;
}
let clazz = "row icon-row counter-row";
if (isEven) clazz += " even";
let row = addEl('div', clazz, parent);
row.setAttribute("id", key);
let icon = addEl('span', 'icon icon-more', row);
addEl('span', 'label', row, label);
let value = addEl('span', 'value', row, '---');
value.setAttribute('id', key + ".sumOk");
let display = addEl('div', clazz + " msgDetails hidden", parent);
display.setAttribute('id', key + ".ok");
row.addEventListener('click', function (ev) {
let rs = display.classList.toggle('hidden');
if (rs) {
icon.classList.add('icon-more');
icon.classList.remove('icon-less');
}
else {
icon.classList.remove('icon-more');
icon.classList.add('icon-less');
}
});
callListeners(api.EVENTS.counterDisplayCreated,row);
}
function validKey(key) { function validKey(key) {
if (!key) return; if (!key) return;
return key.replace(/[^a-z_:A-Z0-9-]/g, ''); return key.replace(/[^a-z_:A-Z0-9-]/g, '');
@@ -470,7 +419,6 @@
if (!(condition instanceof Array)) condition = [condition]; if (!(condition instanceof Array)) condition = [condition];
return condition; return condition;
} }
function conditionOk(name){ function conditionOk(name){
let condition = getConditions(name); let condition = getConditions(name);
if (!condition) return true; if (!condition) return true;
@@ -504,97 +452,6 @@
else row.classList.add('hidden'); else row.classList.add('hidden');
} }
let caliv = 0; let caliv = 0;
function createCalSetInput(configItem, frame, clazz) {
let el = addEl('input', clazz, frame);
let cb = addEl('button', '', frame, 'C');
//el.disabled=true;
cb.addEventListener('click', (ev) => {
let cs = document.getElementById("calset").cloneNode(true);
cs.classList.remove("hidden");
cs.querySelector(".heading").textContent = configItem.label || configItem.name;
let vel = cs.querySelector(".val");
if (caliv != 0) window.clearInterval(caliv);
caliv = window.setInterval(() => {
if (document.body.contains(cs)) {
fetch(apiPrefix + "/api/calibrate?name=" + encodeURIComponent(configItem.name))
.then((r) => r.text())
.then((txt) => {
if (txt != vel.textContent) {
vel.textContent = txt;
}
})
.catch((e) => {
alert(e);
hideOverlay();
window.clearInterval(caliv);
})
}
else {
window.clearInterval(caliv);
}
}, 200);
showOverlay(cs, false, [{
label: 'Set', click: () => {
el.value = vel.textContent;
let cev = new Event('change');
el.dispatchEvent(cev);
}
}]);
})
el.setAttribute('name', configItem.name)
return el;
}
function createCalValInput(configItem, frame, clazz) {
let el = addEl('input', clazz, frame);
let cb = addEl('button', '', frame, 'C');
//el.disabled=true;
cb.addEventListener('click', (ev) => {
const sv = function (val, cfg) {
if (configItem.eval) {
let v = parseFloat(val);
let c = parseFloat(cfg);
return (eval(configItem.eval));
}
return v;
};
let cs = document.getElementById("calval").cloneNode(true);
cs.classList.remove("hidden");
cs.querySelector(".heading").textContent = configItem.label || configItem.name;
let vel = cs.querySelector(".val");
let vinp = cs.querySelector("input");
vinp.value = el.value;
if (caliv != 0) window.clearInterval(caliv);
caliv = window.setInterval(() => {
if (document.body.contains(cs)) {
fetch(apiPrefix + "/api/calibrate?name=" + encodeURIComponent(configItem.name))
.then((r) => r.text())
.then((txt) => {
txt = sv(txt, vinp.value);
if (txt != vel.textContent) {
vel.textContent = txt;
}
})
.catch((e) => {
alert(e);
hideOverlay();
window.clearInterval(caliv);
})
}
else {
window.clearInterval(caliv);
}
}, 200);
showOverlay(cs, false, [{
label: 'Set', click: () => {
el.value = vinp.value;
let cev = new Event('change');
el.dispatchEvent(cev);
}
}]);
})
el.setAttribute('name', configItem.name)
return el;
}
function createInput(configItem, frame, clazz) { function createInput(configItem, frame, clazz) {
let el; let el;
if (configItem.type === 'boolean' || configItem.type === 'list') { if (configItem.type === 'boolean' || configItem.type === 'list') {
@@ -628,9 +485,6 @@
el.setAttribute('name', configItem.name); el.setAttribute('name', configItem.name);
return el; return el;
} }
if (configItem.type === 'filter') {
return createFilterInput(configItem, frame, clazz);
}
el = addEl('input', clazz, frame); el = addEl('input', clazz, frame);
if (configItem.readOnly) el.setAttribute('disabled', true); if (configItem.readOnly) el.setAttribute('disabled', true);
el.setAttribute('name', configItem.name) el.setAttribute('name', configItem.name)
@@ -684,54 +538,6 @@
} }
} }
function createFilterInput(configItem, frame) {
let el = addEl('div', 'filter', frame);
let ais = createInput({
type: 'list',
name: configItem.name + "_ais",
list: ['aison', 'aisoff'],
readOnly: configItem.readOnly
}, el);
let mode = createInput({
type: 'list',
name: configItem.name + "_mode",
list: ['whitelist', 'blacklist'],
readOnly: configItem.readOnly
}, el);
let sentences = createInput({
type: 'text',
name: configItem.name + "_sentences",
readOnly: configItem.readOnly
}, el);
let data = addEl('input', undefined, el);
data.setAttribute('type', 'hidden');
let changeFunction = function () {
let cv = data.value || "";
let parts = cv.split(":");
ais.value = (parts[0] == '0') ? "aisoff" : "aison";
mode.value = (parts[1] == '0') ? "whitelist" : "blacklist";
sentences.value = parts[2] || "";
}
let updateFunction = function () {
let nv = (ais.value == 'aison') ? "1" : "0";
nv += ":";
nv += (mode.value == 'blacklist') ? "1" : "0";
nv += ":";
nv += sentences.value;
data.value = nv;
let chev = new Event('change');
data.dispatchEvent(chev);
}
mode.addEventListener('change', updateFunction);
ais.addEventListener("change", updateFunction);
sentences.addEventListener("change", updateFunction);
data.addEventListener('change', function (ev) {
changeFunction();
});
data.setAttribute('name', configItem.name);
if (configItem.readOnly) data.setAttribute('disabled', true);
return data;
}
let moreicons = ['icon-more', 'icon-less']; let moreicons = ['icon-more', 'icon-less'];
function collapseCategories(parent, expand) { function collapseCategories(parent, expand) {
@@ -1270,41 +1076,6 @@
return s + parts[0].substr(parts[0].length - dig); return s + parts[0].substr(parts[0].length - dig);
} }
let valueFormatters = { let valueFormatters = {
formatCourse: {
f: function (v) {
let x = parseFloat(v);
let rt = x * 180.0 / Math.PI;
if (rt > 360) rt -= 360;
if (rt < 0) rt += 360;
return rt.toFixed(0);
},
u: '°'
},
formatKnots: {
f: function (v) {
let x = parseFloat(v);
x = x * 3600.0 / 1852.0;
return x.toFixed(2);
},
u: 'kn'
},
formatWind: {
f: function (v) {
let x = parseFloat(v);
x = x * 180.0 / Math.PI;
if (x > 180) x = -1 * (360 - x);
return x.toFixed(0);
},
u: '°'
},
mtr2nm: {
f: function (v) {
let x = parseFloat(v);
x = x / 1852.0;
return x.toFixed(2);
},
u: 'nm'
},
kelvinToC: { kelvinToC: {
f: function (v) { f: function (v) {
let x = parseFloat(v); let x = parseFloat(v);
@@ -1320,46 +1091,6 @@
}, },
u: '' u: ''
}, },
formatDepth: {
f: function (v) {
let x = parseFloat(v);
return x.toFixed(1);
},
u: 'm'
},
formatLatitude: {
f: function (v) {
let x = parseFloat(v);
if (isNaN(x)) return '-----';
return formatLonLatsDecimal(x, 'lat');
},
u: ''
},
formatLongitude: {
f: function (v) {
let x = parseFloat(v);
if (isNaN(x)) return '-----';
return formatLonLatsDecimal(x, 'lon');
},
u: ''
},
formatRot: {
f: function (v) {
let x = parseFloat(v);
if (isNaN(x)) return '---';
x = x * 180.0 / Math.PI;
return x.toFixed(2);
},
u: '°/s'
},
formatXte: {
f: function (v) {
let x = parseFloat(v);
if (isNaN(x)) return '---';
return x.toFixed(0);
},
u: 'm'
},
formatDate: { formatDate: {
f: function (v) { f: function (v) {
v = parseFloat(v); v = parseFloat(v);
@@ -1388,8 +1119,6 @@
}, },
u: '' u: ''
} }
} }
Object.freeze(valueFormatters); Object.freeze(valueFormatters);
for (let k in valueFormatters){ for (let k in valueFormatters){
@@ -1412,17 +1141,6 @@
} }
return u; return u;
} }
function sourceName(v) {
if (v == 0) return "N2K";
for (let n in channelList) {
if (v == channelList[n].id) return n;
if (v >= channelList[n].id && v <= channelList[n].max) {
return n;
}
}
if (v < minUser) return "---";
return "USER[" + v + "]";
}
let lastSelectList = []; let lastSelectList = [];
buttonHandlers.uploadBin=function(ev) { buttonHandlers.uploadBin=function(ev) {
let el = document.getElementById("uploadFile"); let el = document.getElementById("uploadFile");
@@ -1686,8 +1404,7 @@
config: 2, //called when the config data is loaded,data is the config object config: 2, //called when the config data is loaded,data is the config object
dataItemCreated: 4, //data is an object with dataItemCreated: 4, //data is an object with
// name: the item name, element: the frame item of the boat data display // name: the item name, element: the frame item of the boat data display
status: 5, //status received, data is the status object status: 5 //status received, data is the status object
counterDisplayCreated: 6 //data is the row for the display
} }
}; };
function callListeners(event,data){ function callListeners(event,data){