{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Library Examples" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Archiving information" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from datetime import datetime, timedelta\n", "\n", "import polars as pl\n", "from pytz import UTC\n", "\n", "from epicsarchiver import ArchiverAppliance\n", "\n", "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-cell" ] }, "outputs": [], "source": "import math\nimport re\nimport sys\n\nimport epicsarchiver.retrieval.EPICSEvent_pb2 as _ee\nfrom epicsarchiver.retrieval.EPICSEvent_pb2 import SCALAR_DOUBLE, PayloadInfo, ScalarDouble\nfrom epicsarchiver.retrieval.pb import escape_bytes\nimport responses\nfrom aioresponses import aioresponses as _aioresponses_ctx\n\n_YEAR = 2026\n_BASE_SECS = 8_640_000\n\n\ndef _make_doc_events(n=30):\n return [\n ScalarDouble(\n secondsintoyear=_BASE_SECS + i * 10,\n nano=int(abs(math.sin(i)) * 1_000_000_000),\n val=28.0 + 0.5 * math.sin(i * 0.4),\n severity=1,\n status=4,\n fieldvalues=[\n _ee.FieldValue(name=\"EGU\", val=\"degC\"),\n _ee.FieldValue(name=\"PREC\", val=\"2\"),\n ],\n )\n for i in range(n)\n ]\n\n\ndef _make_pb(pvname):\n events = _make_doc_events()\n info = PayloadInfo(type=SCALAR_DOUBLE, pvname=pvname, year=_YEAR)\n info_bytes = escape_bytes(info.SerializeToString())\n events_bytes = b\"\\n\".join(escape_bytes(e.SerializeToString()) for e in events)\n return info_bytes + b\"\\n\" + events_bytes\n\n\n_host = \"archiver.example.org\"\n_retrieval_url = f\"http://{_host}:17668/retrieval/data/getData.raw\"\n_matching_url = f\"http://{_host}:17668/retrieval/bpl/getMatchingPVs\"\n_pb_body = _make_pb(\"EXAMPLE:TEMPERATURE\")\n\n_rsps = responses.RequestsMock(assert_all_requests_are_fired=False)\n_rsps.add(responses.GET, _retrieval_url, body=_pb_body, status=200)\n# Search endpoint returns a JSON list of matching PV names.\n_rsps.add(\n responses.GET,\n _matching_url,\n json=[\"EXAMPLE:TEMPERATURE\", \"EXAMPLE:TEMPERATURE2\", \"EXAMPLE:PRESSURE\"],\n status=200,\n)\n_rsps.start()\n\n_async_mock = _aioresponses_ctx()\n_async_mock.start()\n_async_mock.get(\n re.compile(r\"http://archiver\\.example\\.org:17668/.*\"),\n body=_pb_body,\n repeat=True,\n)" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "archiver = ArchiverAppliance(\"archiver.example.org\")\n", "pv = \"EXAMPLE:TEMPERATURE\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Getting Data" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "_, events = archiver.get_events(pv, datetime.now(tz=UTC) - timedelta(seconds=1), datetime.now(tz=UTC))\n", "events" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df = archiver.get_data(pv, datetime.now(tz=UTC) - timedelta(seconds=30), datetime.now(tz=UTC))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Async Fetch Data" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from epicsarchiver.retrieval.client.async_archiver_retrieval import AsyncArchiverRetrieval\n", "from pytz import timezone" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tz = timezone(\"Europe/Stockholm\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "async with AsyncArchiverRetrieval(archiver.hostname) as a_archiver:\n", " print(await a_archiver.get_events(pv, datetime.now(tz=tz) - timedelta(microseconds=100), datetime.now(tz=tz)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "async with AsyncArchiverRetrieval(archiver.hostname) as a_archiver:\n", " print(await a_archiver.get_all_events([pv, \"EXAMPLE:TEMPERATURE2\", \"EXAMPLE:TEMPERATURE3\"], datetime.now(tz=tz) - timedelta(microseconds=100), datetime.now(tz=tz)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Displaying and Calculating Summaries" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "\n", "plt.plot(df[\"date\"], df[\"val\"])\n", "plt.xlabel(\"time\")\n", "plt.ylabel(\"val\")\n", "plt.tight_layout()\n", "# NBVAL_IGNORE_OUTPUT" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from epicsarchiver.retrieval.client.processor import Processor, ProcessorName" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df_mean = archiver.get_data(\n", " pv,\n", " datetime.now(tz=UTC) - timedelta(seconds=6000),\n", " datetime.now(tz=UTC),\n", " Processor(ProcessorName.MEAN, 20),\n", ")\n", "plt.plot(df_mean[\"date\"], df_mean[\"val\"])\n", "plt.xlabel(\"time\")\n", "plt.ylabel(\"val (mean, 20s bins)\")\n", "plt.tight_layout()\n", "# NBVAL_IGNORE_OUTPUT" ] }, { "cell_type": "markdown", "source": "## Raw PB Response\n\nFor full control you can fetch the raw protobuf response with `get_data_raw` and decode it yourself with `parse_pb_data`. This is the building block used by `get_events` and `get_data`.", "metadata": {} }, { "cell_type": "code", "source": "from epicsarchiver.retrieval.pb import parse_pb_data\n\n# get_data_raw returns the underlying HTTP response; its body is the raw\n# Archiver Appliance PB byte stream, which parse_pb_data turns into events.\nresponse = archiver.get_data_raw(\n pv, datetime.now(tz=UTC) - timedelta(seconds=30), datetime.now(tz=UTC)\n)\nmeta, raw_events = parse_pb_data(response.content)\nmeta", "metadata": {}, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": "## Searching for PV Names\n\n`search` returns the PV names matching a regex pattern. Optionally restrict the results to PVs that recorded data in a time range with `start`/`end`, and cap the number of results with `limit`.", "metadata": {} }, { "cell_type": "code", "source": "# Optionally pass start/end to filter by time range and limit to cap results.\narchiver.search(\"EXAMPLE:.*\", limit=10)", "metadata": {}, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": "## Exporting Events to Other Formats\n\n`write_events` serialises a list of events to a binary stream in one of the `Format` options used by the `export` command: `JSON`, `CSV`, `ARROW`, or `PARQUET`.", "metadata": {} }, { "cell_type": "code", "source": "import io\n\nfrom epicsarchiver.write.export_format import Format, write_events\n\n# Write the events to an in-memory buffer as CSV. Format also supports\n# JSON, ARROW, and PARQUET. These formats require the [polars] extra.\nbuffer = io.BytesIO()\nwrite_events(buffer, Format.CSV, events=raw_events, meta=meta)\nprint(\"\\n\".join(buffer.getvalue().decode().splitlines()[:4]))", "metadata": {}, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": "## Reading a Local PB File\n\n`read_pb_file` parses an Archiver Appliance `.pb` file from disk into the same `(metadata, events)` tuple returned by `parse_pb_data`, without contacting a server.", "metadata": {} }, { "cell_type": "code", "source": "from pathlib import Path\n\nfrom epicsarchiver.retrieval.pb import read_pb_file\n\n# Persist the raw response to a local .pb file, then read it back.\n_pb_path = Path(\"example.pb\")\n_pb_path.write_bytes(response.content)\nfile_meta, file_events = read_pb_file(str(_pb_path))\n_pb_path.unlink() # clean up the temporary file\nfile_events[:3]", "metadata": {}, "execution_count": null, "outputs": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-cell" ] }, "outputs": [], "source": "_rsps.stop()\n_rsps.reset()\n_async_mock.stop()" } ], "metadata": { "kernelspec": { "display_name": "jupyter", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.14.5" } }, "nbformat": 4, "nbformat_minor": 2 }