Hello,
Quick question in regards to the Audio component in Perspective.
I wish to have a sound play when a critical alarm is triggered.
What would be the best way to achieve this?
Anyone have any experience with this?
Hello,
Quick question in regards to the Audio component in Perspective.
I wish to have a sound play when a critical alarm is triggered.
What would be the best way to achieve this?
Anyone have any experience with this?
You cannot rely on the browser your Perspective client is using to allow auto-play of your sound, nor be sure the sound on that PC is even on. You cannot even rely on there being an open Perspective client to play the sound.
Critical audible alerts must be wired to the system, not to any client. Preferably directly to the system's PLC, but possibly to the Ignition gateway (where a gateway event can use system.util.playSoundClip()
to play through the gateway's sound card).
If Ignition handles defining alarm priority, what is considered best practice for the alerts to be wired to a PLC? I've always wanted to ask others what they do on this. I know I could hard code in the PLC, but then that opens up discrepancies between what the HMI shows as an alarm priority and the PLC.
I usually setup an alarm listener and then send this data to the PLC by a gateway event. The alarm listener opens up the possibility to handle different priorities or even other alarm properties.
If a PLC is going to sound or flash the alarm (literally), I don't make the logic rely on the gateway. That's the point of having the PLC do it.
Right, so how do you correlate the two (HMI <--> PLC)? We usually wire horns/lights to the PLC simply because that's easier to do, not because it's a "critical" function. Just curious on what others do on this, not meaning to hijack a thread or get in a needless debate.
When there is an HMI independent of Ignition (I prefer Vision on machines...), I don't see how the priority coordination can be anything other than custom.
When Ignition is also the HMI, I prefer that the PLC simply generate the alarms, with Ignition following the PLC's lead for critical alarms, and Ignition setting the priority for anything else. And Ignition handling all acknowledgements, if any.
Ok, custom is all I could think of as well.
Thanks for the feedback!
Here's how i solved it.
playAlarm
False
upon creation).playAlarm
runScript()
to check for active alarms:runScript("len(system.alarm.queryStatus(priority=['Critical'], state=['ActiveUnacked'])) > 0", 2500)
True/False
) updates the playAlarm
property.playAlarm
to Audio Component's props.play
play
property of the Audio Component directly to the playAlarm
property.props.source
https://www2.cs.uic.edu/~i101/SoundFiles/taunt.wav
Views/AlarmView
).To enable sound playback globally, on any view or through a main view, i:
playAlarm
value./headerview
in this case.You really should not be running that expression binding on a view like that. You're going to cause yourself a lot of headaches if/when you have lots of clients connected all running that query every 2.5 seconds.
Instead, run a timer script on the gateway that runs your script and just writes the either the count of alarms or a boolean value to a tag. Then you can use your binding off of that tag instead of a runScript
expression. This guarantees it to be up to date and only running once every 2.5 seconds no matter how many clients you have.
Thank you so much, man.
I'm going to revise this and update the solution accordingly.
Any feedback is greatly appreciated
This still doesn't solve all problems, specifically in regards to issues pturmel mentioned. But hopefully this is somewhat more efficient.
I created a gateway timer script to monitor active critical alarms and update a memory tag named CriticalAlarmCount.
results = system.alarm.queryStatus(priority=["Critical"], state=["ActiveUnacked"])
critical_alarms = len(results)
system.tag.writeBlocking(["[TagProvider]TagFolder/CriticalAlarmCount"], [critical_alarms])
I added a custom session property named playAlarm with this expression binding:
try({[TagProvider]TagFolder/CriticalAlarmCount} > 0, false)
..triggering True when any critical alarm is active.
On the View where the Audio Component is located, I created a property change script for playAlarm
.
def valueChanged(self, previousValue, currentValue, origin, missedEvents):
if currentValue.value == True:
self.getChild("root").getChild("Audio").props.play = True
...sets Audio.props.play to True when playAlarm becomes True.
playAlarm
logic.If i were to use the gateway and system.util.playSoundClip for this - does anyone have any resources or tips for how to set that up?
Using system.util.playSoundClip("/sound/alarm.wav", 1.0, False) to trigger sound from GW (file is mounted to docker volume)
Getting an error that the file format is not supported by javax.sound.sampled API requirments
As far as i can see from the error, the requirements are these:
Error message:
Caused by: org.python.core.PyException: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian, and buffers of 128020 to 128020 bytes is supported.
... 26 common frames omitted
Caused by: java.lang.IllegalArgumentException: No line matching interface Clip supporting format PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian, and buffers of 128020 to 128020 bytes is supported.
at java.desktop/javax.sound.sampled.AudioSystem.getLine(Unknown Source)
at com.inductiveautomation.ignition.common.script.builtin.SystemUtilities.playSoundClip(SystemUtilities.java:288)
I'm using a wav file with a bitrate of 705 kbps, which is a uncompressed 16-bit PCM WAV file
From what i can see, this audio file should work. Anyone have any thoughts?
Your sampling rate is too high if those requirements are strict.
I would not expect a docker container to emulate sound hardware, and if it did, where would the sound go?
Gateway sound generation presumes gateway hardware with a sound card.
Okay. It seems you're right. I am still new to this and was not aware of this. But thanks for pointing that out.
Consider using a VM instead of docker. Many hypervisors do provide sound card emulation that routes to the hypervisor's hardware.