Skip to content

Property Definition

Property definitions within adapter-registration.yaml.

Properties can be defined at:

  • device type level (device_types[].properties)
  • custom function level (custom_functions[].properties)
  • bootstrap config (bootstrap_config)
  • access profile field level (access-model.yaml person_profiles[].fields[])

Structure

properties:
  property_name:
    type: string          # required - data type
    required: true        # optional - is value mandatory?
    default: "value"      # optional - default value
    description: "desc"   # optional - property description
    # type-specific fields...

Common Fields

Field Type Required Default Description
type string yes - Property data type
required bool no false Marks mandatory property
default any no null Default value
description string/object no "" Description (supports multi-language)
category string no null UI grouping category (overrides function-level category)
sensitive bool no false Marks sensitive data (passwords, keys)
private bool no false When true, property is not exposed to UI (internal to adapter)

Multi-language Description

Description supports two formats:

# simple string
description: "Door address on the panel"

# multi-language dictionary
description:
  en: "Door address on the panel"
  cs: "Adresa dveri na panelu"

When processing, the en key is preferred, otherwise the first available value.

Supported Types

Integer Types

Type C# Type Range
int int -2,147,483,648 to 2,147,483,647
uint uint 0 to 4,294,967,295
long long -9,223,372,036,854,775,808 to ...
ulong ulong 0 to 18,446,744,073,709,551,615
short short -32,768 to 32,767
ushort ushort 0 to 65,535
byte byte 0 to 255
sbyte sbyte -128 to 127

Decimal Types

Type C# Type Description
float float single-precision floating point
double double double-precision floating point
decimal decimal high-precision decimal
currency decimal alias for decimal (financial values)

Other Primitive Types

Type C# Type Description
string string text string
host HostAddress DNS hostname, IPv4, or IPv6 address
ipv4 HostAddress IPv4 address only
bool bool boolean true/false
guid Guid UUID identifier
datetime DateTime date and time
datetimeoffset DateTimeOffset date and time with timezone
timespan TimeSpan time interval

Special Types

Type Description
enum enumeration type - requires values field
byte[] byte array
<type>[] array of any type (e.g., int[], string[])
CustomType reference to custom enum defined in adapter

Device Reference Types

When property type matches a type_id defined in the same adapter, it becomes a device reference - a cross-link to another Thing in the device tree.

Type C# Type JSON Value Description
TypeName TypeName? "guid-string" Single device reference (nullable)
TypeName[] IReadOnlyList<TypeName> ["guid1", "guid2"] Array of device references

Single Device Reference

device_types:
  - type_id: DoorAlarm
    properties:
      target_door:
        type: Door           # matches type_id "Door"
        required: true
        description: "Door this alarm monitors"

Generated C#:

public Door? TargetDoor { get; set; }

JSON configuration:

{ "target_door": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }

Array Device Reference (Many-to-Many)

For relationships where one Thing references multiple others:

device_types:
  - type_id: Zone
    properties:
      partitions:
        type: Partition[]       # [] suffix for array
        required: false
        description: "Partitions this zone belongs to"

Generated C#:

internal readonly List<Partition> PartitionsBuilder = [];
public IReadOnlyList<Partition> Partitions => PartitionsBuilder;

JSON configuration:

{ "partitions": ["partition-guid-1", "partition-guid-2"] }

Resolution

Device references are resolved after the entire device tree is built:

  1. All Things are created with their device_id
  2. Parent/Children relationships are established
  3. Device references are resolved by looking up target GUIDs
  4. AddInboundReference() is called for reverse navigation
  5. Deferred validations run (can access resolved references)

Reverse Navigation

Every Thing tracks which other Things reference it via ReferencedBy:

// Forward navigation
zone.Partitions  // IReadOnlyList<Partition>

// Reverse navigation  
partition.ReferencedBy.OfType<Zone>()  // all zones referencing this partition

Type-specific Fields

For String

Field Type Description
max_length int maximum string length
pattern string regex validation pattern
properties:
  serial_number:
    type: string
    max_length: 32
    pattern: "^[A-Z0-9]+$"
    description: "Device serial number"

For Host Addresses

Use host for device connection endpoints that may be DNS names or IP literals. Use ipv4 only when the device or SDK explicitly requires IPv4.

properties:
  ip_address:
    type: host
    required: true
    description: "Panel host or IP address"

Both host and ipv4 generate Pq.Adapters.Framework.HostAddress properties. host accepts DNS hostnames, IPv4, and IPv6. ipv4 accepts only dotted IPv4.

For Numeric Types

Field Type Description
range int[2] allowed range [min, max]
properties:
  door_address:
    type: uint
    required: true
    range: [1, 32]
    description: "Door address (1-32)"

For Enum

Field Type Description
values string[] list of allowed values
properties:
  reader_mode:
    type: enum
    values: ["card_only", "pin_only", "card_and_pin"]
    default: "card_only"
    description: "Reader authentication mode"

Generated Validation

The source generator creates FluentValidation validators based on the definition:

Definition Generated Validation
required: true .NotNull()
required: true + type: string .NotNull().NotEmpty()
max_length: N .MaximumLength(N)
pattern: "regex" .Matches(@"regex")
type: host host/IP validation
type: ipv4 IPv4 validation
range: [min, max] .InclusiveBetween(min, max)
type: enum + values .Must(x => values.Contains(x))

Access Profile Fields

access-model.yaml uses the same property definition shape for person_profiles[].fields[], with one difference: fields are listed as array items and include a name field:

person_profiles:
  - slot_type: User
    fields:
      - name: user_level
        type: int
        required: false
        default: 0
        range: [0, 3]
        category: alarm
        description: "Alarm user level"
      - name: duress_code
        type: string
        sensitive: true
        pattern: "^[0-9]{4,8}$"

Supported fields are the same where applicable: type, required, default, range, max_length, pattern, values, category, description, and sensitive.

Profile fields generate typed profile records used by access synchronization. YAML defaults become C# property initializers. Required fields are checked by generated mapping before adapter Transform() executes.

Examples

Complex Device Properties

device_types:
  - type_id: door-controller
    name: Door Controller
    properties:
      address:
        type: uint
        required: true
        range: [1, 64]
        description: "Controller address on RS-485 bus"

      name:
        type: string
        max_length: 64
        description: "User-defined controller name"

      firmware_version:
        type: string
        pattern: "^\\d+\\.\\d+\\.\\d+$"
        description: "Firmware version (semver format)"

      unlock_duration:
        type: uint
        default: 5
        range: [1, 60]
        description:
          en: "Door unlock duration in seconds"
          cs: "Doba odemknuti dveri v sekundach"

      authentication_mode:
        type: enum
        values: ["card", "pin", "card_and_pin", "fingerprint"]
        default: "card"
        description: "Primary authentication method"

Properties with Category and Sensitive

device_types:
  - type_id: controller
    properties:
      host:
        type: host
        required: true
        category: connection
        description: "Controller host or IP address"

      port:
        type: uint
        default: 4370
        category: connection
        range: [1, 65535]
        description: "TCP port"

      password:
        type: string
        required: true
        category: connection
        sensitive: true
        description: "Device password"

Bootstrap Config Properties

bootstrap_config:
  connection:
    host:
      type: host
      required: true
      description: "Controller hostname or IP address"

    port:
      type: uint
      default: 4370
      range: [1, 65535]
      description: "TCP port number"

Nullable Behavior

Properties are nullable based on type and required combination:

type required C# type
string false string?
string true string
host false HostAddress?
host true HostAddress
ipv4 false HostAddress?
ipv4 true HostAddress
int false int?
int true int
enum false string?
enum true string

Naming Conventions

  • property names in YAML: snake_case
  • generated C# properties: PascalCase
door_address: ...    # YAML
public uint DoorAddress { get; set; }  // generated C#

Private Properties

Properties marked with private: true are not exposed to UI through DeviceAdapterInformation. They are still generated as C# properties and can be used internally by the adapter.

Use Cases

  • Technical settings determined by protocol capabilities (e.g., use_framework_timers)
  • Internal configuration that users should not modify
  • Protocol-specific parameters

Framework-level Private

Define in functions.yaml to make property always private across all adapters:

# functions.yaml
Door:
  properties:
    use_framework_timers:
      type: "bool"
      default: true
      private: true  # always hidden from UI

Adapter-level Override

Override framework property to make it private in specific adapter:

# adapter-registration.yaml
device_types:
  - type_id: "AccessControlReader"
    category: door
    functions:
      Door:
        use_framework_timers:
          private: true
          default: false  # Panel manages timers
      Reader:

Adapter overrides can:

  • Make a public property private
  • Change the default value
  • Both

Adapter cannot make a private framework property public (security).

Device Category

Each device type must specify a category for UI icon selection.

Required Field

device_types:
  - type_id: "X1100"
    name: "Access Controller"
    category: panel  # required

Available Categories

Category Description Typical Devices
door Door access point ACR, door controller
reader Credential reader Card reader, biometric
panel Main controller X1100, X1200
module Expansion module X100, X200, X300
input Input point Monitor point, sensor
output Output point Relay, control point
partition Alarm zone MPG, area
keypad Security keypad Arming station
detector Intrusion sensor PIR, contact

Categories are normalized to lowercase in generated code.

Device Tree Ordering

The device tree is sorted for display. By default, siblings under the same parent are ordered: leaf types before container types (a container is any type that can have children), then by category, then by the type's address key, then by natural name. The address key is the type's unique properties (else the discovery identity, else an address property). Digit runs sort numerically, so address: 2 comes before address: 10 and Port1 before Port2.

Two optional device_type keys override the defaults.

order (optional, int)

Explicit position for this type among its siblings; lower sorts first. When omitted, the position is derived from category and whether the type can contain children.

sort_by (optional, list of property names)

Orders instances of this type among same-type siblings, in priority order (natural comparison). Overrides the default address key.

device_types:
  - type_id: "X100"
    category: module
    unique: [bus, address]   # default sort key — also orders the tree
    # order: 50              # optional: force this type's sibling position
    # sort_by: [address]     # optional: order instances by address only