Skip to content

Asset Generation

The asset generation system transforms YAML device definitions into strongly-typed C# base classes for Modbus devices. This eliminates manual register mapping and ensures consistent device communication code.

Overview

YAML device definitions live in schemas/assets/modbus/. The generator reads these files and produces abstract C# base classes in src/Voltimax.Edge.Control.Modbus/Registers/Generated/ with register address constants, typed read/write methods, byte order and scaling handling, and device-specific enum types.

Quick Start

powershell
dotnet run --project tools/Voltimax.Iot.Tools -- schema asset generate

YAML Definition Format

Each device file defines its identity, protocol settings, and register map.

Device section

yaml
device:
  id: EastronSdm630           # PascalCase, becomes class name + "AssetBase"
  manufacturer: Eastron
  model: SDM630-Modbus
  description: Three-phase energy meter
  assetTypes: [Grid, Building, Solar]

The id is required and determines the generated class name. assetTypes lists compatible asset types (Grid, Building, Solar, Battery, Charger, Load).

Protocol section

yaml
protocol:
  type: modbus
  addressing: oneBased        # or zeroBased
  registerPacking: wordHighFirst  # or wordLowFirst
  byteOrder: bigEndian        # or littleEndian

Check the device manual for the correct addressing scheme, byte order, and word order. Most devices use 1-based addressing with big-endian byte order and high-word-first packing. See Troubleshooting for diagnosing incorrect settings.

Registers section

Registers are grouped by Modbus function (input for FC 04, holding for FC 03/06/16, coils for FC 01/05/15, discreteInputs for FC 02), then by logical category:

yaml
registers:
  input:
    voltages:
      - id: phase1Voltage
        address: 30001
        type: float32
        access: read
        unit: volt
  holding:
    settings:
      - id: baudRate
        address: 40001
        type: uint16
        access: readWrite
        enumRef: BaudRate

Each register requires id (camelCase, becomes PascalCase property), address, and type. Optional: access (default read; use readWrite for writable holding registers), scaling (applied to raw value), unit, description, and enumRef (reference to a device-specific enum).

Supported types: uint16, int16, uint32, int32, float32, float64, bool. Types spanning multiple registers (32/64-bit) use the protocol's registerPacking setting.

Enums section

Device-specific enums for typed register values:

yaml
enums:
  BaudRate:
    2400: 0
    4800: 1
    9600: 2

Reference enums from registers via enumRef: BaudRate. The generated enum is prefixed with the device ID (e.g., EastronSdm630BaudRate). Values starting with a number get a Value prefix.

Generated Output

For each YAML file, the generator produces an abstract partial class (e.g., EastronSdm630AssetBase) inheriting from ModbusAssetBase. The class contains register address constants, async read methods per input/holding register, async write methods for registers with readWrite access, and scaling applied automatically for registers with a scaling factor. See the generated files in src/Voltimax.Edge.Control.Modbus/Registers/Generated/ for the exact output.

Create a concrete class inheriting from the generated base to implement CollectSnapshotAsync using the generated read methods.

Adding a New Device

  1. Create the YAML file in schemas/assets/modbus/manufacturer-model.yaml
  2. Define device metadata - id, manufacturer, model, assetTypes
  3. Configure protocol - check the device manual for addressing, byte order, and word order
  4. Define registers - group by function (input/holding) and category
  5. Generate: dotnet run --project tools/Voltimax.Iot.Tools -- schema asset generate
  6. Create concrete class inheriting from the generated base

Refer to existing definitions (e.g., schemas/assets/modbus/eastron-sdm630.yaml) for working examples.

Best Practices

Naming

  • Device ID: PascalCase, manufacturer + model (EastronSdm630)
  • Register IDs: camelCase (phase1Voltage, totalPower)
  • Enum names: PascalCase (BaudRate, OperatingMode)

Register organization

Group registers by function within each section:

yaml
registers:
  input:
    voltages:      # Voltage measurements
    currents:      # Current measurements
    power:         # Power measurements
    energy:        # Energy counters
  holding:
    configuration: # Device settings
    setpoints:     # Control setpoints

Documentation

Include units and descriptions in register definitions - they flow into XML doc comments on the generated methods.