Fix Orion AMS mapping and show printer health details

This commit is contained in:
Joshua King
2026-10-18 09:29:07 -04:00
parent f672de484e
commit 3c940f8027
15 changed files with 1104 additions and 24 deletions
+71 -3
View File
@@ -5,6 +5,7 @@
#include <cmath>
#include <cstdio>
#include <cstdint>
#include <cstdlib>
#include <string>
#include <vector>
@@ -99,9 +100,13 @@ struct Tray {
std::string label, type, color, active;
};
struct HealthNotice { std::string code, message, severity; };
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::vector<HealthNotice> health_notices;
std::string remaining_unit, nozzle_unit, bed_unit;
std::string finish_time;
float progress = NAN, nozzle = NAN, nozzle_target = NAN, bed = NAN, bed_target = NAN;
@@ -112,12 +117,70 @@ struct Snapshot {
std::vector<Tray> trays;
bool live() const { return connected && is_on(online) && valid_text(status); }
int notice_count() const {
int loaded = 0;
for (const auto &notice : health_notices)
if (valid_text(notice.code) || valid_text(notice.message)) ++loaded;
char *end;
const long count = std::strtol(hms_count.c_str(), &end, 10);
return end != hms_count.c_str() && *end == '\0' && count >= 0 && count < 10000
? std::max(loaded, static_cast<int>(count)) : loaded;
}
int health_severity_rank() const {
int rank = 1, loaded = 0;
for (const auto &notice : health_notices) {
if (!valid_text(notice.code) && !valid_text(notice.message)) continue;
++loaded;
const auto severity = lower(notice.severity);
rank = std::max(rank, severity == "fatal" || severity == "serious" ? 3 : severity == "info" ? 1 : 2);
}
// Missing/unloaded messages cannot establish an info-only notification.
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 (is_on(hms_error)) {
for (const auto &notice : health_notices)
if (valid_text(notice.message)) return notice.message;
return "Printer health notification; tap status for details";
}
return "";
}
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)) {
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 += "\n\n";
}
if (is_on(hms_error)) {
details += "HMS = Health Management System\n";
int loaded = 0;
for (const auto &notice : health_notices) {
if (!valid_text(notice.code) && !valid_text(notice.message)) continue;
details += "\nNotice " + std::to_string(++loaded);
if (valid_text(notice.severity)) details += " / " + notice.severity;
details += "\n";
if (valid_text(notice.code)) details += notice.code + "\n";
details += valid_text(notice.message) ? notice.message : "Message not supplied by Home Assistant.";
details += "\n";
}
if (loaded == 0) details += "\nNotification is active; details have not arrived from Home Assistant.\n";
if (notice_count() > loaded)
details += "\n" + std::to_string(notice_count() - loaded) + " more notification(s). View all in Home Assistant.\n";
}
return details.empty() ? "No current printer health notifications." : details;
}
std::string status_text() const {
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 (is_on(hms_error)) return "HMS ALERT";
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 == "pause" || state == "paused") return "PAUSED";
@@ -129,7 +192,9 @@ struct Snapshot {
uint32_t status_color() const {
if (!live()) return MUTED;
const auto state = lower(status);
if (is_on(print_error) || is_on(hms_error) || state == "failed") return RED;
if (is_on(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;
return GREEN;
}
@@ -145,7 +210,7 @@ namespace bambu_display {
struct TrayWidgets { lv_obj_t *card, *swatch, *label; };
struct GaugeWidgets { lv_obj_t *arc, *value, *detail; };
struct Widgets {
lv_obj_t *status, *task, *top_progress, *remaining, *layers, *stage;
lv_obj_t *status, *task, *top_progress, *remaining, *layers, *stage, *health_details;
GaugeWidgets progress, nozzle, bed, fan, aux, exhaust;
std::vector<TrayWidgets> trays;
};
@@ -192,7 +257,10 @@ inline void render(const Snapshot &data, const Widgets &widgets) {
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();
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());
for (size_t i = 0; i < std::min(data.trays.size(), widgets.trays.size()); ++i) {
const auto &tray = data.trays[i];
const auto &widget = widgets.trays[i];