본문으로 건너뛰기

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

속성

속성타입설명
TagNamestring태그 이름
Valueobject태그 값
TimestampDateTime값이 읽힌 시각 (UTC)
QualityTagQuality데이터 품질 (Good, Bad, Uncertain)
DataTypeType값의 .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

속성

속성타입설명
TagNamestring태그 이름 (고유 식별자)
DriverIdstring드라이버 ID
Addressstring장비 주소 (예: Modbus 레지스터)
DataTypestring데이터 타입 (Int16, Float, String 등)
ScanRateint스캔 주기 (밀리초)
Enabledbool태그 활성화 여부

사용 예시

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 = trueBigEndianDoubleCodec, BigEndianShortCodec, BigEndianIntCodec

사용 예시:

// Program.cs
builder.Services.AddCaffeine(); // Little-Endian (기본값)
builder.Services.AddCaffeine(o => o.UseBigEndianCodecs = true); // Big-Endian

app.Services.UseCaffeine(); // LoggerFactory 연결 (선택 사항)

CaffeineOptions

AddCaffeine() 등록 시 사용하는 옵션 클래스입니다.

속성타입기본값설명
UseBigEndianCodecsboolfalseBig-Endian 코덱 사용 여부

UseCaffeine()

앱 시작 시 DI 컨테이너의 ILoggerFactoryLogExtensions에 연결합니다.

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);
속성타입설명
SensorIdstring센서 고유 식별자
Valuedouble측정값
Unitstring단위 (예: "°C", "bar")
TimestampDateTimeOffset측정 시각 (UTC)
QualitySensorQuality데이터 품질 등급

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; }
}
속성타입설명
SupportedProtocolsIReadOnlyList<string>지원 프로토콜 목록 (예: ["ModbusTCP"])
MaxMessagesPerSecondint초당 최대 처리 메시지 수 (0 = 무제한)
SupportsOfflineBufferingbool오프라인 버퍼링 지원 여부
SupportsBidirectionalbool읽기/쓰기 양방향 통신 지원 여부
SupportedSensorCategoriesIReadOnlyList<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.Core 어셈블리: Caffeine.Core.dll (v2.0.6) .NET 플랫폼: .NET 10.0