dashboard: add grouped temperature overview tiles
This commit is contained in:
+14
@@ -930,3 +930,17 @@ Architecture expectation:
|
|||||||
- Dashboard ESP32-S3 consumes temperature telemetry from the Cargo ESP API.
|
- Dashboard ESP32-S3 consumes temperature telemetry from the Cargo ESP API.
|
||||||
|
|
||||||
The dashboard should not directly read cargo/fridge DS18B20 sensors for v1.
|
The dashboard should not directly read cargo/fridge DS18B20 sensors for v1.
|
||||||
|
|
||||||
|
### Temperature Sensor Grouping
|
||||||
|
|
||||||
|
Temperature sensors now support a `group` field in addition to the existing `weather` flag.
|
||||||
|
|
||||||
|
Supported group values:
|
||||||
|
|
||||||
|
- `cabin`
|
||||||
|
- `fridge`
|
||||||
|
- `outside`
|
||||||
|
- `battery`
|
||||||
|
- `other`
|
||||||
|
|
||||||
|
The dashboard overview combines multiple online sensors in the same group into one tile. For example, two fridge sensors may display as `34°/45°` under a single `Fridge` tile. Sensors marked `weather: true` continue to be treated as the outside/weather sensor for dashboard display.
|
||||||
|
|||||||
@@ -248,3 +248,17 @@ Planned next work:
|
|||||||
- Vehicle data page
|
- Vehicle data page
|
||||||
- CAN/OBD-II integration
|
- CAN/OBD-II integration
|
||||||
- BNO085/BNO086 tilt visualization
|
- BNO085/BNO086 tilt visualization
|
||||||
|
|
||||||
|
### Temperature Sensor Grouping
|
||||||
|
|
||||||
|
Temperature sensors now support a `group` field in addition to the existing `weather` flag.
|
||||||
|
|
||||||
|
Supported group values:
|
||||||
|
|
||||||
|
- `cabin`
|
||||||
|
- `fridge`
|
||||||
|
- `outside`
|
||||||
|
- `battery`
|
||||||
|
- `other`
|
||||||
|
|
||||||
|
The dashboard overview combines multiple online sensors in the same group into one tile. For example, two fridge sensors may display as `34°/45°` under a single `Fridge` tile. Sensors marked `weather: true` continue to be treated as the outside/weather sensor for dashboard display.
|
||||||
|
|||||||
@@ -315,3 +315,17 @@ Current dashboard features:
|
|||||||
- WiFi signal indicator
|
- WiFi signal indicator
|
||||||
- Cargo ESP connectivity indicator
|
- Cargo ESP connectivity indicator
|
||||||
- Fast status polling using field-filtered API requests
|
- Fast status polling using field-filtered API requests
|
||||||
|
|
||||||
|
### Temperature Sensor Grouping
|
||||||
|
|
||||||
|
Temperature sensors now support a `group` field in addition to the existing `weather` flag.
|
||||||
|
|
||||||
|
Supported group values:
|
||||||
|
|
||||||
|
- `cabin`
|
||||||
|
- `fridge`
|
||||||
|
- `outside`
|
||||||
|
- `battery`
|
||||||
|
- `other`
|
||||||
|
|
||||||
|
The dashboard overview combines multiple online sensors in the same group into one tile. For example, two fridge sensors may display as `34°/45°` under a single `Fridge` tile. Sensors marked `weather: true` continue to be treated as the outside/weather sensor for dashboard display.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
static const char *DASHBOARD_VERSION = "0.1.36-temp-tiles";
|
static const char *DASHBOARD_VERSION = "0.1.37-temp-groups";
|
||||||
|
|
||||||
// Update these if your Cargo ESP AP credentials are different.
|
// Update these if your Cargo ESP AP credentials are different.
|
||||||
static const char *CARGO_WIFI_SSID = "OverlandController";
|
static const char *CARGO_WIFI_SSID = "OverlandController";
|
||||||
|
|||||||
@@ -19,10 +19,8 @@ static lv_obj_t *battery_charge_pulse_arc = nullptr;
|
|||||||
static lv_obj_t *battery_current_label = nullptr;
|
static lv_obj_t *battery_current_label = nullptr;
|
||||||
static lv_obj_t *battery_estimate_label = nullptr;
|
static lv_obj_t *battery_estimate_label = nullptr;
|
||||||
static lv_obj_t *battery_soc_label = nullptr;
|
static lv_obj_t *battery_soc_label = nullptr;
|
||||||
static lv_obj_t *inside_temp_value_label = nullptr;
|
static lv_obj_t *temp_tile_value_labels[4] = {nullptr};
|
||||||
static lv_obj_t *inside_temp_name_label = nullptr;
|
static lv_obj_t *temp_tile_name_labels[4] = {nullptr};
|
||||||
static lv_obj_t *outside_temp_value_label = nullptr;
|
|
||||||
static lv_obj_t *outside_temp_name_label = nullptr;
|
|
||||||
static lv_obj_t *system_status_label = nullptr;
|
static lv_obj_t *system_status_label = nullptr;
|
||||||
static lv_obj_t *wifi_icon_label = nullptr;
|
static lv_obj_t *wifi_icon_label = nullptr;
|
||||||
static lv_obj_t *wifi_bars_obj[4] = {nullptr};
|
static lv_obj_t *wifi_bars_obj[4] = {nullptr};
|
||||||
@@ -60,10 +58,8 @@ static bool pending_relay_previous_state = false;
|
|||||||
static String last_battery_current_text;
|
static String last_battery_current_text;
|
||||||
static String last_battery_estimate_text;
|
static String last_battery_estimate_text;
|
||||||
static String last_battery_soc_text;
|
static String last_battery_soc_text;
|
||||||
static String last_inside_temp_value_text;
|
static String last_temp_tile_value_text[4];
|
||||||
static String last_inside_temp_name_text;
|
static String last_temp_tile_name_text[4];
|
||||||
static String last_outside_temp_value_text;
|
|
||||||
static String last_outside_temp_name_text;
|
|
||||||
static String last_system_status_text;
|
static String last_system_status_text;
|
||||||
static int last_wifi_bar_count = -1;
|
static int last_wifi_bar_count = -1;
|
||||||
static bool last_cargo_api_ok = false;
|
static bool last_cargo_api_ok = false;
|
||||||
@@ -74,18 +70,61 @@ static String on_off(bool value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static String compact_temp_name(const char *raw_name)
|
|
||||||
|
static String normalize_temp_group(String group, const String &name, bool weather)
|
||||||
{
|
{
|
||||||
String name = raw_name && raw_name[0] ? String(raw_name) : String("Inside");
|
group.toLowerCase();
|
||||||
|
group.trim();
|
||||||
|
|
||||||
name.replace(" Area", "");
|
if (weather || group == "weather" || group == "outside") {
|
||||||
name.replace(" Zone", "");
|
return "outside";
|
||||||
|
|
||||||
if (name.length() > 14) {
|
|
||||||
name = name.substring(0, 14);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return name;
|
if (group == "fridge" || group == "freezer" || group == "cooler") {
|
||||||
|
return "fridge";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group == "battery" || group == "bms") {
|
||||||
|
return "battery";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group == "cabin" || group == "inside" || group == "interior") {
|
||||||
|
return "cabin";
|
||||||
|
}
|
||||||
|
|
||||||
|
String lower_name = name;
|
||||||
|
lower_name.toLowerCase();
|
||||||
|
|
||||||
|
if (lower_name.indexOf("fridge") >= 0 || lower_name.indexOf("freezer") >= 0 || lower_name.indexOf("cooler") >= 0) {
|
||||||
|
return "fridge";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lower_name.indexOf("outside") >= 0 || lower_name.indexOf("ambient") >= 0) {
|
||||||
|
return "outside";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lower_name.indexOf("battery") >= 0 || lower_name.indexOf("bms") >= 0) {
|
||||||
|
return "battery";
|
||||||
|
}
|
||||||
|
|
||||||
|
return group.length() ? group : "cabin";
|
||||||
|
}
|
||||||
|
|
||||||
|
static int temp_group_index(const String &group)
|
||||||
|
{
|
||||||
|
if (group == "cabin") return 0;
|
||||||
|
if (group == "fridge") return 1;
|
||||||
|
if (group == "outside") return 2;
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String temp_group_label(int index, const String &fallback)
|
||||||
|
{
|
||||||
|
if (index == 0) return fallback.length() ? fallback : "Cabin";
|
||||||
|
if (index == 1) return "Fridge";
|
||||||
|
if (index == 2) return "Outside";
|
||||||
|
if (index == 3) return "Other";
|
||||||
|
return "Temp";
|
||||||
}
|
}
|
||||||
|
|
||||||
static String format_hours(float hours)
|
static String format_hours(float hours)
|
||||||
@@ -611,10 +650,9 @@ static void parse_status_json(const String &body)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (doc["temps"].is<JsonArray>()) {
|
if (doc["temps"].is<JsonArray>()) {
|
||||||
String inside_name = "Inside";
|
String tile_names[4] = {"Cabin", "Fridge", "Outside", "Other"};
|
||||||
String inside_value = "--";
|
String tile_values[4] = {"--", "--", "--", "--"};
|
||||||
String outside_name = "Outside";
|
bool tile_has_value[4] = {false, false, false, false};
|
||||||
String outside_value = "--";
|
|
||||||
|
|
||||||
for (JsonObject temp : doc["temps"].as<JsonArray>()) {
|
for (JsonObject temp : doc["temps"].as<JsonArray>()) {
|
||||||
bool enabled = temp["enabled"] | false;
|
bool enabled = temp["enabled"] | false;
|
||||||
@@ -625,23 +663,38 @@ static void parse_status_json(const String &body)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String value = String((float)(temp["temperature_f"] | 0.0), 1);
|
const char *raw_name = temp["name"] | "";
|
||||||
|
const char *raw_group = temp["group"] | "";
|
||||||
|
|
||||||
|
String name = raw_name && raw_name[0] ? String(raw_name) : String("Cabin");
|
||||||
|
String group = normalize_temp_group(String(raw_group), name, weather);
|
||||||
|
int index = temp_group_index(group);
|
||||||
|
|
||||||
|
int rounded = (int)round((float)(temp["temperature_f"] | 0.0));
|
||||||
|
String value = String(rounded);
|
||||||
value += "°";
|
value += "°";
|
||||||
|
|
||||||
if (weather) {
|
if (tile_has_value[index]) {
|
||||||
outside_name = "Outside";
|
tile_values[index] += "/";
|
||||||
outside_value = value;
|
tile_values[index] += value;
|
||||||
} else {
|
} else {
|
||||||
const char *name = temp["name"] | "Inside";
|
tile_values[index] = value;
|
||||||
inside_name = compact_temp_name(name);
|
tile_has_value[index] = true;
|
||||||
inside_value = value;
|
|
||||||
|
if (index == 0) {
|
||||||
|
name.replace(" Area", "");
|
||||||
|
name.replace(" Zone", "");
|
||||||
|
tile_names[index] = name.length() ? name : "Cabin";
|
||||||
|
} else {
|
||||||
|
tile_names[index] = temp_group_label(index, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set_label_text_if_changed(inside_temp_value_label, last_inside_temp_value_text, inside_value);
|
for (int i = 0; i < 4; i++) {
|
||||||
set_label_text_if_changed(inside_temp_name_label, last_inside_temp_name_text, inside_name);
|
set_label_text_if_changed(temp_tile_value_labels[i], last_temp_tile_value_text[i], tile_values[i]);
|
||||||
set_label_text_if_changed(outside_temp_value_label, last_outside_temp_value_text, outside_value);
|
set_label_text_if_changed(temp_tile_name_labels[i], last_temp_tile_name_text[i], tile_names[i]);
|
||||||
set_label_text_if_changed(outside_temp_name_label, last_outside_temp_name_text, outside_name);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doc["relays"].is<JsonArray>()) {
|
if (doc["relays"].is<JsonArray>()) {
|
||||||
@@ -864,59 +917,39 @@ static void create_overland_overview_screen()
|
|||||||
lv_obj_align(battery_current_label, LV_ALIGN_TOP_MID, 0, 161);
|
lv_obj_align(battery_current_label, LV_ALIGN_TOP_MID, 0, 161);
|
||||||
lv_obj_add_flag(battery_current_label, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(battery_current_label, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
lv_obj_t *inside_tile = lv_obj_create(temp_card);
|
const int temp_tile_w = 112;
|
||||||
lv_obj_set_size(inside_tile, 236, 132);
|
const int temp_tile_h = 130;
|
||||||
lv_obj_align(inside_tile, LV_ALIGN_TOP_MID, 0, 22);
|
const int temp_tile_x[4] = {8, 140, 8, 140};
|
||||||
lv_obj_set_style_radius(inside_tile, 18, 0);
|
const int temp_tile_y[4] = {18, 18, 160, 160};
|
||||||
lv_obj_set_style_bg_color(inside_tile, lv_color_hex(0x17202A), 0);
|
|
||||||
lv_obj_set_style_border_color(inside_tile, lv_color_hex(0x2F3A46), 0);
|
|
||||||
lv_obj_set_style_border_width(inside_tile, 2, 0);
|
|
||||||
lv_obj_set_style_pad_all(inside_tile, 0, 0);
|
|
||||||
lv_obj_clear_flag(inside_tile, LV_OBJ_FLAG_SCROLLABLE);
|
|
||||||
lv_obj_set_scrollbar_mode(inside_tile, LV_SCROLLBAR_MODE_OFF);
|
|
||||||
|
|
||||||
inside_temp_value_label = lv_label_create(inside_tile);
|
for (int i = 0; i < 4; i++) {
|
||||||
lv_label_set_text(inside_temp_value_label, "--");
|
lv_obj_t *tile = lv_obj_create(temp_card);
|
||||||
lv_obj_set_style_text_color(inside_temp_value_label, lv_color_hex(0xFFFFFF), 0);
|
lv_obj_set_size(tile, temp_tile_w, temp_tile_h);
|
||||||
lv_obj_set_style_text_font(inside_temp_value_label, &lv_font_montserrat_48, 0);
|
lv_obj_align(tile, LV_ALIGN_TOP_LEFT, temp_tile_x[i], temp_tile_y[i]);
|
||||||
lv_obj_set_width(inside_temp_value_label, 220);
|
lv_obj_set_style_radius(tile, 16, 0);
|
||||||
lv_obj_set_style_text_align(inside_temp_value_label, LV_TEXT_ALIGN_CENTER, 0);
|
lv_obj_set_style_bg_color(tile, lv_color_hex(0x17202A), 0);
|
||||||
lv_obj_align(inside_temp_value_label, LV_ALIGN_TOP_MID, 0, 18);
|
lv_obj_set_style_border_color(tile, lv_color_hex(0x2F3A46), 0);
|
||||||
|
lv_obj_set_style_border_width(tile, 2, 0);
|
||||||
|
lv_obj_set_style_pad_all(tile, 0, 0);
|
||||||
|
lv_obj_clear_flag(tile, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
lv_obj_set_scrollbar_mode(tile, LV_SCROLLBAR_MODE_OFF);
|
||||||
|
|
||||||
inside_temp_name_label = lv_label_create(inside_tile);
|
temp_tile_value_labels[i] = lv_label_create(tile);
|
||||||
lv_label_set_text(inside_temp_name_label, "Inside");
|
lv_label_set_text(temp_tile_value_labels[i], "--");
|
||||||
lv_obj_set_style_text_color(inside_temp_name_label, lv_color_hex(0xB8C0C8), 0);
|
lv_obj_set_style_text_color(temp_tile_value_labels[i], lv_color_hex(0xFFFFFF), 0);
|
||||||
lv_obj_set_style_text_font(inside_temp_name_label, &lv_font_montserrat_26, 0);
|
lv_obj_set_style_text_font(temp_tile_value_labels[i], &lv_font_montserrat_30, 0);
|
||||||
lv_obj_set_width(inside_temp_name_label, 220);
|
lv_obj_set_width(temp_tile_value_labels[i], temp_tile_w - 8);
|
||||||
lv_obj_set_style_text_align(inside_temp_name_label, LV_TEXT_ALIGN_CENTER, 0);
|
lv_obj_set_style_text_align(temp_tile_value_labels[i], LV_TEXT_ALIGN_CENTER, 0);
|
||||||
lv_obj_align(inside_temp_name_label, LV_ALIGN_TOP_MID, 0, 84);
|
lv_obj_align(temp_tile_value_labels[i], LV_ALIGN_TOP_MID, 0, 26);
|
||||||
|
|
||||||
lv_obj_t *outside_tile = lv_obj_create(temp_card);
|
temp_tile_name_labels[i] = lv_label_create(tile);
|
||||||
lv_obj_set_size(outside_tile, 236, 132);
|
lv_label_set_text(temp_tile_name_labels[i], i == 0 ? "Cabin" : i == 1 ? "Fridge" : i == 2 ? "Outside" : "Other");
|
||||||
lv_obj_align(outside_tile, LV_ALIGN_BOTTOM_MID, 0, -22);
|
lv_obj_set_style_text_color(temp_tile_name_labels[i], lv_color_hex(0xB8C0C8), 0);
|
||||||
lv_obj_set_style_radius(outside_tile, 18, 0);
|
lv_obj_set_style_text_font(temp_tile_name_labels[i], &lv_font_montserrat_20, 0);
|
||||||
lv_obj_set_style_bg_color(outside_tile, lv_color_hex(0x17202A), 0);
|
lv_obj_set_width(temp_tile_name_labels[i], temp_tile_w - 8);
|
||||||
lv_obj_set_style_border_color(outside_tile, lv_color_hex(0x2F3A46), 0);
|
lv_obj_set_style_text_align(temp_tile_name_labels[i], LV_TEXT_ALIGN_CENTER, 0);
|
||||||
lv_obj_set_style_border_width(outside_tile, 2, 0);
|
lv_obj_align(temp_tile_name_labels[i], LV_ALIGN_TOP_MID, 0, 78);
|
||||||
lv_obj_set_style_pad_all(outside_tile, 0, 0);
|
}
|
||||||
lv_obj_clear_flag(outside_tile, LV_OBJ_FLAG_SCROLLABLE);
|
|
||||||
lv_obj_set_scrollbar_mode(outside_tile, LV_SCROLLBAR_MODE_OFF);
|
|
||||||
|
|
||||||
outside_temp_value_label = lv_label_create(outside_tile);
|
|
||||||
lv_label_set_text(outside_temp_value_label, "--");
|
|
||||||
lv_obj_set_style_text_color(outside_temp_value_label, lv_color_hex(0xFFFFFF), 0);
|
|
||||||
lv_obj_set_style_text_font(outside_temp_value_label, &lv_font_montserrat_48, 0);
|
|
||||||
lv_obj_set_width(outside_temp_value_label, 220);
|
|
||||||
lv_obj_set_style_text_align(outside_temp_value_label, LV_TEXT_ALIGN_CENTER, 0);
|
|
||||||
lv_obj_align(outside_temp_value_label, LV_ALIGN_TOP_MID, 0, 18);
|
|
||||||
|
|
||||||
outside_temp_name_label = lv_label_create(outside_tile);
|
|
||||||
lv_label_set_text(outside_temp_name_label, "Outside");
|
|
||||||
lv_obj_set_style_text_color(outside_temp_name_label, lv_color_hex(0xB8C0C8), 0);
|
|
||||||
lv_obj_set_style_text_font(outside_temp_name_label, &lv_font_montserrat_26, 0);
|
|
||||||
lv_obj_set_width(outside_temp_name_label, 220);
|
|
||||||
lv_obj_set_style_text_align(outside_temp_name_label, LV_TEXT_ALIGN_CENTER, 0);
|
|
||||||
lv_obj_align(outside_temp_name_label, LV_ALIGN_TOP_MID, 0, 84);
|
|
||||||
|
|
||||||
lv_obj_t *vehicle_label = lv_label_create(vehicle_card);
|
lv_obj_t *vehicle_label = lv_label_create(vehicle_card);
|
||||||
lv_label_set_text(vehicle_label, "Vehicle\n\nOffline\n\nFuture:\nCoolant\nTrans Temp\n4WD\nTilt/Roll");
|
lv_label_set_text(vehicle_label, "Vehicle\n\nOffline\n\nFuture:\nCoolant\nTrans Temp\n4WD\nTilt/Roll");
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ void loadDefaultConfig() {
|
|||||||
"Temperature " + String(i + 1),
|
"Temperature " + String(i + 1),
|
||||||
"",
|
"",
|
||||||
i < appConfig.tempSensorCount,
|
i < appConfig.tempSensorCount,
|
||||||
false
|
false,
|
||||||
|
"cabin"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,6 +102,10 @@ void loadConfig() {
|
|||||||
(prefix + "weather").c_str(),
|
(prefix + "weather").c_str(),
|
||||||
appConfig.tempSensors[i].weather
|
appConfig.tempSensors[i].weather
|
||||||
);
|
);
|
||||||
|
appConfig.tempSensors[i].group = preferences.getString(
|
||||||
|
(prefix + "group").c_str(),
|
||||||
|
appConfig.tempSensors[i].group
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
appConfig.bms.enabled = preferences.getBool("bms_enabled", appConfig.bms.enabled);
|
appConfig.bms.enabled = preferences.getBool("bms_enabled", appConfig.bms.enabled);
|
||||||
@@ -136,6 +141,7 @@ void saveConfig() {
|
|||||||
preferences.putString((prefix + "addr").c_str(), appConfig.tempSensors[i].address);
|
preferences.putString((prefix + "addr").c_str(), appConfig.tempSensors[i].address);
|
||||||
preferences.putBool((prefix + "enabled").c_str(), appConfig.tempSensors[i].enabled);
|
preferences.putBool((prefix + "enabled").c_str(), appConfig.tempSensors[i].enabled);
|
||||||
preferences.putBool((prefix + "weather").c_str(), appConfig.tempSensors[i].weather);
|
preferences.putBool((prefix + "weather").c_str(), appConfig.tempSensors[i].weather);
|
||||||
|
preferences.putString((prefix + "group").c_str(), appConfig.tempSensors[i].group);
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.putBool("bms_enabled", appConfig.bms.enabled);
|
preferences.putBool("bms_enabled", appConfig.bms.enabled);
|
||||||
@@ -187,7 +193,9 @@ void printConfig() {
|
|||||||
Serial.print(" / enabled ");
|
Serial.print(" / enabled ");
|
||||||
Serial.print(appConfig.tempSensors[i].enabled ? "true" : "false");
|
Serial.print(appConfig.tempSensors[i].enabled ? "true" : "false");
|
||||||
Serial.print(" / address ");
|
Serial.print(" / address ");
|
||||||
Serial.println(appConfig.tempSensors[i].address);
|
Serial.print(appConfig.tempSensors[i].address);
|
||||||
|
Serial.print(" / group ");
|
||||||
|
Serial.println(appConfig.tempSensors[i].group);
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.println(" BMS:");
|
Serial.println(" BMS:");
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ struct TempSensorConfig {
|
|||||||
String address;
|
String address;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
bool weather;
|
bool weather;
|
||||||
|
String group;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BmsConfig {
|
struct BmsConfig {
|
||||||
|
|||||||
@@ -1183,6 +1183,15 @@ function renderConfigControls(data){
|
|||||||
<div id="tempAddress${i}" class="tempConfigAddress"></div>
|
<div id="tempAddress${i}" class="tempConfigAddress"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<label class="inputHelp" for="tempGroup${i}">Group</label>
|
||||||
|
<select id="tempGroup${i}" onchange="markConfigFieldTouched('tempGroup${i}')">
|
||||||
|
<option value="cabin">Cabin</option>
|
||||||
|
<option value="fridge">Fridge</option>
|
||||||
|
<option value="outside">Outside</option>
|
||||||
|
<option value="battery">Battery</option>
|
||||||
|
<option value="other">Other</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
<div class="tempConfigControls">
|
<div class="tempConfigControls">
|
||||||
<label class="tempCheck">
|
<label class="tempCheck">
|
||||||
<input id="tempEnabled${i}" type="checkbox" onchange="markConfigFieldTouched('tempEnabled${i}'); saveTempConfig()">
|
<input id="tempEnabled${i}" type="checkbox" onchange="markConfigFieldTouched('tempEnabled${i}'); saveTempConfig()">
|
||||||
@@ -1211,6 +1220,11 @@ function renderConfigControls(data){
|
|||||||
if(weather && !configTouched["tempWeather"+i] && document.activeElement!==weather){
|
if(weather && !configTouched["tempWeather"+i] && document.activeElement!==weather){
|
||||||
weather.checked=!!t.weather;
|
weather.checked=!!t.weather;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const group=$("tempGroup"+i);
|
||||||
|
if(group && !configTouched["tempGroup"+i] && document.activeElement!==group){
|
||||||
|
group.value=t.group||"cabin";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1253,6 +1267,7 @@ async function saveTempConfig(){
|
|||||||
const name=$("tempName"+i)?.value.trim() || temps[i].name || temps[i].id;
|
const name=$("tempName"+i)?.value.trim() || temps[i].name || temps[i].id;
|
||||||
const enabled=$("tempEnabled"+i)?.checked || false;
|
const enabled=$("tempEnabled"+i)?.checked || false;
|
||||||
const weather=$("tempWeather"+i)?.checked || false;
|
const weather=$("tempWeather"+i)?.checked || false;
|
||||||
|
const group=$("tempGroup"+i)?.value || temps[i].group || "cabin";
|
||||||
|
|
||||||
await fetch(api("/config/temp"),{
|
await fetch(api("/config/temp"),{
|
||||||
method:"POST",
|
method:"POST",
|
||||||
@@ -1262,7 +1277,8 @@ async function saveTempConfig(){
|
|||||||
name:name,
|
name:name,
|
||||||
address:temps[i].address||"",
|
address:temps[i].address||"",
|
||||||
enabled:enabled,
|
enabled:enabled,
|
||||||
weather:weather
|
weather:weather,
|
||||||
|
group:group
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1272,7 +1288,7 @@ async function saveTempConfig(){
|
|||||||
alert("Temperature config saved");
|
alert("Temperature config saved");
|
||||||
clearConfigTouched([
|
clearConfigTouched([
|
||||||
"tempEnabledCount",
|
"tempEnabledCount",
|
||||||
...temps.flatMap((_,i)=>["tempName"+i,"tempEnabled"+i,"tempWeather"+i])
|
...temps.flatMap((_,i)=>["tempName"+i,"tempEnabled"+i,"tempWeather"+i,"tempGroup"+i])
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2000,6 +2016,7 @@ void buildConfigDocument(JsonObject doc) {
|
|||||||
temp["address"] = appConfig.tempSensors[i].address;
|
temp["address"] = appConfig.tempSensors[i].address;
|
||||||
temp["enabled"] = appConfig.tempSensors[i].enabled;
|
temp["enabled"] = appConfig.tempSensors[i].enabled;
|
||||||
temp["weather"] = appConfig.tempSensors[i].weather;
|
temp["weather"] = appConfig.tempSensors[i].weather;
|
||||||
|
temp["group"] = appConfig.tempSensors[i].group;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2193,6 +2210,7 @@ void applyImportedConfig(JsonObject doc) {
|
|||||||
if (temp["address"].is<String>()) appConfig.tempSensors[index].address = temp["address"].as<String>();
|
if (temp["address"].is<String>()) appConfig.tempSensors[index].address = temp["address"].as<String>();
|
||||||
if (temp["enabled"].is<bool>()) appConfig.tempSensors[index].enabled = temp["enabled"].as<bool>();
|
if (temp["enabled"].is<bool>()) appConfig.tempSensors[index].enabled = temp["enabled"].as<bool>();
|
||||||
if (temp["weather"].is<bool>()) appConfig.tempSensors[index].weather = temp["weather"].as<bool>();
|
if (temp["weather"].is<bool>()) appConfig.tempSensors[index].weather = temp["weather"].as<bool>();
|
||||||
|
if (temp["group"].is<String>()) appConfig.tempSensors[index].group = temp["group"].as<String>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2298,6 +2316,7 @@ void buildStatusDocument(JsonDocument& doc) {
|
|||||||
temp["name"] = appConfig.tempSensors[i].name;
|
temp["name"] = appConfig.tempSensors[i].name;
|
||||||
temp["enabled"] = appConfig.tempSensors[i].enabled;
|
temp["enabled"] = appConfig.tempSensors[i].enabled;
|
||||||
temp["weather"] = appConfig.tempSensors[i].weather;
|
temp["weather"] = appConfig.tempSensors[i].weather;
|
||||||
|
temp["group"] = appConfig.tempSensors[i].group;
|
||||||
temp["online"] = sensors.online[i];
|
temp["online"] = sensors.online[i];
|
||||||
if (sensors.online[i]) {
|
if (sensors.online[i]) {
|
||||||
temp["temperature_f"] = sensors.tempsF[i];
|
temp["temperature_f"] = sensors.tempsF[i];
|
||||||
@@ -2441,6 +2460,8 @@ void sendConfigResponse(Stream& output, bool ok = true) {
|
|||||||
temp["name"] = appConfig.tempSensors[i].name;
|
temp["name"] = appConfig.tempSensors[i].name;
|
||||||
temp["address"] = appConfig.tempSensors[i].address;
|
temp["address"] = appConfig.tempSensors[i].address;
|
||||||
temp["enabled"] = appConfig.tempSensors[i].enabled;
|
temp["enabled"] = appConfig.tempSensors[i].enabled;
|
||||||
|
temp["weather"] = appConfig.tempSensors[i].weather;
|
||||||
|
temp["group"] = appConfig.tempSensors[i].group;
|
||||||
}
|
}
|
||||||
|
|
||||||
serializeJson(doc, output);
|
serializeJson(doc, output);
|
||||||
@@ -3422,6 +3443,7 @@ void handleUpdateTempSensorConfig() {
|
|||||||
if (doc["address"].is<String>()) appConfig.tempSensors[index].address = doc["address"].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["enabled"].is<bool>()) appConfig.tempSensors[index].enabled = doc["enabled"].as<bool>();
|
||||||
if (doc["weather"].is<bool>()) appConfig.tempSensors[index].weather = doc["weather"].as<bool>();
|
if (doc["weather"].is<bool>()) appConfig.tempSensors[index].weather = doc["weather"].as<bool>();
|
||||||
|
if (doc["group"].is<String>()) appConfig.tempSensors[index].group = doc["group"].as<String>();
|
||||||
|
|
||||||
sendOkConfig();
|
sendOkConfig();
|
||||||
}
|
}
|
||||||
@@ -3562,6 +3584,7 @@ void handleTempClear() {
|
|||||||
appConfig.tempSensors[i].address = "";
|
appConfig.tempSensors[i].address = "";
|
||||||
appConfig.tempSensors[i].enabled = false;
|
appConfig.tempSensors[i].enabled = false;
|
||||||
appConfig.tempSensors[i].weather = false;
|
appConfig.tempSensors[i].weather = false;
|
||||||
|
appConfig.tempSensors[i].group = "cabin";
|
||||||
sensors.tempsF[i] = -127.0;
|
sensors.tempsF[i] = -127.0;
|
||||||
sensors.online[i] = false;
|
sensors.online[i] = false;
|
||||||
}
|
}
|
||||||
@@ -3598,6 +3621,7 @@ void handleTempClear() {
|
|||||||
appConfig.tempSensors[configIndex].address = "";
|
appConfig.tempSensors[configIndex].address = "";
|
||||||
appConfig.tempSensors[configIndex].enabled = false;
|
appConfig.tempSensors[configIndex].enabled = false;
|
||||||
appConfig.tempSensors[configIndex].weather = false;
|
appConfig.tempSensors[configIndex].weather = false;
|
||||||
|
appConfig.tempSensors[configIndex].group = "cabin";
|
||||||
sensors.tempsF[configIndex] = -127.0;
|
sensors.tempsF[configIndex] = -127.0;
|
||||||
sensors.online[configIndex] = false;
|
sensors.online[configIndex] = false;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user