Skip to content

History

Demonstrates how to record a Variable's history and configure the server's history database.

Start any OPC UA client (e.g. C02_firststeps.py or C12_browser.py) against this server to read and (for the writable variables) write the values. Read the recorded history back with the client's historyRead::

data = client.historyRead("ns=1;i=1001", start, end)
for dv in data.dataValues:
    print(dv.sourceTimestamp, dv.value)

A history database has to be configured before server.start(). capacity bounds how many samples each historizing Variable keeps — once a Variable's store is full, the oldest sample is evicted to make room for the newest. maxResponseSize is a different kind of limit: a server-wide cap, unrelated to capacity, on how many samples one historyRead response carries. A request spanning more values than that gets back only the first maxResponseSize of them plus a continuation point — a client is expected to call historyRead again with that token until it comes back empty. The high-level client.historyRead(...) does not do that on its own, so a client that ignores continuation points sees a silently truncated result rather than an error.

print("--- 1. History Database ---")

server.config.setHistoryDatabase(capacity=1000, maxResponseSize=200)

2. Historizing variables

historizing=True is short for historizing=o6.History(): record a sample on every Write, keeping the database's default capacity. o6.History(...) customizes that per Variable — capacity= overrides the default store size, and strategy="poll" samples the Variable's value every interval seconds through an internal MonitoredItem instead of hooking into the Write service call. That is what a Variable whose value changes some other way — a read callback, a lower-level update — needs in order to be historized at all, since there is no Write for an on-write strategy to hook into.

print()
print("--- 2. Historizing Variables ---")

temperature = server.addVariable(
    "Temperature",
    server.objectsNode,
    22.5,
    nodeId="ns=1;i=1001",
    historizing=True,
)

pressure = server.addVariable(
    "Pressure",
    server.objectsNode,
    1013.25,
    nodeId="ns=1;i=1002",
    historizing=o6.History(capacity=500, strategy="poll", interval=0.5),
)

3. Run and update loop

server.start() blocks until server.stop(). Both Variables change once per cycle here, so either strategy would capture them just the same — pressure uses poll only to show how it is configured. A data-source-backed Variable (see S07_data_source.py), whose value changes through a read callback and never through a Write, is the case that actually needs it.

    print()
    print("--- 3. Run and Update Loop ---")

    server.start()
    print(f"Server running at {endpoint_url}")
    print("Press Ctrl+C to stop.")

    try:
        cycle = 0
        while True:
            cycle += 1
            temperature(22.5 + (cycle % 50) * 0.1)
            pressure(1013.25 + (cycle % 20) * 0.5)

            if cycle % 10 == 0:
                print(
                    f"Cycle {cycle}: Temp = {temperature():.1f}°C, "
                    f"Pressure = {pressure():.1f}hPa"
                )

            time.sleep(1.0)

    except KeyboardInterrupt:
        print("Shutting down...")
    finally:
        server.stop()
        print("Server stopped.")


if __name__ == "__main__":
    main()

Source Code

Download S11_history.py to run it locally.