# 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 ![](https://i.imgur.com/pkGha1O.png) ## TODO: ## Flowchart ![](https://i.imgur.com/eQMlt6Q.png) # 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 } ```