频率与温度读取

能读取什么

频率和温度是最简单的一类变量:单相、单值、没有数组。

业务含义OI类型倍率单位
电网频率200FUInt16-2Hz
表内温度2010Int16-1℃

两个对象的属性结构完全相同:

属性名称类型读写
1逻辑名OctetString只读
2数值UInt16 / Int16只读
3换算及单位ScalerUnit只读

索引只能是 0,这两个对象没有数组实例,传非零索引会被 validate_oad 拒绝。

数据地址表

业务含义OI属性索引类型倍率单位
电网频率200F20UInt16-2Hz
表内温度201020Int16-1℃
频率无符号,温度有符号
  • 频率是 UInt16,正常范围 45~65 Hz,线上 5000 = 50.00 Hz
  • 温度是 Int16,可以是负值(低温环境下),线上 -55 = -5.5 ℃

用 UInt16 解析温度,-5.5 ℃ 会变成 65481 ℃。

最小完整示例

一次连接读两个值:

#include <dlt698/app.hpp>
#include <dlt698/standard/catalog.hpp>
#include <iostream>

int main() {
    using namespace dlt698;
    namespace oi = standard::oi;

    const standard::DeviceLayout layout{standard::Wiring::three_phase, 4, 21};

    app::ClientOptions options;
    options.protocol.server.bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    app::Client client(options);
    auto connected = client.connect_tcp("127.0.0.1", 6980);
    if (!connected) {
        std::cerr << connected.error().context << '\n';
        return 1;
    }

    auto freq = standard::make_oad(oi::frequency, 2, 0, layout);
    auto temp = standard::make_oad(oi::internal_temperature, 2, 0, layout);
    if (!freq || !temp) {
        std::cerr << "bad layout\n";
        client.disconnect();
        return 1;
    }

    auto response = client.get_list({freq.value(), temp.value()});
    if (!response) {
        std::cerr << response.error().context << '\n';
        client.disconnect();
        return 1;
    }

    // get_list 返回完整 GetResponse:外层成功只表示传输成功,
    // 每项仍要单独判断是 DAR 还是 Data —— 这就是"部分成功"。
    const auto& attributes = response.value().attributes;
    static const char* kNames[] = {"frequency", "temperature"};
    for (std::size_t i = 0; i < attributes.size(); ++i) {
        const auto& entry = attributes[i];
        if (const auto dar = std::get_if<std::uint8_t>(&entry.result)) {
            std::cerr << kNames[i] << " unsupported, DAR=" << unsigned(*dar) << '\n';
            continue;
        }
        // 建议按回显的 OAD 决定如何解释,而不是依赖请求顺序。
        const model::Oad& oad = entry.attribute;
        const auto& data = std::get<model::Data>(entry.result);
        auto numbers = standard::engineering_values(oad, data, layout);
        if (numbers && !numbers.value().empty())
            std::cout << (oad.oi == oi::frequency ? "frequency" : "temperature") << " = "
                      << standard::decimal_text(numbers.value()[0]) << ' '
                      << standard::unit_symbol(numbers.value()[0].scaling.unit) << '\n';
    }
    // 输出:
    // frequency = 50.00 Hz
    // temperature = 35.2 ℃

    client.disconnect();
    return 0;
}

常用变体

分开读取

auto freq = standard::make_oad(oi::frequency, 2, 0, layout);
auto value = client.get(freq.value());

频率偏差判断

频率正常范围 45~65 Hz:

const std::string text = standard::decimal_text(numbers.value()[0]);
// "50.00" 正常;"49.98" 偏低;"50.02" 偏高

判定门限按当地电网规程确定,库不做判断。

温度越限告警

温度可以设上下限:

// 高温告警:> 85 ℃
// 低温告警:< -25 ℃
// 门限由应用决定,库不提供默认阈值

表内温度是电表自身器件温度,不是环境温度或绕组温度,与油浸式变压器测的绕组温度不是一回事。

请求与响应报文

以下示例固定:SA 六个 00 字节、逻辑地址 0、CA=0、PIID=0、控制域请求 43/响应 C3。

读取电网频率

请求(200F/2/0):

68 17 00 43 05 00 00 00 00 00 00 00 72 79 05 01 00 20 0F 02 00 00 1C 0C 16

响应(UInt16 5000,即 50.00 Hz):

68 1C 00 C3 05 00 00 00 00 00 00 00 BC FF 85 01 00 20 0F 02 00 01 12 13 88 00 00 30 D7 16
字段字节含义
85服务:GET-Response
01GET-Normal
00PIID-ACD=0
20 0F 02 00回显 OAD:频率,属性 2,索引 0
01选择子:Data
12数据类型:UInt16
13 88原始值 5000
00 / 00FollowReport / TimeTag 不存在

读取表内温度

请求(2010/2/0):

68 17 00 43 05 00 00 00 00 00 00 00 72 79 05 01 00 20 10 02 00 00 44 7D 16

响应(Int16 352,即 35.2 ℃):

68 1C 00 C3 05 00 00 00 00 00 00 00 BC FF 85 01 00 20 10 02 00 01 10 01 60 00 00 B0 9D 16

注意数据类型是 10(Int16),与频率的 12(UInt16)不同。

负温度

若设备报 Int16 -55,线上是 FF C9:

原始字节原始值工程值
FF C9-55-5.5 ℃

decimal_text 输出 -5.5。

带 PIID 的请求

同一 OAD 上多个请求靠 PIID 区分响应:

PIID=1:   68 17 00 43 05 00 00 00 00 00 00 00 72 79 05 01 01 20 0F 02 00 00 37 08 16
PIID=0x21: 68 17 00 43 05 00 00 00 00 00 00 00 72 79 05 01 21 20 0F 02 00 00 57 8D 16

客户端自动管理 PIID,手工构造报文时才需要关心。

相关配置

配置位置说明
SessionOptions::request_timeout库连接参数单次 GET 超时,默认 5 秒
温度/频率告警门限应用侧库不提供默认值

常见失败

现象原因处理
DAR=4设备不提供该变量频率和温度都不是必备功能,低端表可能只有其中一个
负温度显示为六万多度按 UInt16 解析温度温度是 Int16
频率显示 5000忘了倍率 -2线上 5000 是 50.00 Hz
温度显示 352忘了倍率 -1线上 352 是 35.2 ℃
传非零索引被拒这两个对象没有数组索引固定 0,validate_oad 返回 invalid_length
get_list 返回成功但某项无值部分成功外层 Result 只表示传输成功,逐项查 DAR