属性与状态机
属性
| 类别 | 属性 | 类型 | 访问 | 说明 |
|---|---|---|---|---|
| 静态 | is_service_ready / PnSService.is_service_ready | bool | 只读 | 本机服务是否就绪 |
last_error / PnSService.last_error | str | 只读 | 全应用最近一次失败文案(sticky,成功路径不清空) | |
last_error_code / PnSService.last_error_code | PnSErr | 只读 | 全应用最近一次失败的调用错误码。从未失败为 OK | |
service_connected / PnSService.service_connected | bool | 只读 | 主站是否周期交换。服务没起来 = False | |
service_state / PnSService.service_state | PnSState | 只读 | 运行态。服务没起来 = UNKNOWN | |
service_wait_reason / PnSService.service_wait_reason | str | 只读 | 等待原因。服务没起来 = 「服务未就绪」 | |
service_status_message / PnSService.service_status_message | str | 只读 | 状态文案。服务没起来 = 「服务未就绪」 | |
| 连接与会话 | connected | bool | 只读 | IO 控制器是否已经建立周期数据交换。True 才表示周期数据在换 |
attached | bool | 只读 | 本 SDK 会话是否已连上本机服务。stop 不改变 | |
is_running / is_started | bool | 只读 | IO 设备是否已启用(start 之后、stop 之前) | |
| 运行态 | state | PnSState | 只读 | 运行态枚举。读不到真实状态为 UNKNOWN,不要当成 NONE |
wait_reason | str | 只读 | 本会话等待原因。主站已连时为空 | |
ever_connected | bool | 只读 | 是否曾与 IO 控制器建立过连接。True 且 connected 为 False = 掉线 | |
| 错误码 | error_code | PnSRuntimeErrorCode | 只读 | 最近一次运行错误。未识别值 UNKNOWN |
error_code_raw | int | 只读 | 运行错误原值(0 = 无错误)。未识别值仍经本属性透传 | |
error_message | str | 只读 | 运行错误中文消息 | |
last_service_error | str | 只读 | 本会话最近一次失败文案(sticky,成功路径不清空) | |
| 整区字节 | input | bytes | 只读 | 整块回读,名字反着 —— 对应 `process_data.Out` 那块,见下方说明 |
output | bytes | 只读 | 整块快照,名字反着 —— 对应 `process_data.In` 那块,与 read() 同源 | |
output_committed | bool | 只读 | 写出那块是否已提交到共享区(写过且已送达)。未 start / 提交失败 = False |
input / output 的名字是反的svc.input 和 svc.output 沿用服务端内存区的叫法,方向与 process_data 那套正好相反:
| 属性 | 对应过程数据里的哪一块 |
|---|---|
svc.input | 和 process_data.Out / outputs_mapping(S) 同一块(不是 In 那块) |
svc.output | 和 process_data.In / inputs_mapping(S) 同一块(不是 Out 那块) |
日常别用它们:svc.read() / svc.write() 与 process_data.In / Out 的名字和含义一致,用那套。只有要整段裸字节时才用 svc.input / svc.output,用之前先看清上表。
模块函数与类属性等价(类属性无括号)。服务没起来写 last_error,不抛。
from darra_pns import (
is_service_ready, service_connected, service_state,
service_wait_reason, last_error,
)
ready = is_service_ready()
master = service_connected()
st = service_state()
wait = service_wait_reason()
err = last_error()
PnSState
运行态类型。取值见 枚举参考。
PnSRuntimeErrorCode
运行错误码类型。取值见 枚举参考。
启停
构造签名见 初始化。start 一次,不要每个周期调用。
start()
def start(self) -> PnSErr
启用 IO:启动本机服务、建立过程数据通道、POST /api/start。已 start 且尚未 stop 则幂等返回 PnSErr.OK。
这不是主站已周期交换,主站是否在换数据看 connected。同一时刻只允许一个实时会话,第二个返回 PnSErr.NOT_AVAILABLE(契约见 SDK 连接契约)。
示例:
rc = svc.start()
if rc != PnSErr.OK:
print(svc.last_service_error)
stop()
def stop(self) -> None
停用 IO(POST /api/stop)。过程数据通道与会话都留着,可以再 start。未 start 或已 stop 幂等。不是 close。
示例:
svc.stop()
close()
def close(self) -> None
断开本机服务会话。Q 会被清掉(清的是 Q 的净荷窗:PPM 输出区前 3 字节 IOPS 前缀不动);I 留着,等下一个程序。幂等,with 退出会调本方法。放开之后这个实例不能再用,要重新 PnSService()。实时主路径同时让出实时连接门。
示例:
svc.close()
运行态
state
运行态(只读)。start / stop 只管启用 / 停用 IO 设备;本属性始终按现场如实读。读不到真实状态为 UNKNOWN,不要当成 NONE。
@property
def state(self) -> PnSState
示例:
if svc.state == PnSState.DATA_EXCHANGE:
print("周期数据交换正常")
wait_reason
@property
def wait_reason(self) -> str
本会话等待原因。主站已连时为空。循环 if not svc.connected 时读本属性或 last_service_error。
示例:
if not svc.connected:
print(svc.wait_reason)
ever_connected
@property
def ever_connected(self) -> bool
是否曾与 IO 控制器建立过连接。False = 从未连过;True 且 connected == False = 掉线。掉线后此判别仍保留。
示例:
if not svc.connected and svc.ever_connected:
print("掉线")
错误码
error_code
@property
def error_code(self) -> PnSRuntimeErrorCode
最近一次运行错误(枚举)。未识别值 UNKNOWN。原值仍经 error_code_raw 透传。中文消息用 error_message。
示例:
err = svc.error_code
text = svc.error_message
raw = svc.error_code_raw
error_code_raw
@property
def error_code_raw(self) -> int
运行错误原值(0 = 无错误)。未识别值仍经本属性透传。
示例:
raw = svc.error_code_raw
error_message
@property
def error_message(self) -> str
运行错误中文消息。未识别码返回带原值的说明,不丢信息。
示例:
print(svc.error_message)
last_service_error
@property
def last_service_error(self) -> str
本会话最近一次失败文案(sticky)。成功路径不清空。循环 if not connected 时若本属性为空,读 wait_reason。
示例:
print(svc.last_service_error)
诊断
诊断子对象 diagnostics,以及读同一份数据的扁平属性。字段逐条见 诊断。运行中先看这里,再去碰过程数据。
| 类别 | 属性 | 类型 | 访问 | 说明 |
|---|---|---|---|---|
| 入口 | diagnostics | PnSDiagnostics | 只读 | 诊断子对象(快照 / IOPS / 报警 / 记录) |
diag_snapshot | PnSServiceDiagSnapshot | 只读 | 诊断快照。字段见 [诊断](./diagnostics) | |
io_status | PnSServiceIoStatus | 只读 | IOPS / IOCS。`0x80` = GOOD。见 [诊断](./diagnostics) | |
alarms / alarm_history | list | 只读 | 活动报警 / 历史(最近 500 条)。空列表不是失败 | |
alarm_count / critical_alarm_count | int | 只读 | 活动报警总数 / Critical 报警数。与 alarms 同源 | |
im_data | PnSServiceImData | 只读 | I&M 标识:站名、厂商 / 设备 ID、订货号 | |
process_data | ProcessData | 只读 | 过程数据视图,写 Q / 读 I。见 [过程数据](./io) |
示例:
snap = svc.diag_snapshot
if not snap.ok:
print(snap.message)
else:
print("Up" if snap.link_up else "Down")
for a in svc.alarms:
print(a.message)
IOPS 要看 svc.io_status.all_good —— 数值在,不等于这一拍能用。
完整示例
from darra_pns import PnSErr, PnSService
with PnSService() as svc:
rc = svc.start()
if rc != PnSErr.OK:
print(svc.last_service_error)
else:
while running:
if not svc.connected:
print(svc.state)
print(svc.wait_reason)
print(svc.error_message)
continue
svc.write_bool("Q0.0", True) # 写 Q
from_plc = svc.read_bool("I0.0") # 读 I
_ = from_plc
svc.stop()