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
<ItemGroup>
<PackageReference Include="Voltimax.Iot.SunSpec.Analyzers"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="sunspec-models\*.xml" />
</ItemGroup>Optionally configure the target namespace:
<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.
<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:
/// <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:
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 withIdandLengthpropertiesSunSpecModelAttribute- marks generated classes with model ID and lengthSunSpecPointAttribute- marks properties with point ID, type, offset, and length
Model Registry
A SunSpecModels class provides runtime lookup of all generated models:
public static class SunSpecModels
{
public static IReadOnlyDictionary<int, Type> All { get; }
public static Type? GetModelType(int modelId);
}How It Works
- Parse - SMDX files are parsed from XML into an internal
SpecificationModel - Categorize - models are grouped by category (Inverter, Storage, Meter, etc.)
- Render - the
SunSpecCSharpRendereruses the Roslyn syntax API to emit well-formed C# code - 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
- Place the SMDX file in the directory referenced by
AdditionalFiles - Build - the generator picks up the new file automatically
- The corresponding model class appears in IntelliSense immediately
No CLI command needed. The generator runs as part of the normal build.
Configuration
| MSBuild Property | Default | Description |
|---|---|---|
SunSpecGeneratedNamespace | Voltimax.Iot.SunSpec.Models | Root 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:
| ID | When |
|---|---|
VGEN004 | Unexpected error during generation |
VGEN005 | XML/SMDX file could not be parsed |
VGEN003 | Referenced file not found |