C++ Migration Guide
Release-by-release migration notes for the SmartSpectra C++ SDK: breaking API changes, renamed headers, and what each upgrade requires.
Applies to SmartSpectra C++ SDK v3.x.
The SDK previously emitted informational log chatter by default. From v3.3.0
the default level is SmartSpectraLogLevel::kWarning. If you relied on the
informational output, restore it via SmartSpectraConfig::log_level:
SmartSpectraConfig config;
config.log_level = presage::smartspectra::SmartSpectraLogLevel::kInfo;Setting the GLOG_minloglevel environment variable still works and is never
overridden by the SDK default.
presage::smartspectra::MetricsToJsonSoA previously returned nlohmann::json and required customers to have nlohmann/json.hpp reachable on their compile path through the bundled SDK headers. It now returns absl::StatusOr<std::string> — the SDK no longer ships nlohmann/json.hpp and the public header (smartspectra/messages/metrics.h) no longer references it.
// Before (v3.1.0-rc.3 and earlier):
#include <nlohmann/json.hpp>
nlohmann::json j = presage::smartspectra::MetricsToJsonSoA(metrics);
double pr = j["series"]["cardio.pulse_rate"]["values"][0];
// After (v3.1.0-rc.4+):
#include <absl/status/statusor.h>
#include <string>
auto json = presage::smartspectra::MetricsToJsonSoA(metrics);
if (!json.ok()) {
// handle absl::InvalidArgumentError (serialization failure)
}
// Write the serialized JSON to a file / network / log, or parse it back
// into a JSON object using the JSON library of your choice (nlohmann/json,
// rapidjson, simdjson, etc.) — the SDK no longer opinionates this.
std::string serialized = *json;The on-the-wire JSON layout ({"series": {"<name>": {"timestamps": [...], "values": [...]}, ...}}) is unchanged.
Migrating from SDK v1.x to v3.0 (C++).
The SDK now operates in continuous mode by default. The OperationMode enum and related container type aliases have been removed. Configure the SDK with SmartSpectraConfig and use SmartSpectra directly.
// Before:
Settings<OperationMode::Continuous, IntegrationMode::Rest> settings;
CpuContinuousRestForegroundContainer container(settings);
// After:
presage::smartspectra::SmartSpectraConfig config;
config.api_key = "...";
config.requested_metrics =
presage::smartspectra::SmartSpectraConfig::BreathingMetrics();
presage::smartspectra::SmartSpectra spectra(config);For timed sessions that previously depended on spot-style container behavior:
config.enable_accumulated_output = true;
spectra.UseFile("video.mp4").SetMaxDuration(30000).Build();
// For live camera sessions, keep timing in application code and call Stop().Use SmartSpectra directly instead of Container abstractions.
// Before:
#include <smartspectra/container/foreground_container.hpp>
container::CpuRestForegroundContainer container(settings);
container.Initialize();
container.Run();// After:
#include <smartspectra/smartspectra.h>
#include <smartspectra/smartspectra_config.h>
presage::smartspectra::SmartSpectraConfig config;
config.api_key = "...";
presage::smartspectra::SmartSpectra spectra(config);
const auto source_error = spectra.UseCamera().Build();
if (!source_error.ok()) {
LOG(ERROR) << source_error.FullMessage();
return;
}
if (const auto err = spectra.Start(); !err.ok()) {
LOG(ERROR) << err.FullMessage();
return;
}Use the SmartSpectra public headers and protobuf metric headers directly:
#include <smartspectra/smartspectra.h>
#include <smartspectra/smartspectra_config.h>
#include <smartspectra/messages/metrics.h>The current API separates source configuration from source creation. After
calling UseCamera(), UseFile(), or UseCustomInput(), call Build() and
check the returned SmartSpectraError before Start().
// Before:
spectra.UseCamera();
spectra.Start();// After:
const auto source_error =
spectra.UseCamera().SetResolution(1280, 720).SetFps(30).Build();
if (!source_error.ok()) {
LOG(ERROR) << source_error.FullMessage();
return;
}
if (const auto err = spectra.Start(); !err.ok()) {
LOG(ERROR) << err.FullMessage();
return;
}If you omit source configuration entirely, Start() still defaults to camera 0.
If an older integration assumed pulse-related output was part of the default
metric set, update it explicitly. BreathingMetrics() is the named breathing
bundle. DefaultSupportedMetrics() is the fallback used when
requested_metrics is empty and currently delegates to BreathingMetrics().
presage::smartspectra::SmartSpectraConfig config;
config.api_key = "...";
config.requested_metrics =
presage::smartspectra::SmartSpectraConfig::BreathingMetrics();
config.AddMetrics(
presage::smartspectra::SmartSpectraConfig::CardioMetrics());Older container-based integrations linked SmartSpectra::Container. The
installed v3 package exposes the public C++ SDK as SmartSpectra::SDK.
# Before:
target_link_libraries(my_app SmartSpectra::Container)
# After:
target_link_libraries(my_app SmartSpectra::SDK)Older source-build integrations may have linked the Edge target directly as
Physiology::Edge. That target is not a customer-facing installed package
target in v3. Use the installed SmartSpectra package and link SmartSpectra::SDK.
sudo apt install libsmartspectra-dev# Before:
target_link_libraries(my_app Physiology::Edge)
# After:
target_link_libraries(my_app SmartSpectra::SDK)The generated protobuf message namespace has been renamed from
presage::physiology to presage::smartspectra. Older container classes
already lived under presage::smartspectra::container; current public SDK
classes and generated *.pb.h messages now share the top-level
presage::smartspectra namespace.
// Before:
presage::physiology::MetricsBuffer metrics_buffer;
presage::physiology::Metrics edge_metrics;
// After:
presage::smartspectra::SmartSpectraConfig config;
presage::smartspectra::Metrics metrics;The shared protobuf message schemas (insights, metric_types, metrics,
point_types, status) also move from package presage.physiology to
package presage.smartspectra. The on-the-wire byte format of serialized
messages is unchanged (field numbers are untouched).
google.protobuf.Any.type_url strings, JSON @type fields, and
DescriptorPool lookups all key off the fully-qualified message name, which
moves from presage.physiology.<Message> to presage.smartspectra.<Message>.
A new SDK build cannot decode Any-wrapped or JSON-keyed payloads written by
an older build of the SDK, and vice versa. Cross-version interop between old
and new builds is not supported as part of this migration.
If your application persists Any-wrapped blobs or stores JSON with @type
fields keyed by the old type name, regenerate those artifacts with the new
SDK before deploying. Re-emitting the data is the only supported path.
This migration covers the C++ public surface and the proto package
declarations. Related platform surfaces are documented separately:
- Android Java/Kotlin (
com.presage.physiology.proto.*→com.presagetech.smartspectra.proto.*): consumers building against the new Android SDK release should update their generated-proto imports as part of the Android upgrade. See the Android Migration Guide for the platform-specific import examples. - Python proto wheel (
SmartSpectra-Messages): the internal Python wheel now publishes the generated protobuf modules undersmartspectra.messages.*to match the SDK package identity. See the "Python Proto Wheel" section below for the import examples.
The Android JNI-bound classes com.presage.physiology.Messages and
com.presage.physiology.emd.security.AndroidKeyStoreHelper are pinned by
native .so JNI symbol names and are not renamed by this migration or by
the Java protobuf migration; their cleanup is tracked as a further follow-up.
The old public surface combined smartspectra/container/... headers with
physiology/modules/... generated protobuf headers. Current consumers include
the SmartSpectra SDK headers and protobuf metric headers directly.
// Before:
#include <smartspectra/container/foreground_container.hpp>
#include <smartspectra/container/settings.hpp>
#include <physiology/modules/messages/metrics.h>
// After:
#include <smartspectra/smartspectra.h>
#include <smartspectra/smartspectra_config.h>
#include <smartspectra/messages/metrics.h>The SDK now exports a single -I root (<prefix>/include); the previous
secondary -I<prefix>/include/physiology propagation is gone.
Installed CMake package variables now use the one-word SMARTSPECTRA_*
prefix. There are no compatibility aliases for the old names, so update
consumer CMakeLists.txt files and CI flags in one pass.
| Old | New |
|---|---|
SMART_SPECTRA_VERSION | SMARTSPECTRA_VERSION |
SMART_SPECTRA_VERSION_MAJOR | SMARTSPECTRA_VERSION_MAJOR |
SMART_SPECTRA_VERSION_MINOR | SMARTSPECTRA_VERSION_MINOR |
SMART_SPECTRA_VERSION_PATCH | SMARTSPECTRA_VERSION_PATCH |
SMART_SPECTRA_VERSION_PLAIN | SMARTSPECTRA_VERSION_PLAIN |
SMART_SPECTRA_INSTALL_INCLUDE_DIR | SMARTSPECTRA_INSTALL_INCLUDE_DIR |
SMART_SPECTRA_INSTALL_LIB_DIR | SMARTSPECTRA_INSTALL_LIB_DIR |
SMART_SPECTRA_INSTALL_CMAKE_DIR | SMARTSPECTRA_INSTALL_CMAKE_DIR |
PHYSIOLOGY_EDGE_ARCHITECTURE | SMARTSPECTRA_ARCHITECTURE |
PHYSIOLOGY_EDGE_MODEL_DIRECTORY | SMARTSPECTRA_MODEL_DIRECTORY |
PHYSIOLOGY_EDGE_GRAPH_DIRECTORY | SMARTSPECTRA_GRAPH_DIRECTORY |
PHYSIOLOGY_EDGE_MLX_ENABLED | SMARTSPECTRA_MLX_ENABLED |
PHYSIOLOGY_EDGE_MLX_METALLIB_PATH | SMARTSPECTRA_MLX_METALLIB_PATH |
PHYSIOLOGY_EDGE_AUTO_FINALIZE | SMARTSPECTRA_AUTO_FINALIZE |
The user-facing CMake option for disabling remote model delivery was also renamed:
- cmake -DDISABLE_REMOTE_MODEL_DELIVERY=ON ...
+ cmake -DSMARTSPECTRA_DISABLE_REMOTE_MODEL_DELIVERY=ON ...The installed MLX helper module was renamed from PhysiologyEdge_mlx.cmake to
SmartSpectra_mlx.cmake. SmartSpectraConfig.cmake includes this helper
automatically on Apple/MLX builds, so only consumers that include the helper
directly need to change anything.
- include("${CMAKE_CURRENT_LIST_DIR}/PhysiologyEdge_mlx.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/SmartSpectra_mlx.cmake")In this release the helper's public CMake API was also renamed from the
PhysiologyEdge_ / _PhysiologyEdge_ / PHYSIOLOGY_EDGE_ /
physiology_edge_ prefixes to SmartSpectra_ / _SmartSpectra_ /
SMARTSPECTRA_ / _SMARTSPECTRA_ / _smartspectra_. This is a hard
rename — no compatibility aliases or deprecation shims are provided, so
consumers calling the old names will see "Unknown CMake command" errors at
configure time.
| Old name | New name |
|---|---|
PhysiologyEdge_finalize_target | SmartSpectra_finalize_target |
PhysiologyEdge_copy_mlx_metallib_to_target | SmartSpectra_copy_mlx_metallib_to_target |
target property _PHYSIOLOGY_EDGE_FINALIZED | target property _SMARTSPECTRA_FINALIZED |
global property _PHYSIOLOGY_EDGE_TARGETS_TO_FINALIZE | global property _SMARTSPECTRA_TARGETS_TO_FINALIZE |
custom target _physiology_edge_deploy_metallib | custom target _smartspectra_deploy_metallib |
message(STATUS "PhysiologyEdge: …") | message(STATUS "SmartSpectra: …") |
The installed SmartSpectra package exposes only the SmartSpectra::*
targets (SmartSpectra::SDK for application consumers). Physiology::Edge
is an internal source-build target and is not part of the installed
package — see "Single Package SDK" above.
To apply all renames mechanically across a downstream consumer's CMake sources, run from the repo root:
git ls-files -z '*.cmake' '*.cmake.in' 'CMakeLists.txt' '**/CMakeLists.txt' \
| xargs -0 sed -i \
-e 's/PhysiologyEdge_finalize_target/SmartSpectra_finalize_target/g' \
-e 's/PhysiologyEdge_copy_mlx_metallib_to_target/SmartSpectra_copy_mlx_metallib_to_target/g' \
-e 's/_PHYSIOLOGY_EDGE_FINALIZED/_SMARTSPECTRA_FINALIZED/g' \
-e 's/_PHYSIOLOGY_EDGE_TARGETS_TO_FINALIZE/_SMARTSPECTRA_TARGETS_TO_FINALIZE/g' \
-e 's/_physiology_edge_deploy_metallib/_smartspectra_deploy_metallib/g' \
-e 's/"PhysiologyEdge: /"SmartSpectra: /g'(On macOS, replace sed -i with sed -i ''.)
Protobuf metric headers used to live under physiology/modules/messages/.
The modules/ nesting level has been dropped — messages/ now sits directly
under the new include base.
// Before:
#include <physiology/modules/messages/metrics.h>
#include <physiology/modules/messages/metric_types.pb.h>
#include <physiology/modules/messages/status.h>
// After:
#include <smartspectra/messages/metrics.h>
#include <smartspectra/messages/metric_types.pb.h>
#include <smartspectra/messages/status.h>Several headers — and the raw proto sources — that were previously installed publicly are no longer shipped:
<physiology/modules/configuration.h>— generated build-feature#defines, never a stable public API. No replacement.<physiology/modules/filesystem_absl.h>— internal filesystem helper. No replacement.<smartspectra/messages/protobuf_enum.h>— internal enum-reflection helper (AllEnumValues); reachable only via full Protobuf reflection and unused by the public API. No replacement.<smartspectra/video_source/camera_controls.h>— theCameraControlsinterface is not reachable through the public SDK (camera setup goes throughUseCamera, which owns the source internally). No replacement.- The raw
messages/*.protosources — build against the generatedmessages/*.pb.h(still shipped) instead.
If your code transitively included any of these, vendor your own equivalent or open an issue describing the use case.
The SDK now exposes a single version header at <smartspectra/version.hpp>.
The previous <physiology/version.h> and the transitional <smartspectra/edge_version.h>
are retired; both have been collapsed into <smartspectra/version.hpp>.
// Before:
#include <physiology/version.h>
// After:
#include <smartspectra/version.hpp>The version macros are now namespaced as SMART_SPECTRA_VERSION_MAJOR,
SMART_SPECTRA_VERSION_MINOR, SMART_SPECTRA_VERSION_PATCH,
SMART_SPECTRA_VERSION_STRING, and SMART_SPECTRA_VERSION_PLAIN. The
constexpr accessors under presage::smartspectra::GetVersionMajor() /
GetVersionMinor() / GetVersionPatch() / GetVersionString() /
GetVersionPlain() are unchanged in name and signature.
Public header filenames in <prefix>/include/smartspectra/ now expose the
direct SDK surface instead of the old container surface:
// Before: // After:
<smartspectra/container/foreground_container.hpp> <smartspectra/smartspectra.h>
<smartspectra/container/settings.hpp> <smartspectra/smartspectra_config.h>
<physiology/modules/messages/metrics.h> <smartspectra/messages/metrics.h>
<physiology/modules/messages/status.h> <smartspectra/messages/status.h>The internal Python protobuf wheel now publishes the generated modules under the SmartSpectra package identity:
# Before:
import physiology.modules.messages.metrics_pb2 as metrics
from physiology.modules.messages import status_pb2
# After:
import smartspectra.messages.metrics_pb2 as metrics
from smartspectra.messages import status_pb2