Jump to content

ConnectCAD Socket - Number of Circuits


Recommended Posts

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 by spettitt
Link to comment
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.

Link to comment

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.

image.png.3631c8879bd2210592d0790d42e147dc.pngNumSktTest.vwx

 

In my actual application, I'm using vs.ForEachObjectInList to traverse inside the intended device and locate the socket PIO.

Link to comment

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. 😞

Link to comment

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

Link to comment
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.

Link to comment
  • Vectorworks, Inc Employee

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

  • Like 2
Link to comment

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...!

  • Like 1
Link to comment
  • 4 months later...

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.

image.png.14a1bf8d4ff0754d26e95eba977f7702.png

 

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!
 

Link to comment
  • Vectorworks, Inc Employee

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

Link to comment
  • 1 month later...
Posted (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:
image.thumb.png.f362297ecc56a7c149de64272a628c57.png

 

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.

image.png.e12d4039a42560949d4453ee119b74f1.png

 

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 by spettitt
Link to comment
  • Vectorworks, Inc Employee

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

Link to comment
Posted (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.

image.thumb.png.b1f1e4e66ef39df120f7f79899ba3e10.png

 

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 by spettitt
Link to comment
  • Vectorworks, Inc Employee
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.

image.thumb.png.b1f1e4e66ef39df120f7f79899ba3e10.png

 

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.

Link to comment
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:

 

image.png.8e5f9ab6b4233a29af7b9e7e7d8b73d8.png

Link to comment
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!

Link to comment
  • 2 weeks later...
  • Vectorworks, Inc Employee

@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

Link to comment
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.

Link to comment

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...