Applies To:
  • CitectSCADA 5.xx
  • CitectHMI 5.xx

I want to run some Cicode to do something when alarms (or a specific alarm) become active. How do I do this? 

There are quite a few ways of doing this and depending on what you want to do you need to decide what is best for your application. I will try to explain the different ways to do it with their advantages and disadvantages.


Action for a single alarm (e.g. Notify someone that a specific alarm went on/off/ack)

If you need to perform an action when a specific alarm changes state your best option is to use "Alarm properties as tags" to create event to run your cicode.

Example: To make a cicode function run when alarm MYALARM is acknowledged.

First you need to set up an Alarm I/O Device to enable "Alarm properties as tags". Then create an event with trigger "MYALARM.Ack" or "MYALARM.On" depending on which status change you want the action to be triggered, and in the action field you fill in your cicode function (e.g. MyFunc()).

Calling a Cicode function from an event creates a new (background) task so there are no blocking issues, but be sure not to start too many user tasks at once. (As limited by the [Code]Threads parameter).

(An alternative might be to include Cicode functions in the alarm description of digital, time-stamped and advanced alarms. However such a Cicode function must be a non-blocking, and must return a value).

Action for all alarms (e.g. Create some custom logging)

You can use the Alarm Event queue to retrieve a list of what has changed.

When you enable [Alarm]EventQue, CitectSCADA creates a queue named EventQue on the alarm server where it stores each change that occurs in the alarm system. A queue in CitectSCADA can only contain one string and one integer element. The alarm event queue sets the queue integer element to the record number and the queue string element to what you've set in [Alarm]EventFmt. For example you could store the alarm display field {LogState} in the queue string and then you know exactly why that alarm was put in the queue.

The next step is to read out the queue with QueRead() and process the alarms one by one in the rate you like with user cicode that can be blocking. Just remember to put something significant into the queue string because the alarm can have changed state again between when it was put onto the queue until you read out additional alarm information with AlarmGetFieldRec(). This code has to be run at the alarm server but the code can be made efficient.


Do not use Alarm categories Ack/On/Off action as it will be not be called per alarm, but rather only once per category. So if in one alarm scan time 3 alarms in that category become active, the Ack/On/Off action is only called once.

If you have an "acknowledge all" button on your alarm page it will cause serious CPU usage if your alarm action function is not really small and fast. Actions like acknowledge all above would just cause a lot of tasks to be started and remember you do not have more than [CODE]Threads before things start to go nasty.

Do not use AlarmFirstCatRec() type functions trying to find the alarm and AlarmGetFieldRec() to read the state. The search will use a lot of CPU time and you will be limited into running it on the alarm server witch might have other more important things to use it's CPU for. These functions are good for things like counting the number of active alarms but should not be done for detecting state changes.