Add weather temperature sensor flag
This commit is contained in:
+5
-1
@@ -637,4 +637,8 @@ Request:
|
||||
{
|
||||
"id": "relay_1",
|
||||
"state": true
|
||||
}
|
||||
}\n\n### Weather temperature sensor flag
|
||||
|
||||
Temperature sensor config entries now include `weather: true`.
|
||||
|
||||
When a configured temp sensor has `weather: true`, the WebUI may show it as the outside/weather temperature badge. The `/status` temp objects also include this flag so HTTP, UART, USB serial, and future Pico clients can identify the selected outside-air sensor without guessing from the sensor name.\n
|
||||
@@ -105,5 +105,4 @@ Future additions must be implemented on:
|
||||
UART JSON
|
||||
HTTP API
|
||||
|
||||
before parity is considered maintained.
|
||||
|
||||
before parity is considered maintained.\n\n- Temperature sensor config/status parity now includes the `weather` boolean flag for outside-air display selection.\n
|
||||
@@ -265,4 +265,8 @@ Pico sends:
|
||||
|
||||
Alternative:
|
||||
|
||||
{"type":"clear_temp","slot":1}
|
||||
{"type":"clear_temp","slot":1}\n\n### Temperature weather flag
|
||||
|
||||
`status_response.config.temperature_sensors[]` and `status_response.temps[]` include `weather: false`.
|
||||
|
||||
`config_temp` may include `weather: true` to mark one configured sensor as the outside/weather sensor. Pico clients should treat this as optional and default missing values to `false`.\n
|
||||
@@ -163,4 +163,4 @@ Examples:
|
||||
5. Add config backup/restore.
|
||||
6. Improve BMS out-of-range behavior without changing NimBLE connect timeout.
|
||||
|
||||
- Fixed WebUI temperature probe scan by registering `/temps/scan`, `/temps/assign`, and `/temps/clear` firmware routes.
|
||||
- Fixed WebUI temperature probe scan by registering `/temps/scan`, `/temps/assign`, and `/temps/clear` firmware routes.\n\n- Added per-temperature-sensor `weather` flag and WebUI outside temperature badge with emoji thresholds: below 50°F ice, 50-74°F happy, 75-84°F sun, and 85°F+ fire.\n
|
||||
@@ -31,7 +31,8 @@ void loadDefaultConfig() {
|
||||
"temp_" + String(i + 1),
|
||||
"Temperature " + String(i + 1),
|
||||
"",
|
||||
i < appConfig.tempSensorCount
|
||||
i < appConfig.tempSensorCount,
|
||||
false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -90,6 +91,10 @@ void loadConfig() {
|
||||
(prefix + "enabled").c_str(),
|
||||
appConfig.tempSensors[i].enabled
|
||||
);
|
||||
appConfig.tempSensors[i].weather = preferences.getBool(
|
||||
(prefix + "weather").c_str(),
|
||||
appConfig.tempSensors[i].weather
|
||||
);
|
||||
}
|
||||
|
||||
appConfig.bms.enabled = preferences.getBool("bms_enabled", appConfig.bms.enabled);
|
||||
@@ -124,6 +129,7 @@ void saveConfig() {
|
||||
preferences.putString((prefix + "name").c_str(), appConfig.tempSensors[i].name);
|
||||
preferences.putString((prefix + "addr").c_str(), appConfig.tempSensors[i].address);
|
||||
preferences.putBool((prefix + "enabled").c_str(), appConfig.tempSensors[i].enabled);
|
||||
preferences.putBool((prefix + "weather").c_str(), appConfig.tempSensors[i].weather);
|
||||
}
|
||||
|
||||
preferences.putBool("bms_enabled", appConfig.bms.enabled);
|
||||
|
||||
@@ -17,6 +17,7 @@ struct TempSensorConfig {
|
||||
String name;
|
||||
String address;
|
||||
bool enabled;
|
||||
bool weather;
|
||||
};
|
||||
|
||||
struct BmsConfig {
|
||||
|
||||
@@ -28,6 +28,8 @@ const char INDEX_HTML[] PROGMEM = R"rawliteral(
|
||||
body{margin:0;background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Arial,sans-serif}
|
||||
.wrap{max-width:980px;margin:0 auto;padding:14px 14px 90px}
|
||||
.top{display:flex;justify-content:space-between;gap:12px;align-items:center;margin-bottom:12px}
|
||||
.topRight{display:grid;gap:6px;justify-items:end}
|
||||
.weatherBadge{font-size:20px;font-weight:900;color:var(--text);padding:8px 12px}
|
||||
h1{font-size:21px;margin:0}.sub{color:var(--muted);font-size:13px;margin-top:4px}
|
||||
.pill{border:1px solid var(--line);border-radius:999px;padding:7px 10px;color:var(--muted);font-size:12px;white-space:nowrap}
|
||||
.tabs{position:fixed;left:0;right:0;bottom:0;background:#080c11;border-top:1px solid var(--line);display:grid;grid-template-columns:repeat(3,1fr);z-index:10}
|
||||
@@ -67,8 +69,11 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
|
||||
<h1 id="device">Overland Controller</h1>
|
||||
<div class="sub" id="subtitle">Local camp dashboard</div>
|
||||
</div>
|
||||
<div class="topRight">
|
||||
<div class="pill weatherBadge" id="weatherBadge" style="display:none">--</div>
|
||||
<div class="pill" id="conn">Connecting...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="overviewPage" class="page active">
|
||||
<div class="grid">
|
||||
@@ -233,6 +238,29 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
|
||||
const $=id=>document.getElementById(id);
|
||||
function fmt(n,d=1){return typeof n==="number"?n.toFixed(d):"--"}
|
||||
function temp(v){return typeof v==="number"?fmt(v,1)+"°F":"Offline"}
|
||||
function weatherEmoji(f){
|
||||
if(typeof f!=="number") return "";
|
||||
if(f < 50) return "🧊";
|
||||
if(f < 75) return "🙂";
|
||||
if(f < 85) return "☀️";
|
||||
return "🔥";
|
||||
}
|
||||
function renderWeatherBadge(data){
|
||||
const badge=$("weatherBadge");
|
||||
if(!badge) return;
|
||||
|
||||
const sensor=(data.temps||[]).find(t=>t.enabled && t.weather && t.online && typeof t.temperature_f==="number");
|
||||
if(!sensor){
|
||||
badge.style.display="none";
|
||||
badge.textContent="--";
|
||||
return;
|
||||
}
|
||||
|
||||
const rounded=Math.round(sensor.temperature_f);
|
||||
badge.textContent=`${weatherEmoji(rounded)} ${rounded}°F`;
|
||||
badge.title=sensor.name||sensor.id||"Weather sensor";
|
||||
badge.style.display="";
|
||||
}
|
||||
function formatHours(hours){
|
||||
if(typeof hours!=="number" || !isFinite(hours) || hours<=0){
|
||||
return "Idle";
|
||||
@@ -303,6 +331,7 @@ function render(data){
|
||||
$("conn").textContent="Live";
|
||||
$("conn").className="pill good";
|
||||
$("device").textContent=data.config?.device_name||"Overland Controller";
|
||||
renderWeatherBadge(data);
|
||||
|
||||
const b=data.battery||{};
|
||||
$("soc").textContent=fmt(b.soc,0);
|
||||
@@ -510,6 +539,10 @@ function renderConfigControls(data){
|
||||
<input id="tempEnabled${i}" type="checkbox" ${t.enabled?"checked":""}>
|
||||
On
|
||||
</label>
|
||||
<label>
|
||||
<input id="tempWeather${i}" type="checkbox" ${t.weather?"checked":""}>
|
||||
Weather
|
||||
</label>
|
||||
</div>`).join("");
|
||||
}
|
||||
}
|
||||
@@ -553,6 +586,7 @@ async function saveTempConfig(){
|
||||
const name=$("tempName"+i)?.value.trim() || temps[i].name || temps[i].id;
|
||||
const manual=$("tempEnabled"+i)?.checked;
|
||||
const enabled=(i<count) || manual;
|
||||
const weather=$("tempWeather"+i)?.checked || false;
|
||||
|
||||
await fetch("/config/temp",{
|
||||
method:"POST",
|
||||
@@ -561,7 +595,8 @@ async function saveTempConfig(){
|
||||
id:temps[i].id,
|
||||
name:name,
|
||||
address:temps[i].address||"",
|
||||
enabled:enabled
|
||||
enabled:enabled,
|
||||
weather:weather
|
||||
})
|
||||
});
|
||||
}
|
||||
@@ -884,6 +919,7 @@ void buildStatusDocument(JsonDocument& doc) {
|
||||
temp["id"] = appConfig.tempSensors[i].id;
|
||||
temp["name"] = appConfig.tempSensors[i].name;
|
||||
temp["enabled"] = appConfig.tempSensors[i].enabled;
|
||||
temp["weather"] = appConfig.tempSensors[i].weather;
|
||||
temp["online"] = sensors.online[i];
|
||||
if (sensors.online[i]) {
|
||||
temp["temperature_f"] = sensors.tempsF[i];
|
||||
@@ -970,6 +1006,7 @@ void buildStatusDocument(JsonDocument& doc) {
|
||||
tempConfig["name"] = appConfig.tempSensors[i].name;
|
||||
tempConfig["address"] = appConfig.tempSensors[i].address;
|
||||
tempConfig["enabled"] = appConfig.tempSensors[i].enabled;
|
||||
tempConfig["weather"] = appConfig.tempSensors[i].weather;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1924,6 +1961,7 @@ void handleUpdateTempSensorConfig() {
|
||||
if (doc["name"].is<String>()) appConfig.tempSensors[index].name = doc["name"].as<String>();
|
||||
if (doc["address"].is<String>()) appConfig.tempSensors[index].address = doc["address"].as<String>();
|
||||
if (doc["enabled"].is<bool>()) appConfig.tempSensors[index].enabled = doc["enabled"].as<bool>();
|
||||
if (doc["weather"].is<bool>()) appConfig.tempSensors[index].weather = doc["weather"].as<bool>();
|
||||
|
||||
sendOkConfig();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user