I am working on an Ignition project using Perspective, and I want to create a toast notification using a popup. The popup should automatically close after a certain delay (e.g., 5 seconds) without blocking the main thread. Here's what I've tried so far:
Opening the Popup: I'm using system.perspective.openPopup, and that works perfectly.
Closing the Popup After Delay
tried using system.util.invokeAsynchronous to create a separate thread and used time.sleep to add a delay.
After the delay, I called system.perspective.closePopup to close the popup.
However, this doesn't seem to work as expected, but the closePopup function does not execute or fails silently. Here's the relevant part of my code:
import system
import time
class ToastManager:
@staticmethod
def open_toast(popup_id, view_path, params=None, duration=5):
# Open the popup
system.perspective.openPopup(popup_id, view_path, params)
# Asynchronous task to close the popup after a delay
def async_task():
time.sleep(duration) # Wait for the specified duration
system.perspective.closePopup(popup_id) # Attempt to close the popup
system.util.invokeAsynchronous(async_task)
The popup opens successfully, but the closePopup function does not work. If I call the async_task function directly it closes the popup with delay. But with invokeAsynchronous it does not close or throw any error.
Where I am getting wrong on this? Seems like the invoke invokeAsynchronous is not working. Where is this going wrong?
Platform Ignition Platform8.1.30 (b2023071408)
I only want to close the popup using project library scripting.
Questions
Is it possible to call system.perspective.closePopup from an asynchronous thread using invokeAsynchronous?
Do I need to use a different method to close the popup from a separate thread?
Is there a recommended way to achieve this functionality in Ignition Perspective?
Sleep = bad.
Just add a timer on the view itself which closes itself. Set the time on load to a custom prop, and add a custom prop to get the difference in seconds between now and the first load prop and compare to your open seconds. If true, use an on change script to close the popup passing in "" as the view name
I like your idea but Can you tell me how to check the condition in every seconds? Do I need to set a CRON job to check the condition and close the popup?
In Perspective Property Editor scroll down to CUSTOM.
Create a new custom property startTime.
Create an expression binding on startTime with the expression, now(0). This will fire once when the popup opens and save the current timestamp in the custom property.
Create a second tag, timeout.
Add an expression binding, (now(1000) - {this.custom.startTime}) > 5000
This will evaluate every 1000 ms and will return true when the popup has been open for 5000 ms.
Right-click on custom.timeout and select Edit Change Script. Add the script,
def valueChanged(self, previousValue, currentValue, origin, missedEvents):
if currentValue.value:
system.perspective.closePopup("")
Tips: now(0) β Runs once on load. now() β Runs at the default scan rate - typically 1000 ms. now(4321) β Runs every 4321 ms.
This will work but I don't want to use tag browser for this operation due to architectural constraints. That's my last hope. I can use similar condition which You have given directly inside my class and check until the condition meets.
But I am more curious why the invokeAsynchronous does not execute the async_task in my above example? If I Call the async_task() directly it works. I mean it waits until the duration and closes the popup. But not with invokeAsynchronous. For toast implementation I don't want to make things complicate if the invokeAsynchronous works.
If you are referring to post #6, then I don't know. I've had no reason to use Toast or create a class for such a simple task. The expression bindings and change events are simple, built-in and use resources efficiently.
I have implemented a class to enhance the codeβs reusability. Although it is not a simple popup, we are utilizing popups for the toast functionality. Regrettably, there is no alternative to popups in Ignition. Nevertheless, I am employing toast to display information throughout the application. I have provided a snippet of my requirements for this question. In actuality, the requirements are quite intricate.
If you can see my first reply to your answer and help me understand why the invokeAsynchronous does not able to execute the async_task(). That will be helpful.
Did you see my example? While it isn't a popup it shows a timer example, instead of changing text you close the popup and instead of the button starting the timer it starts when you open the popup.