English     Dutch     French     German     Spanish

STANDARD: Metadata for Solar Plants

Last modified by Wim Verheirstraeten on 2023/10/06 18:41

This standard is important for those who work on the frontend and want to visualize data from solarplants and those who write so-called "eniris-meters".

Below you will find the standard for how solar installations and their components can be linked to influx db and the interrelationships between the components.
This "metadata" and other related info of the installation and its components are also described. The entirety of this description is typically stored in a "data.json" file, which is then stored in neo4j.

Background solar plant levels

A solar plant consists of:

  1. Plant level - at the connection point with the rest of the building's or premises' electrical installation. Contains one or more solar installations.
  2. Installation level - group of inverters from one manufacturer or measured by one device (such as a solar gateway, solar hub, ...). (Usually in portals all inverters from one manufacturer are grouped as one installation). Has one or more solar inverters as children.
  3. Inverter level - individual inverters. Can contain one or more strings.
  4. String level - individual solar panel strings. Can contain one or more modules.
  5. Module level - individual solar module level. Primarily used by Solar Edge. Physical meaning is to be verified.
  6. Solar panel level - individual solar panel.

For each level there is data in influx db in a metric. See also STANDARD: Metrics data collection and STANDARD: Messages & alarm messages

LevelInflux metric / measurementExample usage
PlantsolarPlantMetricsAll solar production combined for one address
InstallationsolarInstallationMetricsAll solar production from one portal, from one solar gateway, from one solar assistance solar hub
InvertersolarInverterMetricsSolar production from an individual inverter
StringsolarStringMetricsSolar production from an individual string
ModulesolarModuleMetricsSolar production from an individual module
PanelssolarPanelsMetricsSolar production from an individual plant

Metadata structure

See Metadata for devices standard

Installation metadata

class SolarInstallation {
   /*
        General (required!) properties
    */

    nodeId: string = "";
    nodeType: "solarInstallation" = "solarInstallation";
    nodeInfluxSeries: any[] = [];
    nodeParentsIds: string[] = [];
    nodeChildrenIds: string[] = [];
    name: string  = "";
    isInstaller: true = true;
    isAdmin: true = true;
   /*
        Important optional properties
    */

    info: {
      installationType?: string; // Type of the installation
     installationDate?: string; // Date at which an installation was built, in ISO8601 format
     activationDate?: string; // Date at which Eniris started collecting information about an installation, in ISO8601 format
     commissioningDate?: string; // Date at which an installation was approved after completion of any required tests, in ISO8601 format
     minimalIrradiation?: number = 0; // The minimal irradiation in Wh/m², before an installation should be active (used to calculate the uptime)
     productionOffset?: {
        date: string; // in ISO8601 format
       value: number;
      }; // Specify the total production for a particular date
     productionScalingFactor: number = 1; // Rescale all production values by this particular value
     productionPrediction?: {
        mode: "sumOfChildren"
      }|{
        mode: "systemPower_kWp"
        systemPower_kWp: number
      }|{
        mode: "panelConfiguration",
        panelConfiguration: {panelType: string, systemPower_kWp: number, azimuth_degrees: number, tilt_degrees: number}[]
      } = { mode: "sumOfChildren" }; // The predicted production (used to calculate the PR can be calculated as either: 1) the sum of the predicted production of the child inverters, 2) predicted using a kWp value, 3) predicted using a panel configuration defined at the installation level
     productionDistribution?: {
        isStoredInVault: true
      }|{
        isStoredInVault: false,
        values: number[] // Twelve numbers, with a sum equal to one, specifying how the production of an installation is distributed over the months of a year
     } = { isStoredInVault: true };
     /*
        Less important optional properties
      */

      timezone?: string; // Not yet in use, but this will be important in the future. Use one of the tz database names: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
     imageUrl?: string = ""; // An empty string is treated the same as if the imageUrl were undefined
     location?: {
        address?: {
          street?: string,
          zip?: string,
          city?: string,
          state?: string,
          country?: string
        };
        coordinates?: { lat?: number, lng?: number }; // {lat: 0, lng: 0} is treated the same as if the position were undefined
       referenceMeteoStation?: string; // If no pyrano meters are defined, this is used to calculate the performance ratio. If left undefined and if there is a valid position, the meteostation closest to the position is automatically used
       predictionMeteoStation?: string; // If no pyrano meters are defined, this is used to calculate the performance ratio. If left undefined and if there is a valid position, the meteostation closest to the position is automatically used
     };
      contacts?: ({
        contactType: string,
        isLocallyStored: true,
        id: string,
        name: string,
        telephone: string,
        email: string,
        language: "NL"|"FR"|"EN"|"DE",
      }|{
        contactType: string,
        isLocallyStored: false,
        nodeId: string,
        contactId: string
      })[] = [];
      code?: string = "";
      unit?: "EUR"|"kWh" = "kWh";
      note?: string = "";
      dataCapture?: {
        dataCaptureType: "scraping",
        name: string,
        url: string,
        scriptLocation: string,
        username: string
      }|{
        dataCaptureType: "api",
        name: string,
        url: string,
        scriptLocation: string,
        username?: string,
        key?: string
      }|{
        dataCaptureType: "fileUpload",
        name: string,
        scriptLocation: string,
        server: string,
        folder: string
      }|{
        dataCaptureType: "solarGateway",
        model: "CSE-H55N2",
        serialNumber: string,
        protocolDrivers: string[]
      }|{
        dataCaptureType: "moxa",
        series: "OnCell G3100",
        serialNumber: string,
        protocolDrivers: string[]
      }|{
        dataCaptureType: "solarHub",
        serialNumber: string
      } = { dataCaptureType: "api", name: "", url: "" }; // THIS SOLAR INSTALLATION PROPERTY IS NOT AVAILABLE FOR SOLAR PLANTS
     dataLink?: {
        dataLinkType: "ethernet"
      }|{
        dataLinkType: "wifi",
        SSID: string
      }|{
        dataLinkType: "cellular",
        SIM: string,
        IMEI: string,
        IPAddress: string
      } = { dataLinkType: "ethernet" };
      isActive?: bool = true;
    }
}

Inverter metadata

For inverters, the standard metadata should look like:

class SolarInverter {
   /*
        General (required!) properties
    */

    nodeId: string = "";
    nodeType: "solarInverter" = "solarInverter";
    nodeInfluxSeries: any[] = [];
    nodeParentsIds: string[] = [];
    nodeChildrenIds: string[] = [];
    name: string  = "";
    isInstaller: true = true;
    isAdmin: true = true;
    info: {
     /*
        Optional properties
      */

      status?: {
        isActive: true
      }|{
        isActive: false
        deactivationDate: string
        replacedBy: string
      } = { isActive: true };
      model?: string;
      serialNumber?: string;
      series?: string;
      maxPower_kWh: number;
      manufacturer?: string;
      activationDate?: string; // ISO8601 format, such as 2022-01-24T23:08:17.000Z
     installationDate?: string; // ISO8601 format, such as 2022-01-24T23:08:17.000Z
     commissioningDate?: string; // ISO8601 format, such as 2022-01-24T23:08:17.000Z
     productionScalingFactor: number = 1; // Rescale all production values by this particular value
     productionPrediction?: {
        mode: "sumOfChildren"
      }|{
        mode: "systemPower_kWp"
        systemPower_kWp: number
      }|{
        mode: "panelConfiguration",
        panelConfiguration: {panelType: string, systemPower_kWp: number, azimuth_degrees: number, tilt_degrees: number}[]
      } = { mode: "sumOfChildren" }; // The predicted production (used to calculate the PR can be calculated as either: 1) the sum of the predicted production of the child strings, 2) predicted using a kWp value, 3) predicted using a panel configuration defined at the inverter level
   protocolDriverParameters?: dict; //Optional. Used by the solar gateway / moxa software. Not necessary to fill out by hand.
   }
}

String metadata

The methode infoStrings() of an Eniris-Meter gives back a list of all possible strings, connected to their parents (inverters). For a string, the standard metadata should look like:

class SolarString {
   /*
        General (required!) properties
    */

    nodeId: string = "";
    nodeType: "solarString" = "solarString";
    nodeInfluxSeries: any[] = [];
    nodeParentsIds: string[] = [];
    nodeChildrenIds: string[] = [];
    name: string  = "";
    isInstaller: true = true;
    isAdmin: true = true;
   /*
        Optional properties
    */

    info: {
      serialNumber?: string;
      model?: string;
      series?: string;
      manufacturer?: string;
      activationDate?: string; // ISO8601 format, such as 2022-01-24T23:08:17.000Z
     installationDate?: string; // ISO8601 format, such as 2022-01-24T23:08:17.000Z
     commissioningDate?: string; // ISO8601 format, such as 2022-01-24T23:08:17.000Z
     status?: {
        isActive: true
      }|{
        isActive: false
        deactivationDate: string
        replacedBy: string
      } = { isActive: true };
      productionScalingFactor: number = 1; // Rescale all production values by this particular value
     productionPrediction?: {
        mode: "systemPower_kWp"
        systemPower_kWp: number
      }|{
        mode: "panelConfiguration",
        panelConfiguration: {panelType: string, systemPower_kWp: number, azimuth_degrees: number, tilt_degrees: number}[]
      } = { mode: "systemPower_kWp", systemPower_kWp: 0 }; // The predicted production (used to calculate the PR can be calculated as either): 1) predicted using a kWp value, 3) predicted using a panel configuration defined at the inverter level
   }
}

Module metadata

For a module, the standard physical metadata should look like:

{
   "nodeId": "SolarString00001",
   "nodeType": "solarModule",
   "nodeInfluxSeries": [
        {
           "database": "eniris",
           "retentionPolicy": "rp_one_m",
           "measurement": "solarStringMetrics",
           "tags": {
               "stringId": "0030f9112b54",
               "serialNo": "A713O3084"
            },
           "fields": [
               "actualPowerTot_W",
               "voltage_V",
               "current_A"
            ]
        }
    ],
   "nodeParentsIds": [
       "SolarInverter00001"
    ],
   "nodeChildrenIds": [],
   "active": true,
   "replaceBy": "",
   "manufacturer": "",
   "serialNo": "",
   "series": "",
   "model": "",
   "systemPower_kWp": 0, #default value is 0
   "configuration": [
        {
           "numberOfPanels": 0.0,
           "typeOfPanels": "",
           "systemPower_kWp": 400,
           "azimut_degr": 10,
           "tilt_degr": 10
        }
    ]
}

With the "id" we retrieve data from the corresponding metric in influx.

The methode getPhyiscalInfo() of an Eniris-Meter gives back a list of all possible modules

Pyranometer metadata

Pyranometers are the children of installations. So they are at the same level as inverters. 

class Pyranometer {
   /*
        General (required!) properties
    */

    nodeId: string = "";
    nodeType: "pyranometer";
    nodeInfluxSeries: any[] = [];
    nodeParentsIds: string[] = [];
    nodeChildrenIds: string[] = [];
    name: string = "";
    isInstaller: true = true;
    isAdmin: true = true;
   /*
        Optional properties
    */

    info?: {
      status?: {
        isActive: true
      }|{
        isActive: false
        deactivationDate: string
        replacedBy: string
      } = { isActive: true };
      serialNumber?: string,
      model?: string,
      series?: string,
      manufacturer?: string,
      azimut_degrees?: number = 0,
      tilt_degrees?: number = 0;
   };
}

Power meter metadata

Power meters are the children of installations. So they are at the same level as inverters. 

class Powermeter {
   /*
        General (required!) properties
    */

    nodeId: string = "";
    nodeType: "powerMeter";
    nodeInfluxSeries: any[] = [];
    nodeParentsIds: string[] = [];
    nodeChildrenIds: string[] = [];
    name: string = "";
    isInstaller: true = true;
    isAdmin: true = true;
   /*
        Optional properties
    */

    info: {
     /*
        Optional properties
      */

      status?: {
        isActive: true
      }|{
        isActive: false
        deactivationDate: string
        replacedBy: string
      } = { isActive: true };
      isOfficial?: bool = false;
      model?: string;
      serialNumber?: string;
      series?: string;
      maxPower_kWh: number;
      manufacturer?: string;
      activationDate?: string; // ISO8601 format, such as 2022-01-24T23:08:17.000Z
     installationDate?: string; // ISO8601 format, such as 2022-01-24T23:08:17.000Z
 }
}

Customer file metadata

Power meters are the children of installations. So they are at the same level as inverters. 

class CustomerFile {
 /*
    General (required!) properties
  */

  nodeId: string = "";
  nodeType: "customerFile";
  nodeInfluxSeries: any[] = [];
  nodeParentsIds: string[] = [];
  nodeChildrenIds: string[] = [];
  name: string = "";
  isInstaller: true = true;
  isAdmin: true = true;
 /*
    Optional properties
  */

  info: {
   /*
      Less important optional properties
    */

    code?: string = "";
    imageUrl?: string = ""; // An empty string is treated the same as if the imageUrl were undefined
   address?: {
      street: string,
      zip: string,
      city: string,
      state: string,
      country: string
    } = {street: "", zip: "", city: "", state: "", country: ""};
    position?: { lat: number, lng: number }; // {lat: 0, lng: 0} is treated the same as if the position were undefined
   contacts?: ({
      contactType: string,
      isLocallyStored: true,
      id: string,
      name: string,
      telephone: string,
      email: string,
      language: "NL"|"FR"|"EN"|"DE",
    }|{
      contactType: string,
      isLocallyStored: false,
      deviceId: string,
      nodeId: string
    })[] = [];
  }
}
    

Applications

(c) Eniris, 2024