|
252 | 252 |
|
253 | 253 | // ---- helpers ---- |
254 | 254 | function isC() { return unit === 1; } |
255 | | - function toDisplayTemp(c) { return isC() ? c : (c * 9 / 5 + 32); } |
| 255 | + function toDisplayTemp(c) { return isC() ? c : (c * 9 / 5 + 32); } // native C -> display unit |
| 256 | + function fromDisplayTemp(v) { return isC() ? v : (v - 32) * 5 / 9; } // display unit -> native C |
256 | 257 | function unitLabel() { return isC() ? "°C" : "°F"; } |
| 258 | + function isTempControl(c) { return c && c.type === "sensor-based"; } |
257 | 259 |
|
258 | 260 | function humanize(sec) { |
259 | 261 | sec = Math.round(sec); |
|
441 | 443 |
|
442 | 444 | // ---- schedule dialog ---- |
443 | 445 | var scheduleTarget = null; |
| 446 | + function rangeText(c) { |
| 447 | + if (isTempControl(c)) { |
| 448 | + return "(" + Math.round(toDisplayTemp(c.min)) + "–" + Math.round(toDisplayTemp(c.max)) + unitLabel() + ")"; |
| 449 | + } |
| 450 | + return "(" + c.min + "–" + c.max + ")"; |
| 451 | + } |
444 | 452 | function openSchedule(name) { |
445 | 453 | scheduleTarget = name; |
446 | 454 | var c = statusByName[name] || {}; |
| 455 | + var isTemp = isTempControl(c); |
447 | 456 | document.getElementById("scheduleTitle").textContent = "Schedule: " + name; |
448 | | - document.getElementById("onRange").textContent = "(" + c.min + "–" + c.max + ")"; |
449 | | - document.getElementById("offRange").textContent = "(" + c.min + "–" + c.max + ")"; |
| 457 | + document.getElementById("onRange").textContent = rangeText(c); |
| 458 | + document.getElementById("offRange").textContent = rangeText(c); |
450 | 459 | fetch("/configureControl?control=" + encodeURIComponent(name)) |
451 | 460 | .then(function (r) { return r.json(); }) |
452 | 461 | .then(function (cfg) { |
453 | | - ["percentageOfDayOnTime","numberOfTimesToRun","normalValueOn","normalValueOff","overrideDefaultDurationSeconds"] |
| 462 | + ["percentageOfDayOnTime","numberOfTimesToRun","overrideDefaultDurationSeconds"] |
454 | 463 | .forEach(function (k) { document.getElementById(k).value = cfg[k]; }); |
| 464 | + // Temperatures are stored natively in Celsius; show them in the display unit. |
| 465 | + document.getElementById("normalValueOn").value = isTemp ? Math.round(toDisplayTemp(cfg.normalValueOn)) : cfg.normalValueOn; |
| 466 | + document.getElementById("normalValueOff").value = isTemp ? Math.round(toDisplayTemp(cfg.normalValueOff)) : cfg.normalValueOff; |
455 | 467 | updateScheduleHints(); |
456 | 468 | document.getElementById("scheduleDialog").showModal(); |
457 | 469 | }) |
|
468 | 480 | document.getElementById("numberOfTimesToRun").addEventListener("input", updateScheduleHints); |
469 | 481 | document.getElementById("scheduleSave").addEventListener("click", function () { |
470 | 482 | var c = statusByName[scheduleTarget] || {}; |
| 483 | + var isTemp = isTempControl(c); |
471 | 484 | var data = { control: scheduleTarget }; |
472 | 485 | var ok = true; |
473 | | - ["percentageOfDayOnTime","numberOfTimesToRun","normalValueOn","normalValueOff","overrideDefaultDurationSeconds"] |
474 | | - .forEach(function (k) { |
475 | | - var el = document.getElementById(k); |
476 | | - data[k] = el.value; |
477 | | - if ((k === "normalValueOn" || k === "normalValueOff") && |
478 | | - (Number(el.value) < c.min || Number(el.value) > c.max)) { |
479 | | - el.classList.add("invalid"); ok = false; |
480 | | - } else { el.classList.remove("invalid"); } |
481 | | - }); |
482 | | - if (!ok) { toast("Value out of range (" + c.min + "–" + c.max + ")"); return; } |
| 486 | + ["percentageOfDayOnTime","numberOfTimesToRun","overrideDefaultDurationSeconds"] |
| 487 | + .forEach(function (k) { data[k] = document.getElementById(k).value; }); |
| 488 | + // Temperature fields are entered in the display unit; validate there, then |
| 489 | + // convert back to native Celsius (the controller's storage unit). |
| 490 | + ["normalValueOn","normalValueOff"].forEach(function (k) { |
| 491 | + var el = document.getElementById(k); |
| 492 | + var nativeVal = isTemp ? Math.round(fromDisplayTemp(Number(el.value))) : Number(el.value); |
| 493 | + if (nativeVal < c.min || nativeVal > c.max) { el.classList.add("invalid"); ok = false; } |
| 494 | + else { el.classList.remove("invalid"); } |
| 495 | + data[k] = nativeVal; |
| 496 | + }); |
| 497 | + if (!ok) { toast("Value out of range " + rangeText(c)); return; } |
483 | 498 | post("/configureControl", data) |
484 | 499 | .then(function () { document.getElementById("scheduleDialog").close(); refresh(); }) |
485 | 500 | .catch(function (e) { toast("Save failed"); }); |
|
0 commit comments