Beyond Traditional API Calls
When most developers think about communicating with backend systems, they imagine REST APIs, GraphQL endpoints, or database queries. But KOS applications face a fundamentally different challenge: they need to stay synchronized with physical devices that are constantly changing, performing operations, and encountering real-world conditions that affect their behavior.
Traditional request-response patterns fall short when your coffee machine needs to tell your application that a cartridge just ran empty, or when a calibration sequence needs to provide real-time progress updates over several minutes. KOS addresses these challenges through six distinct communication patterns, each designed for specific types of data exchange with physical systems.
These patterns work together to create applications that feel naturally responsive to physical reality, where changes in the real world immediately reflect in your user interface, and where complex operations provide clear feedback about their progress.
The Six Essential Patterns
1. Endpoints – Your Data Foundation
Endpoints provide the foundational data that models need to operate. Think of them as the baseline information that establishes what your application knows about the physical world before real-time updates begin.
When your beverage dispenser application starts up, it needs to know what ingredients are available, what recipes exist, and what the current device configuration looks like. This isn’t real-time data—it’s the established state from which everything else builds.
import { kosModel, IKosDataModel } from "@kosdev-code/kos-ui-sdk";
@kosModel({ modelTypeId: "ingredient-model", singleton: false })
export class IngredientModelImpl implements IKosDataModel {
async load(): Promise<void> {
// Baseline data load via endpoint
const [error, ingredients] = await this.ingredientService.getIngredients();
if (error) {
this.logger.error("Failed to load ingredients", error);
return;
}
// Process baseline data
this.updateIngredientsFromBaseline(ingredients);
}
}Endpoints excel at bulk data operations, complex queries, and situations where you need immediate responses. They’re perfect for search functionality, detailed filtering, and any scenario where the application needs to ask specific questions about the current state of the system.
The key insight is that endpoints establish your baseline reality, while other patterns handle how that reality changes over time.
2. Topics – Real-Time Reality Updates
While endpoints tell you what is, topics tell you what just happened. They’re the nervous system of your KOS application, carrying real-time updates from the physical world directly to your models.
Topics shine when physical events need immediate representation in your user interface. When someone presses a dispense button, when a pump completes its cycle, or when a sensor detects a change in conditions, topics ensure your application responds instantly.
import { kosModel, kosTopicHandler, IKosDataModel } from "@kosdev-code/kos-ui-sdk";
@kosModel({ modelTypeId: "dispense-model", singleton: false })
export class DispenseModelImpl implements IKosDataModel {
// Real-time dispense progress updates
@kosTopicHandler({
topic: TOPIC_DISPENSE_PROGRESS,
websocket: true
})
handleDispenseProgress(payload: DispenseProgressPayload): void {
// Real-time delta update from backend
this.currentProgress = payload.progress;
this.remainingTime = payload.remainingMs;
// Update UI immediately with current progress
this.notifyProgressUpdate();
}
}The beauty of topics lies in their efficiency. Instead of your application constantly asking “has anything changed?”, the backend system simply announces changes as they occur. This creates applications that feel naturally responsive because they’re reacting to real events rather than polling for updates.
Topics create the foundation for user interfaces that feel alive and connected to the physical systems they control.
3. Configuration Properties – Operational Intelligence
Configuration properties represent the adjustable aspects of your physical systems—the parameters that operators can tune to optimize performance, customize behavior, or adapt to changing conditions.
Unlike static configuration files, KOS configuration properties are living values that come with rich metadata about how to display them, what ranges are valid, and how they should be converted between different units of measurement.
import { kosModel, kosConfigProperty, KosConfigProperty, IKosDataModel } from "@kosdev-code/kos-ui-sdk";
@kosModel({ modelTypeId: "pump-model", singleton: false })
export class PumpModelImpl implements IKosDataModel {
// Configurable operational parameter
@kosConfigProperty({
path: "assembly:core:board:micro:pump:S4",
attribute: "nominalRate"
})
private nominalRateConfig!: KosConfigProperty<number>;
// Access configured flow rate with automatic type conversion
get flowRate(): number {
return this.nominalRateConfig.value ?? 1.0; // Default fallback
}
// Update operational configuration
async updateFlowRate(newRate: number): Promise<void> {
this.nominalRateConfig.updateProperty(newRate);
this.logger.info(`Flow rate updated to ${newRate} for pump ${this.pumpPath}`);
}
}Configuration properties bridge the gap between your application’s user interface and the physical parameters that control device behavior. They make it possible to build configuration screens that automatically handle validation, unit conversion, and persistence without requiring custom code for each parameter.
This pattern is particularly powerful because it separates the concerns of how values are stored and managed from how they’re presented to users, making applications both more maintainable and more adaptable to different deployment scenarios.
4. Futures – Managing Complex Operations
Some operations in the physical world simply take time. Calibrating a pump might require several minutes of precise movements and measurements. Updating firmware could take an hour or more. These aren’t quick API calls—they’re extended procedures that need careful monitoring and user feedback.
Futures provide structured support for these long-running operations, offering progress tracking, cancellation capabilities, and clear status reporting throughout the operation lifecycle.
import { kosModel, kosFuture, Future, IKosDataModel } from "@kosdev-code/kos-ui-sdk";
@kosModel({ modelTypeId: "calibration-model", singleton: false })
export class CalibrationModelImpl implements IKosDataModel {
@kosFuture()
calibrationFuture?: Future<CalibrationResult>;
// Start long-running calibration process
async startCalibration(pumpId: string): Promise<void> {
const [error, future] = await this.calibrationService.startPumpCalibration(pumpId);
if (error) {
this.logger.error("Failed to start calibration", error);
return;
}
this.calibrationFuture = future;
}
}Futures transform potentially frustrating user experiences into informative, manageable processes. Instead of wondering whether a calibration is working or has failed, users see clear progress indication and can make informed decisions about whether to continue or cancel operations.
They also establish clear contracts between the backend and frontend about what information will be provided during long-running operations, making both sides of the system more predictable and reliable.
5. Troubles – When Things Go Wrong
Physical systems encounter problems. Cartridges run empty, sensors drift out of calibration, pumps develop blockages, and maintenance becomes necessary. The Trouble system provides structured support for detecting, reporting, and resolving these real-world issues.
Troubles aren’t just error messages—they’re actionable information about specific physical components that need attention, complete with context about how the problems affect system operation.
import { kosModel, kosDependency, TroubleContainerModel, TroubleModel, IKosDataModel } from "@kosdev-code/kos-ui-sdk";
@kosModel({ modelTypeId: "pump-model", singleton: false })
export class PumpModelImpl implements IKosDataModel {
@kosDependency({ modelType: TroubleContainerModel.type })
troubleContainer!: TroubleContainerModel;
devicePath: string = "/assembly/pumps/S4";
// Get troubles affecting this specific pump
get troubles(): TroubleModel[] {
return this.troubleContainer.troubles
.getIndexByKey("byIface", this.devicePath)
.sort((a, b) => b.rank - a.rank); // Critical issues first
}
// Business logic based on trouble state
get canOperate(): boolean {
const criticalTroubles = this.troubles.filter((t) => t.severity >= 8);
return criticalTroubles.length === 0;
}
}Troubles create applications that can intelligently respond to changing physical conditions. When a cartridge needs replacement, the system can automatically disable affected beverages. When calibration is required, maintenance procedures can be prioritized appropriately.
This pattern makes applications feel intelligent and proactive rather than simply reactive to user input.
6. State Beans – Physical Reality Monitoring
Some aspects of physical systems simply cannot be controlled by software—they can only be observed. Door positions, sensor readings, probe states, and environmental conditions represent the physical reality that applications need to respond to but cannot directly influence.
State beans provide read-only access to these physical conditions, updating automatically as the real world changes.
import { kosModel, kosStateProp, KosStateProp, kosModelEffect, IKosDataModel } from "@kosdev-code/kos-ui-sdk";
@kosModel({ modelTypeId: "door-model", singleton: false })
export class DoorModelImpl implements IKosDataModel {
// Read-only state property - reflects physical door state
@kosStateProp({
path: "/hardware/doors/front",
attribute: "state"
})
private doorState!: KosStateProp<"open" | "closed">;
// Access current physical state
get isOpen(): boolean {
return this.doorState.value === "open";
}
// React to physical state changes
@kosModelEffect({
dependencies: (model) => [model.doorState.value],
})
handleDoorStateChange(): void {
const currentState = this.doorState.value;
// Business logic based on physical state
if (currentState === "open") {
this.pauseOperations();
this.showMaintenanceAccess();
} else {
this.resumeOperations();
this.hideMaintenanceAccess();
}
}
}State beans make applications naturally responsive to physical conditions. Safety systems can automatically engage when doors open, quality controls can activate when sensors detect contamination, and operational procedures can adapt to environmental conditions without requiring manual intervention.
Choosing the Right Pattern
The power of KOS communication patterns lies not just in their individual capabilities, but in understanding when and how to combine them effectively. Each pattern serves specific scenarios, and using the right one for each situation creates applications that feel natural and responsive.
For baseline data and bulk operations, endpoints provide efficient, comprehensive data loading. Use them when you need to establish initial state or perform complex queries against existing data.
For real-time responsiveness, topics ensure immediate updates when physical conditions change. They’re essential when users need to see the current state of ongoing operations or when system coordination requires instant communication.
For operational parameters, configuration properties provide structured access to the adjustable aspects of your physical systems, complete with validation, conversion, and persistence handling.
For extended procedures, futures transform potentially opaque operations into manageable, monitorable processes with clear progress indication and user control.
For system health, troubles provide structured information about physical problems and their impact on system operation, enabling intelligent responses to changing conditions.
For physical monitoring, state beans offer read-only access to conditions that your application needs to respond to but cannot control.
Building Responsive Physical Interfaces
Understanding these patterns enables you to build applications that feel naturally connected to the physical systems they control. Instead of generic web interfaces that happen to control hardware, you can create experiences that reflect the unique characteristics and constraints of physical devices.
When a user starts a dispense operation, they see real-time progress through topics, understand any system limitations through troubles, and can monitor physical conditions through state beans. Configuration properties let them optimize performance for their specific environment, while futures provide clear feedback during longer maintenance procedures.
This creates applications that feel intelligent and responsive because they’re built on communication patterns specifically designed for the realities of physical system integration.
Ready to apply these patterns? Continue with Building Your First KOS Model to see how these communication patterns integrate into actual model development, or explore Advanced Integration Patterns for complex scenarios involving multiple devices and coordinated operations.
