# 提供的节点

> 内置 OPC UA 服务器所提供的内容、也是它提供的全部内容的列表：点位、Logic 变量、报警和设备命令，在你允许写入之前每一行都保持只读；还说明客户端在哪里找到每一项，以及更新后的工作站需要做什么。

**提供的节点** 是 Connector 上 OPC UA 服务器面板的第四张卡片。服务器只提供这份列表：连上来的客户端能找到这里列出的点位、Logic 变量、报警和设备命令，找不到别的。卡片在标题下面就这么说：“服务器只提供这份列表：每一行是一个点位、一个 Logic 变量、一个报警或一条设备命令。在你允许写入之前，行保持只读。允许后，客户端的写入与其他所有写入走同一条路径，并连同客户端会话记入诊断日志。”查看 Connector 可以读这张卡片，配置 Connector 可以改动它。

## 空列表 {#an-empty-list}

列表起初为空，新工作站如此，从一个整台提供所有设备的版本更新而来的工作站也是如此。列表为空时，卡片上的提醒写着：“列表为空，因此服务器不提供本工作站的任何内容：在你添加行之前，OPC UA 客户端找不到任何点位、变量、报警或命令。”服务器仍在监听，仍接受 [客户端访问](connector-opcua-client-access) 允许的会话，但这些会话浏览到的地址空间里没有本工作站的任何东西。代理在 `server_status` 里读到同样的情况，列表为空时 `servesNothing` 为 true。

## 表格 {#the-table}

| 列 | 显示什么 |
| --- | --- |
| **信号源** | 这一行提供的内容，按选择框给它的名称显示；还没有选信号源时显示“尚无信号源”。 |
| **访问** | **只读** 或 **读写**，设备命令则显示 **可调用**。 |
| **节点** | 配置给客户端的地址，形式为 `nsu=<namespace>;s=<identifier>`；这一行什么都不提供时为空。 |

各行先按类型（点位、变量、报警、命令）排列，再按名称排列。一行都没有时，表格显示“还没有提供任何节点。用新建行添加一个。”点击一行就选中它，并在表格下面打开它的字段；选中哪一行属于你所在的那个窗口。

| 命令 | 做什么 | 置灰的时候（情形） | 不显示的时候（角色） |
| --- | --- | --- | --- |
| **新建行** | 添加一行还什么都不提供的只读行并选中它，以便接着选择它的信号源。操作记录条显示“已在 OPC UA 服务器的列表中添加行。请选择它的信号源。” | 有运行记录占用着工作站，或者运行时已停止。 | 没有“配置 Connector”时。 |
| **删除行**（危险色） | 立即删除表格中选中的那一行，不再询问；它的悬停提示写出这一行所提供的信号源，操作记录条确认删除。信号源本身不受影响：客户端再也找不到它的节点。 | 没有选中任何行（“请在列表中选择要删除的行。”）、有运行记录占用着工作站，或者运行时已停止。 | 没有“配置 Connector”时。 |

## 一行的字段 {#a-rows-fields}

每个字段一改就保存，服务器稍后就提供新的这一行，不会断开任何会话：它每秒读取列表十次。

| 字段 | 做什么 | 取值和默认值 |
| --- | --- | --- |
| **信号源** | 这一行提供的内容。列表以“（无）”开头，接着是已启用设备上每一个已启用的点位，按驱动、设备和它自己的名称命名（“点位 · Simulated · Oven · Temperature”），然后是每一个持有值的 Logic 变量，按所在文件夹和名称命名（“变量 · Oven / Setpoint”），然后是每一个报警，按同样方式命名（“报警 · Oven / High temperature”），最后是已启用设备的每一条命令：设备页面上声明的命令，以及协议固定的命令，例如充电桩的命令（“命令 · OCPP · Charger · Reset”）。一个信号源在列表中只能出现一次。这一行按标识保存信号源，所以改名后这一行仍停在同一个信号源上，服务器随后以新名称提供它。列表不再提供的信号源仍保持选中并显示名称，已禁用的点位或命令会附上被排除的原因，只有已经不存在的信号源才会连同标识一起显示为缺失。点位的 [使用者](connector-tags#the-used-by-card) 卡片会列出提供它的行。 | 新行为“（无）”。 |
| **访问** | 客户端能否写这一行。信号源不接受写入时，**读写** 仍留在列表里但置灰，悬停提示写着“该信号源不接受写入：只有有写访问权限的点位或内部存储值变量才接受。”选择报警会让这一行回到只读。命令行的这个字段不显示选择框，而是把 **可调用** 作为固定值显示，因为命令是被调用的，不被读取或写入。 | **只读** 或 **读写**；命令固定为 **可调用**。新行为只读。 |

字段下面有一行说明这一行为客户端做什么：

| 卡片显示 | 什么时候 |
| --- | --- |
| “这一行还没有提供任何值：请选择信号源。” | 还没有选信号源。 |
| “这一行的信号源已不存在，因此服务器不为它提供任何内容。” | 点位、变量、报警或命令已被删除。 |
| “客户端可以读取这个节点，但不能写入。” | 只读的点位或变量。 |
| “客户端可以读写这个节点：每次写入都会连同客户端会话记入诊断日志。” | 标为读写的点位或变量。 |
| “客户端读取报警的 Active、Acked、State、Priority 和 Message，从不写入。” | 报警。 |
| “只要这条命令在列表中，客户端就可以把它作为所属设备的方法来调用。” | 设备命令。 |

再往下，**客户端在此处找到它** 后面跟着节点。

## 一行会拒绝什么 {#what-a-row-refuses}

列表规则拒绝的改动不会保存：原因以红字显示在这一行的字段上方，改动留在屏幕上供你修正，这一行继续提供原来提供的内容。

| 卡片显示 | 什么时候 |
| --- | --- |
| “该信号源已在列表中：客户端在那一行提供的节点上找到它。” | 这个信号源已在另一行中。 |
| “该信号源不能写入：请选择有写访问权限的点位或内部存储值变量，或者让这一行保持只读。” | 在只读点位、从不写入的驱动的点位、表达式变量、报警、命令或已不存在的信号源上要求读写。 |
| “接受写入的行需要指定写入目标点位或变量。” | 在没有信号源的行上要求读写，这只有代理能要求。 |
| “列表中的这一行已不存在。请重新加载后重试。” | 你编辑的时候，这一行在别处被删除了，比如另一个窗口或某个代理。 |

有运行记录占用着工作站或运行时已停止时，改动像页面上的其他改动一样被拒绝，原因显示在操作记录条上，不会保存任何东西。

## 客户端在哪里找到每个信号源 {#where-a-client-finds-each-source}

| 信号源 | 在哪里 | 客户端读到什么 |
| --- | --- | --- |
| 点位 | 一直在的地方：在它所属设备的命名空间 `http://opcfoundation.org/UA/<driver>.<device>/` 中，使用点位自己的名称。列表出现之前就配置好的客户端，也在同一个地址找到它。浏览地址空间的客户端，在 Objects 下的 `Devices` 文件夹里、以其设备命名的对象中找到它。 | 设备应答的值，连同质量和时间戳，与 Connector 读到的一样。 |
| Logic 变量 | 在 Objects 下的 `Logic` 文件夹里，位于 Logic 自己的文件夹中，在服务器的命名空间 `http://opcfoundation.org/UA/EdgeTranslator/` 中使用它的 Logic 地址（`Variables.Oven.Setpoint`）。 | 它的值，按工作站唯一的一套转换确定类型：Boolean，整数为 Int64，小数为 Double，文本为 String，日期和时间为 DateTime。没有有效值的变量读作 BadDataUnavailable。 |
| 报警 | 在 Objects 下的 `Alarms` 文件夹里，位于 Logic 自己的文件夹中，作为一个使用其 Logic 地址（`Alarms.Oven.HighTemperature`）的对象。 | 五个只读成员：Active 和 Acked（Boolean）、State（Int32：0 为正常，1 为活动未确认，2 为活动已确认，3 为已复归未确认）、Priority 和 Message（String）。报警在质量变差期间保持其状态时，Active、Acked 和 State 读作 UncertainLastUsableValue。 |
| 命令 | 所属设备的一个方法，位于设备的点位旁边。 | 用命令声明的值调用，返回设备应答的内容。 |

无论列表提供某台设备的什么内容，每台设备都保留自己的命名空间，所以另一台设备的点位加入或离开列表时，客户端找到命名空间的索引不会变化。列表一项都没有列出的设备没有任何节点。

## 写入 {#writing}

客户端的写入只有在标为读写的行上才会到达工作站；写入到达的那一刻会再次核对列表，所以刚刚改成只读的行绝不会被写入。对点位的写入像所有来自外部的写入一样进入其设备的送达队列，应答要等设备；对内部存储值变量的写入经过 Logic 写入漏斗，并转换为变量的类型。信号源锁定同样适用：正在运行的 Process 占用的信号源会被拒绝。每一次写入都会连同客户端的应用程序和会话记入诊断日志。表达式变量和报警从不接受写入，服务器应答 BadNotWritable。命令是被调用的，不是被写入的，客户端只能调用列表中的命令。

## 更新后的工作站 {#an-updated-station}

从没有列表的版本更新而来的工作站，原先提供每台设备的每一个点位。它的列表起初为空，所以更新之后，在列表组建好之前，它的 OPC UA 服务器不提供任何内容：为客户端读取的每个点位添加一行，把客户端写入的那些标为读写，并添加客户端调用的命令。更新之前配置好的客户端会在原来的地址找到每个点位，所以客户端那边无需任何改动。

## 通过代理 {#with-an-agent}

```text
server_list_upsert(source: "Connector.Simulated.Oven.Temperature")
server_list_upsert(source: "Variables.Oven.Setpoint", access: "ReadAndWrite")
server_list_upsert(source: "Alarms.Oven.HighTemperature")
server_status()
```

代理创建的行是只读的，除非 `access` 另有说明；`server_list_delete` 按标识删除一行。这些工具在[工具，按范围列出](agent-tools#connector--configure)中说明。

## 列表不做的事 {#what-the-list-does-not-do}

列表不会打开服务器（打开它的是命令栏上的启用），不决定哪个客户端可以连接（由 [客户端访问](connector-opcua-client-access) 决定），也不会从外部确认报警：确认仍是操作员的命令。它提供上面这些值，不提供 OPC UA 报警与条件事件。持有图像、图标或颜色的变量不会出现在列表中，设备描述中的常量也不会被提供。
