## Summary

Follow-up to the feature/OrcaSonar review. Scopes the new behavior to the
OrcaSonar agent, fixes several AMS-sync and lifecycle bugs, and makes the
MQTT tests run in CI. Non-OrcaSonar agents keep their existing behavior.

## Changes

Discovery
- Gate the background SSDP scan to a configured OrcaSonar machine instead of
  running for every non-BBL profile; drive discovery on demand from the
  machine-select popup and back off idle rounds from 5s to 60s.
- Add NSLocalNetworkUsageDescription and NSBonjourServices to both macOS
  Info.plist templates.

AMS sync
- Resolve id-less printer-set trays by material type in get_ams_cobox_infos
  and the sidebar badge loop, matching sync_ams_list, so combo arrays and
  badges stay aligned.
- Keep a printer-set tray that resolved by type out of the "unknown or
  incompatible filaments" dialog.

AMS device UI
- Gate the "Empty" tray classification, and the editable temperature fields,
  to the OrcaSonar agent; Bambu keeps "?" and read-only presets.
- Validate AMS material temps on confirm: reject out-of-range values and
  min > max before the command is sent.

Storage tab
- Bind the show/hide handler on the panel's ancestors (StoragePanel and
  MonitorPanel) and unbind on destruction, so the Bambu file system stops
  when the tab is left.

Transport
- Load /etc/ssl/cert.pem on macOS in add_platform_root_certificates, after
  set_default_verify_paths.
- Release lifecycle_mutex before start()'s connect wait so stop() can cancel
  the attempt and signal completion instead of stalling the UI thread.

Localization
- Add OrcaFilesPanel.cpp to list.txt and regenerate the catalogs.

## Tests
- Un-hide the loopback MockBroker integration tests (ephemeral port, no
  network) so ctest registers and runs them.
- Mock broker tracks SUBSCRIBE/UNSUBSCRIBE and delivers push_report only to a
  subscribed topic; the reconnect test asserts the re-SUBSCRIBE.
- Add bbl empty-tray cases, an AMS combo-alignment case, and unknowns
  assertions to the AMS sync tests.
This commit is contained in:
Lam Wei Lun
2026-10-06 12:09:23 +08:00
parent 029bc7928f
commit ccbb73baaf
46 changed files with 15790 additions and 9552 deletions
+12 -4
View File
@@ -397,8 +397,9 @@ private:
return true;
}
void ssdp_round()
bool ssdp_round()
{
bool emitted = false;
namespace asio = boost::asio;
using asio::ip::udp;
try {
@@ -436,8 +437,10 @@ private:
if (make_machine_alive_json(usn, sender.address().to_string(), location, machine_alive)) {
nlohmann::json machine = nlohmann::json::parse(machine_alive);
const std::string device_id = machine["dev_id"].get<std::string>();
if (seen_ids.insert(device_id).second && m_emit)
if (seen_ids.insert(device_id).second && m_emit) {
m_emit(machine_alive);
emitted = true;
}
}
}
} else if (error != asio::error::would_block && error != asio::error::try_again) {
@@ -450,14 +453,19 @@ private:
} catch (const std::exception& error) {
BOOST_LOG_TRIVIAL(warning) << "OrcaSonarDiscovery: SSDP round failed: " << error.what();
}
return emitted;
}
void browse_loop()
{
// Idle rounds back off to avoid a permanent 8s M-SEARCH when no OrcaSonar is present.
std::chrono::seconds interval(5);
while (m_running.load()) {
ssdp_round();
const bool found = ssdp_round();
std::unique_lock<std::mutex> lock(m_wait_mutex);
m_wait_cv.wait_for(lock, std::chrono::seconds(5), [this] { return !m_running.load(); });
m_wait_cv.wait_for(lock, found ? std::chrono::seconds(5) : interval, [this] { return !m_running.load(); });
interval = found ? std::chrono::seconds(5)
: std::chrono::seconds(std::min<long long>(interval.count() * 2, 60));
}
}