# Project Library Message Handler

**URL:** <https://forum.inductiveautomation.com/t/project-library-message-handler/104174>\
**Category:** Ignition\
**Tags:** ignition81, perspective\
**Created:** [March 25, 2025, 4:22pm UTC](https://forum.inductiveautomation.com/t/project-library-message-handler/104174 "2025-03-25T16:22:59Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![arice](https://avatars.discourse-cdn.com/v4/letter/a/ed8c4c/32.png) [@arice](https://forum.inductiveautomation.com/u/arice)\
**Post date:** [March 25, 2025, 4:22pm UTC](https://forum.inductiveautomation.com/t/project-library-message-handler/104174/1 "2025-03-25T16:22:59Z")

</div>

I have created a Project library script that i want to send out a message to be received by a popup. I know the script is being executed exactly where i have placed this messageSender because i have written to a tag directly before it. My question is whethere it is possible to send a message from the script and if so what scope should it be and what scope should the handler from the popup be?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 25, 2025, 4:27pm UTC](https://forum.inductiveautomation.com/t/project-library-message-handler/104174/2 "2025-03-25T16:27:07Z")

</div>

Using `system.perspective.sendMessage()`, by default, depends on being called from a Perspective scope. The project library doesn't have a scope of its own, but runs in the scope of whatever event calls the library function.

If you call into the library from a Perspective event, the library will use the scope of that event for the information needed by `system.perspective.sendMessage()`. If you call your library script from something other than a Perspective event, you will need to provide the session and page IDs in the `system.perspective.sendMessage()` call.

Edit: a little birdie let me know of a typo....

---

<div class="post-metadata">

**Author:** ![arice](https://avatars.discourse-cdn.com/v4/letter/a/ed8c4c/32.png) [@arice](https://forum.inductiveautomation.com/u/arice)\
**Post date:** [March 25, 2025, 4:35pm UTC](https://forum.inductiveautomation.com/t/project-library-message-handler/104174/3 "2025-03-25T16:35:08Z")

</div>

Ok sorry trying to understand. The script is being called from a startup event on the popup. So i should use the system.util.sendMessage() instead of the perspective.sendMessage?

---

<div class="post-metadata">

**Author:** ![arice](https://avatars.discourse-cdn.com/v4/letter/a/ed8c4c/32.png) [@arice](https://forum.inductiveautomation.com/u/arice)\
**Post date:** [March 25, 2025, 5:23pm UTC](https://forum.inductiveautomation.com/t/project-library-message-handler/104174/4 "2025-03-25T17:23:26Z")

</div>

I am calling the project library script from the popup onStartup event in the script this is how I am calling it:

`system.perspective.sendMessage('ClosePopup')`

Then I have a messge handler setup on the same popup that looks like this:

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/2/2/221be38f62f384e5e5448082d58f93a99adcf1a9.png)

Both the variable in this script and the closePopup arent working.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 25, 2025, 5:26pm UTC](https://forum.inductiveautomation.com/t/project-library-message-handler/104174/5 "2025-03-25T17:26:32Z")

</div>

Please show your actual popup startup event. You'll have to show your library script, too.

---

<div class="post-metadata">

**Author:** ![arice](https://avatars.discourse-cdn.com/v4/letter/a/ed8c4c/32.png) [@arice](https://forum.inductiveautomation.com/u/arice)\
**Post date:** [March 25, 2025, 5:27pm UTC](https://forum.inductiveautomation.com/t/project-library-message-handler/104174/6 "2025-03-25T17:27:51Z")

</div>

![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/1/4/14d5c8db6308585f7d82faa1943c05a8bb97ec69.png)

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 25, 2025, 5:30pm UTC](https://forum.inductiveautomation.com/t/project-library-message-handler/104174/7 "2025-03-25T17:30:57Z")

</div>

A timer object is not a project library object, and its function will never have Perspective scope, since it runs in a different thread.

(You should avoid jython stdlib objects, and especially avoid sleeping or timing in events.)

---

<div class="post-metadata">

**Author:** ![arice](https://avatars.discourse-cdn.com/v4/letter/a/ed8c4c/32.png) [@arice](https://forum.inductiveautomation.com/u/arice)\
**Post date:** [March 25, 2025, 5:35pm UTC](https://forum.inductiveautomation.com/t/project-library-message-handler/104174/8 "2025-03-25T17:35:22Z")

</div>

Sorry Timer is the library that i created and it is working. Here is the code from my script called Timer:

```python
import threading
import time

class ResettableTimer:
    def __init__ (self, interval, function, args=None, kwargs=None):
        self.interval = interval
        self.function = function
        self.args = args if args is not None else []
        self.kwargs = kwargs if kwargs is not None else {}
        self.timer = None
        self.is_running = False

    def _run(self):
        self.is_running = False
# path = '[default]ClosePopup'
# system.tag.writeBlocking(path, True)
        system.perspective.sendMessage('ClosePopup') # <-- Here is where I am calling the sendMessage
        self.function(*self.args, **self.kwargs)

    def start(self):
        if not self.is_running:
            self.timer = threading.Timer(self.interval, self._run)
            self.timer.start()
            self.is_running = True
            #path = '[default]ClosePopup'
            #system.tag.writeBlocking(path, True)

    def reset(self):
        if self.is_running:
            self.timer.cancel()
        self.start()

    def cancel(self):
         if self.is_running:
            self.timer.cancel()
            self.is_running = False

```

If I uncomment the two lines under def\_run then it writes to that tag five seconds after the popup opens so i know the code is being called.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 25, 2025, 6:03pm UTC](https://forum.inductiveautomation.com/t/project-library-message-handler/104174/9 "2025-03-25T18:03:51Z")

</div>

You are using `threading.Timer` to run your function. It will never have Perspective scope. Don't use `threading.Timer`.

---

<div class="post-metadata">

**Author:** ![arice](https://avatars.discourse-cdn.com/v4/letter/a/ed8c4c/32.png) [@arice](https://forum.inductiveautomation.com/u/arice)\
**Post date:** [March 25, 2025, 6:10pm UTC](https://forum.inductiveautomation.com/t/project-library-message-handler/104174/10 "2025-03-25T18:10:02Z")

</div>

Can i use any timer in this script that will have perspective scope? Or is there a better way to accomplish what I am trying to do which is close the popup after a certain amount of time unless i set the reset timer funciton?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 25, 2025, 6:31pm UTC](https://forum.inductiveautomation.com/t/project-library-message-handler/104174/11 "2025-03-25T18:31:51Z")

</div>

Use a couple view custom properties. Have the first bound to the expression `now(0)`. Have the second bound to just `now()`. Then use a change script on the latter to compute the time between the two, and if greater than desired, the script can close the popup.

To reset the timer, write a new start timestamp (from `system.date.now()`, typically) to the start timestamp property.

Note, this topic is an example of a classic "XY" problem, where you ask for help on a task that you've decided will solve your real problem, instead of asking for help solving your real problem.

In the Ignition platform, uses of jython timers, or any kind of `.sleep()`, or any kind of unbounded loops, are all big red flags that your approach to your problem is flawed.

---

<div class="post-metadata">

**Author:** ![arice](https://avatars.discourse-cdn.com/v4/letter/a/ed8c4c/32.png) [@arice](https://forum.inductiveautomation.com/u/arice)\
**Post date:** [March 25, 2025, 8:20pm UTC](https://forum.inductiveautomation.com/t/project-library-message-handler/104174/12 "2025-03-25T20:20:50Z")

</div>

Thanks for the help
