That's perfect! Thanks.
So final implementation.
tags:
[client]Alarms/Alarm_Sound String selected alarm sound name, no extension
[client]Alarms/Alarm_Sound_EN Boolean alarm sound enabled
[client]Alarms/AlarmSoundOptions Dataset dataset of alarm sound name options [Value, Label]
[client]Alarms/Sound_Volume Double volume level 0 - 100
Sound library:
import os
import errno
alarmSoundPath = 'C:\SCADA\Alarm Sounds'
def alarmSoundPathExists():
'''
Checks to see if the alarmSoundPath folder exists. Creates it if it does not.
Args:
n/a
Returns
folder (bool) : true if file path exists, or was successfully created
'''
path = alarmSoundPath
#check to see that file path exists
folder = False
if not os.path.exists(path):
#create the folder if it doesn't exist
try:
os.makedirs(path)
folder = True
except OSError as e:
if errno.EEXIST != e.errno:
raise
#folder exists, continue
else:
folder = True
return folder
def getAlarmSoundList():
'''
Get a list of alarm sounds that are available at the alarmSoundPath
Args:
n/a
Returns:
fileList (string list) : list of WAV file names in the directory
'''
path = alarmSoundPath
#check to see that file path exists
folder = alarmSoundPathExists()
#create the file list for return
if folder:
fileList = [ name.split('.')[0] for name in os.listdir(path) if name.upper().endswith('.WAV') ]
else:
fileList = []
return fileList
def getAlarmSoundDataset():
'''
Get a dataset of alarm sounds that are available at the alarmSoundPath
Args:
n/a
Returns:
dataset (dataset) : file names as dataset for use with a dropdown
'''
path = alarmSoundPath
headers = ['Value','Label']
#get file list
fileList = getAlarmSoundList()
#need a list of lists to match the headers
data = [[i, name] for i, name in enumerate(fileList)]
#return dataset
return system.dataset.toDataSet(headers, data)
##################################################################################
############ functions for clients requesting sounds from the gateway ############
##################################################################################
def requestAvailableAlarmSounds():
'''
Request the list of available sounds from the gateway via message handler
Args:
n/a
Returns:
fileList (string list) : list of WAV file names in the directory
'''
#call for gateway to send the list of available alarm sounds
return system.util.sendRequest('Fargo', 'SendAlarmSoundList')
def retrieveSoundBytes(fileName):
'''
Get a sound file from the gateway via message handler
Args:
fileName (string) : alarm sound name to retrieve
Returns:
soundBytes (byte array) : sound file in byte format
'''
#call for gateway to send the alarm sound file in byte format
return system.util.sendRequest('Fargo', 'SendAlarmSound', {'fileName':fileName})
def writeSoundBytes(filePath, soundBytes):
'''
Write sound file to the local client at the alarmSoundPath
Args:
filePath (string) : file to create
soundBytes (byte array) : sound file in byte format
Returns:
n/a
'''
#check to see that file path exists
folder = alarmSoundPathExists()
if folder:
#write the file
system.file.writeFile(filePath, soundBytes)
def updateClientAlarmSounds():
'''
Update alarm sound files on the local client
Args:
n/a
Returns:
n/a
'''
path = alarmSoundPath
tagPath = '[client]Alarms/AlarmSoundOptions'
#remove options until sound files are written - it takes some time
blankDataset = []
system.tag.writeBlocking([tagPath], [blankDataset])
#get the list of available sound files on the gateway
fileList = requestAvailableAlarmSounds()
#for each file
for fileName in fileList:
#generate path to the file
filePath = path + '\\' + fileName + '.wav'
#get the sound file from the gateway in bytes
soundBytes = retrieveSoundBytes(fileName)
#write the sound file to the client file system
writeSoundBytes(filePath, soundBytes)
#update dataset tag for options dropdown
dataset = getAlarmSoundDataset()
system.tag.writeBlocking([tagPath], [dataset])
def playAlarmSound():
'''
Play the selected alarm sound once
Args:
wavFile (string) : path to the wavFile
Returns:
n/a
'''
path = alarmSoundPath
tagsToRead = [
'[client]Alarms/Alarm_Sound', #selected alarm sound file name, no extension
'[client]Alarms/Sound_Volume', #volume level 0 - 100
'[client]Alarms/AlarmSoundOptions', #alarm sound file name options dataset
]
selection, volume, options = [tag.value for tag in system.tag.readBlocking(tagsToRead)]
fileNames = options.getColumnAsList(1)
#selection is valid
if selection and selection in fileNames:
wavFile = path + '\\' + selection + '.wav'
system.util.playSoundClip(wavFile, volume/100.0, True)
def playAlarmSoundLoop():
'''
Continiously play the selected alarm sound
'''
path = alarmSoundPath
tagsToRead = [
'[client]Alarms/Alarm_Sound', #selected alarm sound by file Name (does not include ".wav")
'[client]Alarms/Sound_Volume', #alarm volume level (0 - 100)
'[client]Alarms/Alarm_Sound_EN', #alarm sound enabled
'[System]Gateway/Alarming/Active and Unacked', #active and unacked tag count
'[client]Alarms/AlarmSoundOptions', #alarm sound file name options dataset
]
selection, volume, EN, count, options = [tag.value for tag in system.tag.readBlocking(tagsToRead)]
#alarm sound is enabled
if EN:
#at least one active, unacked alarm
if count > 0:
fileNames = options.getColumnAsList(1)
#selection is valid
if selection and selection in fileNames:
wavFile = path + '\\' + selection + '.wav'
system.util.playSoundClip(wavFile, volume/100.0, True)
playAlarmSoundLoop()
else:
return
else:
return
else:
return
##################################################################################
####### functions for the gateway responding to client requests for sounds #######
##################################################################################
def retrieveAlarmSoundList_MH():
'''
Message handler to retrieve the list of available sound files on the gateway
Args:
n/a
Returns:
fileList (string list) : list of WAV file names in the directory
'''
return getAlarmSoundList()
def retrieveAlarmSound_MH(payload):
'''
Message handler to retrieve sound file from the gateway
Args:
payload (dict) : payload 'fileName' for alarm sound file
Returns:
soundBytes (byte array) : sound file in byte format
'''
path = alarmSoundPath
#filename given
if payload['fileName']:
#generate file path
filePath = path + '\\' + payload['fileName'] + '.wav'
#check to see that the filePath exists
if system.file.fileExists(filePath):
#return the file in byte format
return system.file.readFileAsBytes(filePath)
client startup script:
Sound.updateClientAlarmSounds()
client tag change script AlarmHorn:
#triggers:
#[client]Alarms/Alarm_Sound_EN
#[System]Gateway/Alarming/Active and Unacked
system.util.invokeAsynchronous(Sound.playAlarmSoundLoop)
Gateway message handlers.
SendAlarmSoundList
def handleMessage(payload):
return Sound.retrieveAlarmSoundList_MH()
SendAlarmSound
def handleMessage(payload):
return Sound.retrieveAlarmSound_MH(payload)