Esempio n. 1
0
def wait_for_test_session_start(
    mgr: sl_tag.TagManager, after_time: datetime.datetime = None
) -> None:
    """Wait for a recently-started FlexLogger test session to actually start."""
    if after_time is None:
        after_time = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(
            seconds=-2
        )

    # Wait for LastTestSessionStart to be updated by FlexLogger
    tag_path = get_tag_prefix() + ".Export.System.LastTestSessionStart"
    tag_reader = mgr.get_tag_reader(tag_path, sl_tag.DataType.DATE_TIME)
    while True:
        read_result = tag_reader.read(include_timestamp=True)
        if read_result is not None and read_result.value > after_time:
            assert read_result.timestamp is not None
            last_start = read_result.timestamp
            break
        time.sleep(0.5)

    # In FlexLogger 2020 R3+, the timestamps of the two values will be the same. In
    # older versions, IsTestSessionRunning is updated second.
    tag_path = get_tag_prefix() + ".Export.System.IsTestSessionRunning"
    tag_reader2 = mgr.get_tag_reader(tag_path, sl_tag.DataType.BOOLEAN)
    while True:
        read_result2 = tag_reader2.read(include_timestamp=True)
        if read_result2 is not None and read_result2.value is True:
            assert read_result2.timestamp is not None
            if read_result2.timestamp >= last_start:
                return
        time.sleep(0.5)
Esempio n. 2
0
def start_test_session(mgr: sl_tag.TagManager) -> None:
    """Start a FlexLogger test session."""
    writer = mgr.create_writer(buffer_size=1)
    path = get_tag_prefix() + ".Export.System.IsTestSessionRunning"
    already_running = mgr.read(path)
    if already_running is not None and already_running.value is True:
        raise RuntimeError("There is already a test session running")
    writer.write(path, sl_tag.DataType.BOOLEAN, True)
def create_output_channel(mgr: sl_tag.TagManager, group: str, name: str,
                          data_type: sl_tag.DataType) -> sl_tag.TagData:
    """Create a FlexLogger output channel."""
    # "Import" the channel into FlexLogger.
    full_name = get_tag_prefix() + ".Import.Setpoint.{}.{}".format(group, name)
    mgr.open(full_name, data_type, create=True)

    # Once FlexLogger creates the channel, we'll interact with it as an "export" channel
    # (for both reads and writes).
    full_name = get_tag_prefix() + ".Export.Setpoint.{}".format(name)
    # Go ahead and pre-create the output channel, for ease-of-use. Otherwise, when
    # trying to read its value, we'd have to be prepared for an ApiException complaining
    # that the tag doesn't exist.
    mgr.open(full_name, data_type, create=True)
    return sl_tag.TagData(full_name, data_type)
def print_tags(mgr: sl_tag.TagManager, prefix="") -> None:
    """Print FlexLogger tags that have the given prefix.

    By default, no prefix is included, so all FlexLogger tags are printed. To restrict
    it to just tags *exported* by FlexLogger, use prefix="Export.".
    """
    tag_prefix = get_tag_prefix() + "." + prefix
    with mgr.open_selection([tag_prefix + "*"]) as channels:
        # # Uncomment to hide system tags, such as IsTestSessionRunning
        # chan_names = [name for name in chan_names if ".Export.System." not in name]

        # Hide the tag prefix
        chan_names = [name.replace(tag_prefix, "") for name in channels.values]

        if len(chan_names) == 0:
            print(
                "No channels reported to NI SystemLink; check your project settings"
            )
            return

        max_name_len = max(len(name) for name in chan_names)

        def format_row(
            name: str,
            typ: Union[str, None],
            value: Any,
            timestamp: Union[datetime.datetime, str, None],
        ) -> str:
            columns = (
                name.ljust(max_name_len),
                str(timestamp).ljust(32),
                str(typ).ljust(9),
                str(value).ljust(9),
            )
            return " ".join(columns)

        print(format_row("Name", "Type", "Value", "Timestamp"))

        for name in sorted(chan_names, key=str.casefold):
            reader = channels.values[tag_prefix + name]
            read_result = reader.read(include_timestamp=True)
            value = read_result.value if read_result is not None else None
            data_type = read_result.data_type.name if read_result is not None else None
            timestamp = read_result.timestamp if read_result is not None else None

            print(format_row(name, data_type, value, timestamp))
def wait_forever_for_tag_changes(mgr: sl_tag.TagManager,
                                 tags: List[sl_tag.TagData]) -> None:
    """Watch for tag changes, and print any updates to the console.

    This method will never return.
    """
    def on_tag_changed(tag: sl_tag.TagData,
                       reader: Optional[sl_tag.TagValueReader]) -> None:
        if reader is not None:
            read_result = reader.read()
            value = read_result.value if read_result is not None else None
            print("Value changed to {}".format(value))

    with mgr.create_selection(tags) as selection:
        with selection.create_subscription() as subscription:
            subscription.tag_changed += on_tag_changed

            try:
                while True:
                    time.sleep(100)
            except KeyboardInterrupt:
                return
def _simulate_temp_chamber(mgr: sl_tag.TagManager) -> None:  # noqa: D103
    # fl = flexlogger.Client()
    # .buffered_channel_writer is a thin wrapper around systemlink.tag.BufferedTagWriter
    #  - this wrapper takes TagData objects instead of `path` and `datatype` parameters
    #  - maybe I'll instead modify systemlink.tag.BufferedTagWriter to accept a TagData
    writer = mgr.create_writer(buffer_size=10)
    chans = [
        create_channel(mgr, "Temperature Chamber", "Ceiling", sl_tag.DataType.DOUBLE),
        create_channel(mgr, "Temperature Chamber", "Door", sl_tag.DataType.DOUBLE),
        create_channel(mgr, "Temperature Chamber", "Floor", sl_tag.DataType.DOUBLE),
    ]
    vals = [78.0, 76.0, 74.0]
    try:
        while True:
            now = datetime.datetime.now()
            for chan, val in zip(chans, vals):
                writer.write(chan.path, chan.data_type, val, timestamp=now)
            writer.send_buffered_writes()

            time.sleep(0.1)
            vals = [v + random.normalvariate(0, 0.2) for v in vals]
    except KeyboardInterrupt:
        pass
def create_channel(
    mgr: sl_tag.TagManager, group: str, name: str, data_type: sl_tag.DataType
) -> sl_tag.TagData:
    """Create a FlexLogger channel."""
    tag_path = get_tag_prefix() + ".Import.{}.{}".format(group, name)
    return mgr.open(tag_path, data_type, create=True)
from datetime import timedelta

from systemlink.clients.tag import DataType, TagManager

mgr = TagManager()
tag = mgr.open("MyTags.Example Tag", DataType.DOUBLE, create=True)

with mgr.create_writer(buffer_size=10,
                       max_buffer_time=timedelta(seconds=3)) as writer:
    writer.write(tag.path, tag.data_type, 3.5)
# Note: Exiting the "with" block automatically calls writer.send_buffered_writes()

read_result = mgr.read(tag.path)
assert read_result is not None
assert read_result.value == 3.5
    path = tag.path
    data_type = tag.data_type.name

    if reader is not None:
        read_result = reader.read()
        # A read_result of None means that the tag has no value, but it *must*
        # have a value, because we got a tag_changed event!
        assert read_result is not None
        value = read_result.value
    else:
        value = "???"  # tag has unknown data type

    print(f'Tag changed: "{path}" = {value} ({data_type})')


mgr = TagManager()
if SIMULATE_EXTERNAL_TAG_CHANGES:
    mgr.open("MyTags.Example Tag", DataType.DOUBLE, create=True)
    writer = mgr.create_writer(buffer_size=1)

with ExitStack() as stack:
    # Notes:
    # 1. The tags are assumed to already exist before this example is run, but
    #    setting SIMULATE_EXTERNAL_TAG_CHANGES to True will ensure there is one.
    # 2. Any tags that get added later will NOT automatically appear in the
    #    selection just because the path matches the wildcard used below; you
    #    must call one of the selection's refresh methods to update the tag list
    #    from the server. But even if you do that:
    # 3. The subscription will only contain the tags that were in the selection
    #    when the subscription was created. If you want the subscription to add
    #    new tags that were added to the selection, you must recreate it.
Esempio n. 10
0
def stop_test_session(mgr: sl_tag.TagManager) -> None:
    """Stop the current FlexLogger test session."""
    writer = mgr.create_writer(buffer_size=1)
    path = get_tag_prefix() + ".Export.System.IsTestSessionRunning"
    writer.write(path, sl_tag.DataType.BOOLEAN, False)