If I don't have a PLC but I have the project, most of our tags are within UDTs which are already developed, so these are fairly easy to create manually or using a tool that takes in a list of instance names and parameters and creates the udt instances for me.
Without a PLC, in v8, you can convert tags between opc and memory without any information being removed (this wasn't in the case in v7).
I use this script, just copied into the script console, to convert tag json copied into the clipboard, between OPC & memory types. Actual memory tags or any other tags won't be affected, only those that were originally OPC will be affected.
Just comment in/out the bottom two lines, then paste back into the tag browser (need to right click, paste - Ctrl+V doesn't work for tags). It works for tags as well as UDT definitions and their tags.
EDIT 2024-07-01
from java.awt.datatransfer import StringSelection
from java.awt.datatransfer import Clipboard
from java.awt import Toolkit
from java.awt.datatransfer import DataFlavor
### clipboard functions ###
def setup():
global toolkit
global clipboard
toolkit = Toolkit.getDefaultToolkit()
clipboard = toolkit.getSystemClipboard()
def writeClipboard(text):
setup()
clipboard.setContents(StringSelection(text), None)
def readClipboard():
setup()
contents = clipboard.getContents(None)
return contents.getTransferData(DataFlavor.stringFlavor)
### end clipboard functions ###
def convertTagSource(obj, valSource='original', insideUdtInstance=False):
"""
Converts tag JSON between memory and their original value source.
This works by looking at the tag's valueSource and identifying property values for other value sources to determine
what the original value source was.
Note: UDT instance tags do not have a lot of this information, so some of these tags are unnecessarily converted
to memory tags such as expression tags. This is unavoidable without reading the tag's config using
system.tag.getConfiguration. But... lazy...
"""
this_fn = convertTagSource
if valSource not in ['original', 'memory']:
raise ValueError('Invalid `valSource` value passed into function. Valid values are "original" or "memory".')
# if the obj is a list, then run through the list and convert any tags contained
if isinstance(obj, list):
for i in range(len(obj)):
obj[i] = this_fn(obj[i], valSource, insideUdtInstance=insideUdtInstance)
# if the obj is a dict, check if it is a tag and convert it if required
if isinstance(obj, dict):
if 'tagType' in obj and obj['tagType'] == 'UdtInstance':
insideUdtInstance = True
if valSource == 'original':
if obj.get('valueSource', None) != 'expr':
# convert back 'opc' source tags
if 'opcItemPath' in obj and obj['opcItemPath'] != '':
obj["valueSource"] = 'opc'
# remove the overridden 'value' from using a memory source
obj.pop('value', None)
# convert back 'reference' source tags
elif 'sourceTagPath' in obj:
obj["valueSource"] = 'reference'
# remove the overridden 'value' from using a memory source
obj.pop('value', None)
if insideUdtInstance and 'valueSource' in obj:
obj.pop('valueSource', None)
obj.pop('value', None)
# if the val_source arg is memory, then convert opc and reference types to memory
elif valSource == 'memory':
if (any(key in obj for key in ['opcItemPath', 'sourceTagPath']) and
obj.get('valueSource', None) != 'expr') or \
(insideUdtInstance and 'tagType' in obj and obj['tagType'] == 'AtomicTag'):
obj["valueSource"] = 'memory'
dt = obj.get('dataType', None)
# set default values for the memory tags, otherwise they're all set to None which is annoying
if dt in ['Boolean']:
obj['value'] = False
elif dt in ['Float4', 'Int4', 'Float8']:
obj['value'] = 0
elif dt in ['String']:
obj['value'] = 'Dev Test'
elif dt is None:
obj['value'] = 0
else:
raise TypeError('Invalid val_source argument value! ({})'.format(valSource))
for key in obj.keys():
if isinstance(obj[key], dict):
obj[key] = this_fn(obj[key], valSource, insideUdtInstance=insideUdtInstance)
if isinstance(obj[key], list):
for i in range(len(obj[key])):
obj[key][i] = this_fn(obj[key][i], valSource, insideUdtInstance=insideUdtInstance)
# if it's just a flat type, ignore it
else:
pass
return obj
def convertTagJsonSourceFromClipboard(convertTo):
""" Converts tag json from """
# make sure you copy some tag json first to the clipboard!
tagsJson = readClipboard()
tags = system.util.jsonDecode(tagsJson)
if convertTo in ['original', 'memory']:
for item in tags:
tags[item] = convertTagSource(tags[item], convertTo)
tags = system.util.jsonEncode(tags)
tags = tags.replace(":True", ":true").replace(":False",
":false") # json technically doesn't capitalise first letter of bool vals.. compare tools whinge
writeClipboard(tags)
else:
system.gui.errorBox("You failed at setting the value source correctly... use 'original' or 'memory' idiot", 'Idiot')
convertTagJsonSourceFromClipboard('memory')
#convertTagJsonSourceFromClipboard('original')
For Vision as well, to get rid of the red overlays, you can disable overlays in the designer: