PTD Message Format
EWAI constructs energy datasets from collecting time-series PTD messages from DERS. EWAI can accept PTD messages from DERs in either text or json format.
In both cases, some header fields are required in order for EWAI to process the message to the final marketplace level data asset:
- DID: The DER DID must be provided, so EWAI can validate message signatures and role authorizations,
- Data Asset EWNS: The ewns of the data asset the message is going to must be provided. This is how EWAI knows which data asset on the marketplace the message belongs to.
When a clean energy data asset is created on a marketplace, the creator must specify the incoming message format type for the asset as either json or text. It cannot be changed later.
EW-MESSAGING CHANNEL
Each PTD message is sent to the EW-Messaging channel which the EWAI-SERVER/EWAI-LISTEN instance has setup. This is related to the EWAI Instance EWNS see messaging doc for more info.
Since the channel uniquely identifies a single EWAI instance (marketplace), this information doesn't have to be provided in each message packet.
TEXT FORMAT
Text messages are simply UTF-8 chars. The DID and EWNS must be provided as the first part of the message using pipe | delimiters. Example:
did={DER DID}|asset={ASSET ENWS}|{MESSAGE PTD DATA}
The message PTD data can be completely arbitrary and up to the publisher of the data asset. They must of course provision the DERs to know what that data is and then send it in properly in the PTD messages. It is also wise to send a timestamp in the message data portion, which must be in ISO8601 format. EWAI can extract that from the message. EWAI also gives each message a timestamp of when it was received, but that may differ from the actual message data timestamp.
An example text message stream might look like this (over time):
did=did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4|asset=solarfarm2.market1.adivate.ewc|time=2020-11-26T17:26:10.075Z;lat=21.266;long=-95.012;minKw=694.86;maxKw=181.56;avgKw=65.28;sensorId=751
did=did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4|asset=solarfarm2.market1.adivate.ewc|time=2020-11-26T17:26:11.075Z;lat=-57.367;long=163.005;minKw=529.85;maxKw=388.21;avgKw=658.17;sensorId=1791
did=did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4|asset=solarfarm2.market1.adivate.ewc|time=2020-11-26T17:26:12.075Z;lat=-19.055;long=78.62;minKw=866.18;maxKw=432.54;avgKw=95.48;sensorId=103
did=did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4|asset=solarfarm2.market1.adivate.ewc|time=2020-11-26T17:26:13.075Z;lat=88.533;long=178.224;minKw=833.68;maxKw=658.91;avgKw=549.33;sensorId=1891
did=did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4|asset=solarfarm2.market1.adivate.ewc|time=2020-11-26T17:26:14.075Z;lat=-61.445;long=179.625;minKw=534.52;maxKw=133.64;avgKw=259.16;sensorId=743
did=did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4|asset=solarfarm2.market1.adivate.ewc|time=2020-11-26T17:26:15.075Z;lat=96.17;long=40.31;minKw=63.99;maxKw=53.29;avgKw=74.06;sensorId=37
did=did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4|asset=solarfarm2.market1.adivate.ewc|time=2020-11-26T17:26:16.075Z;lat=71.97;long=67.09;minKw=84.43;maxKw=69.69;avgKw=47.48;sensorId=80
did=did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4|asset=solarfarm2.market1.adivate.ewc|time=2020-11-26T17:26:17.075Z;lat=72.88;long=18.5;minKw=90.32;maxKw=44.55;avgKw=51.55;sensorId=16
did=did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4|asset=solarfarm2.market1.adivate.ewc|time=2020-11-26T17:26:18.075Z;lat=44.08;long=65.49;minKw=82.04;maxKw=11.06;avgKw=46.66;sensorId=77
did=did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4|asset=solarfarm2.market1.adivate.ewc|time=2020-11-26T17:26:19.075Z;lat=88.45;long=53.52;minKw=24.83;maxKw=11.3;avgKw=51.11;sensorId=71
For timestamp extraction in this case, a RegEx would be used (this is specified when the data asset was created). e.g.:
time=(.*?);
JSON FORMAT
For Json formatted messages, there must be an "ewai" property with the did and asset header information in it:
{
...
"ewai": {
"did": "did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4",
"asset": "solarfarm2.market1.adivate.ewc"
},
...
}
Outside of that required property, the rest of the Json message is completely arbitrary and up to the data asset creator (and DERs which are sending the data). It however must be valid Json of course.
JSON EXAMPLE 1
An full PTD message example might look like:
{"ts":"2020-11-26T17:26:10.075Z","ewai":{"did":"did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4","asset":"solarfarm2.market1.adivate.ewc"},"data":{"loc":{"lat":21.266,"long":-95.012},"minKw":694.86,"maxKw":181.56,"avgKw":65.28,"sensorId":751}}
Or in prettier format:
{
"ts": "2020-11-26T17:26:10.075Z",
"ewai": {
"did": "did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4",
"asset": "solarfarm2.market1.adivate.ewc"
},
"data": {
"loc": {
"lat": 21.266,
"long": -95.012
},
"minKw": 694.86,
"maxKw": 181.56,
"avgKw": 65.28,
"sensorId": 751
}
}
For timestamp extraction in this case, a Json Path specifier would be used (this is specified when the data asset was created). e.g.:
'ts'
JSON EXAMPLE 2
{
"ewai": {
"did": "did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4",
"asset": "solarfarm2.market1.adivate.ewc"
},
"data": {
"loc": {
"lat": 21.266,
"long": -95.012
},
"minKw": 694.86,
"maxKw": 181.56,
"avgKw": 65.28,
"sensor": {
"id": 751,
"time": "2020-11-26T17:26:10.075Z"
}
}
}
The timestamp extraction Json path in this case would be:
'data.sensor.time'
JSON EXAMPLE 3
{
"ewai": {
"did": "did:eth:0x1095C1c4CbF6F5fc9225cda21c822b240DB91eE4",
"asset": "solarfarm2.market1.adivate.ewc"
},
"minKw": 694.86,
"maxKw": 181.56,
"avgKw": 65.28,
"time": "2020-11-26T17:26:10.075Z",
"temp": 42.4
}
}
The timestamp extraction Json path in this case would be:
'time'
SCHEMA VALIDATION
EWAI can perform Json schema validation for Json PTD messages. This can ensure homogenous data in the data-asset and prevent stray (junk) packets from being accepted (either by accident or on purpose). The message Schema is specified by the creator of the data asset.
An example Json Schema for the first Json Message example above is as follows:
{
"type": "object",
"properties": {
"ts": {
"type": "string"
},
"ewai": {
"type": "object",
"properties": {
"did": {
"type": "string"
},
"asset": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"did",
"asset"
]
},
"data": {
"type": "object",
"properties": {
"loc": {
"type": "object",
"properties": {
"lat": {
"type": "number"
},
"long": {
"type": "number"
}
},
"required": [
"lat",
"long"
]
},
"minKw": {
"type": "number"
},
"maxKw": {
"type": "number"
},
"avgKw": {
"type": "number"
},
"sensorId": {
"type": "integer"
}
},
"additionalProperties": false,
"required": [
"loc",
"minKw",
"maxKw",
"avgKw",
"sensorId"
]
}
},
"additionalProperties": false,
"required": [
"ts",
"ewai",
"data"
]
}