Voice notifications to local computer speakers

I have been playing with the alarms and can see that they are quite powerful, one question though.

Pronunciation of English alarms has always been an issue when speaking in technical terms, sometimes its nice to be able to play the voice alarm back to hear what its going to sound like and tweak the phonetic spelling to suit your particular requirements.

I suggest either a notification block in the pipeline that sends the audio stream to your speakers or a similar test notification page from the gateway console that can send dummy alarms and have them play back.

I guess if you had the notification block that sent them to speakers it could be used for testing as well as an actual computer that speaks out alarms while they are active.

Perhaps one day you could even extend this idea to make a computer (client) running ignition an entry in the roster so that you could send spoken / audible alerts to it and alert people in the area.

For now just a way to test what the TTS sounds like speaking my particular alarm would be great though!

Hi,

Thanks for the feedback. I’ve had a similar thought, and envisioned the feature request for console based enunciation as well. Not sure when we’ll be able to make it happen, but at least we’ve structured things so that it’s possible.

The first challenge is where to put this. Given that the voice notification is only one type of “pluggable” profile, the UI isn’t really set up to handle more complicated features like this. Your idea of a new type of notification block/profile could work, and even though it doesn’t go out to the clients, some people might just want to hook up the gateway machine to a PA. We might also be able to put something into the gateway, on the notification profile.

The next thing we need to look into is the fact that the voice engine supports various options for pronunciation tweaking and text “normalization” (where things like “@” are automatically converted to “at”). We should probably make it possible to edit these entries, so that your alarm names, display paths, and custom messages can stay as normal as possible, and your adjustments go into a centralized table and are applied automatically.

Regards,

Yes I was thinking about the whole PA thing too but didn’t want to complicate things. I guess the client side playback gets a bit more tricky, I would prefer to be able to play alarms from the streaming client though. It would be nice if each client computer could be setup as a contact for rostered playback in some future version.

This would tie in nicely to the whole simultaneous / sequential escalation block options you were discussing in a previous post as you could have a computer on the shop floor yell out alerts but if they were not acknowledged then a management or maintenance console could be escalated to yell out the same alert. Of course you have to be able to handle the computer not being on to serve the request but that would be the same as a phone not being on to receive a phone call I guess.

Anyway, back on topic - for now I have been going to the ivona website and selecting the voice I want and just typing in the alarms to get playback through my browser.

I wasn’t aware of the customisations though, perhaps ill download the android application and see if the same settings / tweaks are available there so that I can sift through them to look for anything helpful.

For anyone interested, the Ivona android app (for phones and tablets) looks to be free. Might be a good way to double check things are speaking how you hoped.

Greetings,

I have actually worked on scripting into the voice module. I have it sending “message strings” on alarm tag changes.
Had to create a gateway “listener” and a client event script. I can post some of it if you like. My particular application uses the serial port open/close to trigger the push to talk on a Ken-wood base station radio which then broadcasts to all the maintenance personnel. I would like to be able to “slow Katherine down” just a little bit…

I would be very interested in what you have scripted. I have been considering a similar implementation and would much prefer building on an existing base.

Bill

anyone could kindly show me how to setup my alarm notification via local computer speakers?
thank you?

This would be awesome if I could do this. Does anyone have any examples of this?

I will try to remember to post a write up on how to do this tomorrow

I used the “messaging system”
You have to have a gateway message handler script.

Then you will need a client that has speakers you can play the audio payload with:
It will need a “client message handler script”:

Then to utilize the system on the tags that you want to configure the alarms for:


You will want to configure the Active and Cleared both. The tags will of course have to have an alarm configured in the tag properties nothing out of the ordinary for that but it does need an alarm.
For the clear:

There are some other general notes.In my receive alarm scripts I use the com port literally as a low voltage switch that engages a “Touch To Talk” microphone on a ken-wood brand base station.
I had to engineer a very custom cable to get the audio out the 3 mm headphone jack to the audio line of the base station.
Your mileage may vary on your purpose and intent. It does WORK though.
What you get from this are System event triggered audible alarms. It has been working in my application for several years now. I haven’t spent anymore time looking for a “cleaner solution” because this one works for us. By now I would imagine there would be some module that could be purchase that could do this out the box maybe but The way we use it works and I maintain it.
I do also have a little script running on the PC that once a day deletes all the temp .WAV files but that isn’t done with Ignition.

1 Like

This is fantastic.

I just now noticed it

Thank you, thank you

1 Like

now, if only we could get the speed of her speech a bit slower

Has anyone tried this in perspective with the new audio component?

This thread is from 2013 so it's all Vision. I suggest that you start a new thread and tag it as Perspective. Reference this one if any of it is relevant.

1 Like

I was curious, where actually does the file get saved. I cannot find it anywhere. I wonder if it gets overwritten.

The directory for our system is in the screenshot.
A few YEARS later I developed this script that runs on a scheduled task to delete these files. I am certain there are plenty of other ways, but this script works a treat. I have it email me when it is complete. The script itself is a result of some web searching, I could send it if I remove my personal details but if you've made it this far you don't need the script from me. This is not a perspective project for sure. Somewhere in this post I also mention the custom serial cable that needs made to interface this into an actual 2way radio broadcast system. Or I thought so, this is quite an old thread.

Decent, thank you.

Our gateway is linux. I wonder if that's why I couldn't find it.

I was asking about perspective to see if you tested the message audio payload with the "session events" message in perspective to see if a perspective session could receive it and play it. I tried without any luck.

Actually, I did get this working over perspective. Caveat being that the sound player must be user initiated in the browser or app. There is ways around it I am sure.
The only main difference was the bottom portion of the code and the addition of a "Perspective Session Event Message".

Gateway Event Message

def handleMessage(payload):
    # Import necessary Java and Ignition classes
    from com.inductiveautomation.ignition.gateway import IgnitionGateway
    from com.inductiveautomation.ignition.gateway.services.tts import TTSEngineManager
    from com.inductiveautomation.ignition.gateway.services.tts import TTSSpeed
    from javax.sound.sampled import AudioSystem
    from javax.sound.sampled import AudioFileFormat
    from java.io import File
    from java.util import Base64
    from org.apache.commons.io import IOUtils
    from java.io import File, FileInputStream
    
    # Initialize a logger for this script
    log = system.util.getLogger("Voice")
    
    # Extract the 'message' field from the payload
    txtReceived = payload['message']
    
    # Define the desired language for text-to-speech (TTS)
    language = "katherine"
    
    # Assign the received message to a variable
    message1 = txtReceived
    
    # Get the Ignition Gateway context
    ctx = IgnitionGateway.get()
    
    # Get the TTS engine manager service
    ttsMgr = ctx.getModuleServicesManager().getService(TTSEngineManager)
    
    # Check if TTS manager is available
    if ttsMgr is None:
        log.info("TTS manager is not currently available.")
    else:
        # Get the available voices for TTS
        voices = ttsMgr.getVoices()
        
    log.info("Available voices: %s" % voices)
    log.info("Voice: %s: %s" % (language, message1))
    
    # Select the desired voice for TTS based on the specified language
    voiceToUse = voices[0]  # Default to the first voice
    for voice in voices:
        if str(voice.getName()) == str(language):
            voiceToUse = voice
            break
    
    # Set the desired speed for TTS (e.g., TTSSpeed.Slow)
    # Note: The next line is commented out, so it won't affect the script execution.
    # ttsMgr.getTalkerFor(voiceToUse).setDesiredSpeed(TTSSpeed.Slow)
    
    # Set the desired speed for TTS (e.g., TTSSpeed.Slow) for the 'voice' instead of 'voiceToUse'
    ttsMgr.getTalkerFor(voice).setDesiredSpeed(TTSSpeed.Slow)
    
    # Render the TTS audio stream for the message using the selected 'voiceToUse'
    strm = ttsMgr.getTalkerFor(voiceToUse).render(message1)
    
    # Define the file path to save the TTS audio file
    filePath = "C:\\tmpFile.wav"
    f = File(filePath)
    
    # Write the TTS audio stream to the WAV file
    AudioSystem.write(strm, AudioFileFormat.Type.WAVE, f)
    
    # Read the WAV file as bytes
    fis = FileInputStream(f)
    fileBytes = IOUtils.toByteArray(fis)
    fis.close()  # Close the FileInputStream explicitly
    
    # Encode the audio bytes in Base64
    base64encodedString = Base64.getEncoder().encodeToString(fileBytes)
        
    # Read the current dataset from the tag to get active session IDs
#    currentData = system.tag.read("[default]ActiveSessions").getValue()
#    pyData = system.dataset.toPyDataSet(currentData)
        
    # Send the audio message to each active session
    log = system.util.getLogger("SessionMessageSender")
    
#    for row in pyData:
#        sessionid = row["sessionid"]
#        log.info("Sending message to session: " + sessionid)
#        system.perspective.sendMessage(
#            messageType='ttsAudioResponse',
#            payload={'audioData': base64encodedString},
#            scope='session',
#            sessionid=sessionid
#        )
    system.util.sendMessage(
        project="AlarmMonitor",  # Replace with your actual project name
        messageHandler="ttsAudioResponse",  # Replace with your actual message handler name
        payload={'audioData': base64encodedString}
        
    )

Perspective Session Event Message

def handleMessage(session, payload):


#        # Extract the Base64-encoded audio data
#        audioData = payload['audioData']
#    
        # Extract session ID
        sessionId = session.props.id
#    
#        # Log session ID and audio data for debugging
#        logger = system.util.getLogger("AudioHandler")
#        logger.info("Audio data received in session ID '{}': {}".format(sessionId, audioData))
#    
#        # Decode and handle the audio data...
#        # The implementation here will depend on your specific requirements and setup.
        

        audioData = payload['audioData']
        # Convert to a data URL. The format (e.g., "audio/wav") should match your audio data.
        audioDataURL = "data:audio/wav;base64," + audioData
       # Store this URL in a session custom property
        session.custom.audioDataURL = audioDataURL
        logger = system.util.getLogger("AudioHandler")
        logger.info("Audio data received in session ID '{}'".format(sessionId))

That Perspective Session Message "audioDataURL" converts it to a url so it can be played in the perspective sound component.