MEW-01 REST API

Post Reply
KlausHi
Posts: 5
Joined: Sat Jun 20, 2020 3:31 pm

Sun Jun 21, 2020 9:49 am

Hello,
I've just installed a MEW-01 energy meter to examine the daily, weekly and monthly power consumption. My goal is to fetch the current and historical data from the SUPLA CLOUD provided REST API with a Python program. I managed to fetch the current data but I'm missing some knowledge about how to fetch the historical data and I'm looking for sources to get this knowledge.

I found a discussion in the Polish spoken SUPLA forum . Since I do not understand Polish I tried to use google translator. This is tiring :? .

The REST API is documented here SUPLA REST API at swaggerhub . I fetched the current data successfully from /api/channels/1 and subsequently I tried to fetch historical data from /api/channels/1/measurement-logs - but without luck,

I guess that only active energy data for each phase are available as historical data. This is sufficient for me.

My questions are:
  • Does anybody know where to find information how to access historical data. Examples in any programming language are welcome.
  • Does anybody know where the active energy samples are stored - within the MEW-01 or within the SUPLA CLOUD?
  • What is the sample rate or the resolution in time for the data?
I think it is not intended to poll all the time to get the data :-)

Thank you in advance
KlausHi
Posts: 5
Joined: Sat Jun 20, 2020 3:31 pm

Wed Jun 24, 2020 10:02 am

pzygmunt, thank you.

For those who try to do the same I'll provide my Python code snippets (with private information erased):

Code: Select all

import requests
import json

myAuthorizationString = 'Bearer ...'
mySuplaServer         = 'https://svrxyz.supla.org'
mySuplaChannel        = 123456

def doRequest(uri, headers, params={}):
    apiVersion = "/2.3.0"
    response   = requests.get(mySuplaServer + "/api" + apiVersion + uri, headers=headers, params=params)
    print('request to: ' + response.url)
    print('response code: ' + str(response.status_code))
    return response


# Test No. 1, try to access current data
print("\n--- Try to access current data at /channels/{id}")
uri      = '/channels/' + str(mySuplaChannel) 
headers  = { 'Authorization' : myAuthorizationString, 'Accept' : 'application/json' }
response = doRequest(uri, headers)
if response.status_code == 200:
    parsed = json.loads(response.text)
    print(json.dumps(parsed, indent=4, sort_keys=True)) # pretty print json

# Test No. 2, try to access historical json formatted data
print("\n--- Try to access historical json formatted data at /channels/{id}/measurement-logs")
uri      = '/channels/' + str(mySuplaChannel) + '/measurement-logs' 
params   = { 'order' : 'ASC', 'limit' : '2', 'afterTimestamp' : '1592985331' }
headers  = { 'Authorization' : myAuthorizationString, 'Accept' : 'application/json' }
response = doRequest(uri, headers, params)
if response.status_code == 200:
    parsed = json.loads(response.text)
    print(json.dumps(parsed, indent=4, sort_keys=True)) # pretty print json

# Test No. 3, try to access  historical zipped csv formatted data
print("\n--- Try to access historical zipped csv formatted data at /channels/{id}/measurement-logs-csv")
uri      = '/channels/' + str(mySuplaChannel) + '/measurement-logs-csv'
headers  = { 'Authorization' : myAuthorizationString, 'Accept' : 'application/zip' }
response = doRequest(uri, headers)
if response.status_code == 200:
    with open("data.csv.zip", mode = "wb") as myFile:
        myFile.write(response.content) #save zip-file
Running this script results in:

Code: Select all

--- Try to access current data at /channels/{id}
request to: https://svrxyz.supla.org/api/2.3.0/channels/123456
response code: 200
{
    "altIcon": 0,
    "caption": null,
    "channelNumber": 0,
    "flags": 0,
    "function": {
        "caption": "Electricity meter",
        "id": 310,
        "maxAlternativeIconIndex": 0,
        "name": "ELECTRICITYMETER",
        "possibleActions": [],
        "possibleVisualStates": [
            "default"
        ]
    },
    "functionId": 310,
    "hidden": false,
    "id": 1,
    "inheritedLocation": true,
    "iodeviceId": 1,
    "locationId": 2,
    "param1": 0,
    "param2": 0,
    "param3": 0,
    "textParam1": null,
    "textParam2": null,
    "textParam3": null,
    "type": {
        "caption": "Electricity meter",
        "id": 5000,
        "name": "ELECTRICITYMETER",
        "output": false
    },
    "typeId": 5000,
    "userIconId": null
}

--- Try to access historical json formatted data at /channels/{id}/measurement-logs
request to: https://svrxyz.supla.org/api/2.3.0/channels/123456/measurement-logs?order=ASC&limit=2&afterTimestamp=1592985331
response code: 200
[
    {
        "date_timestamp": "1592985931",
        "fae_balanced": null,
        "phase1_fae": "5373162",
        "phase1_fre": "16650",
        "phase1_rae": "896",
        "phase1_rre": "2169194",
        "phase2_fae": "14779916",
        "phase2_fre": "15840",
        "phase2_rae": "2",
        "phase2_rre": "9666342",
        "phase3_fae": "9307750",
        "phase3_fre": "325070",
        "phase3_rae": null,
        "phase3_rre": "2694206",
        "rae_balanced": null
    },
    {
        "date_timestamp": "1592986531",
        "fae_balanced": null,
        "phase1_fae": "5373206",
        "phase1_fre": "16650",
        "phase1_rae": "896",
        "phase1_rre": "2169454",
        "phase2_fae": "14781374",
        "phase2_fre": "15840",
        "phase2_rae": "2",
        "phase2_rre": "9668290",
        "phase3_fae": "9308898",
        "phase3_fre": "325080",
        "phase3_rae": null,
        "phase3_rre": "2694382",
        "rae_balanced": null
    }
]

--- Try to access historical zipped csv formatted data at /channels/{id}/measurement-logs-csv
request to: https://svrxyz.supla.org/api/2.3.0/channels/123456/measurement-logs-csv
response code: 200

KlausHi
Posts: 5
Joined: Sat Jun 20, 2020 3:31 pm

Wed Jun 24, 2020 8:59 pm

Sorry, my first test above did not provide the expected "current data". I wonder about the resulting data. But during my try and error I used an undocumented API feature calling the service without API version within the URL. With this shortend URL you'll get the current data.

My example code in Python:

Code: Select all

import requests
import json

myAuthorizationString = 'Bearer ...'
mySuplaServer         = 'https://svrxyz.supla.org'
mySuplaChannel        = 123456

def doRequestWithoutApiVersion(uri, headers, params={}):
    response   = requests.get(mySuplaServer + "/api" + uri, headers=headers, params=params)
    print('request to: ' + response.url)
    print('response code: ' + str(response.status_code))
    return response


# Test No. 1, try to access current data
print("\n--- Try to access current data at /channels/{id}")
uri      = '/channels/' + str(mySuplaChannel) 
headers  = { 'Authorization' : myAuthorizationString, 'Accept' : 'application/json' }
response = doRequestWithoutApiVersion(uri, headers)
if response.status_code == 200:
    parsed = json.loads(response.text)
    print(json.dumps(parsed, indent=4, sort_keys=True)) # pretty print json
and the result when calling the script provides the current data:

Code: Select all

--- Try to access current data at /channels/{id}
request to: https://svrxyz.supla.org/api/channels/123456
response code: 200
{
    "connected": true,
    "currency": "",
    "enabled": true,
    "phases": [
        {
            "current": 0.09,
            "frequency": 50.01,
            "number": 1,
            "phaseAngle": 110.6,
            "powerActive": 7.01784,
            "powerApparent": 21.04198,
            "powerFactor": 0.28,
            "powerReactive": -18.4431,
            "totalForwardActiveEnergy": 54.63414,
            "totalForwardReactiveEnergy": 0.192,
            "totalReverseActiveEnergy": 0.00904,
            "totalReverseReactiveEnergy": 21.88868,
            "voltage": 237.24
        },
        {
            "current": 0.849,
            "frequency": 50.01,
            "number": 2,
            "phaseAngle": 129.2,
            "powerActive": 115.24546,
            "powerApparent": 198.10018,
            "powerFactor": 0.58,
            "powerReactive": -114.8436,
            "totalForwardActiveEnergy": 148.92318,
            "totalForwardReactiveEnergy": 0.16162,
            "totalReverseActiveEnergy": 2e-05,
            "totalReverseReactiveEnergy": 97.84298,
            "voltage": 237.76
        },
        {
            "current": 0.301,
            "frequency": 50.01,
            "number": 3,
            "phaseAngle": 161.9,
            "powerActive": 66.76162,
            "powerApparent": 70.78694,
            "powerFactor": 0.925,
            "powerReactive": -21.24812,
            "totalForwardActiveEnergy": 94.22224,
            "totalForwardReactiveEnergy": 3.25318,
            "totalReverseActiveEnergy": 0,
            "totalReverseReactiveEnergy": 27.14854,
            "voltage": 239.37
        }
    ],
    "pricePerUnit": 0,
    "support": 40959,
    "totalCost": 0
}
I wonder if this is intended or what the meaning of the data are when doing a GET request to /api/2.3.0/channels/{id}?
KlausHi
Posts: 5
Joined: Sat Jun 20, 2020 3:31 pm

Thu Jun 25, 2020 8:01 am

I've gained some more knowledge. So as not to use an undocumented feature I modified the request for my first test to the URL with the API-version included. If you add an additional query parameter "include=state" you'll get the current data within the response.

My modified Python code snippet:

Code: Select all

# Test No. 1, try to access current data
print("\n--- Try to access current data at /channels/{id}")
uri      = '/channels/' + str(mySuplaChannel) 
headers  = { 'Authorization' : myAuthorizationString, 'Accept' : 'application/json' }
params   = { 'include' : 'state' }
response = doRequest(uri, headers, params)
if response.status_code == 200:
    parsed = json.loads(response.text)
    print(json.dumps(parsed, indent=4, sort_keys=True)) # pretty print json
The calling's result:

Code: Select all

--- Try to access current data at /channels/{id}
request to: https://svrxyz.supla.org/api/2.3.0/channels/123456?include=state
response code: 200
{
    "altIcon": 0,
    "caption": null,
    "channelNumber": 0,
    "flags": 0,
    "function": {
        "caption": "Electricity meter",
        "id": 310,
        "maxAlternativeIconIndex": 0,
        "name": "ELECTRICITYMETER",
        "possibleActions": [],
        "possibleVisualStates": [
            "default"
        ]
    },
    "functionId": 310,
    "hidden": false,
    "id": 1,
    "inheritedLocation": true,
    "iodeviceId": 1,
    "locationId": 2,
    "param1": 0,
    "param2": 0,
    "param3": 0,
    "state": {
        "connected": true,
        "currency": "",
        "phases": [
            {
                "current": 0.074,
                "frequency": 50,
                "number": 1,
                "phaseAngle": 98.9,
                "powerActive": 3.20456,
                "powerApparent": 17.34792,
                "powerFactor": 0.154,
                "powerReactive": -16.79552,
                "totalForwardActiveEnergy": 55.0893,
                "totalForwardReactiveEnergy": 0.192,
                "totalReverseActiveEnergy": 0.00908,
                "totalReverseReactiveEnergy": 22.0786,
                "voltage": 237.43
            },
            {
                "current": 0.674,
                "frequency": 50,
                "number": 2,
                "phaseAngle": 107,
                "powerActive": 66.48066,
                "powerApparent": 156.02822,
                "powerFactor": 0.428,
                "powerReactive": -122.74294,
                "totalForwardActiveEnergy": 150.8434,
                "totalForwardReactiveEnergy": 0.16326,
                "totalReverseActiveEnergy": 2e-05,
                "totalReverseReactiveEnergy": 98.927,
                "voltage": 236.1
            },
            {
                "current": 0.344,
                "frequency": 50,
                "number": 3,
                "phaseAngle": 176.6,
                "powerActive": 81.15104,
                "powerApparent": 80.13132,
                "powerFactor": 0.995,
                "powerReactive": -4.89528,
                "totalForwardActiveEnergy": 94.80014,
                "totalForwardReactiveEnergy": 3.2538,
                "totalReverseActiveEnergy": 0,
                "totalReverseReactiveEnergy": 27.42044,
                "voltage": 236.97
            }
        ],
        "pricePerUnit": 0,
        "support": 40959,
        "totalCost": 0
    },
    "textParam1": null,
    "textParam2": null,
    "textParam3": null,
    "type": {
        "caption": "Electricity meter",
        "id": 5000,
        "name": "ELECTRICITYMETER",
        "output": false
    },
    "typeId": 5000,
    "userIconId": null
KlausHi
Posts: 5
Joined: Sat Jun 20, 2020 3:31 pm

Sun Jun 28, 2020 11:19 am

Some more understanding about the historical json formatted data:

The timestamp denotes epoch time (time_t) GMT. The sample interval is 600 seconds (10 minutes).

The identifiers are made of
  • fae -> forward active energy
  • rae -> reverse active energy
  • fre -> forward reactive energy
  • rre -> reverse reactive energy
The energy values are accumulated and have to divided by 100.000 to get the values in kWh.
Post Reply

Return to “Help”