Ignition alarmAcked Scripts Need tag.value.value to Set Ack Bits

Erik Lindqvist6 min read
HMI / SCADAOther ManufacturerTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

The Word stays at 1 (0001) instead of 3 (0011) because the alarmAcked script throws on its first line, so the write never executes. Inside an Ignition alarm event script, tag.value is a qualified value (value + quality + timestamp), not an integer. OR-ing it with (1 << 1) raises a type error. The second line has a separate defect: tagPath is already the path object, and tagPath.value does not resolve to a writable path string.

writeBlocking and Other Fixes That Leave the Word at 1

These are the usual first attempts. Each one fails for the same reason: the script aborts before it reaches the write.

Attempted fix Why the Word stays at 1
Swap system.tag.writeAsync for system.tag.writeBlocking The exception fires on the bitwise OR, one line before the write. Changing the write function changes nothing that runs.
Change the mask (| 2, + 2) The left operand is still a qualified value object. Any arithmetic or bitwise operator on it fails the same way.
Move the test from a Memory tag to an OPC tag Tag type is irrelevant. The Memory tag was a valid test bed, and the script logic is what is broken.
Wrap the path as [tagPath.value] The path object has no usable .value for this purpose. Even with the OR fixed, the write targets nothing valid.

This is a logic fault. No timing, load, or comms quantity is involved. The deciding quantity is whether the script runs to completion, and tag diagnostics show that directly.

Qualified Value and TagPath Objects in the Alarm Event Scope

Alarm event scripts (alarmActive, alarmCleared, alarmAcked) execute in the Gateway scope. The tag argument exposes tag properties, and each property returns a qualified value. The integer lives one level deeper:

  • tag.value is the qualified value object.
  • tag.value.value is the raw integer that can take a bitmask.
  • tag.value.quality is the quality code. Check it before trusting the number.

tagPath is a TagPath object that points at the source tag (the Word), not at the alarm. system.tag.writeAsync accepts it directly in a list ([tagPath]). Converting it with str(tagPath) gives an explicit string and makes the path readable in log output.

The corrected minimum script:

def alarmAcked(tag, tagPath, alarmName, alarmEvent, alarmPath, ackedBy, missedEvents):
    val = tag.value.value | (1 << 1)
    system.tag.writeAsync([tagPath], [val])

Reading the Failure in Tag Diagnostics and Gateway Logs

Confirm the exception before you change code, so the fix matches the fault.

  1. In the Designer Tag Browser, right-click the Word tag and open its diagnostics. Script errors on tag events are reported there with the exception text.
  2. Open the Gateway web page and go to the Status logs. Filter for script or tag event errors raised at the time of the acknowledgment.
  3. A type error that mentions unsupported operand types for | confirms the qualified value problem. An error on the write call, or no write at all, points to the path argument.
  4. Add a logger line before the OR if the diagnostics are not conclusive: system.util.getLogger("AlarmAck").info("raw=%s path=%s" % (tag.value, str(tagPath))). The logged raw shows the value, quality, and timestamp triple instead of a bare integer.
Quantity Expected Where to read it
Word value before ack 1 (bit 0 set) Tag Browser value column
Word value after ack 3 (bits 0 and 1 set) Tag Browser value column, OPC client for PLC tags
Script execution result No error entries Tag diagnostics, Gateway Status logs
Source quality at event Good tag.value.quality via logger
Acknowledging user Operator username ackedBy argument

Read-Modify-Write Procedure for a Shared PLC Status Word

The minimum fix works on a Memory tag. On a live PLC Word, another problem appears: the PLC and the HMI both write bits in the same register. tag.value.value is the value captured when the alarm event fired. If the PLC sets or clears another bit between that moment and the write, the script writes the stale Word back and overwrites the PLC's change. Shrink that window with a fresh read:

  1. Resolve the path once: path = str(tagPath).
  2. Read the current Word: qv = system.tag.readBlocking([path])[0].
  3. Abort if qv.quality is not good. Writing a mask onto a bad-quality value writes garbage to the PLC.
  4. Set only the ack bit: newVal = int(qv.value) | (1 << 1).
  5. Write it: system.tag.writeBlocking([path], [newVal]). Check the returned quality so failures appear in the log.
def alarmAcked(tag, tagPath, alarmName, alarmEvent, alarmPath, ackedBy, missedEvents):
    log = system.util.getLogger("AlarmAck")
    path = str(tagPath)
    qv = system.tag.readBlocking([path])[0]
    if not qv.quality.isGood():
        log.warn("Ack bit not written, bad quality on %s" % path)
        return
    newVal = int(qv.value) | (1 << 1)
    result = system.tag.writeBlocking([path], [newVal])[0]
    log.info("%s acked by %s, wrote %d, result %s" % (path, ackedBy, newVal, result))

A fresh read narrows the race window but does not remove it. Only the PLC side removes it completely. Either give the HMI its own acknowledge Word that the PLC copies into the status word, or write to a bit-level item if the device driver supports bit addressing on that register.

Alarm Mode, Ack Mode, and Bit Reset Pitfalls

  • Alarm mode clears on ack. If the alarm is configured as Equal with setpoint 1, writing 3 makes the condition false and the alarm clears the instant it is acknowledged. Use Bit State mode with bit position 0 so the alarm tracks bit 0 only, whatever bit 1 does.
  • Ack Mode set to Auto. Auto-acknowledge fires alarmAcked when the alarm clears, with no operator action. Bit 1 then gets set by the system instead of the user. Set Ack Mode to Manual for operator acknowledgment.
  • Nobody resets bit 1. If neither side clears the ack bit, the next occurrence of the alarm starts with bit 1 already true. On the WinCC 7.2 side, the PLC normally cleared it when bit 0 dropped. Keep that logic in the PLC, or clear it with a mask such as val & ~(1 << 1) in alarmActive.
  • Multiple alarms on one Word. Each alarm's alarmAcked fires independently. Simultaneous acks from shelved or grouped alarms produce overlapping read-modify-write cycles on the same register. This is the strongest argument for a separate ack register.
  • Acks from the PLC side. If the PLC can acknowledge (bit 1 set by a panel pushbutton), Ignition does not ack the alarm journal entry by itself. Use a tag change script that calls system.alarm.acknowledge to keep both sides in step.

Confirming the Ack Bit Round Trip

  1. On the Memory tag, write 1. Confirm the alarm goes active in the alarm status table.
  2. Acknowledge from the table. The Word must read 3 within one scan of the tag group, and the AlarmAck logger entry must show the operator in ackedBy.
  3. Confirm the alarm stays active and acknowledged, not cleared. If it clears, recheck the alarm mode.
  4. Write 0. The alarm clears and no new ack event fires, which confirms Ack Mode is not Auto.
  5. Repeat against the PLC Word while the PLC toggles an unrelated bit, and confirm that bit survives the ack write.

FAQ

How do I get the integer value of a tag inside an Ignition alarm event script?

Use tag.value.value. tag.value returns a qualified value object, so bitwise or arithmetic operators on it raise a type error and the rest of the script never runs.

How do I pass tagPath to system.tag.writeAsync in alarmAcked?

Pass the object directly as [tagPath], or convert it with str(tagPath) for an explicit string. Do not use tagPath.value. The path already points at the source Word tag.

How do I stop my ack bit write from overwriting PLC bits in the same Word?

Read the Word fresh with system.tag.readBlocking immediately before the write, then OR only the ack bit. To remove the race entirely, move acknowledgment to a dedicated HMI ack register that the PLC merges. If the script runs cleanly, the Word updates on a Memory tag, and the PLC tag still refuses writes with a good driver connection, collect the Gateway logs and the device driver diagnostics and open a case with Inductive Automation support. Include the driver type and the exact item path.

Back to blog