Skip to content

SunSpec Analyzers

Voltimax.Iot.SunSpec.Analyzers is a Roslyn incremental source generator that produces strongly-typed C# classes for SunSpec device models at compile time from SMDX/XML specification files.

Setup

xml
<ItemGroup>
  <PackageReference Include="Voltimax.Iot.SunSpec.Analyzers"
                    OutputItemType="Analyzer"
                    ReferenceOutputAssembly="false" />
</ItemGroup>

<ItemGroup>
  <AdditionalFiles Include="sunspec-models\*.xml" />
</ItemGroup>

Optionally configure the target namespace:

xml
<PropertyGroup>
  <SunSpecGeneratedNamespace>MyCompany.SunSpec.Models</SunSpecGeneratedNamespace>
</PropertyGroup>

The default namespace is Voltimax.Iot.SunSpec.Models.

Input Format

The generator reads SMDX (SunSpec Model Definition XML) files - the standard format used by the SunSpec Alliance to define device models. Each file describes a single model with its points (registers) and metadata.

xml
<sunSpecModels>
  <model id="103" name="Inverter (Three Phase)" len="50">
    <block len="50">
      <point id="A" offset="0" type="uint16" units="A" />
      <point id="PhVphA" offset="3" type="uint16" units="V" />
      <point id="W" offset="12" type="int16" units="W" />
      <!-- ... -->
    </block>
  </model>
  <strings>
    <model>
      <description>Three-phase inverter model</description>
    </model>
    <point id="A">
      <description>AC Total Current</description>
    </point>
  </strings>
</sunSpecModels>

Generated Output

For each SMDX file, the generator produces several types in categorized sub-namespaces (e.g., Voltimax.Iot.SunSpec.Models.Inverter).

Model Classes

Each model becomes a sealed class implementing ISunSpecModel:

csharp
/// <summary>SunSpec Model 103: Inverter (Three Phase).</summary>
/// <remarks>Three-phase inverter model</remarks>
[SunSpecModel(103, 50)]
public sealed class InverterThreePhase : ISunSpecModel
{
    public const int ModelId = 103;
    public const int ModelLength = 50;

    int ISunSpecModel.Id => ModelId;
    int ISunSpecModel.Length => ModelLength;

    /// <summary>AC Total Current</summary>
    [SunSpecPoint("A", "uint16", Offset = 0, Length = 1)]
    public ushort? A { get; set; }

    /// <summary>Phase A Voltage</summary>
    [SunSpecPoint("PhVphA", "uint16", Offset = 3, Length = 1)]
    public ushort? PhVphA { get; set; }

    // ...
}

Inline Enums

Points with symbol definitions generate nested enum types:

csharp
public enum InverterThreePhase_St
{
    Off = 1,
    Sleeping = 2,
    Starting = 3,
    Mppt = 4,
    Throttled = 5,
    ShuttingDown = 6,
    Fault = 7,
    Standby = 8,
}

Base Types

The generator emits shared infrastructure types:

  • ISunSpecModel - interface with Id and Length properties
  • SunSpecModelAttribute - marks generated classes with model ID and length
  • SunSpecPointAttribute - marks properties with point ID, type, offset, and length

Model Registry

A SunSpecModels class provides runtime lookup of all generated models:

csharp
public static class SunSpecModels
{
    public static IReadOnlyDictionary<int, Type> All { get; }
    public static Type? GetModelType(int modelId);
}

How It Works

  1. Parse - SMDX files are parsed from XML into an internal SpecificationModel
  2. Categorize - models are grouped by category (Inverter, Storage, Meter, etc.)
  3. Render - the SunSpecCSharpRenderer uses the Roslyn syntax API to emit well-formed C# code
  4. Deduplicate - models with colliding class names get their model ID appended as a suffix

The generator handles name collisions automatically. If two models would produce the same class name, they are disambiguated with their model ID (e.g., InverterThreePhase vs InverterThreePhase103).

Adding a New SunSpec Model

  1. Place the SMDX file in the directory referenced by AdditionalFiles
  2. Build - the generator picks up the new file automatically
  3. The corresponding model class appears in IntelliSense immediately

No CLI command needed. The generator runs as part of the normal build.

Configuration

MSBuild PropertyDefaultDescription
SunSpecGeneratedNamespaceVoltimax.Iot.SunSpec.ModelsRoot namespace for generated types

Models are organized into sub-namespaces by category (derived from the SMDX model metadata).

Diagnostics

This generator uses the shared diagnostic codes. The most relevant for SunSpec models:

IDWhen
VGEN004Unexpected error during generation
VGEN005XML/SMDX file could not be parsed
VGEN003Referenced file not found