Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

This endpoint retrieves generation data of multiple inverters.

此端点用于提交分组设备的多个逆变器的发电数据。

Table of Contents

Table of Contents
stylenone

Changelogs

Version

Date

Changes by

Description of change

V1.0

Mar 29, 2024

Que Nguyen

  • Added Table of Contents.

  • Added Changelogs.

V1.0.1

April 5, 2024

Que Nguyen

  • AccumulatedPowerInKWh renames to AccumulatedEnergyInKWh

V1.0.2

April 8, 2024

Que Nguyen

  • Updated the document:

    • AccumulatedEnergyInKWhvalidation rule restricted to 3 decimal places

    • PeriodProductionInKWh validation rule restricted to 3 decimal places

V1.0.3

April 10, 2024

Que Nguyen

  • Added Release Status.

V1.0.4

May 13, 2024

Que Nguyen

  • Added Maximum generation data of all devices received: 3000 records

  • 一次性最大接受提交的电量记录数为3000,即一次性最多发送3000天的数据。

V1.0.5

Que Nguyen

  • Added Rate Limit Description.

V1.0.6

Que Nguyen

  • Added Response Date Process Id resource

Release status

Environment

Status

Released Date

Version

DEV

Status
colourGreen
titleReleased

V1.0.6

UAT

Status
colourGreen
titleRELEASED

V1.0.6

PROD

Status
colourGreen
titleRELEASED

V1.0.5

Device Inverters Resource

Devices (required) - array[object] - Array of Inverter Daily Data Resource

This refers to data generation for daily data of multiple devices

Maximum generation of all devices received per request payload: 3000 records

这是指多个设备日常数据的数据生成。

一次性最大接受提交的电量记录数为3000,即一次性最多发送3000天的数据。

Code Block
languagejson
{
  "Devices": [
    {
      "RemoteInvId": "STR10000000338444",
      "Data": [
        {
          "Timestamp": "2023-05-01",
          "PeriodProductionInKWh": "0.123",
          "AccumulatedEnergyInKWh": "5.123"
        },
        {
          "Timestamp": "2023-05-02",
          "PeriodProductionInKWh": "0.234",
          "AccumulatedEnergyInKWh": "5.357"
        }
      ]
    }
  ]
}

Inverter Daily Data Resource

RemoteInvId (required) text

This refers to a unique identifier assigned to an inverter.

ex: STR1000000033862740

这指的是分配给逆变器的唯一标识符

例如:STR1000000033862740

Data (required) array[object] - Array of Daily Data Resource

This refers to data generation at a particular frequency type

Maximum generation data received per request payload: 3000 records

这指的是在特定频率类型下的数据生成。

一次性最大接受提交的电量记录数为3000,即一次性最多发送3000天的数据。

Code Block
languagejson
{
  "Data": [
    {
      "Timestamp": "2023-05-01",
      "PeriodProductionInKWh": "0.123",
      "AccumulatedEnergyInKWh": "5.123"
    },
    {
      "Timestamp": "2023-05-02",
      "PeriodProductionInKWh": "0.234",
      "AccumulatedEnergyInKWh": "5.357"
    },
    {
      "Timestamp": "2023-05-03",
      "PeriodProductionInKWh": "0.456",
      "AccumulatedEnergyInKWh": "5.813"
    }
  ],
  "RemoteInvId": "STR10000000338444"
}

Daily Data Resource

Timestamp (required) text

The time to capture data in the format 'YYYY-MM-DD'

ex: 2023-04-05

捕获数据的时间,格式为 'YYYY-MM-DD'

例如:2023-04-05

PeriodProductionInKWh (required) number

Energy generation

ex: 0.123

日发电量

例如:0.123

AccumulatedEnergyInKWh (required) number

Accumulated Energy generation

累计发电量

ex: 100.123

Code Block
languagejson
{
  "Timestamp": "2023-05-01",
  "PeriodProductionInKWh": "0.123",
  "AccumulatedEnergyInKWh": "5.123"
}

API Definition

Status
colourGreen
titlePost
/public/v2/generation-datas/batches

Request

Headers

Content-Type

application/json

Authorization

Bearer {{access_token}}

Payload

Devices (required) - array[object] - Array of Inverter Daily Data Resource

This refers to data generation for daily data of multiple devices

Maximum generation of all devices received per request payload: 3000 records

这是指多个设备日常数据的数据生成。

一次性最大接受提交的电量记录数为3000,即一次性最多发送3000天的数据。

Devices[n].RemoteInvId (required) text

This refers to a unique identifier assigned to an inverter.

ex: STR1000000033862740

这指的是分配给逆变器的唯一标识符

例如:STR1000000033862740

Devices[n].Data[m].Timestamp (required) text

The time to capture data in the format 'YYYY-MM-DD'

ex: 2023-04-05

捕获数据的时间,格式为 'YYYY-MM-DD'

例如:2023-04-05

Devices[n].Data[m].PeriodProductionInKWh (required) number

Energy generation

ex: 0.123

日发电量

例如:0.123

Devices[n].Data[m].AccumulatedEnergyInKWh (required) number

Accumulated Energy generation

累计发电量

ex: 100.123

Code Block
curl --location 'https://uat-api.redex.eco/public/v2/generation-datas/batches' \
--header 'Authorization: Bearer {{access_token}}' \
--header 'Content-Type: application/json' \
--data '{
  "Devices": [
    {
      "RemoteInvId": "TLGMIV500002000338634980432-INV20EN",
      "Data": [
        {
          "Timestamp": "2022-05-13",
          "PeriodProductionInKWh": 3157.288,
          "AccumulatedEnergyInKWh": 3361.328
        }
      ]
    },
    {
      "RemoteInvId": "TLGMIV500002000338634980432-INV30EN",
      "Data": [
        {
          "Timestamp": "2022-05-13",
          "PeriodProductionInKWh": 3157.288,
          "AccumulatedEnergyInKWh": 3361.328
        }
      ]
    }
  ]
}'

Response

Headers

Content-Type

application/json

Response Body

Response Body

Data.ProcessId uuid

Process unique identifier

Errors list of error objects

Please see "Getting Started - #Error Object" for more details

请查看Getting Started - #Error Object以获得更多信息。

Meta null object

Return null object

StatusCode integer

Http Status codes standard. Example 200, 201, 404.

http状态码,如200,201,404

Message text

Response message: Success or error message.

返回成功或错误的信息。

Info

201 Success

Code Block
languagejson
{
    "StatusCode": 201,
    "Errors": null,
    "Meta": null,
    "Data": {
      "ProcessId": 2024
    },
    "Message": "Send Power Data successfully"
}
Warning

400 Bad Request

Code Block
languagejson
{
  "Data": null
  "StatusCode": 400,
  "Errors": [],
  "Meta": null,
  "Message": "Bad Request"
}
Warning

422 Unprocessable Entity

Code Block
languagejson
{
  "Data": null,
  "StatusCode": 422,
  "Errors": [],
  "Meta": null,
  "Message": "Unprocessable Entity"
}
Warning

401 Unauthorized

Code Block
languagejson
{
  "Data": null,
  "StatusCode": 401,
  "Errors": [],
  "Meta": null,
  "Message": "Unauthorized"
}
Warning

403 Forbidden

Code Block
languagejson
{
  "Data": null,
  "StatusCode": 403,
  "Errors": [],
  "Meta": null,
  "Message": "Forbidden"
}

Rate limit

Rate Limit Algorithm: Fixed Window

In fixed window rate limiting, a fixed time window (e.g., one minute, one hour) is used to track the number of requests or actions allowed within that window. Requests exceeding the limit are either rejected or throttled until the window resets.

Rate Limiting Overview

Our API employs rate limiting to ensure fair usage and protect the performance and availability of the service. Combination of Global Policy and Operation Policy

Global Policy

  • Rate Limit: 3000 requests per 5 minute(s)

  • Renewal Period: 300 second(s)

  • Key: IP Address

  • Increment Condition: Any Request

Operation Policy

  • Rate Limit: 5 requests per 5 second(s)

  • Renewal Period: 5 second(s)

  • Key: accound-id business account Id.

  • Increment Condition: Any Request

Rate Limit Details

  1. Rate Limit by Key:

    1. Key: This ensures that rate limits are applied uniquely for each business account id.

    2. Request Limit: Each key is allowed to make up to 5 requests per 5 seconds.

    3. Reset Interval: The limit resets every 5 seconds.

  2. Response Headers:

    1. Retry-After: Sent when the rate limit is exceeded, indicating how long to wait before making another request.

Exceeding the Rate Limit

When the rate limit is exceeded, the API will return a 429 Too Many Requests status code. The response will include a Retry-After header specifying the number of seconds to wait before making a new request.

Example Response When Rate Limit is Exceeded

Code Block
languagejson
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json

{
    "Data": null,
    "Errors": null,
    "StatusCode": 429,
    "Message": "Rate limit exceeded",
    "Meta": null
}

Demo(for reference only)

Code Block
languagec#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;

using Demo;  

public class Program
{
    private static readonly HttpClient client = new HttpClient();
    private static readonly SemaphoreSlim semaphore = new SemaphoreSlim(5); // Control concurrency
    private const int DataBatchSize = 3000; // Number of data items per batch
    private const int MaxRequestsPer5Seconds = 5; // Maximum requests per 5 seconds
    private static readonly TimeSpan RequestInterval = TimeSpan.FromSeconds(5); // Request interval
    private static string AccessToken = "YOUR_ACCESS_TOKEN_HERE"; // Replace with your actual AccessToken
    private const string ApiEndpoint = "YOUR_API_ENDPOINT_HERE"; // API endpoint URL

    public static async Task Main(string[] args)
    {
        // Sample data using the PowerGenerationData class
        var dataList = new List<PowerGenerationData>
        {
            new PowerGenerationData
            {
                RemoteInvId = "MY78222522114",
                Timestamp = "2023-07-01",
                PeriodProductionInKWh = "0.123",
                AccumulatedEnergyInKWh = "5.123"
            },
            new PowerGenerationData
            {
                RemoteInvId = "MY78222522115",
                Timestamp = "2023-07-02",
                PeriodProductionInKWh = "0.234",
                AccumulatedEnergyInKWh = "5.357"
            }
            // Continue adding data items
        };

        await ProcessAndSendDataInBatchesAsync(dataList);
    }

    private static async Task ProcessAndSendDataInBatchesAsync(List<PowerGenerationData> dataList)
    {
        // Calculate total number of data batches
        int totalDataBatches = (int)Math.Ceiling(dataList.Count / (double)DataBatchSize);

        // Process data in batches
        for (int batchIndex = 0; batchIndex < totalDataBatches; batchIndex++)
        {
            var batchData = dataList.Skip(batchIndex * DataBatchSize).Take(DataBatchSize).ToList();

            // Group data by RemoteInvId and map to DataItem
            var groupedDevices = batchData
                .GroupBy(item => item.RemoteInvId)
                .Select(g => new Device
                {
                    RemoteInvId = g.Key,
                    Data = g.Select(d => new DataItem
                    {
                        Timestamp = d.Timestamp,
                        PeriodProductionInKWh = d.PeriodProductionInKWh,
                        AccumulatedEnergyInKWh = d.AccumulatedEnergyInKWh
                    }).ToList()
                })
                .ToList();

            // Create request body
            var requestBody = new RequestBody { Devices = groupedDevices };
            var json = JsonConvert.SerializeObject(requestBody);

            // Control request rate
            await semaphore.WaitAsync();
            try
            {
                // Send request
                await PostDataAsync(json);

                // Wait to limit request frequency
                if ((batchIndex + 1) % MaxRequestsPer5Seconds == 0)
                {
                    await Task.Delay(RequestInterval);
                }
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            finally
            {
                semaphore.Release();
            }
        }
    }

    private static async Task PostDataAsync(string jsonData)
    {
        var requestMessage = new HttpRequestMessage(HttpMethod.Post, ApiEndpoint)
        {
            Content = new StringContent(jsonData, Encoding.UTF8, "application/json")
        };

        // Add Authorization header
        requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);

        var response = await client.SendAsync(requestMessage);

        if (response.IsSuccessStatusCode)
        {
            Console.WriteLine("Data sent successfully.");
        }
        else
        {
            var responseContent = await response.Content.ReadAsStringAsync();
            Console.WriteLine($"Failed to send data: {responseContent}");
        }
    }
}

public class RequestBody
{
    [JsonProperty("Devices")]
    public List<Device> Devices { get; set; }
}

public class Device
{
    [JsonProperty("RemoteInvId")]
    public string RemoteInvId { get; set; }

    [JsonProperty("Data")]
    public List<DataItem> Data { get; set; }
}

public class DataItem
{
    [JsonProperty("Timestamp")]
    public string Timestamp { get; set; }

    [JsonProperty("PeriodProductionInKWh")]
    public string PeriodProductionInKWh { get; set; }

    [JsonProperty("AccumulatedEnergyInKWh")]
    public string AccumulatedEnergyInKWh { get; set; }
}

public class PowerGenerationData
{
    [JsonProperty("RemoteInvId")]
    public string RemoteInvId { get; set; }

    [JsonProperty("Timestamp")]
    public string Timestamp { get; set; }

    [JsonProperty("PeriodProductionInKWh")]
    public string PeriodProductionInKWh { get; set; }

    [JsonProperty("AccumulatedEnergyInKWh")]
    public string AccumulatedEnergyInKWh { get; set; }
}