Create Simulation
This example demonstrates how to create and run a thermal simulation on an existing G-Code in the Helio Additive platform. Simulations analyze the thermal properties of your print to identify potential quality issues.
GraphQL Operations
Section titled “GraphQL Operations”Create the following GraphQL files, then run your language’s codegen tool to generate the types.
mutation CreateSimulation($input: CreateSimulationInput!) { createSimulation(input: $input) { id name }}query Simulation($id: ID!) { simulation(id: $id) { id name status progress thermalIndexGcodeUrl }}API Reference:
- CreateSimulationInput - Input parameters for creating a simulation
- SimulationStatus enum - Possible simulation status values
- Simulation type - Full simulation object structure
Code Example
Section titled “Code Example”-
Setup the client and configuration
index.ts import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client";import { CreateSimulationDocument } from "./mutations/__generated/CreateSimulation.generated";import { SimulationDocument } from "./queries/__generated/Simulation.generated";// Load PAT from environmentconst PAT = process.env.PAT;if (!PAT) {throw new Error("PAT environment variable is required");}// Create Apollo Clientconst client = new ApolloClient({cache: new InMemoryCache(),link: new HttpLink({uri: "https://api.helioadditive.com/graphql",headers: {"Content-Type": "application/json",Authorization: `Bearer ${PAT}`,},}),});// Replace with an actual G-Code ID from your accountconst GCODE_ID = process.env.GCODE_ID ?? "your-gcode-id";main.py import asyncioimport osimport timeimport httpxfrom client.client import Client# Load PAT from environmentPAT = os.environ.get("PAT")if not PAT:raise ValueError("PAT environment variable is required")# Replace with an actual G-Code ID from your accountGCODE_ID = os.environ.get("GCODE_ID", "your-gcode-id")# Create GraphQL clientheaders = {"Authorization": f"Bearer {PAT}"}graphql_client = Client(url="https://api.helioadditive.com/graphql",headers=headers,http_client=httpx.AsyncClient(headers=headers, timeout=60))src/main.rs use graphql_client::{GraphQLQuery, Response};use reqwest::header::{AUTHORIZATION, CONTENT_TYPE};use std::time::{Duration, SystemTime, UNIX_EPOCH};#[derive(GraphQLQuery)]#[graphql(schema_path = "schema.graphqls",query_path = "mutations/CreateSimulation.graphql",response_derives = "Debug")]struct CreateSimulation;#[derive(GraphQLQuery)]#[graphql(schema_path = "schema.graphqls",query_path = "queries/Simulation.graphql",response_derives = "Debug")]struct Simulation;// Load from environment in main()let pat = std::env::var("PAT").expect("PAT environment variable must be set");let gcode_id = std::env::var("GCODE_ID").unwrap_or_else(|_| "your-gcode-id".to_string());src/main.cpp #include <iostream>#include <string>#include <thread>#include <chrono>#include <cstdlib>#include <cpr/cpr.h>#include <boost/json.hpp>#include "CreateSimulationClient.h"#include "SimulationClient.h"#include "graphqlservice/GraphQLResponse.h"#include "graphqlservice/JSONResponse.h"namespace CreateSimulation = graphql::client::mutation::CreateSimulation;namespace Simulation = graphql::client::query::Simulation;// Helper function to send GraphQL HTTP requestsgraphql::response::Value sendHttpRequest(const std::string& query,graphql::response::Value& variables,const std::string& pat) {std::string body = boost::json::serialize(boost::json::object{{"query", query},{"variables", boost::json::parse(graphql::response::toJSON(std::move(variables))).as_object()}});auto response = cpr::Post(cpr::Url{"https://api.helioadditive.com/graphql"},cpr::Header{{"Content-Type", "application/json"},{"Authorization", "Bearer " + pat}},cpr::Body{body});return graphql::response::parseJSON(boost::json::serialize(boost::json::parse(response.text).as_object()["data"].as_object()));}// Load PAT from environment in main()const char* pat_env = std::getenv("PAT");if (!pat_env) {std::cerr << "PAT environment variable is required" << std::endl;return 1;}std::string pat(pat_env);// Replace with an actual G-Code ID from your accountconst char* gcode_env = std::getenv("GCODE_ID");std::string gcodeId = gcode_env ? gcode_env : "your-gcode-id"; -
Create the simulation
Create a new simulation for the specified G-Code.
async function createSimulationEntry(gcodeId: string, name: string) {const { data } = await client.mutate({mutation: CreateSimulationDocument,variables: {input: {gcodeId: gcodeId,name: name,},},});const simulationId = data?.createSimulation?.id;if (!simulationId) {throw new Error("Failed to create simulation");}return simulationId;}async def create_simulation_entry(gcode_id: str, name: str) -> str:"""Create a simulation and return its ID."""result = await graphql_client.create_simulation(input={"gcodeId": gcode_id,"name": name,})return result.idasync fn create_simulation_entry(client: &reqwest::Client,pat: &str,gcode_id: &str,name: &str,) -> Result<String, Box<dyn std::error::Error>> {let variables = create_simulation::Variables {input: create_simulation::CreateSimulationInput {gcode_id: gcode_id.to_string(),name: name.to_string(),room_temperature: None,stabilized_air_temperature: None,constant_nozzle_temperature: None,constant_platform_temperature: None,constant_fan_speed: None,air_temperature_above_build_plate: None,},};let response = client.post("https://api.helioadditive.com/graphql").header(CONTENT_TYPE, "application/json").header(AUTHORIZATION, format!("Bearer {}", pat)).json(&CreateSimulation::build_query(variables)).send().await?;let body: Response<create_simulation::ResponseData> = response.json().await?;Ok(body.data.unwrap().create_simulation.id)}std::string createSimulationEntry(const std::string& gcodeId,const std::string& name,const std::string& pat) {const std::string query = CreateSimulation::GetRequestText();graphql::response::Value variables = CreateSimulation::serializeVariables(CreateSimulation::Variables{.input = CreateSimulation::CreateSimulationInput{.gcodeId = gcodeId,.name = name}});auto response = CreateSimulation::parseResponse(sendHttpRequest(query, variables, pat));return response.createSimulation.id;} -
Poll and wait for simulation to complete
After creation, the simulation needs to run. Poll the status until it’s finished.
async function waitForSimulationComplete(simulationId: string): Promise<void> {return new Promise((resolve, reject) => {const checkStatus = async () => {const { data } = await client.query({query: SimulationDocument,variables: { id: simulationId },fetchPolicy: "no-cache",});const status = data?.simulation?.status;const progress = data?.simulation?.progress;console.log(`Simulation status: ${status}, progress: ${progress}%`);if (status === "FINISHED") {console.log(`Thermal Index G-Code URL: ${data?.simulation?.thermalIndexGcodeUrl}`);resolve();} else if (status === "FAILED") {reject(new Error("Simulation failed"));} else {// Poll every 2 secondssetTimeout(checkStatus, 2000);}};checkStatus();});}async def wait_for_simulation_complete(simulation_id: str) -> None:"""Poll until the simulation is complete."""while True:result = await graphql_client.simulation(id=simulation_id)status = result.statusprogress = result.progressprint(f"Simulation status: {status}, progress: {progress}%")if status == "FINISHED":print(f"Thermal Index G-Code URL: {result.thermal_index_gcode_url}")returnelif status == "FAILED":raise Exception("Simulation failed")await asyncio.sleep(2)async fn wait_for_simulation_complete(client: &reqwest::Client,pat: &str,simulation_id: &str,) -> Result<(), Box<dyn std::error::Error>> {loop {let variables = simulation::Variables {id: simulation_id.to_string(),};let response = client.post("https://api.helioadditive.com/graphql").header(CONTENT_TYPE, "application/json").header(AUTHORIZATION, format!("Bearer {}", pat)).json(&Simulation::build_query(variables)).send().await?;let body: Response<simulation::ResponseData> = response.json().await?;let sim = body.data.unwrap().simulation.unwrap();println!("Simulation status: {:?}, progress: {}%", sim.status, sim.progress);match sim.status.as_str() {"FINISHED" => {if let Some(url) = sim.thermal_index_gcode_url {println!("Thermal Index G-Code URL: {}", url);}return Ok(());}"FAILED" => return Err("Simulation failed".into()),_ => tokio::time::sleep(Duration::from_secs(2)).await,}}}void waitForSimulationComplete(const std::string& simulationId, const std::string& pat) {while (true) {const std::string query = Simulation::GetRequestText();graphql::response::Value variables = Simulation::serializeVariables(Simulation::Variables{.id = simulationId});auto response = Simulation::parseResponse(sendHttpRequest(query, variables, pat));std::string status = response.simulation->status;int progress = response.simulation->progress;std::cout << "Simulation status: " << status << ", progress: " << progress << "%" << std::endl;if (status == "FINISHED") {if (response.simulation->thermalIndexGcodeUrl) {std::cout << "Thermal Index G-Code URL: " << *response.simulation->thermalIndexGcodeUrl << std::endl;}return;} else if (status == "FAILED") {throw std::runtime_error("Simulation failed");}// Poll every 2 secondsstd::this_thread::sleep_for(std::chrono::seconds(2));}} -
Put it all together
Combine all the steps into a single function and run it.
async function createSimulation(gcodeId: string, name: string) {console.log(`Creating simulation for G-Code: ${gcodeId}`);// Create the simulationconst simulationId = await createSimulationEntry(gcodeId, name);console.log(`Simulation created with ID: ${simulationId}`);// Wait for simulation to completeconsole.log("Waiting for simulation to complete...");await waitForSimulationComplete(simulationId);console.log("Simulation finished!");return simulationId;}// Example usageconst simulationName = `simulation-${Date.now()}`;createSimulation(GCODE_ID, simulationName).then((id) => console.log(`Successfully completed simulation: ${id}`)).catch(console.error);async def create_simulation(gcode_id: str, name: str) -> str:"""Create and wait for a simulation to complete."""print(f"Creating simulation for G-Code: {gcode_id}")# Create the simulationsimulation_id = await create_simulation_entry(gcode_id, name)print(f"Simulation created with ID: {simulation_id}")# Wait for simulation to completeprint("Waiting for simulation to complete...")await wait_for_simulation_complete(simulation_id)print("Simulation finished!")return simulation_idif __name__ == "__main__":simulation_name = f"simulation-{int(time.time())}"simulation_id = asyncio.run(create_simulation(GCODE_ID, simulation_name))print(f"Successfully completed simulation: {simulation_id}")#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> {let pat = std::env::var("PAT").expect("PAT environment variable must be set");let gcode_id = std::env::var("GCODE_ID").unwrap_or_else(|_| "your-gcode-id".to_string());let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();let simulation_name = format!("simulation-{}", timestamp);let client = reqwest::Client::new();println!("Creating simulation for G-Code: {}", gcode_id);// Create the simulationlet simulation_id = create_simulation_entry(&client, &pat, &gcode_id, &simulation_name).await?;println!("Simulation created with ID: {}", simulation_id);// Wait for simulation to completeprintln!("Waiting for simulation to complete...");wait_for_simulation_complete(&client, &pat, &simulation_id).await?;println!("Simulation finished!");println!("Successfully completed simulation: {}", simulation_id);Ok(())}std::string createSimulation(const std::string& gcodeId,const std::string& name,const std::string& pat) {std::cout << "Creating simulation for G-Code: " << gcodeId << std::endl;// Create the simulationstd::string simulationId = createSimulationEntry(gcodeId, name, pat);std::cout << "Simulation created with ID: " << simulationId << std::endl;// Wait for simulation to completestd::cout << "Waiting for simulation to complete..." << std::endl;waitForSimulationComplete(simulationId, pat);std::cout << "Simulation finished!" << std::endl;return simulationId;}int main() {const char* pat_env = std::getenv("PAT");if (!pat_env) {std::cerr << "PAT environment variable is required" << std::endl;return 1;}std::string pat(pat_env);const char* gcode_env = std::getenv("GCODE_ID");std::string gcodeId = gcode_env ? gcode_env : "your-gcode-id";auto timestamp = std::chrono::system_clock::now().time_since_epoch().count();std::string simulationName = "simulation-" + std::to_string(timestamp);try {std::string simulationId = createSimulation(gcodeId, simulationName, pat);std::cout << "Successfully completed simulation: " << simulationId << std::endl;} catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;return 1;}return 0;}
Running the Example
Section titled “Running the Example”-
Create a
.env.localfile with your PAT and G-Code ID:Terminal window PAT="your-personal-access-token"GCODE_ID="your-gcode-id" -
Update the
GCODE_IDwith a valid G-Code ID from your account that is inREADYstatus. -
Run the example:
Terminal window bun run index.tsTerminal window uv run main.pyTerminal window cargo runTerminal window mkdir build && cd buildcmake .. -DVCPKG_DIR=$(pwd)/../vcpkg/installed/arm64-osxmake./ExampleApp