Caffeine.Core API
Caffeine Framework의 핵심 모듈 API 레퍼런스입니다.
개요
Caffeine.Core는 프레임워크의 핵심 기능을 제공하는 모듈로, 드라이버 개발과 태그 관리를 위한 필수 인터페이스와 클래스를 포함합니다.
네임스페이스: Caffeine.Core
어셈블리: Caffeine.Core.dll
.NET 버전: .NET 10.0
주요 인터페이스
IDriver
드라이버 구현을 위한 기본 인터페이스입니다.
네임스페이스: Caffeine.Core.Abstractions
설명
모든 Caffeine 드라이버는 IDriver 인터페이스를 구현해야 합니다. 이 인터페이스는 장비 연결, 데이터 읽기/쓰기, 태그 관리 등의 핵심 기능을 정의합니다.
주요 메서드
ConnectAsync()
장비에 비동기로 연결합니다.
Task<bool> ConnectAsync(CancellationToken cancellationToken = default);
매개변수:
cancellationToken(CancellationToken): 작업 취소 토큰
반환값: Task<bool> - 연결 성공 시 true, 실패 시 false
예외:
TimeoutException: 연결 시간 초과InvalidOperationException: 이미 연결된 상태
사용 예시:
public class ModbusDriver : IDriver
{
public async Task<bool> ConnectAsync(CancellationToken cancellationToken = default)
{
try
{
// Modbus TCP 연결
await _client.ConnectAsync("192.168.1.100", 502, cancellationToken);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "연결 실패");
return false;
}
}
}
DisconnectAsync()
장비 연결을 비동기로 해제합니다.
Task DisconnectAsync();
반환값: Task - 비동기 작업
사용 예시:
public async Task DisconnectAsync()
{
await _client.DisconnectAsync();
_logger.LogInformation("연결 해제 완료");
}
ReadTagAsync()
지정된 태그의 값을 비동기로 읽습니다.
Task<TagValue?> ReadTagAsync(string tagName, CancellationToken cancellationToken = default);
매개변수:
tagName(string): 읽을 태그 이름cancellationToken(CancellationToken): 작업 취소 토큰
반환값: Task<TagValue?> - 태그 값 또는 null (태그가 없는 경우)
사용 예시:
var temperature = await driver.ReadTagAsync("Equipment1.Temperature");
if (temperature != null)
{
Console.WriteLine($"온도: {temperature.Value}°C");
}
WriteTagAsync()
지정된 태그에 값을 비동기로 씁니다.
Task<bool> WriteTagAsync(string tagName, object value, CancellationToken cancellationToken = default);
매개변수:
tagName(string): 쓸 태그 이름value(object): 쓸 값cancellationToken(CancellationToken): 작업 취소 토큰
반환값: Task<bool> - 쓰기 성공 시 true
사용 예시:
bool success = await driver.WriteTagAsync("Equipment1.SetPoint", 75.5);
if (success)
{
Console.WriteLine("설정값 변경 완료");
}
주요 클래스
TagValue
태그의 값과 메타데이터를 나타내는 클래스입니다.
네임스페이스: Caffeine.Core.Models
속성
| 속성 | 타입 | 설명 |
|---|---|---|
TagName | string | 태그 이름 |
Value | object | 태그 값 |
Timestamp | DateTime | 값이 읽힌 시각 (UTC) |
Quality | TagQuality | 데이터 품질 (Good, Bad, Uncertain) |
DataType | Type | 값의 .NET 타입 |
생성자
public TagValue(string tagName, object value, TagQuality quality = TagQuality.Good)
사용 예시:
var tagValue = new TagValue(
tagName: "Equipment1.Temperature",
value: 72.5,
quality: TagQuality.Good
);
Console.WriteLine($"{tagValue.TagName}: {tagValue.Value} at {tagValue.Timestamp}");
TagConfiguration
태그 설정을 정의하는 클래스입니다.
네임스페이스: Caffeine.Core.Abstractions.Tags
속성
| 속성 | 타입 | 설명 |
|---|---|---|
TagName | string | 태그 이름 (고유 식별자) |
DriverId | string | 드라이버 ID |
Address | string | 장비 주소 (예: Modbus 레지스터) |
DataType | string | 데이터 타입 (Int16, Float, String 등) |
ScanRate | int | 스캔 주기 (밀리초) |
Enabled | bool | 태그 활성화 여부 |
사용 예시
var tagConfig = new TagConfiguration
{
TagName = "Equipment1.Temperature",
DriverId = "ModbusTCP_001",
Address = "40001",
DataType = "Float",
ScanRate = 1000, // 1초마다 읽기
Enabled = true
};
열거형
TagQuality
태그 데이터의 품질을 나타냅니다.
네임스페이스: Caffeine.Core.Models
public enum TagQuality
{
Good = 0, // 정상 데이터
Bad = 1, // 오류 데이터
Uncertain = 2 // 불확실한 데이터
}
사용 예시:
if (tagValue.Quality == TagQuality.Good)
{
// 정상 데이터 처리
ProcessData(tagValue.Value);
}
else
{
_logger.LogWarning($"데이터 품질 불량: {tagValue.Quality}");
}
예제
기본 드라이버 구현
using Caffeine.Core.Abstractions;
using Caffeine.Core.Models;
public class MyCustomDriver : IDriver
{
private readonly ILogger<MyCustomDriver> _logger;
private bool _isConnected;
public MyCustomDriver(ILogger<MyCustomDriver> logger)
{
_logger = logger;
}
public async Task<bool> ConnectAsync(CancellationToken cancellationToken = default)
{
_logger.LogInformation("장비 연결 시작");
// 연결 로직
await Task.Delay(100, cancellationToken);
_isConnected = true;
_logger.LogInformation("장비 연결 완료");
return true;
}
public async Task DisconnectAsync()
{
_logger.LogInformation("장비 연결 해제");
_isConnected = false;
await Task.CompletedTask;
}
public async Task<TagValue?> ReadTagAsync(string tagName, CancellationToken cancellationToken = default)
{
if (!_isConnected)
{
throw new InvalidOperationException("연결되지 않음");
}
// 태그 읽기 로직
var value = await ReadFromEquipmentAsync(tagName, cancellationToken);
return new TagValue(tagName, value, TagQuality.Good);
}
public async Task<bool> WriteTagAsync(string tagName, object value, CancellationToken cancellationToken = default)
{
if (!_isConnected)
{
throw new InvalidOperationException("연결되지 않음");
}
// 태그 쓰기 로직
await WriteToEquipmentAsync(tagName, value, cancellationToken);
return true;
}
private async Task<object> ReadFromEquipmentAsync(string tagName, CancellationToken cancellationToken)
{
// 실제 장비 읽기 구현
await Task.Delay(10, cancellationToken);
return 42.5; // 예시 값
}
private async Task WriteToEquipmentAsync(string tagName, object value, CancellationToken cancellationToken)
{
// 실제 장비 쓰기 구현
await Task.Delay(10, cancellationToken);
}
}
태그 구독 및 처리
using Caffeine.Core.Models;
public class TagSubscriber
{
private readonly IDriver _driver;
private readonly ILogger<TagSubscriber> _logger;
public TagSubscriber(IDriver driver, ILogger<TagSubscriber> logger)
{
_driver = driver;
_logger = logger;
}
public async Task SubscribeAndProcessAsync(string[] tagNames, CancellationToken cancellationToken)
{
await _driver.ConnectAsync(cancellationToken);
while (!cancellationToken.IsCancellationRequested)
{
foreach (var tagName in tagNames)
{
var tagValue = await _driver.ReadTagAsync(tagName, cancellationToken);
if (tagValue != null && tagValue.Quality == TagQuality.Good)
{
ProcessTagValue(tagValue);
}
}
await Task.Delay(1000, cancellationToken); // 1초 대기
}
await _driver.DisconnectAsync();
}
private void ProcessTagValue(TagValue tagValue)
{
_logger.LogInformation($"태그: {tagValue.TagName}, 값: {tagValue.Value}, 시각: {tagValue.Timestamp}");
// 비즈니스 로직 처리
if (tagValue.Value is double temperature && temperature > 80)
{
_logger.LogWarning($"고온 경고: {temperature}°C");
}
}
}
DI 등록
AddCaffeine()
Caffeine.Core 구성요소를 DI 컨테이너에 일괄 등록하는 확장 메서드입니다.
네임스페이스: Caffeine.Core.Extensions
public static IServiceCollection AddCaffeine(
this IServiceCollection services,
Action<CaffeineOptions>? configure = null)
동작:
IDataCodec<double>,IDataCodec<short>,IDataCodec<int>Singleton 등록- 이미 등록된 서비스는 덮어쓰지 않음 (멱등 보장)
CaffeineOptions.UseBigEndianCodecs = true시 Big-Endian 코덱 자동 선택
코덱 등록 옵션:
| 옵션 | 등록되는 코덱 |
|---|---|
UseBigEndianCodecs = false (기본값) | LittleEndianDoubleCodec, LittleEndianShortCodec, LittleEndianIntCodec |
UseBigEndianCodecs = true | BigEndianDoubleCodec, BigEndianShortCodec, BigEndianIntCodec |
사용 예시:
// Program.cs
builder.Services.AddCaffeine(); // Little-Endian (기본값)
builder.Services.AddCaffeine(o => o.UseBigEndianCodecs = true); // Big-Endian
app.Services.UseCaffeine(); // LoggerFactory 연결 (선택 사항)
CaffeineOptions
AddCaffeine() 등록 시 사용하는 옵션 클래스입니다.
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
UseBigEndianCodecs | bool | false | Big-Endian 코덱 사용 여부 |
UseCaffeine()
앱 시작 시 DI 컨테이너의 ILoggerFactory를 LogExtensions에 연결합니다.
public static IServiceProvider UseCaffeine(this IServiceProvider provider)
호출하지 않아도 Codec은 정상 동작하며, 로깅만 NullLogger 폴백으로 유지됩니다.
센싱 추상화
도메인-불가지론적 센싱 인터페이스입니다. 로보틱스, 농업, 산업 IoT 등 모든 센싱 소스에 적용 가능합니다.
네임스페이스: Caffeine.Core.Abstractions.Sensing
ISensingCapability
센싱 능력을 나타내는 인터페이스입니다.
public interface ISensingCapability
{
string CapabilityName { get; }
IObservable<TelemetryReading> TelemetryStream { get; }
SensorCategory Category { get; }
}
| 멤버 | 설명 |
|---|---|
CapabilityName | 센싱 능력 이름 (예: "TemperatureSensor") |
TelemetryStream | 실시간 텔레메트리 Rx 스트림 |
Category | 센서 분류 (SensorCategory enum) |
사용 예시:
public class TemperatureSensor : ISensingCapability
{
public string CapabilityName => "TemperatureSensor";
public IObservable<TelemetryReading> TelemetryStream => _subject.AsObservable();
public SensorCategory Category => SensorCategory.Temperature;
private readonly Subject<TelemetryReading> _subject = new();
public void PublishReading(double celsius)
{
_subject.OnNext(new TelemetryReading(
SensorId: "TEMP-001",
Value: celsius,
Unit: "°C",
Timestamp: DateTimeOffset.UtcNow,
Quality: SensorQuality.Good));
}
}
TelemetryReading
텔레메트리 측정값 불변 레코드입니다.
public record TelemetryReading(
string SensorId,
double Value,
string Unit,
DateTimeOffset Timestamp,
SensorQuality Quality);
| 속성 | 타입 | 설명 |
|---|---|---|
SensorId | string | 센서 고유 식별자 |
Value | double | 측정값 |
Unit | string | 단위 (예: "°C", "bar") |
Timestamp | DateTimeOffset | 측정 시각 (UTC) |
Quality | SensorQuality | 데이터 품질 등급 |
SensorQuality
센서 데이터 품질 등급 열거형입니다.
public enum SensorQuality { Good, Uncertain, Bad, Unknown }
SensorCategory
센서 분류 표준화 열거형입니다. (v2.0.4에서 EC 등 수산/식물 카테고리 추가)
위치: src/Caffeine.Core/Abstractions/Sensing/SensorCategory.cs
public enum SensorCategory
{
Unknown = 0, // default(SensorCategory) 안전값
// 공통 환경
Temperature = 1, // 온도 (°C)
Humidity = 2, // 습도 (%RH)
Pressure = 3, // 기압 (hPa)
// 공기 품질 (10번대)
Ammonia = 10, // 암모니아 (ppm) — 축산
CarbonDioxide = 11, // CO2 (ppm)
Illuminance = 12, // 조도 (lux)
// 수질 (20번대) — AquaFarm
DissolvedOxygen = 20, // 용존 산소 (mg/L)
Ph = 21, // pH
Salinity = 22, // 염분 (ppt)
WaterTemperature = 23, // 수온 (°C)
Turbidity = 24, // 탁도 (NTU)
ElectricalConductivity = 25, // 전기전도도 (mS/cm)
// 토양/식물 (30번대) — GreenFarm
SoilMoisture = 30, // 토양 수분 (%)
SoilTemperature = 31, // 토양 온도 (°C)
LightIntensity = 32, // PAR (μmol/m²/s)
// 전기/기계 (40번대)
Voltage = 40, // 전압 (V)
Current = 41, // 전류 (A)
Weight = 42, // 중량/하중 (kg) — TMR 로드셀
Flow = 43, // 유량 (L/min)
Other = 99
}
| 번호 범위 | 분류 | 주요 값 |
|---|---|---|
| 0 / 1–3 | 공통 / 기본 환경 | Unknown(0), Temperature(1), Humidity(2), Pressure(3) |
| 10–12 | 공기 품질 | Ammonia(10), CarbonDioxide(11), Illuminance(12) |
| 20–25 | 수질 (AquaFarm) | DissolvedOxygen(20), Ph(21), Salinity(22), WaterTemperature(23), Turbidity(24), ElectricalConductivity(25) |
| 30–32 | 토양/식물 (GreenFarm) | SoilMoisture(30), SoilTemperature(31), LightIntensity(32) |
| 40–43 | 전기/기계 | Voltage(40), Current(41), Weight(42), Flow(43) |
| 99 | 기타 | Other |
안전 추상화
도메인-불가지론적 안전 정책 및 모니터링 인터페이스입니다.
네임스페이스: Caffeine.Core.Abstractions.Safety
ISafetyPolicy
작업 요청에 대해 허용/거부를 판정하는 안전 정책 인터페이스입니다.
public interface ISafetyPolicy
{
string PolicyName { get; }
int Priority { get; }
Task<SafetyEvaluationResult> EvaluateAsync(OperationRequest request, CancellationToken ct = default);
}
| 멤버 | 설명 |
|---|---|
PolicyName | 정책 이름 |
Priority | 평가 우선순위 (높을수록 먼저 평가) |
EvaluateAsync | 작업 요청에 대한 안전 평가 수행 |
ISafetyPolicyEngine
복수 정책을 조합하여 평가하는 인터페이스입니다.
public interface ISafetyPolicyEngine
{
IReadOnlyList<ISafetyPolicy> Policies { get; }
Task<SafetyEvaluationResult> EvaluateAllAsync(OperationRequest request, CancellationToken ct = default);
}
ISafetyMonitor
안전 위반 이벤트 Rx 스트림을 제공하는 모니터 인터페이스입니다.
public interface ISafetyMonitor
{
IObservable<SafetyViolation> ViolationStream { get; }
}
안전 관련 값 객체
| 타입 | 설명 |
|---|---|
SafetyLevel | 안전 수준 (Safe, Caution, Warning, Danger, Critical) |
SafetyEvaluationResult | 안전 평가 결과 (Level, Message, ViolatedPolicies) |
OperationRequest | 작업 실행 요청 (OperationId, DeviceId, OperationType, Parameters) |
SafetyViolation | 안전 정책 위반 정보 (PolicyId, Description, Severity, OccurredAt) |
사용 예시:
// ISafetyMonitor 구독
_safetyMonitor.ViolationStream
.Where(v => v.Severity >= SafetyLevel.Warning)
.Subscribe(v => _logger.LogWarning("안전 위반: {PolicyId} — {Description}", v.PolicyId, v.Description));
구역 관리 추상화
도메인-불가지논적 구역(Zone) 관리 인터페이스입니다. 공장 구역, 농업 구역, 로보틱스 작업 구역 등 모든 도메인에 적용 가능합니다.
네임스페이스: Caffeine.Core.Abstractions.Zones
IZoneManager
Zone CRUD, 계층 조회, 장치 배치, 상태 집계를 제공하는 11개 메서드 인터페이스입니다.
Zone CRUD (5개 메서드)
Task<ZoneInfo> CreateZoneAsync(ZoneInfo zone, CancellationToken ct = default);
Task<ZoneInfo?> GetZoneAsync(string zoneId, CancellationToken ct = default);
Task<ZoneInfo> UpdateZoneAsync(ZoneInfo zone, CancellationToken ct = default);
Task<bool> DeleteZoneAsync(string zoneId, CancellationToken ct = default);
Task<IReadOnlyList<ZoneInfo>> ListZonesAsync(CancellationToken ct = default);
계층 조회 (1개 메서드)
Task<IReadOnlyList<ZoneInfo>> GetChildZonesAsync(string parentZoneId, CancellationToken ct = default);
장치 배치 (4개 메서드)
Task AssignDeviceAsync(ZoneAssignment assignment, CancellationToken ct = default);
Task<bool> UnassignDeviceAsync(string zoneId, string deviceId, CancellationToken ct = default);
Task<IReadOnlyList<ZoneAssignment>> GetDeviceAssignmentsAsync(string zoneId, CancellationToken ct = default);
Task<IReadOnlyList<ZoneAssignment>> GetZoneAssignmentsByDeviceAsync(string deviceId, CancellationToken ct = default);
상태 집계 (1개 메서드)
Task<ZoneSummary> GetZoneSummaryAsync(string zoneId, CancellationToken ct = default);
IZoneMonitor
구역 변경 이벤트 Rx 스트림을 제공하는 인터페이스입니다.
public interface IZoneMonitor
{
IObservable<ZoneEvent> ZoneEventStream { get; }
}
Zone 관련 값 객체
| 타입 | 설명 |
|---|---|
ZoneInfo | 구역 정보 레코드 (ZoneId, Name, Status, ParentZoneId, Metadata) |
ZoneAssignment | 장치-구역 할당 레코드 (DeviceId, ZoneId, Role) |
ZoneSummary | 구역 상태 집계 레코드 (장치 수, 상태별 분포) |
ZoneStatus | 구역 상태 (Active, Inactive, Maintenance, Warning, Critical) |
ZoneEvent | 구역 변경 이벤트 (ZoneEventType, ZoneId, OccurredAt) |
ZoneEventType | 이벤트 유형 (ZoneCreated, ZoneUpdated, ZoneDeleted, DeviceAssigned, DeviceUnassigned, StatusChanged) |
사용 예시:
// 구역 생성 및 장치 배치
var zone = await _zoneManager.CreateZoneAsync(
new ZoneInfo("ZONE-A1", "조립 구역 A1", ZoneStatus.Active));
await _zoneManager.AssignDeviceAsync(
new ZoneAssignment("DEVICE-001", "ZONE-A1", "Primary"));
// 구역 이벤트 스트림 구독
_zoneMonitor.ZoneEventStream
.Where(e => e.EventType == ZoneEventType.StatusChanged)
.Subscribe(e => _logger.LogInformation("구역 상태 변경: {ZoneId}", e.ZoneId));
IDriverCapabilities
드라이버의 선택적 고급 기능을 조회하기 위한 인터페이스입니다. IDriverModule을 구현하는 드라이버가 선택적으로 추가 구현하여 런타임에 지원 기능을 노출합니다.
위치: src/Caffeine.Core/Abstractions/Drivers/IDriverCapabilities.cs
public interface IDriverCapabilities
{
/// <summary>드라이버가 지원하는 통신 프로토콜 목록 (예: "ModbusTCP", "MQTT", "OPC-UA")</summary>
IReadOnlyList<string> SupportedProtocols { get; }
/// <summary>최대 초당 처리 메시지 수 (0 = 무제한)</summary>
int MaxMessagesPerSecond { get; }
/// <summary>오프라인 버퍼링 지원 여부</summary>
bool SupportsOfflineBuffering { get; }
/// <summary>쌍방향 명령/응답 통신 지원 여부</summary>
bool SupportsBidirectional { get; }
/// <summary>드라이버가 읽을 수 있는 센서 카테고리 목록</summary>
IReadOnlyList<string> SupportedSensorCategories { get; }
}
| 속성 | 타입 | 설명 |
|---|---|---|
SupportedProtocols | IReadOnlyList<string> | 지원 프로토콜 목록 (예: ["ModbusTCP"]) |
MaxMessagesPerSecond | int | 초당 최대 처리 메시지 수 (0 = 무제한) |
SupportsOfflineBuffering | bool | 오프라인 버퍼링 지원 여부 |
SupportsBidirectional | bool | 읽기/쓰기 양방향 통신 지원 여부 |
SupportedSensorCategories | IReadOnlyList<string> | 읽을 수 있는 센서 카테고리 이름 목록 |
사용 예시:
// 드라이버가 IDriverCapabilities를 구현하는지 확인
if (driver is IDriverCapabilities caps)
{
Console.WriteLine($"Protocols: {string.Join(", ", caps.SupportedProtocols)}");
Console.WriteLine($"Max msg/s: {caps.MaxMessagesPerSecond}");
Console.WriteLine($"Bidirectional: {caps.SupportsBidirectional}");
Console.WriteLine($"Sensor categories: {string.Join(", ", caps.SupportedSensorCategories)}");
}
Modbus 드라이버 구현 예시:
// ModbusTcpDriver (Caffeine.Drivers.ModbusTcp)
IReadOnlyList<string> SupportedProtocols => new[] { "ModbusTCP" };
int MaxMessagesPerSecond => 100;
bool SupportsOfflineBuffering => false;
bool SupportsBidirectional => true;
// ModbusRtuDriver (Caffeine.Drivers.ModbusRtu) — 시리얼 대역폭 제한
int MaxMessagesPerSecond => 20;
참고 항목
- Caffeine.Client API - 클라이언트 SDK
- Caffeine.Infrastructure API - 인프라 서비스
- Edge↔Cloud 통신 API - 전송 추상화 및 오프라인 버퍼
- 드라이버 개발 가이드
- 첫 번째 드라이버 만들기
네임스페이스: Caffeine.Core 어셈블리: Caffeine.Core.dll (v2.0.6) .NET 플랫폼: .NET 10.0