# Flexchain Instruction Document - LITE
## API Links:
##### (POST, GET):
> FlexibilityOfferFunction: https://flexchain-functionapp-testenv.azurewebsites.net/api/flexibilityOffers
> FlexibilityRequestFunction: https://flexchain-functionapp-testenv.azurewebsites.net/api/flexibilityRequests
> Flex_MatchingAlgo_Function: https://flexchain-functionapp-testenv.azurewebsites.net/api/flex_matching_algo_Results
##### (GET) (a specific entry)
> FlexibilityOfferGetFunction: https://flexchain-functionapp-testenv.azurewebsites.net/api/flexibilityOffers/{UserID}
> FlexibilityRequestGetFunction: https://flexchain-functionapp-testenv.azurewebsites.net/api/flexibilityRequests/{RequestID}
> Flex_MatchingAlgo_Get_Function: https://flexchain-functionapp-testenv.azurewebsites.net/api/flex_matching_algo_Results/{RequestID}
##### (DELETE: specific entry) [by DSO: ALL USING {RequestID}]
> FlexibilityOfferDelFunction: https://flexchain-functionapp-testenv.azurewebsites.net/api/flexibilityOffers/{RequestID}
> FlexibilityRequestDelFunction: https://flexchain-functionapp-testenv.azurewebsites.net/api/flexibilityRequests/{RequestID}
> Flex_MatchingAlgoDelFunction: https://flexchain-functionapp-testenv.azurewebsites.net/api/flex_matching_algo_Results/{RequestID}
##### (Blind MatchingAlgo GET):
> Flex_MatchingAlgo_Blind_Function: https://flexchain-functionapp-testenv.azurewebsites.net/api/flex_matching_algo_Results_blind/{RequestID}
##### Validity Check Function (GET):
> ValidityCheck_Get_Function: https://flexchain-functionapp-testenv.azurewebsites.net/api/flex_validity_check/
>
#### Timer Trigger Functions
DeleteFlexOfferTimerTrigger: timerTrigger
DeleteFlexRequestTimerTrigger: timerTrigger
DeletematchingAlgoTimerTrigger: timerTrigger
MatchingAlgoPostTimerTrigger: timerTrigger
## Offer, Request, Matching Algo Body Format (JSON):
### Offer Format:
```
"UserId": "user001",
"FlexOfferList": [
{
"BidPriceCtpEUList": "null",
"endFlexShiftTimeSlot": "2021-10-05T21:00:00Z",
"RequestId": "Req000001",
"startFlexShiftTimeSlot": "2021-10-05T19:00:00Z",
"totalFlexOfferedEU": -6,
"id": null
},
{
"BidPriceCtpEUList": "null",
"endFlexShiftTimeSlot": "2021-10-05T19:15:00Z",
"RequestId": "Req000002",
"startFlexShiftTimeSlot": "2021-10-05T19:00:00Z",
"totalFlexOfferedEU": 2,
"id": null
},
{
"BidPriceCtpEUList": "8, 10, 12, 13",
"endFlexShiftTimeSlot": "2021-10-05T19:15:00Z",
"RequestId": "Req000006",
"startFlexShiftTimeSlot": "2021-10-05T19:00:00Z",
"totalFlexOfferedEU": 4,
"id": null
},
{
"BidPriceCtpEUList": "7",
"endFlexShiftTimeSlot": "2021-10-05T19:15:00Z",
"RequestId": "Req000007",
"startFlexShiftTimeSlot": "2021-10-05T19:00:00Z",
"totalFlexOfferedEU": 4,
"id": null
}
]
```
### Request Format:
#### (for fixed price):
```
"RequestId": "Req000001",
"Mode": "fcfs",
"FullfillmentFactor": 50,
"MarketType": "fixedPrice",
"MaxPriceCtpEU": null,
"PriceOfferCtpEU": "7",
"ReferencePriceCtpEU": "null",
"TimeSlot": "2021-10-05T15:15:00Z",
"TotalFlexRequestedEU": "-11",
“MatchingAlgoCheck”: false
"RequestId": "Req000005",
"Mode": "fcfs",
"FullfillmentFactor": 0,
"MarketType": "fixedPrice",
"MaxPriceCtpEU": null,
"PriceOfferCtpEU": "null",
"ReferencePriceCtpEU": "null",
"TimeSlot": "2021-06-13T22:16:00Z",
"TotalFlexRequestedEU": "null",
“MatchingAlgoCheck”: false
```
#### (for auction):
```
"RequestId": "Req000006",
"Mode": "MiP",
"FullfillmentFactor": 50,
"MarketType": "auction",
"MaxPriceCtpEU": 12,
"PriceOfferCtpEU": "null",
"ReferencePriceCtpEU": "10",
"TimeSlot": "2021-10-05T15:00:00Z",
"TotalFlexRequestedEU": "7",
“MatchingAlgoCheck”: false
"RequestId": "Req000008",
"Mode": "MiP",
"FullfillmentFactor": null,
"MarketType": "auction",
"MaxPriceCtpEU": null,
"PriceOfferCtpEU": "null",
"ReferencePriceCtpEU": "null",
"TimeSlot": "2021-10-05T15:00:00Z",
"TotalFlexRequestedEU": "null",
“MatchingAlgoCheck”: false
```
### Matching Algo Result Format (The format in which matching algo results are stored in the table):
```
"response": [
{
"_id": {
"$oid": "640aea889d4f350d11121249"
},
"requestId": "req0001",
"reachedFullFillmentFactor": true,
"results": [
{
"userId": "us1",
"flexEU": 6
},
{
"userId": "us2",
"flexEU": 4
},
{
"userId": "us3",
"flexEU": 1
}
]
},
{
"_id": {
"$oid": "640aea889d4f350d1112124c"
},
"requestId": "req00011",
"reachedFullFillmentFactor": false,
"results": null
}
]
```
## Note:
### In Requests:
**‘market_type’ can be:**
‘fixed_price’: The grid operator offers a fixed price (“reference_price_ctpEU”: null, “price_offered_ctpEU”: [int]) for flexibility
‘auction’: A market based auction decides the price (“reference_price_ctpEU”: [int], “price_offered_ctpEU”: null)
<!-- ‘isBlind’ can be:
True: The volume requested by the grid operator is not known (“total_flex_requested_EU”: null)
False: The volume requested by the grid operator is known (“total_flex_requested_EU”: [int]) -->
**‘loc’:** List of HEMS UserIds with suitable location
### In Offers:
In case **‘market_type’: ‘fixed_price’,** the price is already written in the flexibility request. Therefore:
‘price_bid_ctEU_list’ list:null.
In case **‘market_type’: ‘auction’,** the EU prices are sent as list
‘price_bid_ctpEU_list’: […]
**"start_flex_shift_timeslot ":** start of timeslot to which flex must be shifted, null if "traded_flexibility_EU":0
**"end_flex_shift_timeslot ":** start of timeslot to which flex must be shifted, null if "traded_flexibility_EU":0
## Details on the Modes:
#### Note:
For https://flexchain-functionapp-testenv.azurewebsites.net/api/flex_matching_algo_Results
> We do not put any details (Json) as the body for POST request. **The server will take data from FlexibilityRequest and FlexibilityOffer and use the Matching Algorithm.** The result of the matching algorithm is stored in the the flex_matching_algo_Results table in the database.
## Cron Jobs
### DeleteALL Cron Job:
#### Every 2 weeks.
```
request dropping collection
offers dropping collection
matching algo result dropping collection
```
### MatchingAlgo POST Cron Job:
#### Every 15 min.
```
matching algo result POST method
```
## (Blind MatchingAlgo GET):
To call
`http://localhost:7071/api/flex_matching_algo_Results_blind/{RequestID}`
As **GET** method.
Body:
> {
> “userId” : “value”,
> “password” : “value”
> }
## Removing Duplicacy in Matching Algo Results
Since the Requests and Offers are only being removed once every 2 weeks, there can be a scenario where `A,B,C` requests and `W,X,Y,Z` offers give `P,Q,R` matching algorithm results at time `T`. Since the inputs are not removed, at time `T + 15min` another `P,Q,R` results will be created, thus making redundency.
To eliminate this, we have included a check called `MatchingAlgoCheck`. It is there for each request and it is set to false initially.
When matching algorithm is called, the `MatchingAlgoCheck` for all the used requests are set to true. And during matching algorithm calculation we are using an if statement that allows only requests with `MatchingAlgoCheck=false` to be included in the calculation.
## Blind Matching Algo
It is required when a user tries to check if their offer was accepted for a particular request (and if accepted, then how much) without gaining knowledge of the accepted offers from other users.
User has to use the endpoint with requestid:
https://flexchain-functionapp-testenv.azurewebsites.net/api/flex_matching_algo_Results_blind/{RequestID}
The body format for the GET request is:
{
```
"UserId": "us1",
"Password": "abc"
```
}
The response format is:
In case user offer was accepted:
```
{
"status": 200,
"errors": [],
"warnings": [],
"information": [],
"response": {
"us1": 6,
"Total": 11
}
}
```
In case user offer was not accepted:
```
{
"status": 403,
"errors": [
{
"message": "Offer Not Accepted",
"type": "ForbiddenError",
"data": null
}
],
"warnings": [],
"information": [],
"response": null
}
```
## Hash Format
```
RequestID +
BidPriceCtpEUList +
TotalFlexOfferedEU +
StartFlexShiftTimeslot +
EndFlexShiftTimeslot
```
So hash value:
`SHA3(RequestID + BidPriceCtpEUList + TotalFlexOfferedEU + StartFlexShiftTimeslot + EndFlexShiftTimeslot)`
#### Merkle Tree

## TODO:
## Flowchart

# Hager MQTT API
### Abbreviations
EU = Energy Unit
Ctp = Cent per unit
## Get Flexibility Requests (Hager -> AWSI )
Topic: flexibility-request
```
{
"userId": "user0001"
}
```
## Send Flexibility Response (AWSI -> Hager )
Topic: flexibility-response
```
{
"requests": [
{
"id": "req001",
"timeSlot": "2021-10-05T15:15:00Z",
"totalFlexRequestedEU": -11,
"marketType": "fixedPrice",
"priceOfferCtpEUs": 7,
"maxPriceCtpEU": null,
},
{
"id": "req003",
"timeSlot": "2021-10-05T15:45:00Z",
"totalFlexRequestedEU": -8,
"marketType": "fixedPrice",
"priceOfferCtpEUs": 6,
"maxPriceCtpEU": null,
},
{
"id": "req007",
"timeSlot": "2021-10-05T17:15:00Z",
"totalFlexRequestedEU": 9,
"marketType": "auction",
"priceOfferCtpEUs": null,
"maxPriceCtpEU": 14,
}
]
}
```
## Send Flexibility Offer (Hager -> AWSI)
Topic: flexibility-offer
```
{
"offer": {
"userId": "user0001",
"offers": [
{
"requestId": "req001",
"endFlexShiftTimeSlot": "2021-10-05T21:00:00Z",
"startFlexShiftTimeSlot": "2021-10-05T19:00:00Z",
"totalFlexOfferedEU": -6,
"bidPriceCtpEUList": []
}
]
},
"hash": "<hash>"
}
```
## Send Matching Algo result (AWSI -> Hager)
Topic: flexibility-result
```
{
"results": [
{
"requestId": "req001",
"flexEU": -3,
"matchingResult": 0,
},
{
"requestId": "req003",
"flexEU": -5
"matchingResult": 0,
},
{
"requestId": "req007",
"flexEU": 0
"matchingResult": 1,
}
]
}
```
MatchingResult:
0 = offer has won & fullfillmentFactor was reached
1 = offer was considered but did not win & fullfillmentFactor was reached
2 = offer was considered, fullfillmentFactor was not reached
3 = offer was not considered because the offer was invalid (wrong hash)
**Flexibility must only be provided if MatchingResult = 0**
## Send Flexibility Verification (Hager -> AWSI)
Topic: flexibility-verification
```
{
"requestId": "req007",
"userId": "user0001",
"totalFlexDeliveredEU": 9
}
```