cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - Help us improve the PTC Community by taking this short Community Survey! X

CREOSON - Beta-3 is Available!

DavidBigelow
17-Peridot

CREOSON - Beta-3 is Available!

CRESON Beta-3 is Available!

 

CEOSON is OpenSource Automation for CREO Parametric using JSON Transactions!

 

The latest release of CREOSON contains some new commands for BOM Exports and Dimensions with additional commands for Feature, File and Geometry related operations in CREO Parametric.  Here is a summary of the new commands by group:

 
bom (new function family)
  • get_paths
dimension (new function family)
  • copy
  • list
  • set
  • show
  • user_select
feature
  • user_select_csys
file
  • get_length_units
  • get_mass_units
  • set_length_units
  • set_mass_units
geometry
  • get_edges
  • get_surfaces

 

The latest Pre-Packaged Distribution is located here!

 

If you have any questions, please post them here...  Bugs and Feature Requests should go to the GitHub Project

 

The Help Documentation within CREOSON contains all the updated command/function information and examples.

 

Thanks for all the great feedback!

 

 

18 REPLIES 18

Hello,

i tested CREOSON JSON server and page playground and all works perfectly.

I have skills in Visual Basic for Application for Microsoft Office.

Is there a step by step guide to configure Visual Studio and .json file? Just a few sample applications. I need help to learn how to post and retrive JSON data. Unfortunately You Tube files are not useful.

Anyway thank you for this open source project.

Can't wait to see more of the Windchill connectivity APIs coming to CREOSON. Thank you for this awesome work.

 

I've started writing my own CreoSON class in AHK. Try running the example bellow without lines 20 to 31 first.

 

obj := new CreoSON()

obj.creoSONUrl := "http://localhost:9056/creoson"
asmName := "large_assy.asm"

res1 := obj.connect(obj.creoSONUrl)

arr1 := Utils.ParseJson(res1)

sessionId := arr1["sessionId"]

res2 := obj.getWorkDirPath(obj.creoSONUrl, sessionId)

MsgBox, % "response 1:`n" . res1 . "`n`n"
	. "response 1 converted:`n" . Utils.BuildJson(arr1) . "`n`n"
	. "sessionId: " . sessionId . "`n`n"
	. "response 2:`n" . res2 . "`n`n"
	. "last status: " . obj.status

res3 := obj.openCADFile(obj.creoSONUrl, sessionId, asmName)

; look for "error":true in the response string
if inStr(res3, """""error"""":true") {
	MsgBox, % res3
}

res4 := obj.getBOMPathsFromAsm(obj.creoSONUrl, sessionId, asmName)

arr4 := Utils.ParseJson(res4)

Utils.Array_Gui(arr4)

ExitApp


;=================== classes =========================

class CreoSON {
	
	status := "N/A"
	creoSONUrl := "N/A"

	connect(creoSONUrl) {
	
		reqBody =
		(LTrim Join
			{
			  "command": "connection",
			  "function": "connect"
			}
		)

		WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1")
		WinHTTP.Open("POST", creoSONUrl, 0)
		WinHTTP.SetRequestHeader("Content-Type", "application/json")
		try {
			WinHTTP.Send(reqBody)
			this.status := WinHTTP.Status
			response := WinHTTP.ResponseText
		} catch e {
			MsgBox, % e.message
			ExitApp
		}
		
		return response
		
	}
	
	getWorkDirPath(creoSONUrl, sessionId) {
	
		reqBody =
		(LTrim Join
			{
			  "sessionId": "%sessionId%",
			  "command": "creo",
			  "function": "pwd"
			}
		)

		WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1")
		WinHTTP.Open("POST", creoSONUrl, 0)
		WinHTTP.SetRequestHeader("Content-Type", "application/json")
		try {
			WinHTTP.Send(reqBody)
			this.status := WinHTTP.Status
			response := WinHTTP.ResponseText
		} catch e {
			MsgBox, % e.message
			ExitApp
		}
		
		return response
	
	}
	
	getBOMPathsFromAsm(creoSONUrl, sessionId, asmFileName := "plate_assy.asm") {
	
		reqBody =
		(LTrim Join	
			{
			  "sessionId": "%sessionId%",
			  "command": "bom",
			  "function": "get_paths",
			  "data": {
				"file": "%asmFileName%"
			  }
			}
		)

		WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1")
		WinHTTP.Open("POST", creoSONUrl, 0)
		WinHTTP.SetRequestHeader("Content-Type", "application/json")
		try {
			WinHTTP.Send(reqBody)
			this.status := WinHTTP.Status
			response := WinHTTP.ResponseText
		} catch e {
			MsgBox, % e.message
			ExitApp
		}
		
		return response
	
	}
	
	openCADFile(creoSONUrl, sessionId, asmFileName := "plate_assy.asm") {
	
		reqBody =
		(LTrim Join	
			{
			  "sessionId": "%sessionId%",
			  "command": "file",
			  "function": "open",
			  "data": {
				"file": "%asmFileName%",
				"display": true,
				"activate": true
			  }
			}
		)

		WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1")
		WinHTTP.Open("POST", creoSONUrl, 0)
		WinHTTP.SetRequestHeader("Content-Type", "application/json")
		try {
			WinHTTP.Send(reqBody)
			this.status := WinHTTP.Status
			response := WinHTTP.ResponseText
		} catch e {
			MsgBox, % e.message
			ExitApp
		}
		
		return response
		
	}
	
}

; ============== libs and functions from ahk community ==================

class Utils {

	/****************************************************************************************
		Function: BuildJson(obj) 
			Builds a JSON string from an AutoHotkey object

		Parameters:
			obj - An AutoHotkey array or object, which can include nested objects.

		Remarks:
			Originally Obj2Str() by Coco,
			http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/page-2#entry588373
			
			Modified to use double quotes instead of single quotes and to leave numeric values
			unquoted.

		Returns:
			The JSON string
	*/
	BuildJson(obj) 
	{
		str := "" , array := true
		for k in obj {
			if (k == A_Index)
				continue
			array := false
			break
		}
		for a, b in obj
			str .= (array ? "" : """" a """: ") . (IsObject(b) ? this.BuildJson(b) : this.IsNumber(b) ? b : """" b """") . ", "	
		str := RTrim(str, " ,")
		return (array ? "[" str "]" : "{" str "}")
	}

	/****************************************************************************************
		Function: ParseJson(jsonStr)
			Converts a JSON string into an AutoHotkey object

		Parameters:
			jsonstr - the JSON string to convert

		Remarks:
			Originally by Getfree,
			http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/#entry588268

		Returns:
			The AutoHotkey object.
	*/
	ParseJson(jsonStr)
	{
		SC := ComObjCreate("ScriptControl") 
		SC.Language := "JScript"
		ComObjError(false)
		jsCode =
		(
		function arrangeForAhkTraversing(obj){
			if(obj instanceof Array){
				for(var i=0 ; i<obj.length ; ++i)
					obj[i] = arrangeForAhkTraversing(obj[i]) ;
				return ['array',obj] ;
			}else if(obj instanceof Object){
				var keys = [], values = [] ;
				for(var key in obj){
					keys.push(key) ;
					values.push(arrangeForAhkTraversing(obj[key])) ;
				}
				return ['object',[keys,values]] ;
			}else
				return [typeof obj,obj] ;
		}
		)
		SC.ExecuteStatement(jsCode "; obj=" jsonStr)
		return this.convertJScriptObjToAhks( SC.Eval("arrangeForAhkTraversing(obj)") )
	}

	/*!
		Function: convertJScriptObjToAhks(jsObj)
			Used by ParseJson()
	*/
	convertJScriptObjToAhks(jsObj)
	{
		if(jsObj[0]="object"){
			obj := {}, keys := jsObj[1][0], values := jsObj[1][1]
			loop % keys.length
				obj[keys[A_INDEX-1]] := this.convertJScriptObjToAhks( values[A_INDEX-1] )
			return obj
		}else if(jsObj[0]="array"){
			array := []
			loop % jsObj[1].length
				array.insert(this.convertJScriptObjToAhks( jsObj[1][A_INDEX-1] ))
			return array
		}else
			return jsObj[1]
	}

	/*!
		Function: IsNumber(Num)
			Checks if Num is a number.

		Returns:
			True if Num is a number, false if not
	*/
	IsNumber(Num)
	{
		if Num is number
			return true
		else
			return false
	}

	; ============= more functions ======================

	Array_Gui(Array, Parent="") {
		if !Parent
		{
			Gui, +HwndDefault
			Gui, New, +HwndGuiArray +LabelGuiArray +Resize
			Gui, Margin, 5, 5
			Gui, Add, TreeView, w300 h200
			
			Item := TV_Add("Array", 0, "+Expand")
			this.Array_Gui(Array, Item)
			
			Gui, Show,, GuiArray
			Gui, %Default%:Default
			
			WinWait, ahk_id%GuiArray%
			WinWaitClose, ahk_id%GuiArray%
			return
		}
		
		For Key, Value in Array
		{
			Item := TV_Add(Key, Parent)
			if (IsObject(Value))
				this.Array_Gui(Value, Item)
			else
				TV_Add(Value, Item)
		}
		return
		
		GuiArrayClose:
		Gui, Destroy
		return
		
		GuiArraySize:
		GuiControl, Move, SysTreeView321, % "w" A_GuiWidth - 10 " h" A_GuiHeight - 10
		return
	} ; by GeekDude

}

Looks like the code block lines aren't being numbered.

 

Extremely usefull code! I use it a lot.

 

I made one small modification, store WinHTTP as a static variable to speed up multiple requests:

 class HTTP {
sendPOSTHTTPReq(creoSONUrl, reqBody) {
HTTPLabel_Counter := 0
static WinHTTP
HTTPLabel:
if (!IsObject(WinHTTP)){
WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1")
}
WinHTTP.Open("POST", creoSONUrl, 0)
WinHTTP.SetRequestHeader("Content-Type", "application/json")
try {
WinHTTP.Send(reqBody)
;status := WinHTTP.Status
response := WinHTTP.ResponseText
} catch e {
HTTPLabel_Counter++
if (HTTPLabel_Counter < 5){
goto HTTPLabel
}
if (InStr(e.message, "A connection with the server could not be established")){
TrayTip, HttpRequest, % e.message
}
else{
MsgBox, % e.message
}
Exit
}
return response
}
}

  

Hi Mauro,

 

Glad to hear CREOSON was working perfectly! 🙂

 

 

 

We created the JSON interface as a "generic" solution for any language to use.  We are not experts in every language, VB is a good example of something we have used - but only when necessary.

 

The best advice I can give is to look up how to execute a HTTP request to send/receive JSON data using Visual Basic and start experimenting.  The toughest part is going to be figuring out the request/response communications, once you have that figured out... you can focus on CREOSON and automating CREO Parametric with it.

 

The examples are included in the documentation for how to use CREOSON - look at the Functions section in the Help Documentation, you will find the specification and often more than a few examples of how the requests/responses look.

 

Once you figure out how to execute JSON requests with VB, I am sure many others would appreciate any solution you come up with.  So please share what works.

 

The YouTube was meant to be a "taste" of what could be done with the interface... not actual instruction - more motivation. 🙂

 

 

Thanks again for your positive feedback.


Dave

 

 

 

How'd a smiley get into a code block? Don't forget to replace the 'Smiley Very Happy' with ':' and 'D'

James,

 

WOW - you are the MAN!

 

Oh regarding Windchill... I think we are not going to be adding many more functions specific to Windchill for a while... we are using JLINK ya know... (limited functionality) 🙂

 

Dave

@DavidBigelow Even Creo Toolkit has limited functionality dealing with Windchill operations at Creo.

That's seems to be a deadend. 

 

My I ask, in a real world scenario how would you be using CREOSON?

 @JoaoGoncalves ... Well...we use the Windchill interface all the time for automated back end processes ... specifically to take a Bill Of Materials (BOM) as an input, connect to Windchill, create a local workspace, then retrieve components and assemblies ... building the final assembly on the fly. OR, again Windchill specifically, just retrieving components from windchill for batch modification/updates.

 

 

 

 

The CORE of CREOSON is used in commercial products like Nitro-CELL, Nitro-BOM and Nitro-PROGRAM which are used by our customers to automate a variety of things using Excel.

 

 

CREOSON specifically can be as a local application service to integrate CREO Parametric with your existing application(s) (e.g. CREO Parametric becomes another thing to talk to much like a database, excel, text file, or web service vs embedding everything inside CREO Parametric and reaching out to those other data targets).

 

CREOSON an also be used for local task-specific applications (e.g. I can't put logic in a mapkey to run the right commands, but with CREOSON I could evaluate model state/condition/information quickly and then make the right calls to get to a desired result faster).  <-- we see this frustration a lot!

 

As a bonus, CREOSON enables remote manipulation of CREO Parametric (over your network or over the Internet).  No one has really talked about this capability yet and it is not perfect today; however, there was someone early on in the discussions that caught on to the potentials through.  This is a bit of a mind-bender for most users who see CREO Parametric as "in front of them" always.  We all know cloud services are coming like a Freight Train... I personally see CREOSON easily enabling customer-internal, cloud-based, micro-services using CREO Parametric at some point very soon.   The services could easily expensive replace commercial configurators, quoting systems, etc... and reduce the need for outsourcing.  This could be easily done by choosing a more modular and direct approach to delivering highly accurate results very quickly via CREO Parametric - and do it remotely, and headless...  (ex. web page to collect requirements, submit, requirements validated, new part/assembly generated with documentation, results available for download within 30-seconds....)  <--- Note: We have done this in the past for a few customers.

 

There are MANY use cases for CREOSON... the beauty of it - generic, simple, very powerful and can be easily integrated/leveraged by ANY scripting/programming language that can execute JSON requests over HTTP (locally or over the internet)

 

CREOSON is a bit of clay... it is up to you to figure out what you want to build with it.

 

I hope you dig in and give it a try -- I am already blown away by what people have done so far.

 

Dave

Hi,

 

I've tried to retrieve a model from a workspace using the following J-Link class and it didn't work.

 

public class RetrvFile extends DefaultUICommandActionListener {

    /**
     * Declaration of an empty field of a Session object type.
     */
    Session session;

    /**
     * The following method works to override the OnCommand() method of the 
     * UICommandActionListener class. The OnCommand() method triggers when
     * the user clicks the icon.
     * @throws com.ptc.cipjava.jxthrowable
     */
    @Override
    public void OnCommand() throws jxthrowable {

        /**
         * Required: The reference to the session object. The method
         * GetProESession() returns a handle to the current session object.
         */
        session = pfcGlobal.GetProESession();
                
        if (session != null) {
            
            // Workspace full path example
            // wtws://<server_alias>/<workspace_name>/<object_name>.<object_extension>

            String fileFullPath = "wtws://Windchill/ZKL-VaV_Poptavky/test_prt_2.prt";

            ModelDescriptor modelDescr = pfcModel.ModelDescriptor_CreateFromFileName(fileFullPath);
            session.OpenFile(modelDescr);
            Window currentWindow = session.GetCurrentWindow();
            currentWindow.Activate();
            
            MessageDialogOptions options = pfcUI.MessageDialogOptions_Create();
            options.SetDialogLabel("Test");
            
            session.UIShowMessageDialog("Device: " + modelDescr.GetDevice()
                    + "\n" + "Extension: " + modelDescr.GetExtension()
                    + "\n" + "FileName: " + modelDescr.GetFileName()
                    + "\n" + "FullName: " + modelDescr.GetFullName()
                    + "\n" + "GenericName: " + modelDescr.GetGenericName()
                    + "\n" + "InstanceName: " + modelDescr.GetInstanceName()
                    + "\n" + "Host: " + modelDescr.GetHost()
                    + "\n" + "Path: " + modelDescr.GetPath()
                    + "\n" + "String: " + modelDescr.toString(), options);

            
        } else {
            sessionObj.UIShowMessageDialog(session, "Synchronous connection has failed.", null);
        }

    }
    
}

@James62  I think you posted this code in the wrong thread.  

 

CREOSON does it completely differently.

 

Dave

Dave,

 

Can CREOSON open a model from workspace? I tried with CREOSON and it failed, could post that code too if you want.

 

~J

@jfojtik  mmm -- this should be a really simple thing.

 

You should just have to do a windchill set_workspace  - then a normal file open...

 

Can you post the CREOSON code transactions you are trying to execute?

 

Dave

hi Dave,

 

I ran the following AHK code that has a CreoSON class with a few methods.

 

obj := new CreoSON()

obj.creoSONUrl := "http://localhost:9056/creoson"

fileFullPath := "wtws://Windchill/ZKL-VaV_Poptavky/test_prt_2.prt"

res1 := obj.connect(obj.creoSONUrl)

arr1 := Utils.ParseJson(res1)

sessionId := arr1["sessionId"]

res2 := obj.getWorkDirPath(obj.creoSONUrl, sessionId)

/*
MsgBox, % "response 1:`n" . res1 . "`n`n"
	. "response 1 converted:`n" . Utils.BuildJson(arr1) . "`n`n"
	. "sessionId: " . sessionId . "`n`n"
	. "response 2:`n" . res2
*/

res5 := obj.openFileByFullPath(obj.creoSONUrl, sessionId, fileFullPath)

MsgBox, % res5

ExitApp


;=================== classes =========================

class CreoSON {
	
	creoSONUrl := "N/A"

	connect(creoSONUrl) {
	
		reqBody =
		(LTrim Join
			{
			  "command": "connection",
			  "function": "connect"
			}
		)

		return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody)
		
	}
	
	getWorkDirPath(creoSONUrl, sessionId) {
	
		reqBody =
		(LTrim Join
			{
			  "sessionId": "%sessionId%",
			  "command": "creo",
			  "function": "pwd"
			}
		)

		return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody)
	
	}
	
	getBOMPathsFromAsm(creoSONUrl, sessionId, asmFileName := "plate_assy.asm") {
	
		reqBody =
		(LTrim Join	
			{
			  "sessionId": "%sessionId%",
			  "command": "bom",
			  "function": "get_paths",
			  "data": {
				"file": "%asmFileName%"
			  }
			}
		)

		return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody)
	
	}
	
	openFileByName(creoSONUrl, sessionId, fileName := "plate_assy.asm") {
	
		reqBody =
		(LTrim Join	
			{
			  "sessionId": "%sessionId%",
			  "command": "file",
			  "function": "open",
			  "data": {
				"file": "%fileName%",
				"display": true,
				"activate": true
			  }
			}
		)

		return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody)
		
	}

	openFileByFullPath(creoSONUrl, sessionId, fileFullPath) {
	
		fileDir := subStr(fileFullPath,  1, inStr(fileFullPath, "/", , 0) - 1)
		fileName := subStr(fileFullPath, inStr(fileFullPath, "/", , 0) + 1, strLen(fileFullPath))

		reqBody =
		(LTrim Join	
			{
			  "sessionId": "%sessionId%",
			  "command": "file",
			  "function": "open",
			  "data": {
				"file": "%fileName%",
				"dirname": "%fileDir%",
				"display": true,
				"activate": true
			  }
			}
		)

		return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody)
		
	}
	
	class HTTP {

		sendPOSTHTTPReq(creoSONUrl, reqBody) {
		
			WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1")
			WinHTTP.Open("POST", creoSONUrl, 0)
			WinHTTP.SetRequestHeader("Content-Type", "application/json")
			try {
				WinHTTP.Send(reqBody)
				;status := WinHTTP.Status
				response := WinHTTP.ResponseText
			} catch e {
				MsgBox, % e.message
				ExitApp
			}
			
			return response
		
		}

	}

}

; ============== libs and functions from ahk community ==================

class Utils {

	/****************************************************************************************
		Function: BuildJson(obj) 
			Builds a JSON string from an AutoHotkey object

		Parameters:
			obj - An AutoHotkey array or object, which can include nested objects.

		Remarks:
			Originally Obj2Str() by Coco,
			http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/page-2#entry588373
			
			Modified to use double quotes instead of single quotes and to leave numeric values
			unquoted.

		Returns:
			The JSON string
	*/
	BuildJson(obj) 
	{
		str := "" , array := true
		for k in obj {
			if (k == A_Index)
				continue
			array := false
			break
		}
		for a, b in obj
			str .= (array ? "" : """" a """: ") . (IsObject(b) ? this.BuildJson(b) : this.IsNumber(b) ? b : """" b """") . ", "	
		str := RTrim(str, " ,")
		return (array ? "[" str "]" : "{" str "}")
	}

	/****************************************************************************************
		Function: ParseJson(jsonStr)
			Converts a JSON string into an AutoHotkey object

		Parameters:
			jsonstr - the JSON string to convert

		Remarks:
			Originally by Getfree,
			http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/#entry588268

		Returns:
			The AutoHotkey object.
	*/
	ParseJson(jsonStr)
	{
		SC := ComObjCreate("ScriptControl") 
		SC.Language := "JScript"
		ComObjError(false)
		jsCode =
		(
		function arrangeForAhkTraversing(obj){
			if(obj instanceof Array){
				for(var i=0 ; i<obj.length ; ++i)
					obj[i] = arrangeForAhkTraversing(obj[i]) ;
				return ['array',obj] ;
			}else if(obj instanceof Object){
				var keys = [], values = [] ;
				for(var key in obj){
					keys.push(key) ;
					values.push(arrangeForAhkTraversing(obj[key])) ;
				}
				return ['object',[keys,values]] ;
			}else
				return [typeof obj,obj] ;
		}
		)
		SC.ExecuteStatement(jsCode "; obj=" jsonStr)
		return this.convertJScriptObjToAhks( SC.Eval("arrangeForAhkTraversing(obj)") )
	}

	/*!
		Function: convertJScriptObjToAhks(jsObj)
			Used by ParseJson()
	*/
	convertJScriptObjToAhks(jsObj)
	{
		if(jsObj[0]="object"){
			obj := {}, keys := jsObj[1][0], values := jsObj[1][1]
			loop % keys.length
				obj[keys[A_INDEX-1]] := this.convertJScriptObjToAhks( values[A_INDEX-1] )
			return obj
		}else if(jsObj[0]="array"){
			array := []
			loop % jsObj[1].length
				array.insert(this.convertJScriptObjToAhks( jsObj[1][A_INDEX-1] ))
			return array
		}else
			return jsObj[1]
	}

	/*!
		Function: IsNumber(Num)
			Checks if Num is a number.

		Returns:
			True if Num is a number, false if not
	*/
	IsNumber(Num)
	{
		if Num is number
			return true
		else
			return false
	}

	; ============= more functions ======================

	Array_Gui(Array, Parent="") {
		if !Parent
		{
			Gui, +HwndDefault
			Gui, New, +HwndGuiArray +LabelGuiArray +Resize
			Gui, Margin, 5, 5
			Gui, Add, TreeView, w300 h200
			
			Item := TV_Add("Array", 0, "+Expand")
			this.Array_Gui(Array, Item)
			
			Gui, Show,, GuiArray
			Gui, %Default%:Default
			
			WinWait, ahk_id%GuiArray%
			WinWaitClose, ahk_id%GuiArray%
			return
		}
		
		For Key, Value in Array
		{
			Item := TV_Add(Key, Parent)
			if (IsObject(Value))
				this.Array_Gui(Value, Item)
			else
				TV_Add(Value, Item)
		}
		return
		
		GuiArrayClose:
		Gui, Destroy
		return
		
		GuiArraySize:
		GuiControl, Move, SysTreeView321, % "w" A_GuiWidth - 10 " h" A_GuiHeight - 10
		return
	} ; by GeekDude

}

 

 

Notice the response shown from the MsgBox on line 24 on the picture bellow. In the code that is the line that says 'MsgBox, % res5',

 

creoSON-test1.png

 

Thanks.

~J

@James62

 

I think you need a CREOSON to do the following:

 

"windchill" "set_server"

"windchill" "authorize"

"windchill" "set_workspace"

 

THEN

 

"file" "open"

 

I think you are missing a few commands before trying to perform the operation.

 

Dave

 

hi Dave,

 

Thank you for the reply. Finally had a chance to try what you proposed and it worked!

 

Solution using CreoSON and AHK follows. I added a little gui to get user credentials.

 

;Ask for user login credentials
Gui, Add, Edit, vUser x10 w180, Username
Gui, Add, Edit, vPass x10 w180 Password, Password
Gui, Add, Button, Default gSubmit x10 w180, OK
Gui, Show, , Log in
Return

GuiClose:  ;User closed the window.
ExitApp

Submit:
Gui, Submit, NoHide
Gui, Destroy

obj := new CreoSON()

obj.creoSONUrl := "http://localhost:9056/creoson"

fileFullPath := "wtws://Windchill/Workspace on ZKL-VaV_Poptavky/test_prt_2.prt"

res1 := obj.connect(obj.creoSONUrl)

arr1 := Utils.ParseJson(res1)

sessionId := arr1["sessionId"]

res5 := obj.wchSetServer(obj.creoSONUrl, sessionId, "Windchill")

res6 := obj.wchAuthorize(obj.creoSONUrl, sessionId, User, Pass)

res7 := obj.wchSetWorkspace(obj.creoSONUrl, sessionId, "Workspace on ZKL-VaV_Poptavky")

res8 := obj.openFileByFullPath(obj.creoSONUrl, sessionId, fileFullPath)

MsgBox,
(LTrim
	response1:
	%res1%
	
	response5:
	%res5%
	
	response6:
	%res6%
	
	response7:
	%res7%
	
	response8:
	%res8%
	
)

ExitApp


;=================== classes =========================

class CreoSON {
	
	creoSONUrl := "N/A"

	/**
	 * connection : connect
	 */
	connect(creoSONUrl) {
	
		reqBody =
		(LTrim Join
			{
			  "command": "connection",
			  "function": "connect"
			}
		)

		return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody)
		
	}
	
	/**
	 * creo : pwd
	 */
	getWorkDirPath(creoSONUrl, sessionId) {
	
		reqBody =
		(LTrim Join
			{
			  "sessionId": "%sessionId%",
			  "command": "creo",
			  "function": "pwd"
			}
		)

		return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody)
	
	}
	
	/**
	 * bom : get_paths
	 */
	getBOMPathsFromAsm(creoSONUrl, sessionId, asmFileName := "plate_assy.asm") {
	
		reqBody =
		(LTrim Join
			{
			  "sessionId": "%sessionId%",
			  "command": "bom",
			  "function": "get_paths",
			  "data": {
				"file": "%asmFileName%"
			  }
			}
		)

		return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody)
	
	}
	
	/**
	 * file : open
	 */
	openFileByName(creoSONUrl, sessionId, fileName := "plate_assy.asm") {
	
		reqBody =
		(LTrim Join
			{
			  "sessionId": "%sessionId%",
			  "command": "file",
			  "function": "open",
			  "data": {
				"file": "%fileName%",
				"display": true,
				"activate": true
			  }
			}
		)

		return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody)
		
	}

	/**
	 * file : open
	 */
	openFileByFullPath(creoSONUrl, sessionId, fileFullPath) {
	
		fileDir := subStr(fileFullPath,  1, inStr(fileFullPath, "/", , 0) - 1)
		fileName := subStr(fileFullPath, inStr(fileFullPath, "/", , 0) + 1, strLen(fileFullPath))

		reqBody =
		(LTrim Join
			{
			  "sessionId": "%sessionId%",
			  "command": "file",
			  "function": "open",
			  "data": {
				"file": "%fileName%",
				"dirname": "%fileDir%",
				"display": true,
				"activate": true
			  }
			}
		)

		return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody)
		
	}
	
	/**
	 * windchill : set_server
	 */
	wchSetServer(creoSONUrl, sessionId, urlOrAlias) {
	
		reqBody =
		(LTrim Join
			{
			  "sessionId": "%sessionId%",
			  "command": "windchill",
			  "function": "set_server",
			  "data": {
				"server_url": "%urlOrAlias%"
			  }
			}
		)

		return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody)
		
	}
	
	/**
	 * windchill : authorize
	 */
	wchAuthorize(creoSONUrl, sessionId, user, pass) {
	
		reqBody =
		(LTrim Join
			{
			  "sessionId": "%sessionId%",
			  "command": "windchill",
			  "function": "authorize",
			  "data": {
				"user": "%user%",
				"password": "%pass%"
			  }
			}
		)

		return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody)
		
	}
	
	/**
	 * windchill : set_workspace
	 */
	wchSetWorkspace(creoSONUrl, sessionId, workspaceName) {
	
		reqBody =
		(LTrim Join
			{
			  "sessionId": "%sessionId%",
			  "command": "windchill",
			  "function": "set_workspace",
			  "data": {
				"workspace": "%workspaceName%"
			  }
			}
		)

		return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody)
		
	}
	
	/**
	 * Subclass
	 */
	class HTTP {

		sendPOSTHTTPReq(creoSONUrl, reqBody) {
		
			WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1")
			WinHTTP.Open("POST", creoSONUrl, 0)
			WinHTTP.SetRequestHeader("Content-Type", "application/json")
			try {
				WinHTTP.Send(reqBody)
				;status := WinHTTP.Status
				response := WinHTTP.ResponseText
			} catch e {
				MsgBox, % e.message
				ExitApp
			}
			
			return response
		
		}

	}

}

; ============== libs and functions from ahk community ==================

class Utils {

	/****************************************************************************************
		Function: BuildJson(obj) 
			Builds a JSON string from an AutoHotkey object

		Parameters:
			obj - An AutoHotkey array or object, which can include nested objects.

		Remarks:
			Originally Obj2Str() by Coco,
			http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/page-2#entry588373
			
			Modified to use double quotes instead of single quotes and to leave numeric values
			unquoted.

		Returns:
			The JSON string
	*/
	BuildJson(obj) 
	{
		str := "" , array := true
		for k in obj {
			if (k == A_Index)
				continue
			array := false
			break
		}
		for a, b in obj
			str .= (array ? "" : """" a """: ") . (IsObject(b) ? this.BuildJson(b) : this.IsNumber(b) ? b : """" b """") . ", "	
		str := RTrim(str, " ,")
		return (array ? "[" str "]" : "{" str "}")
	}

	/****************************************************************************************
		Function: ParseJson(jsonStr)
			Converts a JSON string into an AutoHotkey object

		Parameters:
			jsonstr - the JSON string to convert

		Remarks:
			Originally by Getfree,
			http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/#entry588268

		Returns:
			The AutoHotkey object.
	*/
	ParseJson(jsonStr)
	{
		SC := ComObjCreate("ScriptControl") 
		SC.Language := "JScript"
		ComObjError(false)
		jsCode =
		(
		function arrangeForAhkTraversing(obj){
			if(obj instanceof Array){
				for(var i=0 ; i<obj.length ; ++i)
					obj[i] = arrangeForAhkTraversing(obj[i]) ;
				return ['array',obj] ;
			}else if(obj instanceof Object){
				var keys = [], values = [] ;
				for(var key in obj){
					keys.push(key) ;
					values.push(arrangeForAhkTraversing(obj[key])) ;
				}
				return ['object',[keys,values]] ;
			}else
				return [typeof obj,obj] ;
		}
		)
		SC.ExecuteStatement(jsCode "; obj=" jsonStr)
		return this.convertJScriptObjToAhks( SC.Eval("arrangeForAhkTraversing(obj)") )
	}

	/*!
		Function: convertJScriptObjToAhks(jsObj)
			Used by ParseJson()
	*/
	convertJScriptObjToAhks(jsObj)
	{
		if(jsObj[0]="object"){
			obj := {}, keys := jsObj[1][0], values := jsObj[1][1]
			loop % keys.length
				obj[keys[A_INDEX-1]] := this.convertJScriptObjToAhks( values[A_INDEX-1] )
			return obj
		}else if(jsObj[0]="array"){
			array := []
			loop % jsObj[1].length
				array.insert(this.convertJScriptObjToAhks( jsObj[1][A_INDEX-1] ))
			return array
		}else
			return jsObj[1]
	}

	/*!
		Function: IsNumber(Num)
			Checks if Num is a number.

		Returns:
			True if Num is a number, false if not
	*/
	IsNumber(Num)
	{
		if Num is number
			return true
		else
			return false
	}

	; ============= more functions ======================

	Array_Gui(Array, Parent="") {
		if !Parent
		{
			Gui, +HwndDefault
			Gui, New, +HwndGuiArray +LabelGuiArray +Resize
			Gui, Margin, 5, 5
			Gui, Add, TreeView, w300 h200
			
			Item := TV_Add("Array", 0, "+Expand")
			this.Array_Gui(Array, Item)
			
			Gui, Show,, GuiArray
			Gui, %Default%:Default
			
			WinWait, ahk_id%GuiArray%
			WinWaitClose, ahk_id%GuiArray%
			return
		}
		
		For Key, Value in Array
		{
			Item := TV_Add(Key, Parent)
			if (IsObject(Value))
				this.Array_Gui(Value, Item)
			else
				TV_Add(Value, Item)
		}
		return
		
		GuiArrayClose:
		Gui, Destroy
		return
		
		GuiArraySize:
		GuiControl, Move, SysTreeView321, % "w" A_GuiWidth - 10 " h" A_GuiHeight - 10
		return
	} ; by GeekDude

}

 

Responses:

creoSON-test2.png

 

Thanks

~J

Sweet!  Congrats on getting that to work!


Dave

Thanks, Now I wish I knew how to do the Upload of all modified objects in local workspace to the server-side workspace. Seems like CreoSON can't do Upload. The rest of Windchill operations I'd be able to do using Windchill Java API.

 

~J

Yea - CREOSON uses JLINK for the Windchill interface - so it is quite limited in this respect.

Good luck!

Dave

Announcements
NEW Creo+ Topics: Real-time Collaboration


Top Tags