Add Elegoo printers to ESPHome fleet display
This commit is contained in:
@@ -32,6 +32,11 @@ inline bool is_on(const std::string &text) {
|
||||
return value == "on" || value == "true" || value == "1";
|
||||
}
|
||||
|
||||
inline bool elegoo_fault(const std::string &text) {
|
||||
const auto value = lower(text);
|
||||
return valid_text(value) && value != "ok" && value != "0" && value != "off" && value != "false";
|
||||
}
|
||||
|
||||
inline std::string humanize(std::string text) {
|
||||
if (!valid_text(text)) return "--";
|
||||
std::replace(text.begin(), text.end(), '_', ' ');
|
||||
@@ -60,6 +65,7 @@ inline std::string remaining(float value, const std::string &unit) {
|
||||
if (unit == "h") minutes = double(value) * 60;
|
||||
else if (unit == "min") minutes = value;
|
||||
else if (unit == "s") minutes = double(value) / 60;
|
||||
else if (unit == "ms") minutes = double(value) / 60000;
|
||||
else return "--"; // Never silently interpret hours as minutes.
|
||||
if (minutes > 1000000) return "--";
|
||||
const auto rounded = static_cast<int>(std::ceil(minutes - 0.001));
|
||||
@@ -74,6 +80,7 @@ inline int duration_seconds(float value, const std::string &unit) {
|
||||
if (unit == "h") seconds = double(value) * 3600;
|
||||
else if (unit == "min") seconds = double(value) * 60;
|
||||
else if (unit == "s") seconds = value;
|
||||
else if (unit == "ms") seconds = double(value) / 1000;
|
||||
else return -1;
|
||||
return seconds <= 60000000 ? static_cast<int>(std::round(seconds)) : -1;
|
||||
}
|
||||
@@ -106,6 +113,9 @@ struct Snapshot {
|
||||
bool connected = false;
|
||||
std::string online, status, task, stage, print_error, hms_error;
|
||||
std::string hms_count, print_error_message, print_error_code;
|
||||
std::string print_error_reason, uv_unit, elapsed_unit;
|
||||
bool elegoo = false, resin = false;
|
||||
float uv = NAN, elapsed = NAN;
|
||||
std::vector<HealthNotice> health_notices;
|
||||
std::string remaining_unit, nozzle_unit, bed_unit;
|
||||
std::string finish_time;
|
||||
@@ -117,6 +127,20 @@ struct Snapshot {
|
||||
std::vector<Tray> trays;
|
||||
|
||||
bool live() const { return connected && is_on(online) && valid_text(status); }
|
||||
bool has_print_error() const {
|
||||
if (!elegoo) return is_on(print_error);
|
||||
return elegoo_fault(print_error) || elegoo_fault(print_error_reason) || lower(status) == "error";
|
||||
}
|
||||
std::string error_message() const {
|
||||
if (!elegoo) return valid_text(print_error_message) ? print_error_message : "Print error reported; tap status for details";
|
||||
std::string message;
|
||||
for (const auto &text : {print_error, print_error_reason}) {
|
||||
if (!elegoo_fault(text)) continue;
|
||||
if (!message.empty()) message += " / ";
|
||||
message += humanize(text);
|
||||
}
|
||||
return message.empty() ? "Print error reported; tap status for details" : message;
|
||||
}
|
||||
int notice_count() const {
|
||||
int loaded = 0;
|
||||
for (const auto ¬ice : health_notices)
|
||||
@@ -138,8 +162,7 @@ struct Snapshot {
|
||||
return loaded == 0 || notice_count() > loaded ? std::max(rank, 2) : rank;
|
||||
}
|
||||
std::string alert_summary() const {
|
||||
if (is_on(print_error))
|
||||
return valid_text(print_error_message) ? print_error_message : "Print error reported; tap status for details";
|
||||
if (has_print_error()) return error_message();
|
||||
if (is_on(hms_error)) {
|
||||
for (const auto ¬ice : health_notices)
|
||||
if (valid_text(notice.message)) return notice.message;
|
||||
@@ -150,10 +173,10 @@ struct Snapshot {
|
||||
std::string health_details() const {
|
||||
if (!live()) return "Printer health data is unavailable. Waiting for a live connection.";
|
||||
std::string details;
|
||||
if (is_on(print_error)) {
|
||||
if (has_print_error()) {
|
||||
details = "PRINT ERROR\n";
|
||||
if (valid_text(print_error_code)) details += print_error_code + "\n";
|
||||
details += valid_text(print_error_message) ? print_error_message : "Message not supplied by Home Assistant.";
|
||||
details += error_message();
|
||||
details += "\n\n";
|
||||
}
|
||||
if (is_on(hms_error)) {
|
||||
@@ -178,13 +201,13 @@ struct Snapshot {
|
||||
if (!connected) return "HA OFFLINE";
|
||||
if (lower(online) == "off" || lower(online) == "false") return "PRINTER OFFLINE";
|
||||
if (!live()) return "SYNCING";
|
||||
if (is_on(print_error)) return "PRINT ERROR";
|
||||
if (has_print_error()) return "PRINT ERROR";
|
||||
if (is_on(hms_error))
|
||||
return health_severity_rank() >= 3 ? "HEALTH ERROR" : health_severity_rank() == 1 ? "HEALTH INFO" : "HEALTH NOTICE";
|
||||
const auto state = lower(status);
|
||||
if (state == "running") return "PRINTING";
|
||||
if (state == "running" || state == "printing") return "PRINTING";
|
||||
if (state == "pause" || state == "paused") return "PAUSED";
|
||||
if (state == "finish" || state == "finished") return "COMPLETE";
|
||||
if (state == "finish" || state == "finished" || state == "complete" || state == "completed") return "COMPLETE";
|
||||
auto text = humanize(status);
|
||||
for (char &c : text) c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
|
||||
return text;
|
||||
@@ -192,10 +215,10 @@ struct Snapshot {
|
||||
uint32_t status_color() const {
|
||||
if (!live()) return MUTED;
|
||||
const auto state = lower(status);
|
||||
if (is_on(print_error) || state == "failed") return RED;
|
||||
if (has_print_error() || state == "failed") return RED;
|
||||
if (is_on(hms_error))
|
||||
return health_severity_rank() >= 3 ? RED : health_severity_rank() == 1 ? 0x00E5E5 : AMBER;
|
||||
if (state == "pause" || state == "paused") return AMBER;
|
||||
if (state == "pause" || state == "paused" || state == "pausing") return AMBER;
|
||||
return GREEN;
|
||||
}
|
||||
};
|
||||
@@ -213,6 +236,8 @@ struct Widgets {
|
||||
lv_obj_t *status, *task, *top_progress, *remaining, *layers, *stage, *health_details;
|
||||
GaugeWidgets progress, nozzle, bed, fan, aux, exhaust;
|
||||
std::vector<TrayWidgets> trays;
|
||||
GaugeWidgets uv{}, layer{};
|
||||
lv_obj_t *elapsed = nullptr;
|
||||
};
|
||||
|
||||
inline void set_text(lv_obj_t *label, const std::string &text) {
|
||||
@@ -238,26 +263,37 @@ inline void render(const Snapshot &data, const Widgets &widgets) {
|
||||
live ? remaining(data.time_left, data.remaining_unit) : "--");
|
||||
set_text(widgets.task, live ? (valid_text(data.task) ? data.task : "No active print")
|
||||
: data.connected ? "Waiting for printer data" : "Waiting for Home Assistant");
|
||||
const float nozzle = data.dual_nozzle ? data.left_nozzle : data.nozzle;
|
||||
const float target = data.dual_nozzle ? data.left_target : data.nozzle_target;
|
||||
render_gauge(widgets.nozzle, live ? nozzle : NAN, live ? celsius(nozzle, data.nozzle_unit) : NAN,
|
||||
300, live ? "/ " + number(target) + " " + data.nozzle_unit : "--");
|
||||
render_gauge(widgets.bed, live ? data.bed : NAN, live ? celsius(data.bed, data.bed_unit) : NAN,
|
||||
120, live ? "/ " + number(data.bed_target) + " " + data.bed_unit : "--");
|
||||
render_gauge(widgets.fan, live ? data.fan : NAN, live ? data.fan : NAN, 100, "%");
|
||||
if (data.dual_nozzle)
|
||||
render_gauge(widgets.aux, live ? data.right_nozzle : NAN,
|
||||
live ? celsius(data.right_nozzle, data.nozzle_unit) : NAN,
|
||||
300, live ? "/ " + number(data.right_target) + " " + data.nozzle_unit : "--");
|
||||
else
|
||||
render_gauge(widgets.aux, live ? data.aux_fan : NAN, live ? data.aux_fan : NAN, 100, "%");
|
||||
render_gauge(widgets.exhaust, live ? data.exhaust_fan : NAN, live ? data.exhaust_fan : NAN, 100, "%");
|
||||
if (data.resin) {
|
||||
render_gauge(widgets.uv, live ? data.uv : NAN,
|
||||
live ? celsius(data.uv, data.uv_unit) : NAN, 100,
|
||||
live && valid_text(data.uv_unit) ? data.uv_unit : "--");
|
||||
const float layer_percent = std::isfinite(data.layer) && std::isfinite(data.total_layers)
|
||||
&& data.layer >= 0 && data.total_layers > 0 ? 100 * data.layer / data.total_layers : NAN;
|
||||
render_gauge(widgets.layer, live ? data.layer : NAN, live ? layer_percent : NAN, 100,
|
||||
live ? "/ " + number(data.total_layers) : "--");
|
||||
set_text(widgets.elapsed, "Elapsed: " + (live ? remaining(data.elapsed, data.elapsed_unit) : "--"));
|
||||
} else {
|
||||
const float nozzle = data.dual_nozzle ? data.left_nozzle : data.nozzle;
|
||||
const float target = data.dual_nozzle ? data.left_target : data.nozzle_target;
|
||||
render_gauge(widgets.nozzle, live ? nozzle : NAN, live ? celsius(nozzle, data.nozzle_unit) : NAN,
|
||||
300, live ? "/ " + number(target) + " " + data.nozzle_unit : "--");
|
||||
render_gauge(widgets.bed, live ? data.bed : NAN, live ? celsius(data.bed, data.bed_unit) : NAN,
|
||||
120, live ? "/ " + number(data.bed_target) + " " + data.bed_unit : "--");
|
||||
render_gauge(widgets.fan, live ? data.fan : NAN, live ? data.fan : NAN, 100, "%");
|
||||
if (data.dual_nozzle)
|
||||
render_gauge(widgets.aux, live ? data.right_nozzle : NAN,
|
||||
live ? celsius(data.right_nozzle, data.nozzle_unit) : NAN,
|
||||
300, live ? "/ " + number(data.right_target) + " " + data.nozzle_unit : "--");
|
||||
else
|
||||
render_gauge(widgets.aux, live ? data.aux_fan : NAN, live ? data.aux_fan : NAN, 100, "%");
|
||||
render_gauge(widgets.exhaust, live ? data.exhaust_fan : NAN, live ? data.exhaust_fan : NAN, 100, "%");
|
||||
}
|
||||
std::string time_line = live ? remaining(data.time_left, data.remaining_unit) : "--";
|
||||
if (live && !data.finish_time.empty()) time_line = data.finish_time + " | " + time_line;
|
||||
set_text(widgets.remaining, time_line);
|
||||
set_text(widgets.layers, live ? "Layer " + number(data.layer) + " / " + number(data.total_layers) : "--");
|
||||
std::string stage = live ? humanize(data.stage) : "Telemetry unavailable";
|
||||
if (live && (is_on(data.print_error) || is_on(data.hms_error))) stage = data.alert_summary();
|
||||
if (live && (data.has_print_error() || is_on(data.hms_error))) stage = data.alert_summary();
|
||||
set_text(widgets.stage, stage);
|
||||
lv_obj_set_style_text_color(widgets.stage, lv_color_hex(live && !data.alert_summary().empty() ? color : MUTED), 0);
|
||||
set_text(widgets.health_details, data.health_details());
|
||||
|
||||
Reference in New Issue
Block a user