spettitt Posted October 20, 2023 Share Posted October 20, 2023 (edited) I'm trying to write back to the 'Number of Circuits' parameter of a ConnectCAD Socket. I can read from it OK, but writes have no effect. I have a bigger script with the problem, but for testing I've stripped it down to this sledgehammer script just to try and get something writing: def overwrite(h): vs.AlrtDialog('Trying Socket') vs.SetRField(h, 'Socket', 'n_circuits', 98) vs.ForEachObject(overwrite, "INSYMBOL & INOBJECT & INVIEWPORT & (PON='Socket')") This calls the AlrtDialog for every socket fine, but does nothing else. I've tried: vs.SetRField(h, 'Socket', 'Number Of Circuits', 98) vs.SetRField(h, 'Socket', 'n_circuits', 98) vs.SetRField(h, 'skt_rec', 'Number Of Circuits', 98) vs.SetRField(h, 'skt_rec', 'n_circuits', 98) In terms of reading from this field, this works fine: curnum = vs.GetRField(h, 'Socket', 'n_circuits') Do I need to use a different method than SetRField to write this parameter? Maybe some sort of choice index? Thanks Edited October 20, 2023 by spettitt Quote Link to comment
Pat Stanford Posted October 20, 2023 Share Posted October 20, 2023 SetRField writes a string you are passing a number. Put quotes around your value or in your bigger script try using Num2Str, Num2StrF, or EvalStr to convert your number into a string. Quote Link to comment
spettitt Posted October 20, 2023 Author Share Posted October 20, 2023 8 minutes ago, Pat Stanford said: SetRField writes a string you are passing a number. Put quotes around your value or in your bigger script try using Num2Str, Num2StrF, or EvalStr to convert your number into a string. Thanks, I've tried this but same result so far. When changing this parameter in the OIP, it validates to an integer regardless of whether you input str, float or int. So it might be that SetRField is the wrong thing to set it if SetRField will always write a string and the parameter needs an integer. Quote Link to comment
Pat Stanford Posted October 20, 2023 Share Posted October 20, 2023 SetRField is the correct way to change parameters. You just have to convert to a string first. Can you upload a simple file with a ConnectCAD Socket so I don't have to learn ConnectCAD to try this? Quote Link to comment
spettitt Posted October 20, 2023 Author Share Posted October 20, 2023 Sure, thanks for having a look. This is a 2024 file. This contains a Device (MyPanel) with a single Socket (the red arrow) inside it. To access the parameter in the OIP, double click the device name (not the socket) to go inside the Device. Of the several objects inside, you can then select the red Socket object, and see 'Number of Circuits' in the OIP. NumSktTest.vwx In my actual application, I'm using vs.ForEachObjectInList to traverse inside the intended device and locate the socket PIO. Quote Link to comment
Pat Stanford Posted October 20, 2023 Share Posted October 20, 2023 In the attached file the script GetN_Circuits Gets and Sets the n_circuits field for a Socket sitting on the active layer. Script GetN_Circuits2, that I thought would get the Socket inside the Device, "THINKS / shows" it is changing the value, but reporting the data in a worksheet shows that it does not change. My Guess is that internal to the device, the socket is kind of a placeholder (like a symbol definition) and we need to work harder to identify the correct object. @JBenghiat @Sam Jones @MullinRJ @michaelk Anyone up for a game of hide and seek? 😉. File with scripts and worksheet attached. NumSktTest-Pat.vwx I tried to post the scripts directly to the forum and got the dreaded 404 error. I think on the EVAL function. 😞 Quote Link to comment
MullinRJ Posted October 21, 2023 Share Posted October 21, 2023 Is it possible the outer PIO (Device) is overwriting the inner PIO (Socket) after the "Socket"."n_circuits" field is written to? If so, I have not been able to see where the previous data is stored. If I place a "Socket" PIO on the Design Layer and run the python script, the value for "n_circuits" is updated to 98. Only when it is embedded in the Device PIO does it not stay updated after the script finishes. Raymond Quote Link to comment
spettitt Posted October 21, 2023 Author Share Posted October 21, 2023 16 hours ago, MullinRJ said: Is it possible the outer PIO (Device) is overwriting the inner PIO (Socket) after the "Socket"."n_circuits" field is written to? It seems something like this to me. The outer Device can modify this parameter in a modal that pops up with the 'Edit Device Array' button in the OIP, so there seems to be some interaction. I'm not sure if I can (or should even try and) script the Edit Device Array process. Quote Link to comment
Vectorworks, Inc Employee Nikolay Zhelyazkov Posted October 22, 2023 Vectorworks, Inc Employee Share Posted October 22, 2023 Hello all, Here is a script that should do what you want: SetNCircs.vwx The problem with your scripts was that they were not setting the data to the sockets inside the device's profile group but to the one that is on the drawing (a temporary object that gets deleted and recreated on each device reset). Best Regards, Nikolay Zhelyazkov 2 Quote Link to comment
spettitt Posted October 22, 2023 Author Share Posted October 22, 2023 Thanks so much @Nikolay Zhelyazkov. Works great. For the sake of future explorers; here is a Python version using a pick prompt rather than processing everything: import vs def writencircuits(hskt): if vs.Eval(hskt, "PON = 'Socket'"): vs.SetRField(hskt, 'Socket', 'n_circuits', '98') def dev(pt): global hdev hdev = vs.PickObject(pt[0], pt[1]) type = vs.GetRField(hdev, 'Device', 'Type') if type == 'CustomPanel': hProfile = vs.GetCustomObjectProfileGroup(hdev) vs.ForEachObjectInList(writencircuits, 1, 0, vs.FInGroup(hProfile)) else: vs.AlrtDialog('That is not a Panel Connector device. Try again') vs.GetPt(dev) I promise this makes sense in the context of my wider plugin...! 1 Quote Link to comment
spettitt Posted February 24 Author Share Posted February 24 Hi @Nikolay Zhelyazkov Just coming back to this, as I think I've got a related issue in a similar application. Would much appreciate your advice please - or anyone's! I'm trying to store object UUIDs to records on each circuit, device and socket so a script can pick up the relationships, as I can't use the ObjectData Evals in a script. I have records for each type, with each having a 'self' UUID field (not mapped in the data manager) and then foreign keys as needed - sockets to device, circuit to src and dst sockets. These use the relevant ObjectData Evals to get the related UUID. Ideally, I wouldn't need my script to populate these fields, so they are ready when a script comes to pick them up later. But currently: - A script is populating all the 'self' fields - Then relying on the data manager mapping to kick in and populate all of the foreign keys - Script continues and carries on with the next task In my snippet below, the AlrtDialog appears twice for each socket (with different handles and UUIDs) - the one on the drawing and the one in the profile group. I'm unsure which is the right approach. def SockUUID(h): if vs.GetObjectVariableInt(h, 1165) == 621: UUIDv = vs.GetObjectUuid(h) vs.SetRField(h, 'SktUUID', 'Self', UUIDv) vs.ResetObject(h) vs.SetObjectVariableBoolean(h, 1167, True) vs.AlrtDialog(f'{h} is {UUIDv}') # prints twice with correct data def DevUUID(h): UUIDv = vs.GetObjectUuid(h) vs.SetRField(h, 'DevUUID', 'Self', UUIDv) hprofile = vs.GetCustomObjectProfileGroup(h) vs.ForEachObjectInList(SockUUID, 1, 0, vs.FInGroup(hprofile)) vs.ResetObject(h) vs.SetObjectVariableBoolean(h, 1167, True) def CircuitUUID(h): UUIDv = vs.GetObjectUuid(h) vs.SetRField(h, 'CircuitUUID', 'Self', UUIDv) vs.ForEachObject(DevUUID, "PON = 'Device'") vs.ForEachObject(CircuitUUID, "PON = 'Circuit'") vs.ForEachObject(SockUUID, "INOBJECT & (PON='Socket')") This all works great - except that the Sockets are not reliably populating their 'Self' UUID field, which may because I'm grabbing the wrong handle. If I draw a new mini design and run my script once - Devices and Circuits have worked great, but sockets fail to populate their self field. If I run it immediately again, the socket UUIDs appear and all is well, but I want this to happen within one script execution. The ideal here would be a mapping for the data manager so that a new object can populate it's 'self' UUID record field without needing the vs.GetObjectUUID call in a script. Is this possible please? Follow up question - out of the two different socket handles, at which one should I find the values of custom record data? I have a custom record mapped to all sockets, but I'm assuming the user-entered values of that record (which are accessed via a worksheet) will only exist at one of those handles. Thank you! Quote Link to comment
Vectorworks, Inc Employee Nikolay Zhelyazkov Posted February 26 Vectorworks, Inc Employee Share Posted February 26 Hello @spettitt, On 2/24/2024 at 6:49 PM, spettitt said: Follow up question - out of the two different socket handles, at which one should I find the values of custom record data? I have a custom record mapped to all sockets, but I'm assuming the user-entered values of that record (which are accessed via a worksheet) will only exist at one of those handles. - The data in the sockets in the profile groups should be more reliable as they do not get deleted on every reset. What is more, the other sockets are just copies of these sockets. Now to the main problem, I suppose that you see the changes on the second run because you miss a device reset to recreate the sockets from the profile group and duplicate them on the drawing. I suppose that simply putting the Device's foreach after the Socket's should resolve this. Important note to keep in mind, once again I will emphasize on this that the sockets on the drawing are mere duplicates of the sockets in the profile group -> the UUIDs in their attached records will most probably be pointing to the sockets in the profile groups. This might actually be useful for you, as in the end you should want to get the sockets in the profile groups. On 2/24/2024 at 6:49 PM, spettitt said: The ideal here would be a mapping for the data manager so that a new object can populate it's 'self' UUID record field without needing the vs.GetObjectUUID call in a script. Is this possible please? - I think that this should be easily doable for devices and circuits, you just have to set up the mapping correctly (not really sure if there is a worksheet function for UUID access though). As for sockets, I think that this will not work out, as you would want the sockets in the drawing to get the UUIDs of the sockets in the profile group, which might not be possible to achieve with the data manager mapping as it would require you to read data from one object and write it in another. Let me know if this helps and if you need any further help/info. Best Regards, Nikolay Zhelyazkov Quote Link to comment
spettitt Posted February 28 Author Share Posted February 28 Hey @Nikolay Zhelyazkov, Thank you for this, sorry for the slow response, been off for a few days. I will have another go in light of what you say. Thanks Simon 1 Quote Link to comment
spettitt Posted April 23 Author Share Posted April 23 (edited) Hi @Nikolay Zhelyazkov, I've kept trying at this but I'm just stuck at what feels like the final hurdle. Could you have a quick look at this file please? There is a script and worksheet. It's all working except for sockets storing their parent device UUID: Once I've run the script and the worksheet is populated, I can edit a device and see that the field is by-instance, even though it's not set as that in the Data Manager. If I toggle that by-instance to calculated, it does show the Device UUID, and then recalculating the worksheet will show it. But that has to be done for every socket. Any ideas on how I can get it to go straight to calculated, please? ExportTesting2.vwx Edited April 23 by spettitt Quote Link to comment
Vectorworks, Inc Employee Nikolay Zhelyazkov Posted April 24 Vectorworks, Inc Employee Share Posted April 24 Hello @spettitt, The problem is that each time you run your script you delete the records from the sockets and attach them again and this resets the mapping. After a consultation with the IFC/Data Manager experts it turned out that you can avoid the data mapping reset using this: def SockRecord(h): vs.Record(h, 'SktUUID') vs.SetRFieldOpt(h, 'SktUUID', 'Dev', True, True) vs.ResetObject(h) vs.SetObjectVariableBoolean(h, 1167, True) Once you change your script like this and fix the mapping for the already existing sockets you should be fine. Best Regards, Nikolay Zhelyazkov Quote Link to comment
spettitt Posted April 24 Author Share Posted April 24 (edited) Thanks for this @Nikolay Zhelyazkov. Adding that line does indeed give me the parent device, but did then affect the sockets getting their self UUID. However then a follow-up script just to write the socket self UUID got me the full house. For what it's for, I don't mind two scripts, so this is great. Thank you. Edited April 24 by spettitt Quote Link to comment
Vectorworks, Inc Employee Nikolay Zhelyazkov Posted April 24 Vectorworks, Inc Employee Share Posted April 24 6 minutes ago, spettitt said: Thanks for this @Nikolay Zhelyazkov. Adding that line does indeed give me the parent device, but did then affect the sockets getting their self UUID. However then a follow-up script just to write the socket self UUID got me the full house. For what it's for, I don't mind two scripts, so this is great. Thank you. Did you put my script in your old script? My change was just 1 line in your old script but I added the whole function for context. Quote Link to comment
spettitt Posted April 24 Author Share Posted April 24 11 minutes ago, Nikolay Zhelyazkov said: Did you put my script in your old script? My change was just 1 line in your old script but I added the whole function for context. That's right, yes. This was what I had: import vs ##################### # First - Reset the SktUUID Record on each socket in each Device prof group def SockRecord(h): vs.Record(h, 'SktUUID') vs.SetRFieldOpt(h, 'SktUUID', 'Dev', True, True) vs.ResetObject(h) vs.SetObjectVariableBoolean(h, 1167, True) def DevSockAddRecord(h): hprofile = vs.GetCustomObjectProfileGroup(h) vs.ForEachObjectInList(SockRecord, 1, 0, vs.FInGroup(hprofile)) vs.ResetObject(h) vs.SetObjectVariableBoolean(h, 1167, True) vs.ForEachObject(DevSockAddRecord, "PON = 'Device'") ##################### # Then go through each Device and post it's Self UUID. # Devices first because they are at the top of the relational chain def DevUUID(h): UUIDv = vs.GetObjectUuid(h) vs.SetRField(h, 'DevUUID', 'Self', UUIDv) vs.ResetObject(h) vs.SetObjectVariableBoolean(h, 1167, True) vs.ForEachObject(DevUUID, "PON = 'Device'") ##################### # For each socket, post it's self UUID and then reset it, so it picks up the Device UUID def SockUUID(h): UUIDv = vs.GetObjectUuid(h) if UUIDv: #vs.Message(f'Found a socket {UUIDv}') vs.SetRField(h, 'SktUUID', 'Self', UUIDv) vs.ResetObject(h) vs.SetObjectVariableBoolean(h, 1167, True) def DevSockUUID(h): hprofile = vs.GetCustomObjectProfileGroup(h) vs.ForEachObjectInList(SockUUID, 1, 0, vs.FInGroup(hprofile)) vs.ResetObject(h) vs.SetObjectVariableBoolean(h, 1167, True) vs.ForEachObject(DevSockUUID, "PON = 'Device'") ##################### # Then go through each Circuit and post it's Self UUID def CircuitUUID(h): UUIDv = vs.GetObjectUuid(h) if UUIDv: #vs.Message(f'Found a circuit {UUIDv}') vs.SetRField(h, 'CircuitUUID', 'Self', UUIDv) vs.ResetObject(h) vs.SetObjectVariableBoolean(h, 1167, True) vs.ForEachObject(CircuitUUID, "PON = 'Circuit'") # Resets for good measure def refreshskt(h): vs.ResetObject(h) vs.SetObjectVariableBoolean(h, 1167, True) def refreshdev(h): hprofile = vs.GetCustomObjectProfileGroup(h) vs.ForEachObjectInList(refreshskt, 1, 0, vs.FInGroup(hprofile)) vs.ResetObject(h) vs.SetObjectVariableBoolean(h, 1167, True) def refreshcircuit(h): vs.ResetObject(h) vs.SetObjectVariableBoolean(h, 1167, True) vs.ForEachObject(refreshdev, "PON = 'Device'") vs.ForEachObject(refreshcircuit, "PON = 'Circuit'") Which produced the below: Quote Link to comment
Vectorworks, Inc Employee Nikolay Zhelyazkov Posted April 24 Vectorworks, Inc Employee Share Posted April 24 Hmm, haven't noticed this. Well, since you have this figured out I suppose that it is ok Quote Link to comment
spettitt Posted April 24 Author Share Posted April 24 28 minutes ago, Nikolay Zhelyazkov said: Hmm, haven't noticed this. Well, since you have this figured out I suppose that it is ok No worries. It's part of a much larger project, and I can integrate the top-up script in to the next stage of the process, so it's a good solution all in all. Thanks for your help! Quote Link to comment
Vectorworks, Inc Employee Conrad Preen Posted May 9 Vectorworks, Inc Employee Share Posted May 9 @spettitt So cool that you are getting into all this 🙂 !!! If in your adventures you find that some scripting hooks are missing do reach out. I would like to add better support for scripting to ConnectCAD and the best way to do that is demand-driven. Conrad Quote Link to comment
spettitt Posted May 9 Author Share Posted May 9 6 hours ago, Conrad Preen said: @spettitt So cool that you are getting into all this 🙂 !!! If in your adventures you find that some scripting hooks are missing do reach out. I would like to add better support for scripting to ConnectCAD and the best way to do that is demand-driven. Conrad Thanks, yes, I will do. The recent Panel Connector Eval certainly helped, and if there is anything in the scripting world I'll flag it, definitely. I should have gotten in to Python a long time ago. I'm at the point now where I'm writing standalone desktop apps in python for all sorts of other things, sometimes including data that has come from VW. I'd love to get in to the SDK but it's a big pill to swallow and the documentation online seems fairly impenetrable for someone new to it, and appears to be pretty old. It would be great if someone could just make a video or small video series on it aimed at people that don't know C++ or the concepts of it. Just a 'getting started' video of how to get installed, set up and write a basic hello world/draw-a-rectangle. If there was an easier 'way in' than written documentation, I think you'd get many more potential partner product developers getting past the first hurdle, including me. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.