Skip to main content
Device models represent physical sensors and actuators within sectors. The system also includes a comprehensive catalog of device types, categories, and units.

Device

Domain model representing a device (sensor or actuator). Devices belong to sectors, and the greenhouse is derived from the sector.
@Serializable
data class Device(
    val id: Long,
    val code: String,
    val tenantId: Long,
    val sectorId: Long,
    val sectorCode: String? = null,
    val name: String? = null,
    val categoryId: Short? = null,
    val categoryName: String? = null,
    val typeId: Short? = null,
    val typeName: String? = null,
    val unitId: Short? = null,
    val unitSymbol: String? = null,
    val isActive: Boolean = true,
    val createdAt: String? = null,
    val updatedAt: String? = null
)

Fields

id
Long
required
Unique identifier for the device
code
String
required
Unique code assigned to the device
tenantId
Long
required
ID of the tenant/client that owns this device
sectorId
Long
required
ID of the sector this device belongs to
sectorCode
String
default:"null"
Code of the parent sector (for display purposes)
name
String
default:"null"
Optional custom name for the device
categoryId
Short
default:"null"
ID of the device category (1 = Sensor, 2 = Actuator)
categoryName
String
default:"null"
Name of the device category
typeId
Short
default:"null"
ID of the device type from catalog
typeName
String
default:"null"
Name of the device type (e.g., “Temperature”, “Humidity”)
unitId
Short
default:"null"
ID of the measurement unit from catalog
unitSymbol
String
default:"null"
Symbol of the measurement unit (e.g., “°C”, ”%”)
isActive
Boolean
default:"true"
Whether the device is currently active
createdAt
String
default:"null"
ISO 8601 timestamp when the device was created
updatedAt
String
default:"null"
ISO 8601 timestamp when the device was last updated

Constants

companion object {
    const val CATEGORY_SENSOR: Short = 1
    const val CATEGORY_ACTUATOR: Short = 2
}

Computed Properties

category
DeviceCategory
Returns the device category enum based on categoryId.
val category: DeviceCategory
    get() = when (categoryId) {
        CATEGORY_SENSOR -> DeviceCategory.SENSOR
        CATEGORY_ACTUATOR -> DeviceCategory.ACTUATOR
        else -> DeviceCategory.SENSOR
    }
initial
String
Returns the first letter for avatar display, checking name, type, category in order.
val initial: String
    get() = name?.firstOrNull()?.uppercaseChar()?.toString()
        ?: typeName?.firstOrNull()?.uppercaseChar()?.toString()
        ?: categoryName?.firstOrNull()?.uppercaseChar()?.toString()
        ?: "D"
Example: “Temperature Sensor” → “T”, null → “D”
displayName
String
Returns a human-readable display name combining available information.
val displayName: String
    get() = name ?: buildString {
        if (typeName != null) {
            append(typeName)
        } else if (categoryName != null) {
            append(categoryName)
        } else {
            append("Device")
        }
        if (unitSymbol != null) {
            append(" ($unitSymbol)")
        }
    }
Example: “Temperature (°C)” or “My Custom Sensor”
categoryDisplayName
String
Returns a formatted category name for display.
val categoryDisplayName: String
    get() = categoryName ?: when (categoryId) {
        CATEGORY_SENSOR -> "Sensor"
        CATEGORY_ACTUATOR -> "Actuator"
        else -> "Unknown"
    }

DeviceCategory

Enum representing device categories.
enum class DeviceCategory {
    SENSOR,
    ACTUATOR
}

Values

  • SENSOR: Device that measures environmental parameters
  • ACTUATOR: Device that controls environmental conditions

API DTOs

DeviceResponse

Response DTO from the API representing a device.
@Serializable
data class DeviceResponse(
    val id: Long,
    val code: String,
    val tenantId: Long,
    val sectorId: Long,
    val sectorCode: String? = null,
    val name: String? = null,
    val categoryId: Short? = null,
    val categoryName: String? = null,
    val typeId: Short? = null,
    val typeName: String? = null,
    val unitId: Short? = null,
    val unitSymbol: String? = null,
    val isActive: Boolean = true,
    val createdAt: String,
    val updatedAt: String
)
toDevice
() -> Device
Converts DeviceResponse to Device domain model.
fun DeviceResponse.toDevice() = Device(
    id = id,
    code = code,
    tenantId = tenantId,
    sectorId = sectorId,
    sectorCode = sectorCode,
    name = name,
    categoryId = categoryId,
    categoryName = categoryName,
    typeId = typeId,
    typeName = typeName,
    unitId = unitId,
    unitSymbol = unitSymbol,
    isActive = isActive,
    createdAt = createdAt,
    updatedAt = updatedAt
)

DeviceCreateRequest

Request DTO for creating a new device. Note: sectorId is required; greenhouse is derived from sector.
@Serializable
data class DeviceCreateRequest(
    val sectorId: Long,
    val name: String? = null,
    val categoryId: Short? = null,
    val typeId: Short? = null,
    val unitId: Short? = null,
    val isActive: Boolean? = true
)

DeviceUpdateRequest

Request DTO for updating an existing device. All fields are optional for partial updates.
@Serializable
data class DeviceUpdateRequest(
    val sectorId: Long? = null,
    val name: String? = null,
    val categoryId: Short? = null,
    val typeId: Short? = null,
    val unitId: Short? = null,
    val isActive: Boolean? = null
)

Device Catalog Models

The system includes a comprehensive catalog of device types, categories, and units.

DeviceCatalogCategory

Domain model for device category from catalog.
data class DeviceCatalogCategory(
    val id: Short,
    val name: String
)

API DTO

@Serializable
data class DeviceCategoryResponse(
    val id: Short,
    val name: String
)

DeviceCatalogType

Domain model for device type from catalog.
data class DeviceCatalogType(
    val id: Short,
    val name: String,
    val description: String?,
    val categoryId: Short,
    val defaultUnitId: Short?,
    val defaultUnitSymbol: String?,
    val controlType: String?
)

API DTO

@Serializable
data class DeviceTypeResponse(
    val id: Short,
    val name: String,
    val description: String? = null,
    val categoryId: Short,
    val categoryName: String? = null,
    val defaultUnitId: Short? = null,
    val defaultUnitSymbol: String? = null,
    val dataType: String? = null,
    val minExpectedValue: Double? = null,
    val maxExpectedValue: Double? = null,
    val controlType: String? = null,
    val isActive: Boolean = true
)

DeviceCatalogUnit

Domain model for measurement unit from catalog.
data class DeviceCatalogUnit(
    val id: Short,
    val symbol: String,
    val name: String,
    val description: String? = null,
    val isActive: Boolean = true
)

API DTO

@Serializable
data class DeviceUnitResponse(
    val id: Short,
    val symbol: String,
    val name: String,
    val description: String? = null,
    val isActive: Boolean = true
)

ActuatorState

Domain model for actuator states (ON, OFF, STANDBY, etc.).
data class ActuatorState(
    val id: Short,
    val name: String,
    val description: String?,
    val isOperational: Boolean,
    val displayOrder: Short,
    val color: String?
)

API DTO

@Serializable
data class ActuatorStateResponse(
    val id: Short,
    val name: String,
    val description: String? = null,
    val isOperational: Boolean = false,
    val displayOrder: Short = 0,
    val color: String? = null
)

Catalog Request DTOs

DeviceCategoryCreateRequest

@Serializable
data class DeviceCategoryCreateRequest(
    val name: String
)

DeviceTypeCreateRequest

@Serializable
data class DeviceTypeCreateRequest(
    val name: String,
    val description: String? = null,
    val categoryId: Short,
    val defaultUnitId: Short? = null,
    val dataType: String? = null,
    val minExpectedValue: Double? = null,
    val maxExpectedValue: Double? = null,
    val controlType: String? = null,
    val isActive: Boolean = true
)

DeviceUnitCreateRequest

@Serializable
data class DeviceUnitCreateRequest(
    val symbol: String,
    val name: String,
    val description: String? = null,
    val isActive: Boolean = true
)

ActuatorStateCreateRequest

@Serializable
data class ActuatorStateCreateRequest(
    val name: String,
    val description: String? = null,
    val isOperational: Boolean = false,
    val displayOrder: Short = 0,
    val color: String? = null
)

Usage Examples

Creating a Device

val device = Device(
    id = 1L,
    code = "DEV001",
    tenantId = 1L,
    sectorId = 1L,
    sectorCode = "SEC001",
    name = "Temperature Sensor 1",
    categoryId = Device.CATEGORY_SENSOR,
    categoryName = "Sensor",
    typeId = 1,
    typeName = "Temperature",
    unitId = 1,
    unitSymbol = "°C",
    isActive = true
)

println(device.displayName) // "Temperature Sensor 1"
println(device.category) // DeviceCategory.SENSOR
println(device.initial) // "T"

Creating a Device via API

val createRequest = DeviceCreateRequest(
    sectorId = 1L,
    name = "Humidity Sensor",
    categoryId = Device.CATEGORY_SENSOR,
    typeId = 2,
    unitId = 2,
    isActive = true
)

val response: DeviceResponse = apiClient.createDevice(
    tenantId = 1L,
    request = createRequest
)

val device: Device = response.toDevice()

Filtering Devices by Category

val devices = getDevices(sectorId = 1L)
val sensors = devices.filter { it.category == DeviceCategory.SENSOR }
val actuators = devices.filter { it.category == DeviceCategory.ACTUATOR }

println("Sensors: ${sensors.size}")
println("Actuators: ${actuators.size}")

Working with Catalog

// Fetch device types for sensors
val categories = apiClient.getDeviceCategories()
val sensorCategory = categories.find { it.id == Device.CATEGORY_SENSOR }

// Get available device types
val types = apiClient.getDeviceTypes()
val temperatureType = types.find { it.name == "Temperature" }

// Get available units
val units = apiClient.getDeviceUnits()
val celsiusUnit = units.find { it.symbol == "°C" }

// Create device with catalog values
val createRequest = DeviceCreateRequest(
    sectorId = 1L,
    categoryId = sensorCategory?.id,
    typeId = temperatureType?.id,
    unitId = celsiusUnit?.id
)

Build docs developers (and LLMs) love