# Consumables Calculation

Each project defines "consumables" that allow tracking how much of a certain product the machine has used during its operation. Each consumable is associated with a product, which could be water, energy, air, raw materials, etc.

## /apis/consumables/\<assetId>

## GET Method

<details>

<summary>Request</summary>

```
HTTP
GET https://{BASE_URL}/apis/consumables/<assetId>
```

dove:&#x20;

* `assetId` : id della sotto macchina da considerare.

#### Query

```
JSON
{
    "subAssetId": "subAssetId"
}
```

dove:&#x20;

* `subAssetId` : id della sotto macchina da considerare. Questo campo può essere omesso se l'asset considerato non è multi macchina.

</details>

By invoking this endpoint with the GET method, you can retrieve the list of all consumables for the specified machine, potentially filtered by sub-machine. This functionality is useful to identify the consumables of the machine and how they are identified, in order to request their calculation.

The response provides useful information about each consumable, such as the supported aggregators, the general and relative units of measurement, and any multipliers to be applied to the data to obtain the correct unit of measurement. An interesting key is "40ImpactOnly," which allows distinguishing between real consumables, associated with physical products, and virtual consumables, associated with other calculable values and used only for Sustainability Analysis.

The data returned in this response can be used to make a POST request to this same endpoint. The keys within the response or the "id" keys in each individual object identify the value that can be specified in the POST request under the "consumableName" key.

## Example

<details>

<summary>Request</summary>

```
HTTP
GET https://matdev.40mat.com/apis/consumables/40-line?subAssetId=M1
```

#### Query

```
JSON
{
    "subAssetId": "M1"
}
```

</details>

In this example, the goal is to obtain the list of all consumables for the machine "40-line," but only valid for the sub-machine "M1."

An example response is shown in the figure. Each object can be interpreted as follows:&#x20;

"*The consumable cons0 is expressed in cubic meters and represents the air used by the machine for processing. The aggregators that can be used for its aggregation are aggr0, aggr1, and aggr2. There is no need to multiply the obtained value to convert it into cubic meters, as it is originally recorded in the table in this format. The unit of measurement to use when calculating the relative consumption of cons0 is cubic meters per bundle, and again, there is no need to multiply the obtained value by a coefficient to get the correct unit of measurement*."

<details>

<summary>Response</summary>

```json
JSON
{
    "cons0": {
        "40ImpactOnly": false,
        "aggregators": [
            "aggr0",
            "aggr1",
            "aggr2"
        ],
        "id": "cons0",
        "multiplier": 1,
        "relativeMultiplier": 1,
        "relativeUnit": "m³ / bundle",
        "unit": "m³",
        "meaning": "Air"
    },
    "cons1": {
        "40ImpactOnly": false,
        "aggregators": [
            "aggr0",
            "aggr1",
            "aggr2"
        ],
        "id": "cons1",
        "multiplier": 1,
        "relativeMultiplier": 1000,
        "relativeUnit": "Wh / bundle",
        "unit": "kWh",
        "meaning": "Energy"
    },
    "cons2": {
        "40ImpactOnly": true,
        "aggregators": [
            "aggr0",
            "aggr1",
            "aggr2"
        ],
        "id": "cons2",
        "multiplier": null,
        "relativeMultiplier": null,
        "relativeUnit": "min / bundle",
        "unit": "min",
        "meaning": "Productive Time"
    },
    "cons3": {
        "40ImpactOnly": true,
        "aggregators": [
            "aggr0",
            "aggr1",
            "aggr2"
        ],
        "id": "cons3",
        "multiplier": null,
        "relativeMultiplier": null,
        "relativeUnit": "min / bundle",
        "unit": "min",
        "meaning": "Down Time"
    }
}
```

</details>

### Code

{% tabs %}
{% tab title="Python" %}

```python
import requests
import json

# Example data for the header
headers = {
    'App-Name': 'matdev-be',
    'Authorization': 'Bearer ey....xy1w'
}

# URL of the third-party API
myDomain = 'matdev.40mat.com'
myAssetId = '40-line'
endpoint = f'/apis/consumables/{myAssetId}'
url = f'https://{myDomain}{endpoint}'


# Make the POST request
response = requests.get(url, headers=headers, )

# Check the response status and return the data
if response.status_code == 200:
    print('Success:')
    print(json.dumps(response.json(), indent=4))
else:
    print('Request failed:')
    print(f'Status code: {response.status_code}')
    print(response.text)

```

{% endtab %}
{% endtabs %}

### OpenAPI

{% openapi src="<https://content.gitbook.com/content/L65nhvmBlLI1fH4sd9ut/blobs/KAvOsMKNpCkRaukQxFnU/OpenAPI_simpliefiedAPIs.yml>" path="/apis/consumables/{assetId}" method="get" %}
[OpenAPI\_simpliefiedAPIs.yml](https://content.gitbook.com/content/L65nhvmBlLI1fH4sd9ut/blobs/KAvOsMKNpCkRaukQxFnU/OpenAPI_simpliefiedAPIs.yml)
{% endopenapi %}

## POST Method

The POST method of the `/apis/consumables/<assetId>` endpoint can be used to calculate the values of a certain consumable. The endpoint provides a set of parameters that, once passed in the body, allow the system to perform data processing.

<details>

<summary>Request</summary>

```
HTTP
POST https://{BASE_URL}/apis/consumables/<assetId>
```

where:&#x20;

* `assetId` : ID of the machine to consider.

#### Query

```
JSON
{
    "subAssetId": "subAssetId"
}
```

where:&#x20;

* `subAssetId` : ID of the sub-machine to consider. This field can be omitted if the asset being considered is not a multi-machine system.

**Body**

```
JSON
{
    "consumableName": "cons1",
    "resampleBy": "unique",
    "from": "2024-03-31T22:00:00.000Z",
    "to": "2024-04-05T21:59:59.999Z",
    "filterBy": {"aggr2": "format-A"},
    "groupBy": "aggr1",
    "limit": None,
    "getRelativeValue": false,
    "calendar": 0
}
```

The body of the request can consist of the following parameters:

* `consumableName` : this string field indicates the name of the consumable that you want to request from the system. To obtain the possible consumables, you can invoke this same endpoint using the [GET method](#get-method): the keys in the response and the values associated with the "id" keys of each object can be used in this parameter as they uniquely identify a consumable. Note that this parameter can be a list of strings, where each string represents a consumable to be requested;
* `from` : the starting point from which you want to begin calculating the data, expressed in UTC in the format "YYYY-MM-DDThh:mm .sssZ" (ISO 8601 Standard);
* `to` : the endpoint of the interval for which you want to calculate the data, expressed in UTC in the format "YYYY-MM-DDThh:mm .sssZ" (ISO 8601 Standard). If this field is omitted or set to null, it will automatically be set to the current time of the request;
* `resampleBy` : this parameter allows you to define the frequency with which to calculate the specified consumable. Since data in the MAT ecosystem is recorded over time, it can be returned with reference to a time period or as a time series. This field allows you to specify how the data should be returned. The allowed values are:
  * unique: this parameter indicates that you want to obtain a single numerical value calculated over the entire interval;
  * {n}m: allows the consumable to be calculated with a frequency of {n} minutes over the selected interval;
  * {n}h: allows the consumable to be calculated with a frequency of {n} hours over the selected interval;
  * {n}d: allows the consumable to be calculated with a frequency of {n} days over the selected interval;
  * {n}w: allows the consumable to be calculated with a frequency of {n} weeks over the selected interval;
* `filterBy` : this field allows you to specify a filter to apply to the data. The value must be a dictionary where the keys represent the fields to filter on, and the value represents what you want to include for that field;
* `groupBy` : this field allows you to group the data according to one of the specified values. The value should be a string indicating the field on which you want to aggregate. For more advanced use, you can specify a list of strings;
* `limit` : this numeric field allows you to specify a maximum number of rows of data to return. If you imagine the data as being written in tables, a "limit" operation allows you to take the last {n} rows of the table. Specifically, "limit" refers to the most recent rows written in the table. If the "resampleBy" field is present, "limit" will be ignored and will have no effect. Additionally, this field can be used in various ways:
  * "limit" without "from" and "to": the last {n} rows written in the table, or more generally, the last {n} data points available, will be retrieved;
  * "limit" with "from" and without "to": the behavior in this case is the same as the previous one. The last {n} data points available will be returned;
  * "limit" with "from" and with "to": in this case, the last {n} rows of data will be returned, taking the "to" field as the endpoint of the interval. The data will be the last ones written before the time specified in the "to" field;
  * "limit" with "to" and without "from": this option is not allowed and will result in an error;
* `getRelativeValue` : this boolean field allows you to specify whether the returned data should be calculated absolutely over the specified interval or normalized according to the production realized during that period;
* `calendar` : boolean value indicating whether the calendar should be considered in data analysis. By default, this value is set to false.

</details>

Below are some usage examples of this call.

## Example - groupBy

The goal of this example is to calculate how much of `cons0` was consumed during the production of different products (`"aggr0"`) in the month of April. To group the data based on the product produced, you need to perform a group by operation on the column dedicated to the produced product, which is `"aggr0"`.

<details>

<summary>Request</summary>

```
HTTP
POST https://matdev.40mat.com/apis/consumables/40-line?subAssetId=M1
```

#### Query

```
JSON
{
    "subAssetId": "M1"
}
```

#### Body

```
JSON
{
    "consumableName": "cons0",
    "resampleBy": "unique",
    "from": "2024-03-31T22:00:00.000Z",
    "to": "2024-04-30T21:59:59.999Z",
    "groupBy": "aggr0"
}
```

</details>

Here is the response. As you can see, for each product produced, a value for the consumable is provided. For example, to produce the product type `prod1`, 915,563.960059166 cubic meters of `cons0` were consumed (the unit of measurement can be retrieved from the GET method call).

<details>

<summary>Response</summary>

```json
JSON
{
    "prod1": [
        {
            "_time": null,
            "cons0": 915563.960059166
        }
    ],
    "prod2": [
        {
            "_time": null,
            "cons0": 855694.6338380575
        }
    ],
    "prod3": [
        {
            "_time": null,
            "cons0": 919579.234770298
        }
    ],
    "prod4": [
        {
            "_time": null,
            "cons0": 787873.2918863297
        }
    ],
    "prod5": [
        {
            "_time": null,
            "cons0": 822642.4476057291
        }
    ]
}
```

</details>

## Example - filterBy

<details>

<summary>Request</summary>

```
HTTP
POST https://matdev.40mat.com/apis/consumables/40-line?subAssetId=M1
```

#### Query

```
JSON
{
    "subAssetId": "M1"
}
```

#### Body

```
JSON
{
    "consumableName": "cons1",
    "resampleBy": "1d",
    "from": "2024-03-31T22:00:00.000Z",
    "to": "2024-04-05T21:59:59.999Z",
    filterBy": {"aggr1": "Luigi"}
}
```

</details>

The objective of this example is to show the daily trend of `cons1` consumption when the operator "Luigi" is recorded. To achieve this, a filter is applied by setting the "filterBy" key and specifying that the value of the operator aggregator must be "Luigi."

The response is as follows. For each day within the selected interval, the value of `cons1` filtered by the operator is provided.

<details>

<summary>Response</summary>

```json
JSON
[
    {
        "_time": "2024-04-01T00:00:00.000",
        "cons1": 436.2197265625
    },
    {
        "_time": "2024-04-02T00:00:00.000",
        "cons1": 180.84536743164062
    },
    {
        "_time": "2024-04-03T00:00:00.000",
        "cons1": 236.50662231445312
    },
    {
        "_time": "2024-04-04T00:00:00.000",
        "cons1": 447.9972839355469
    },
    {
        "_time": "2024-04-05T00:00:00.000",
        "cons1": 279.0506591796875
    }
]
```

</details>

## Example - groupBy, filterBy

<details>

<summary>Request</summary>

```
HTTP
POST https://matdev.40mat.com/apis/consumables/40-line?subAssetId=M1
```

#### Query

```
JSON
{
    "subAssetId": "M1"
}
```

#### Body

```
JSON
{
    "consumableName": "cons1",
    "resampleBy": "1d",
    "from": "2024-03-31T22:00:00.000Z",
    "to": "2024-04-05T21:59:59.999Z",
    "filterBy": {"aggr2": "format-A"},
    "groupBy": "aggr1"
}
```

</details>

In this example, the goal is to obtain the value of `cons1` based on the recorded operator, but only when the format being used was "format-A." To achieve this, in addition to performing a group by operation on the operator field (`"aggr1"`), a filter is applied to retain only the data for the "format-A" format using the "filterBy" key.

<details>

<summary>Response</summary>

```json
JSON
{
    "Luigi": [
        {
            "_time": null,
            "cons1": 35.929522290825844
        }
    ],
    "Mario": [
        {
            "_time": null,
            "cons1": 101.99586488306522
        }
    ],
    "Peach": [
        {
            "_time": null,
            "cons1": 286.14161647856236
        }
    ],
    "Waluigi": [
        {
            "_time": null,
            "cons1": 229.7614924609661
        }
    ],
    "Wario": [
        {
            "_time": null,
            "cons1": 130.8978322893381
        }
    ],
    "Yoshi": [
        {
            "_time": null,
            "cons1": 166.38746522367
        }
    ]
}
```

</details>

## Example - getRelativeValue&#x20;

<details>

<summary>Request</summary>

```
HTTP
POST https://matdev.40mat.com/apis/consumables/40-line?subAssetId=M1
```

#### Query

```
JSON
{
    "subAssetId": "M1"
}
```

#### Body

```
JSON
{
    "consumableName": "cons1",
    "resampleBy": "unique",
    "from": "2024-05-09T00:00:00.000Z",
    "to": null,
    "getRelativeValue": false
}
```

</details>

In the example above, the goal is to obtain the value of the consumable `cons1` from May 9th to the present. The "to" field is set to a null value, thereby extending the reference interval to the current moment. Additionally, in this example, "getRelativeValue" is set to `false`, as the interest is in the total amount of `cons1` consumed.

The response is shown below. From the GET method call, we know that the unit of measurement for `cons1` is kWh, so from May 9th to now, the machine has consumed 881.0794633813202 kWh.

<details>

<summary>Response</summary>

```json
JSON
{
    "cons1": 881.0794633813202
} 
```

</details>

In the following example, the goal is to determine the relative consumption from May 9th to today.

<details>

<summary>Request</summary>

```
HTTP
POST https://matdev.40mat.com/apis/consumables/40-line?subAssetId=M1
```

#### Query

```
JSON
{
    "subAssetId": "M1"
}
```

#### Body

```
JSON
{
    "consumableName": "cons1",
    "resampleBy": "unique",
    "from": "2024-05-09T00:00:00.000Z",
    "to": null,
    "getRelativeValue": true
}
```

</details>

Since the relative unit of measurement for `cons1` is kWh/bundle, we can conclude from the following response that the relative consumption in the reference interval was 0.1195996412032257 kWh per bundle.

<details>

<summary>Response</summary>

```json
JSON
{
    "cons1rel": 0.1195996412032257
}
```

</details>

## Example- consumableName as List

<details>

<summary>Request</summary>

```
HTTP
POST https://matdev.40mat.com/apis/consumables/40-line?subAssetId=M1
```

#### Query

```
JSON
{
    "subAssetId": "M1"
}
```

#### Body

```
JSON
{
    "consumableName": ["cons0", "cons1"],
    "resampleBy": "1d",
    "from": "2025-03-20T22:00:00.000Z",
    "to": "2025-03-25T21:59:59.999Z"
}
```

</details>

The response will be as follows:

<details>

<summary>Response</summary>

```json
[
    {
        "_time": "2025-03-20T00:00:00.000",
        "cons0": 6787.89453125,
        "cons1": 85.8619384765625
    },
    {
        "_time": "2025-03-21T00:00:00.000",
        "cons0": 147577.734375,
        "cons1": 1840.6875
    },
    {
        "_time": "2025-03-22T00:00:00.000",
        "cons0": 148944.78125,
        "cons1": 1845.0185546875
    },
    {
        "_time": "2025-03-23T00:00:00.000",
        "cons0": 157369.109375,
        "cons1": 1926.840576171875
    },
    {
        "_time": "2025-03-24T00:00:00.000",
        "cons0": 150187.703125,
        "cons1": 1822.735595703125
    },
    {
        "_time": "2025-03-25T00:00:00.000",
        "cons0": 151535.375,
        "cons1": 1819.75244140625
    }
]
```

</details>

### Code

{% tabs %}
{% tab title="Python" %}
The following script can be used to make a POST request to the `/apis/consumables` endpoint. Be sure to configure the parameters correctly in the body of the request.

```python
import requests
import json

# Example data for the header
headers = {
    'App-Name': 'matdev-be',
    'Authorization': 'Bearer ey....xy1w'
}

# Example data for the body
body = {
    "consumableName": "cons1",
    "resampleBy": "unique",
    "from": "2024-03-31T22:00:00.000Z",
    "to": "2024-04-05T21:59:59.999Z",
    "filterBy": {"aggr2": "format-A"},
    "groupBy": "aggr1",
    "limit": None,
    "getRelativeValue": false
}

# Example data for the query string
query_params = {
    "subAssetId": "M1"
}

# URL of the third-party API
myDomain = 'matdev.40mat.com'
myAssetId = '40-line'
endpoint = f'/apis/consumables/{myAssetId}'
url = f'https://{myDomain}{endpoint}'

# Make the POST request
response = requests.post(url, headers=headers, json=body, params=query_params )

# Check the response status and return the data
if response.status_code == 200:
    print('Success:')
    print(json.dumps(response.json(), indent=4))
else:
    print('Request failed:')
    print(f'Status code: {response.status_code}')
    print(response.text)
```

{% endtab %}
{% endtabs %}

### OpenAPI

{% openapi src="<https://content.gitbook.com/content/L65nhvmBlLI1fH4sd9ut/blobs/KAvOsMKNpCkRaukQxFnU/OpenAPI_simpliefiedAPIs.yml>" path="/apis/consumables/{assetId}" method="post" %}
[OpenAPI\_simpliefiedAPIs.yml](https://content.gitbook.com/content/L65nhvmBlLI1fH4sd9ut/blobs/KAvOsMKNpCkRaukQxFnU/OpenAPI_simpliefiedAPIs.yml)
{% endopenapi %}
