ESSIM API
Note
This documentation is work in progress and far from finished. New sections will be added in the near future. Whenever questions or feedback is received from end users, we’re trying to update this documentation on the fly. So don’t hesitate to contact us, whenever you run into problems.
Sequence
ESSIM provides a REST API that allows users to interact with ESSIM for starting a simulation, requesting its progress, etc. The usual sequence to invoking a simulation and interacting with it is as follows:
APIs:
/simulation
HTTP Method: POST
Description: Create a new simulation
- Request Body:
endDate: End date of simulation in ISO-8601 format (
YYYY-MM-DDTHH:mm:ss±hh:mm)esdlContents: 64-bit encoded ESDL string
influxURL: URL of InfluxDB instance to store simulation results in
scenarioID: String ID representing the scenario being simulated. This ID is used to name the database in InfluxDB.
simulationDescription: Human-readable description of the simulation visible in the dashboard
startDate: Start date of simulation in ISO-8601 format (
YYYY-MM-DDTHH:mm:ss±hh:mm)user: Name of the user running the simulation. Used to tag the name of the Grafana dashboard
csvFilesLocation: (Optional) To export ESSIM simulation data into CSV, specify a location here
mqttURL: (Optional) To publish ESSIM data to an MQTT bus, specify the URL to an MQTT server here
amqpURL: (Optional) To publish ESSIM data to an AMQP bus, specify the URL to an AMQP server here
kafkaURL: (Optional) To publish ESSIM data to an Apache Kafka server, specify the URL to the server here
nodeConfig: (Optional) To use a remote node with ESSIM, specify the following:
esdlNodeId: The ESDL ID of the asset represented by this node
config: Any key-value configuration to provide this node
mqttHost: MQTT Host URL
mqttPort: MQTT Port number
mqttTopic: Topic to reach the ESDL Node
Example:
{ "user": "john doe", "scenarioID": "essim", "simulationDescription": "A simple ES with one geothermal source and a heat demand", "startDate": "2019-01-01T00:00:00+0100", "endDate": "2020-01-01T00:00:00+0100", "influxURL": "http://influxdb:8086", "esdlContents": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz4KPGVzZGw6RW5lcmd5U3lzdGVtIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zOmVzZGw9Imh0dHA6Ly93d3cudG5vLm5sL2VzZGwiIGVzZGxWZXJzaW9uPSJ2MjEwMiIgdmVyc2lvbj0iMSIgaWQ9ImVlMTBjYTVmLWEwOGQtNDIwMS04MjNjLWZhN2FiY2MxYmExYiIgbmFtZT0iVW50aXRsZWQgRW5lcmd5U3lzdGVtIiBkZXNjcmlwdGlvbj0iIj4KICA8ZW5lcmd5U3lzdGVtSW5mb3JtYXRpb24geHNpOnR5cGU9ImVzZGw6RW5lcmd5U3lzdGVtSW5mb3JtYXRpb24iIGlkPSI3NTE4NDJiNy04MGUxLTRlODItYTIyMi1mZGViZWNhOGE3OTciPgogICAgPGNhcnJpZXJzIHhzaTp0eXBlPSJlc2RsOkNhcnJpZXJzIiBpZD0iMGEzY2I2OTYtMjU1OC00OGY0LTllMjMtYWZmMTFlMTAyMGE0Ij4KICAgICAgPGNhcnJpZXIgeHNpOnR5cGU9ImVzZGw6SGVhdENvbW1vZGl0eSIgbmFtZT0iSGVhdCIgaWQ9ImZjZDYyZThmLWVmN2EtNDA0Yy04ZDNmLWQ5NGU5ZGQ0OGNkMyIgc3VwcGx5VGVtcGVyYXR1cmU9IjgwLjAiIHJldHVyblRlbXBlcmF0dXJlPSI0MC4wIi8+CiAgICA8L2NhcnJpZXJzPgogICAgPHF1YW50aXR5QW5kVW5pdHMgeHNpOnR5cGU9ImVzZGw6UXVhbnRpdHlBbmRVbml0cyIgaWQ9IjNmMWEzNjAzLTIwMTgtNGExNi05N2U5LTY3ZWVlZTE5NWE1YiI+CiAgICAgIDxxdWFudGl0eUFuZFVuaXQgeHNpOnR5cGU9ImVzZGw6UXVhbnRpdHlBbmRVbml0VHlwZSIgcGh5c2ljYWxRdWFudGl0eT0iRU5FUkdZIiB1bml0PSJKT1VMRSIgbXVsdGlwbGllcj0iR0lHQSIgaWQ9ImViMDdiY2NiLTIwM2YtNDA3ZS1hZjk4LWU2ODc2NTZhMjIxZCIgZGVzY3JpcHRpb249IkVuZXJneSBpbiBHSiIvPgogICAgPC9xdWFudGl0eUFuZFVuaXRzPgogIDwvZW5lcmd5U3lzdGVtSW5mb3JtYXRpb24+CiAgPGluc3RhbmNlIHhzaTp0eXBlPSJlc2RsOkluc3RhbmNlIiBuYW1lPSJVbnRpdGxlZCBJbnN0YW5jZSIgaWQ9IjQyYTY0ODU1LWRlODYtNGE2Ni1iMjY3LWIwMGM2NmI0M2I1OCI+CiAgICA8YXJlYSB4c2k6dHlwZT0iZXNkbDpBcmVhIiBuYW1lPSJVbnRpdGxlZCBBcmVhIiBpZD0iN2JjZjVjZDktZDNmZS00NjI2LTg1OWEtYzE2ZDg5ZGRmNTUyIj4KICAgICAgPGFzc2V0IHhzaTp0eXBlPSJlc2RsOkdlb3RoZXJtYWxTb3VyY2UiIG5hbWU9Ikdlb3RoZXJtYWxTb3VyY2VfYjU3MiIgaWQ9ImI1NzJkNmNiLTMxM2UtNDg5Zi1iNDg5LWE4NmJiZDZlY2QyMSI+CiAgICAgICAgPGdlb21ldHJ5IHhzaTp0eXBlPSJlc2RsOlBvaW50IiBsb249IjQuNzAyNzkyMTY3NjYzNTc1IiBDUlM9IldHUzg0IiBsYXQ9IjUyLjEyMTcwNjEzMzM3ODU5Ii8+CiAgICAgICAgPHBvcnQgeHNpOnR5cGU9ImVzZGw6T3V0UG9ydCIgaWQ9IjE1ZmY3MDk5LThiN2YtNDZhZi1iY2M0LTYzZTAzZjE3NzIyZSIgbmFtZT0iT3V0IiBjb25uZWN0ZWRUbz0iYTA5ODU3YjUtNTA5My00OTljLTgzY2UtNTRlY2M1NGE3NTE4IiBjYXJyaWVyPSJmY2Q2MmU4Zi1lZjdhLTQwNGMtOGQzZi1kOTRlOWRkNDhjZDMiPgogICAgICAgICAgPHByb2ZpbGUgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSI1LjAiIGlkPSJhMzgwNGI2Mi00MjA1LTRhZmItYmY3OC02MGNkNzNkMzM5ZjIiPgogICAgICAgICAgICA8cHJvZmlsZVF1YW50aXR5QW5kVW5pdCB4c2k6dHlwZT0iZXNkbDpRdWFudGl0eUFuZFVuaXRSZWZlcmVuY2UiIHJlZmVyZW5jZT0iZWIwN2JjY2ItMjAzZi00MDdlLWFmOTgtZTY4NzY1NmEyMjFkIi8+CiAgICAgICAgICA8L3Byb2ZpbGU+CiAgICAgICAgPC9wb3J0PgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6SGVhdGluZ0RlbWFuZCIgbmFtZT0iSGVhdGluZ0RlbWFuZF9iNTA1IiBpZD0iYjUwNWMxMGItYmRlNC00NjA2LThkNjgtN2Y4ZTAxODhjMzgzIj4KICAgICAgICA8Z2VvbWV0cnkgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIGxvbj0iNC43MTIzODM3NDcxMDA4MzEiIENSUz0iV0dTODQiIGxhdD0iNTIuMTIxOTE2OTI4MzE4ODYiLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSIxNWZmNzA5OS04YjdmLTQ2YWYtYmNjNC02M2UwM2YxNzcyMmUiIGlkPSJhMDk4NTdiNS01MDkzLTQ5OWMtODNjZS01NGVjYzU0YTc1MTgiIG5hbWU9IkluIiBjYXJyaWVyPSJmY2Q2MmU4Zi1lZjdhLTQwNGMtOGQzZi1kOTRlOWRkNDhjZDMiPgogICAgICAgICAgPHByb2ZpbGUgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSI1LjAiIGlkPSJlNGU2OTE5YS1jNTY4LTRlNTgtODkwNC1jZmUzMWI5YjVkN2MiPgogICAgICAgICAgICA8cHJvZmlsZVF1YW50aXR5QW5kVW5pdCB4c2k6dHlwZT0iZXNkbDpRdWFudGl0eUFuZFVuaXRSZWZlcmVuY2UiIHJlZmVyZW5jZT0iZWIwN2JjY2ItMjAzZi00MDdlLWFmOTgtZTY4NzY1NmEyMjFkIi8+CiAgICAgICAgICA8L3Byb2ZpbGU+CiAgICAgICAgPC9wb3J0PgogICAgICA8L2Fzc2V0PgogICAgPC9hcmVhPgogIDwvaW5zdGFuY2U+CjwvZXNkbDpFbmVyZ3lTeXN0ZW0+Cg" }
- Response:
- CREATED (HTTP status code - 201)
status: CREATED
id: Unique ID for this simulation run. This ID will be tagged in all simulation data from this run.
Example:
{ "status": "CREATED", "id": "60c0c0a84840404e8b19df9b" }
- BAD REQUEST (HTTP status code - 400)
status: ERROR
description: Description of the error
Example:
{ "status": "ERROR", "description": "Internal error: Error in Observation Manager init: Connecting to InfluxDB @ http://non-existing-host:8088 timed out. Please check URL!" }
- SERVICE UNAVAILABLE (HTTP status code - 503)
If a simulation is already running while a new one is started, HTTP status code 503 is returned with a text body
Busy.
/simulation/<simulation-id>
HTTP Method: GET
Description: Retrieve meta-data of simulation run. This includes information provided by the user at the time of starting the simulation and some run-time data. This API call can be used to retrieve the dashboard URL as soon as a simulation is CREATED
- Request Body:
None
- Response:
- NOT FOUND (HTTP status code - 404)
status: ERROR
description: Description of the error
Example:
{ "status": "ERROR", "description": "SimulationID 60c0c0a84840404e8b19479b not found!" }
- OK (HTTP status code - 200)
status: The last known status of the simulation.
simRunDate: The date when the simulation was run in ISO-8601 format (
YYYY-MM-DDTHH:mm:ss±hh:mm).transport: An HTML visualisation of ESSIM’s internal transport network trees created per commodity. The HTML pages are URL-encoded and tagged with the name of the network.
dashboardURL: A link to the Grafana dashboard created by ESSIM for this simulation.
Example:
{ "esdlContents": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz4KPGVzZGw6RW5lcmd5U3lzdGVtIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zOmVzZGw9Imh0dHA6Ly93d3cudG5vLm5sL2VzZGwiIGVzZGxWZXJzaW9uPSJ2MjEwMiIgdmVyc2lvbj0iMSIgaWQ9ImVlMTBjYTVmLWEwOGQtNDIwMS04MjNjLWZhN2FiY2MxYmExYiIgbmFtZT0iVW50aXRsZWQgRW5lcmd5U3lzdGVtIiBkZXNjcmlwdGlvbj0iIj4KICA8ZW5lcmd5U3lzdGVtSW5mb3JtYXRpb24geHNpOnR5cGU9ImVzZGw6RW5lcmd5U3lzdGVtSW5mb3JtYXRpb24iIGlkPSI3NTE4NDJiNy04MGUxLTRlODItYTIyMi1mZGViZWNhOGE3OTciPgogICAgPGNhcnJpZXJzIHhzaTp0eXBlPSJlc2RsOkNhcnJpZXJzIiBpZD0iMGEzY2I2OTYtMjU1OC00OGY0LTllMjMtYWZmMTFlMTAyMGE0Ij4KICAgICAgPGNhcnJpZXIgeHNpOnR5cGU9ImVzZGw6SGVhdENvbW1vZGl0eSIgbmFtZT0iSGVhdCIgaWQ9ImZjZDYyZThmLWVmN2EtNDA0Yy04ZDNmLWQ5NGU5ZGQ0OGNkMyIgc3VwcGx5VGVtcGVyYXR1cmU9IjgwLjAiIHJldHVyblRlbXBlcmF0dXJlPSI0MC4wIi8+CiAgICA8L2NhcnJpZXJzPgogICAgPHF1YW50aXR5QW5kVW5pdHMgeHNpOnR5cGU9ImVzZGw6UXVhbnRpdHlBbmRVbml0cyIgaWQ9IjNmMWEzNjAzLTIwMTgtNGExNi05N2U5LTY3ZWVlZTE5NWE1YiI+CiAgICAgIDxxdWFudGl0eUFuZFVuaXQgeHNpOnR5cGU9ImVzZGw6UXVhbnRpdHlBbmRVbml0VHlwZSIgcGh5c2ljYWxRdWFudGl0eT0iRU5FUkdZIiB1bml0PSJKT1VMRSIgbXVsdGlwbGllcj0iR0lHQSIgaWQ9ImViMDdiY2NiLTIwM2YtNDA3ZS1hZjk4LWU2ODc2NTZhMjIxZCIgZGVzY3JpcHRpb249IkVuZXJneSBpbiBHSiIvPgogICAgPC9xdWFudGl0eUFuZFVuaXRzPgogIDwvZW5lcmd5U3lzdGVtSW5mb3JtYXRpb24+CiAgPGluc3RhbmNlIHhzaTp0eXBlPSJlc2RsOkluc3RhbmNlIiBuYW1lPSJVbnRpdGxlZCBJbnN0YW5jZSIgaWQ9IjQyYTY0ODU1LWRlODYtNGE2Ni1iMjY3LWIwMGM2NmI0M2I1OCI+CiAgICA8YXJlYSB4c2k6dHlwZT0iZXNkbDpBcmVhIiBuYW1lPSJVbnRpdGxlZCBBcmVhIiBpZD0iN2JjZjVjZDktZDNmZS00NjI2LTg1OWEtYzE2ZDg5ZGRmNTUyIj4KICAgICAgPGFzc2V0IHhzaTp0eXBlPSJlc2RsOkdlb3RoZXJtYWxTb3VyY2UiIG5hbWU9Ikdlb3RoZXJtYWxTb3VyY2VfYjU3MiIgaWQ9ImI1NzJkNmNiLTMxM2UtNDg5Zi1iNDg5LWE4NmJiZDZlY2QyMSI+CiAgICAgICAgPGdlb21ldHJ5IHhzaTp0eXBlPSJlc2RsOlBvaW50IiBsb249IjQuNzAyNzkyMTY3NjYzNTc1IiBDUlM9IldHUzg0IiBsYXQ9IjUyLjEyMTcwNjEzMzM3ODU5Ii8+CiAgICAgICAgPHBvcnQgeHNpOnR5cGU9ImVzZGw6T3V0UG9ydCIgaWQ9IjE1ZmY3MDk5LThiN2YtNDZhZi1iY2M0LTYzZTAzZjE3NzIyZSIgbmFtZT0iT3V0IiBjb25uZWN0ZWRUbz0iYTA5ODU3YjUtNTA5My00OTljLTgzY2UtNTRlY2M1NGE3NTE4IiBjYXJyaWVyPSJmY2Q2MmU4Zi1lZjdhLTQwNGMtOGQzZi1kOTRlOWRkNDhjZDMiPgogICAgICAgICAgPHByb2ZpbGUgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSI1LjAiIGlkPSJhMzgwNGI2Mi00MjA1LTRhZmItYmY3OC02MGNkNzNkMzM5ZjIiPgogICAgICAgICAgICA8cHJvZmlsZVF1YW50aXR5QW5kVW5pdCB4c2k6dHlwZT0iZXNkbDpRdWFudGl0eUFuZFVuaXRSZWZlcmVuY2UiIHJlZmVyZW5jZT0iZWIwN2JjY2ItMjAzZi00MDdlLWFmOTgtZTY4NzY1NmEyMjFkIi8+CiAgICAgICAgICA8L3Byb2ZpbGU+CiAgICAgICAgPC9wb3J0PgogICAgICA8L2Fzc2V0PgogICAgICA8YXNzZXQgeHNpOnR5cGU9ImVzZGw6SGVhdGluZ0RlbWFuZCIgbmFtZT0iSGVhdGluZ0RlbWFuZF9iNTA1IiBpZD0iYjUwNWMxMGItYmRlNC00NjA2LThkNjgtN2Y4ZTAxODhjMzgzIj4KICAgICAgICA8Z2VvbWV0cnkgeHNpOnR5cGU9ImVzZGw6UG9pbnQiIGxvbj0iNC43MTIzODM3NDcxMDA4MzEiIENSUz0iV0dTODQiIGxhdD0iNTIuMTIxOTE2OTI4MzE4ODYiLz4KICAgICAgICA8cG9ydCB4c2k6dHlwZT0iZXNkbDpJblBvcnQiIGNvbm5lY3RlZFRvPSIxNWZmNzA5OS04YjdmLTQ2YWYtYmNjNC02M2UwM2YxNzcyMmUiIGlkPSJhMDk4NTdiNS01MDkzLTQ5OWMtODNjZS01NGVjYzU0YTc1MTgiIG5hbWU9IkluIiBjYXJyaWVyPSJmY2Q2MmU4Zi1lZjdhLTQwNGMtOGQzZi1kOTRlOWRkNDhjZDMiPgogICAgICAgICAgPHByb2ZpbGUgeHNpOnR5cGU9ImVzZGw6U2luZ2xlVmFsdWUiIHZhbHVlPSI1LjAiIGlkPSJlNGU2OTE5YS1jNTY4LTRlNTgtODkwNC1jZmUzMWI5YjVkN2MiPgogICAgICAgICAgICA8cHJvZmlsZVF1YW50aXR5QW5kVW5pdCB4c2k6dHlwZT0iZXNkbDpRdWFudGl0eUFuZFVuaXRSZWZlcmVuY2UiIHJlZmVyZW5jZT0iZWIwN2JjY2ItMjAzZi00MDdlLWFmOTgtZTY4NzY1NmEyMjFkIi8+CiAgICAgICAgICA8L3Byb2ZpbGU+CiAgICAgICAgPC9wb3J0PgogICAgICA8L2Fzc2V0PgogICAgPC9hcmVhPgogIDwvaW5zdGFuY2U+CjwvZXNkbDpFbmVyZ3lTeXN0ZW0+Cg", "user": "john doe", "scenarioID": "essim", "simulationDescription": "A simple ES with one geothermal source and a heat demand", "startDate": "2018-12-31T23:00:00+0000", "endDate": "2019-12-31T23:00:00+0000", "status": { "state": "COMPLETE", "description": "Finished in PT1.099S" }, "influxURL": "http://influxdb:8086", "simRunDate": "2021-06-09T13:22:48+0000", "transport": [ { "name": "Untitled EnergySystem Heat Network 0", "networkHTMLDiag": "%3C%21DOCTYPE+html%3E%0A%3Chtml+lang%3D%22en%22%3E%0A++%3Chead%3E%0A++++%3Cmeta+charset%3D%22utf-8%22%3E%0A%0A++++%3Ctitle%3E%0A%09Untitled+EnergySystem+Heat+Network+0%0A%09%3C%2Ftitle%3E%0A%0A++++%3Cstyle%3E%0A++++%0A++++.node+%7B%0A++++++++cursor%3A+pointer%3B%0A++++%7D%0A%0A++++.node+circle+%7B%0A++++++fill%3A+%23fff%3B%0A++++++stroke%3A+steelblue%3B%0A++++++stroke-width%3A+3px%3B%0A++++%7D%0A%0A++++.node+text+%7B%0A++++++font%3A+12px+sans-serif%3B%0A++++%7D%0A%0A++++.link+%7B%0A++++++fill%3A+none%3B%0A++++++stroke%3A+%23ccc%3B%0A++++++stroke-width%3A+2px%3B%0A++++%7D%0A++++%0A++++%3C%2Fstyle%3E%0A%0A++%3C%2Fhead%3E%0A%0A++%3Cbody%3E%0A%0A%3C%21--+load+the+d3.js+library+--%3E+%0A%3Cscript+src%3D%22http%3A%2F%2Fd3js.org%2Fd3.v3.min.js%22%3E%3C%2Fscript%3E%0A++++%0A%3Cscript%3E%0A%0Avar+treeData%3D%5B%7B%22parent%22%3A%22null%22%2C%22children%22%3A%5B%7B%22parent%22%3A%22GeothermalSource_b572%28PRODUCER%29%22%2C%22name%22%3A%22b505c10b-bde4-4606-8d68-7f8e0188c383%28CONSUMER%29%22%7D%5D%2C%22name%22%3A%22GeothermalSource_b572%28PRODUCER%29%22%7D%5D%3B%0A%0A%2F%2F+**************+Generate+the+tree+diagram++*****************%0Avar+margin+%3D+%7Btop%3A+20%2C+right%3A+120%2C+bottom%3A+20%2C+left%3A+200%7D%2C%0A++++width+%3D+1960+-+margin.right+-+margin.left%2C%0A++++height+%3D+500+-+margin.top+-+margin.bottom%3B%0A++++%0Avar+i+%3D+0%2C%0A++++duration+%3D+750%2C%0A++++root%3B%0A%0Avar+tree+%3D+d3.layout.tree%28%29%0A++++.size%28%5Bheight%2C+width%5D%29%3B%0A%0Avar+diagonal+%3D+d3.svg.diagonal%28%29%0A++++.projection%28function%28d%29+%7B+return+%5Bd.y%2C+d.x%5D%3B+%7D%29%3B%0A%0Avar+svg+%3D+d3.select%28%22body%22%29.append%28%22svg%22%29%0A++++.attr%28%22width%22%2C+width+%2B+margin.right+%2B+margin.left%29%0A++++.attr%28%22height%22%2C+height+%2B+margin.top+%2B+margin.bottom%29%0A++.append%28%22g%22%29%0A++++.attr%28%22transform%22%2C+%22translate%28%22+%2B+margin.left+%2B+%22%2C%22+%2B+margin.top+%2B+%22%29%22%29%3B%0A%0Aroot+%3D+treeData%5B0%5D%3B%0Aroot.x0+%3D+height+%2F+2%3B%0Aroot.y0+%3D+0%3B%0A++%0Aupdate%28root%29%3B%0A%0Ad3.select%28self.frameElement%29.style%28%22height%22%2C+%22500px%22%29%3B%0A%0Afunction+update%28source%29+%7B%0A%0A++%2F%2F+Compute+the+new+tree+layout.%0A++var+nodes+%3D+tree.nodes%28root%29.reverse%28%29%2C%0A++++++links+%3D+tree.links%28nodes%29%3B%0A%0A++%2F%2F+Normalize+for+fixed-depth.%0A++nodes.forEach%28function%28d%29+%7B+d.y+%3D+d.depth+*+250%3B+%7D%29%3B%0A%0A++%2F%2F+Update+the+nodes%E2%80%A6%0A++var+node+%3D+svg.selectAll%28%22g.node%22%29%0A++++++.data%28nodes%2C+function%28d%29+%7B+return+d.id+%7C%7C+%28d.id+%3D+%2B%2Bi%29%3B+%7D%29%3B%0A%0A++%2F%2F+Enter+any+new+nodes+at+the+parent%27s+previous+position.%0A++var+nodeEnter+%3D+node.enter%28%29.append%28%22g%22%29%0A++++++.attr%28%22class%22%2C+%22node%22%29%0A++++++.attr%28%22transform%22%2C+function%28d%29+%7B+return+%22translate%28%22+%2B+source.y0+%2B+%22%2C%22+%2B+source.x0+%2B+%22%29%22%3B+%7D%29%0A++++++.on%28%22click%22%2C+click%29%3B%0A%0A++nodeEnter.append%28%22circle%22%29%0A++++++.attr%28%22r%22%2C+1e-6%29%0A++++++.style%28%22fill%22%2C+function%28d%29+%7B+return+d._children+%3F+%22lightsteelblue%22+%3A+%22%23fff%22%3B+%7D%29%3B%0A%0A++nodeEnter.append%28%22text%22%29%0A++++++.attr%28%22x%22%2C+function%28d%29+%7B+return+d.children+%7C%7C+d._children+%3F+-13+%3A+13%3B+%7D%29%0A++++++.attr%28%22dy%22%2C+%22.35em%22%29%0A++++++.attr%28%22text-anchor%22%2C+function%28d%29+%7B+return+d.children+%7C%7C+d._children+%3F+%22end%22+%3A+%22start%22%3B+%7D%29%0A++++++.text%28function%28d%29+%7B+return+d.name%3B+%7D%29%0A++++++.style%28%22fill-opacity%22%2C+1e-6%29%3B%0A%0A++%2F%2F+Transition+nodes+to+their+new+position.%0A++var+nodeUpdate+%3D+node.transition%28%29%0A++++++.duration%28duration%29%0A++++++.attr%28%22transform%22%2C+function%28d%29+%7B+return+%22translate%28%22+%2B+d.y+%2B+%22%2C%22+%2B+d.x+%2B+%22%29%22%3B+%7D%29%3B%0A%0A++nodeUpdate.select%28%22circle%22%29%0A++++++.attr%28%22r%22%2C+10%29%0A++++++.style%28%22fill%22%2C+function%28d%29+%7B+return+d._children+%3F+%22lightsteelblue%22+%3A+%22%23fff%22%3B+%7D%29%3B%0A%0A++nodeUpdate.select%28%22text%22%29%0A++++++.style%28%22fill-opacity%22%2C+1%29%3B%0A%0A++%2F%2F+Transition+exiting+nodes+to+the+parent%27s+new+position.%0A++var+nodeExit+%3D+node.exit%28%29.transition%28%29%0A++++++.duration%28duration%29%0A++++++.attr%28%22transform%22%2C+function%28d%29+%7B+return+%22translate%28%22+%2B+source.y+%2B+%22%2C%22+%2B+source.x+%2B+%22%29%22%3B+%7D%29%0A++++++.remove%28%29%3B%0A%0A++nodeExit.select%28%22circle%22%29%0A++++++.attr%28%22r%22%2C+1e-6%29%3B%0A%0A++nodeExit.select%28%22text%22%29%0A++++++.style%28%22fill-opacity%22%2C+1e-6%29%3B%0A%0A++%2F%2F+Update+the+links%E2%80%A6%0A++var+link+%3D+svg.selectAll%28%22path.link%22%29%0A++++++.data%28links%2C+function%28d%29+%7B+return+d.target.id%3B+%7D%29%3B%0A%0A++%2F%2F+Enter+any+new+links+at+the+parent%27s+previous+position.%0A++link.enter%28%29.insert%28%22path%22%2C+%22g%22%29%0A++++++.attr%28%22class%22%2C+%22link%22%29%0A++++++.attr%28%22d%22%2C+function%28d%29+%7B%0A++++++++var+o+%3D+%7Bx%3A+source.x0%2C+y%3A+source.y0%7D%3B%0A++++++++return+diagonal%28%7Bsource%3A+o%2C+target%3A+o%7D%29%3B%0A++++++%7D%29%3B%0A%0A++%2F%2F+Transition+links+to+their+new+position.%0A++link.transition%28%29%0A++++++.duration%28duration%29%0A++++++.attr%28%22d%22%2C+diagonal%29%3B%0A%0A++%2F%2F+Transition+exiting+nodes+to+the+parent%27s+new+position.%0A++link.exit%28%29.transition%28%29%0A++++++.duration%28duration%29%0A++++++.attr%28%22d%22%2C+function%28d%29+%7B%0A++++++++var+o+%3D+%7Bx%3A+source.x%2C+y%3A+source.y%7D%3B%0A++++++++return+diagonal%28%7Bsource%3A+o%2C+target%3A+o%7D%29%3B%0A++++++%7D%29%0A++++++.remove%28%29%3B%0A%0A++%2F%2F+Stash+the+old+positions+for+transition.%0A++nodes.forEach%28function%28d%29+%7B%0A++++d.x0+%3D+d.x%3B%0A++++d.y0+%3D+d.y%3B%0A++%7D%29%3B%0A%7D%0A%0A%2F%2F+Toggle+children+on+click.%0Afunction+click%28d%29+%7B%0A++if+%28d.children%29+%7B%0A++++d._children+%3D+d.children%3B%0A++++d.children+%3D+null%3B%0A++%7D+else+%7B%0A++++d.children+%3D+d._children%3B%0A++++d._children+%3D+null%3B%0A++%7D%0A++update%28d%29%3B%0A%7D%0A%0A%3C%2Fscript%3E%0A++++%0A++%3C%2Fbody%3E%0A%3C%2Fhtml%3E" } ], "dashboardURL": "https://essim-dashboard.hesi.energy/d/gUtvSu6Mk/untitled-energysystem-john-doe-2021-06-09t13-22-48-55" }
/simulation/<simulation-id>/status
HTTP Method: GET
Description: Retrieve status of a simulation run. This API can be used as soon as a simulation is CREATED
- Request Body:
None
- Response:
- NOT FOUND (HTTP status code - 404)
status: ERROR
description: Description of the error
Example:
{ "status": "ERROR", "description": "SimulationID 60c0c0a84840404e8b19479b not found!" }
- OK (HTTP status code - 200)
- Running
State: RUNNING
Description: Percentage progress of the simulation as a limiting to 1.0
{ "State": "RUNNING" "Description": "0.7604529616724739", }
- Finished
State: COMPLETE
Description: Time for simulation to complete
{ "State": "COMPLETE" "Description": "Finished in PT35.306S", }
- Error
State: ERROR
Description: Description of the error
{ "State": "ERROR" "Description": "Cannot connect to InfluxDB service at [http://non-existing-host:8086] to query profile with id 3499a337-1785-4601-8098-3c46b6d42b7c. Please verify the URL!", }
Code Example
Following is a simple code example to access the ESSIM APIs using python. Before you run this example:
Copy the ESDL file below the python example to the same folder as the script. Adjust the name of the file in the script (line 21) appropriately if the name of the ESDL file is changed.
Install the necessary python libraries using
pip install requests pytz.Start ESSIM following the instructions here.
Python Code:
1import json 2import time 3import pytz 4import base64 5import requests 6from os import path 7from datetime import datetime as dt 8 9# Common Constants 10ESSIM_URL = 'http://localhost:8112/essim/simulation' 11INFLUXDB_URL = 'http://influxdb:8086' 12ESSIM_HEADERS = {'Content-Type': 'application/json', 'Accept': 'application/json'} 13ESSIM_DATE_FORMAT = '%Y-%m-%dT%H:%M:%S%z' 14PROGRESS_UPDATE_INTERVAL = 1 # in seconds 15 16# Simulation-specific constants 17ESSIM_USER = 'John Doe' 18ESSIM_SCENARIO_ID = 'TestScenario' 19ESDL_FILE = 'SmallestESDL_np.esdl' 20SIMULATION_DESCRIPTION = 'Testing ESSIM API' 21START_DATE = dt(2021, 1, 1, 0, 0, 0, 0, pytz.UTC) 22END_DATE = dt(2022, 1, 1, 0, 0, 0, 0, pytz.UTC) 23 24 25class ESSIMSimulation: 26 27 def __init__(self, esdl_file): 28 """ 29 Constructor to create an ESSIM Simulation object 30 :param esdl_file: Path to ESDL file to simulate with ESSIM 31 """ 32 self.simulation_id = None 33 self.dashboardURL = None 34 self.esdl_file = esdl_file 35 if not path.exists(self.esdl_file): 36 raise ValueError('File {} does not exist!'.format(path.abspath(self.esdl_file))) 37 38 def encode_esdl(self): 39 """ 40 Function to encode contents of ESDL file into Base64 41 :return: Base64-encoded contents of ESDL file 42 """ 43 with open(self.esdl_file, 'r') as f: 44 esdl_string = f.read().replace('\n', '') 45 message_bytes = esdl_string.encode('utf-8') 46 base64_bytes = base64.b64encode(message_bytes) 47 encoded_esdl = base64_bytes.decode('utf-8') 48 return encoded_esdl 49 50 def display_dashboard_url(self): 51 """ 52 Function to display the Grafana Dashboard URL 53 """ 54 if self.simulation_id is None: 55 print('No simulation is started yet!') 56 return 57 status_path = '{}/{}'.format(ESSIM_URL, self.simulation_id) 58 r = requests.get(url=status_path, headers=ESSIM_HEADERS) 59 response = r.json() 60 status_code = r.status_code 61 if status_code == 200: 62 if 'dashboardURL' in response: 63 self.dashboardURL = response['dashboardURL'] 64 print('Dashboard URL: {}'.format(self.dashboardURL)) 65 else: 66 print('Dashboard URL not found! Simulation meta-data looks like so:\n{}'.format( 67 json.dumps(response, indent=4, sort_keys=True))) 68 elif status_code == 404: 69 print(response['Description']) 70 71 def display_progress(self): 72 """ 73 Function to display progress of ESSIM simulation 74 """ 75 if self.simulation_id is None: 76 print('No simulation is started yet!') 77 return 78 79 status_path = '{}/{}/status'.format(ESSIM_URL, self.simulation_id) 80 while True: 81 r = requests.get(url=status_path, headers=ESSIM_HEADERS) 82 response = r.json() 83 status_code = r.status_code 84 if status_code == 200: 85 if response['State'] == 'RUNNING': 86 print('{:.1f}% complete'.format(100 * float(response['Description']))) 87 time.sleep(PROGRESS_UPDATE_INTERVAL) 88 elif response['State'] == 'COMPLETE': 89 print('Simulation {}'.format(response['Description'])) 90 break 91 elif response['State'] == 'ERROR': 92 print('Simulation failed because of {}'.format(response['Description'])) 93 break 94 elif status_code == 404: 95 print(response['Description']) 96 break 97 98 def start_simulation(self): 99 """ 100 Function to start an ESSIM simulation 101 """ 102 while True: 103 data = { 104 'user': ESSIM_USER, 105 'startDate': START_DATE.strftime(ESSIM_DATE_FORMAT), 106 'endDate': END_DATE.strftime(ESSIM_DATE_FORMAT), 107 'scenarioID': ESSIM_SCENARIO_ID, 108 'simulationDescription': SIMULATION_DESCRIPTION, 109 'influxURL': INFLUXDB_URL, 110 'esdlContents': self.encode_esdl() 111 } 112 print('Starting ESSIM Simulation') 113 r = requests.post(url=ESSIM_URL, data=json.dumps(data), headers=ESSIM_HEADERS) 114 response = r.json() 115 status_code = r.status_code 116 if status_code == 201: 117 self.simulation_id = response['id'] 118 print( 119 'Successfully started ESSIM Simulation with id {id}'.format(id=response['id'])) 120 break 121 elif status_code == 503: 122 print('The ESSIM Engine is busy. Retrying in 5 seconds...') 123 time.sleep(5) 124 else: 125 error = response['description'] 126 print('ESSIM Simulation failed because: {reason}'.format(reason=error)) 127 break 128 129 130if __name__ == '__main__': 131 essim = ESSIMSimulation(ESDL_FILE) 132 essim.start_simulation() 133 essim.display_dashboard_url() 134 essim.display_progress() 135 print('Done!')
ESDL File (sim.esdl):
<?xml version='1.0' encoding='UTF-8'?>
<esdl:EnergySystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:esdl="http://www.tno.nl/esdl" esdlVersion="v2102" version="3" id="ee10ca5f-a08d-4201-823c-fa7abcc1ba1b" name="Untitled EnergySystem" description="">
<energySystemInformation xsi:type="esdl:EnergySystemInformation" id="751842b7-80e1-4e82-a222-fdebeca8a797">
<carriers xsi:type="esdl:Carriers" id="0a3cb696-2558-48f4-9e23-aff11e1020a4">
<carrier xsi:type="esdl:HeatCommodity" name="Heat" id="fcd62e8f-ef7a-404c-8d3f-d94e9dd48cd3" supplyTemperature="80.0" returnTemperature="40.0"/>
</carriers>
<quantityAndUnits xsi:type="esdl:QuantityAndUnits" id="3f1a3603-2018-4a16-97e9-67eeee195a5b">
<quantityAndUnit xsi:type="esdl:QuantityAndUnitType" physicalQuantity="ENERGY" unit="JOULE" multiplier="GIGA" id="eb07bccb-203f-407e-af98-e687656a221d" description="Energy in GJ"/>
</quantityAndUnits>
</energySystemInformation>
<instance xsi:type="esdl:Instance" name="Untitled Instance" id="42a64855-de86-4a66-b267-b00c66b43b58">
<area xsi:type="esdl:Area" name="Untitled Area" id="7bcf5cd9-d3fe-4626-859a-c16d89ddf552">
<asset xsi:type="esdl:GeothermalSource" name="GeothermalSource_b572" id="b572d6cb-313e-489f-b489-a86bbd6ecd21">
<geometry xsi:type="esdl:Point" lon="4.702792167663575" CRS="WGS84" lat="52.12170613337859"/>
<port xsi:type="esdl:OutPort" id="15ff7099-8b7f-46af-bcc4-63e03f17722e" name="Out" connectedTo="a09857b5-5093-499c-83ce-54ecc54a7518" carrier="fcd62e8f-ef7a-404c-8d3f-d94e9dd48cd3">
<profile xsi:type="esdl:SingleValue" value="5.0" id="a3804b62-4205-4afb-bf78-60cd73d339f2">
<profileQuantityAndUnit xsi:type="esdl:QuantityAndUnitReference" reference="eb07bccb-203f-407e-af98-e687656a221d"/>
</profile>
</port>
</asset>
<asset xsi:type="esdl:HeatingDemand" name="HeatingDemand_b505" id="b505c10b-bde4-4606-8d68-7f8e0188c383">
<geometry xsi:type="esdl:Point" lon="4.712383747100831" CRS="WGS84" lat="52.12191692831886"/>
<port xsi:type="esdl:InPort" connectedTo="15ff7099-8b7f-46af-bcc4-63e03f17722e" id="a09857b5-5093-499c-83ce-54ecc54a7518" name="In" carrier="fcd62e8f-ef7a-404c-8d3f-d94e9dd48cd3">
<profile xsi:type="esdl:SingleValue" value="5.0" id="e19ae2d6-3ff7-494c-b8bf-86450d855838">
<profileQuantityAndUnit xsi:type="esdl:QuantityAndUnitReference" reference="eb07bccb-203f-407e-af98-e687656a221d"/>
</profile>
</port>
</asset>
</area>
</instance>
</esdl:EnergySystem>