Python · recipe
Subscribe to data changes in Python
Create a subscription with the publishing interval your consumer actually needs, then add monitored items with their own sampling interval, queue size and deadband. The handler is called on every notification, so keep it cheap and never block in it.
| Stack | asyncua (FreeOpcUa/opcua-asyncio) |
|---|---|
| Version | 2.0.1 |
The code
import asyncio
from asyncua import Client, ua
class Handler:
def datachange_notification(self, node, val, data):
dv = data.monitored_item.Value
print(f"{node} = {val} status={dv.StatusCode} src={dv.SourceTimestamp}")
def status_change_notification(self, status):
print("subscription status:", status)
async def main():
async with Client(url="opc.tcp://opcua.umati.app:4840") as client:
handler = Handler()
# publishing interval = what the consumer needs, not the fastest possible
sub = await client.create_subscription(1000, handler)
node = client.get_node("i=2258")
mfilter = ua.DataChangeFilter(
Trigger=ua.DataChangeTrigger.StatusValue,
DeadbandType=ua.DeadbandType.Absolute.value,
DeadbandValue=0.5,
)
await sub.subscribe_data_change(node, queuesize=10, monitorfilter=mfilter)
await asyncio.sleep(5)
await sub.delete()
asyncio.run(main())
What it prints
i=2258 = 2026-09-08 03:45:00.102000 status=StatusCode(Good) src=2026-09-08 03:45:00.102000
i=2258 = 2026-09-08 03:45:01.104000 status=StatusCode(Good) src=2026-09-08 03:45:01.104000
i=2258 = 2026-09-08 03:45:02.101000 status=StatusCode(Good) src=2026-09-08 03:45:02.101000
Notes
- The 1000 in create_subscription is the publishing interval in milliseconds: how often the server delivers. The sampling interval, set per item, is how often it looks. Confusing the two is the most common subscription mistake in OPC UA.
- Percent deadband needs EURange on the node. Without it the deadband is silently ignored, so use Absolute unless you have checked.
- Size queuesize from the publishing-to-sampling ratio. If it overflows, the overflow bit is set and the status still reads Good: the loss is silent.
- Keep the handler non-blocking. It runs on the client's loop; heavy work there stalls the subscription.
- Add a heartbeat if you need to distinguish 'value unchanged' from 'connection dead'.
What breaks first
Samples go missing while every status code still reads Good
The monitored item's queue overflowed between publishes. Increase queueSize, lengthen the sampling interval, or apply a deadband so fewer samples are generated.
GoodOverloadThe monitored item's queue overflowed between publishes. Increase queueSize, lengthen the sampling interval, or apply a deadband so fewer samples are generated.
Other recipes in this stack
Concepts on this page
Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.