I have started using runScript with a python script library for most of my colour bindings.
The library first stores all client tag colours into a dictionary that I can then use instead of referring to the client tags (suggestion from @pturmel).
The library then has functions defined to return the correct colour for a given ‘thing’ (device status, device mode, etc). You could handle invalid colour values in here
Here’s a snippet:
'''
Library: [shared].devices.colour
Version: 1.1
Description:
Use these functions within colour expression bindings within a runScript function to show the state of devices/equipment.
Examples
Textbox background:
runScript('shared.devices.colour.getDeviceStatusColour', 0, {[Client]System/Pulses/500ms}, 1)
Device graphic background:
runScript('shared.devices.colour.getDeviceStatusColour', 0, {[Client]System/Pulses/500ms}, 0)
'''
''' # REMOVE THIS, fix for forum formatting only
pipeColourCache = {}
pipeColourTagFolderPath = '[Client]Styles/Colours/Pipework'
pipeContents = ['Water', 'CIP']
for cT in pipeContents:
pipeColourCache[cT + ' - Flow'] = system.tag.read(pipeColourTagFolderPath + '/' + cT + ' - Flow').value
pipeColourCache[cT + ' - No Flow'] = system.tag.read(pipeColourTagFolderPath + '/' + cT + ' - No Flow').value
colourCache = {}
colourTagFolderPath = '[Client]Styles/Colours/Devices'
# unfortunately you can't browse client tags, so have to manually type these out...
colourTags = ['Faulted','Faulted Flash','FOI','Invalid State','Paused','Running','Running Flash','Stopped','Stopped Flash','Stopped Text','Device Mode - Manual Abnormal']
for cT in colourTags: colourCache[cT] = system.tag.read(colourTagFolderPath + '/' + cT).value
stateToColourTranslation = {}
stateToColourTranslation['Starting'] = 'Running'
stateToColourTranslation['Stopping'] = 'Stopped'
stateToColourTranslation['Off'] = 'Stopped'
stateToColourTranslation['Auto'] = 'Running'
stateToColourTranslation['Manual'] = 'Device Mode - Manual Abnormal'
def getDeviceStatusColour(valueString, pulseValue, isTextBox=0):
colour = ""
textBoxSuffix = ""
if isTextBox: textBoxSuffix = " Text"
# Non-flashing states
if valueString in ['Stopped','Running']:
colour = _getColourFromState(valueString, isTextBox)
# Flashing states
if valueString in ['Stopping','Starting','Faulted']:
if pulseValue:
colour = _getColourFromState(valueString, isTextBox, 0)
else:
colour = _getColourFromState(valueString, isTextBox, 1)
if colour == "":
colour = _getColourFromState('Invalid State')
return colour
def _getColourFromState(valueString, isTextBox=0, flashColour=0):
textBoxSuffix = ""
flashSuffix = ""
if isTextBox: textBoxSuffix = " Text"
if flashColour: flashSuffix = " Flash"
colour = colourCache.get(stateToColourTranslation.get(valueString, valueString) + textBoxSuffix + flashSuffix, colourCache[stateToColourTranslation.get(valueString, valueString) + flashSuffix])
return colour
and some of my colours:
On each client tag colour tagChange event, to update the cache if the tag changes:
keyName = tagPath.split("/")[-1]
shared.devices.colour.colourCache[keyName] = currentValue.value