自学内容网 自学内容网

hj 212 协议解包php解包,

什么是环保HJ212协议?

HJ212是由国家环保行业制定的数据传输标准协议,通常是通过TCP/P通讯方式进行数据传输的,数据传输报文主要由包头、数据段长度、数据段、CRC校验、包尾组成。重点解析的就是”数据段“的内容,内容包括请求编码(QN)、系统编码(ST)、设备唯一标识(MN)、密码(PW)、命令编码(CN)、指令参数(CP)。请求编码为请求的时间戳,系统编码ST统一规定为22,命令编码CN为该数据包的时间类型,访问密码、设备唯一标识在对接时由平台提供,指令参数为数据内容。

基本报文示例:
##0192QN=20230703220100923;ST=22:CN=2011:PW=123456;MN=BF0F022021090077:Flag=5:CP=&&DataTime=20230703220100:a34001-Rtd=48.5,a34001-Flag=N:a34004-Rtd=31.2,a34004-Flag=N:a34002-Rtd=48.5,a34002-FIaQ=N&&A881

协议包组成:

名称 类型 长度 描述
包头 字符 2 同定为##
数据段长度 十进制整数 A 数据段的ASCII字符数,例如:长192,则写为“0192
数据段 字符 0<=n<=1024 变长的数据
CRC校验 十六进制 4 数据段的校验结果
包尾 字符 2 回车换行()

标准化json:
{
“ST “: “22“,
“MN“:“BFOF022021090077“,
“PW“ : “123456“,
“CN“: “2011“,
“QN“:“20230703220100923“,
“Flag“ : “5“,
“CP“:{
“DataTime": “20230703220100“,
“a34001-Flag :“ N“,
“a34001-Rtd : “48.5“,
“a34002-Flag :“N“,
“a34002-Rtd : “48.5“,
“a34004-Flag :“N“,
“a34004-Rtd : “31.2“,
}
}

常用的标准码说明

1.后面都会加Rtd或Flag,一般是a01001-Rtd或a01001-Flag,其中Rtd是实际的值,Flag为状态一般为N
2.2.单位只是大部分的一个标准,可作为参考
编码(Rtd->数值,Flag->状态) 实际值 单位(参考)
a01001 温度 咖
a01002 湿度 Kpa
a01006 气压 m/s
a01007 风速 0
a01008 风向 ug/m
a34001 TSP扬尘 ug/ms
a34002 PM10 ug/m
a34004 PM2.5 mg/m
a21004 NOz mg/m*
a21005 NO 葱mg/m*
a21026 S0z mg/m*
a21026 S0z dB
LA 噪声 单位(参考)

php接收包解包(没有crc验证)到redis 序列化

<?php
// 设置 Redis 连接
$redisHost = '127.0.0.1';
$redisPort = 6379;
$redis = new Redis();
$redis->connect($redisHost, $redisPort);

// 创建一个 TCP 服务器
$host = '0.0.0.0'; // 监听所有网卡
$port = 21212;     // 自定义端口(与212协议无直接关系,仅供示例)

$socket = stream_socket_server("tcp://$host:$port", $errno, $errstr);

if (!$socket) {
    die("无法创建服务器: $errstr ($errno)\n");
}

echo "服务器已启动,正在监听 $host:$port...\n";

while ($conn = stream_socket_accept($socket)) {
    $data = fread($conn, 2048); // 每次读取2048字节
    if ($data) {
        echo "接收到数据: $data\n";

        // 数据解析(根据212协议对数据结构的定义)
        $parsedData = parse212Data($data);

        // 获取设备唯一标识(MN)
        $MN = $parsedData['MN'] ?? 'unknown_device';
$parsedData = serialize($parsedData);
        // 将解析后的数据存入 Redis,设置过期时间为300秒
        $redis->setex('tsp_data_' . $MN,  300,$parsedData);

        // 发送确认或回复
        fwrite($conn, "数据接收成功,^_^,谢谢测试帅哥!\n");
    }

    fclose($conn);
}

fclose($socket);

function parse212Data($data) {
    // 分离 CP 部分
    //  $data = substr($data, 6, strpos($data, '&&') - 6); // 提取数据段
    
   $data= substr($data, 6);
    $parts = explode('CP=&&', $data, 2);
    $metadata = trim($parts[0]); // CP 之前的数据部分
    $cpContent = isset($parts[1]) ? trim($parts[1]) : '';

    // 解析 CP 之前的数据部分
    $fieldsBeforeCP = explode(';', $metadata);
    $result = [];
    foreach ($fieldsBeforeCP as $field) {
        if (strpos($field, '=') !== false) {
            list($key, $value) = explode('=', $field, 2);
            $result[$key] = $value;
        }
    }

    // 解析 CP 内部的数据
    if (!empty($cpContent)) {
        $cpEndPos = strpos($cpContent, '&&');
        if ($cpEndPos !== false) {
            $cpData = substr($cpContent, 0, $cpEndPos);

            // 用正则表达式精准分割 CP 内容
            $fieldsInCP = preg_split('/[;,]/', $cpData);
            foreach ($fieldsInCP as $field) {
                if (strpos($field, '=') !== false) {
                    list($key, $value) = explode('=', $field, 2);
                    $result[$key] = $value;
                }
            }
        }
    }

    return $result;
}








?>



python 发包测试

import socket

host = 'IP地址或者域名'
port = 21212

# 数据包
data = "##0530QN=20241119164503506;ST=39;CN=2051;PW=123456;MN=ZR118220915203;Flag=5;CP=&&DataTime=20241119163500;a01001-Min=12.54,a01001-Avg=12.87,a01001-Max=13.25,a01001-Flag=N;a01002-Min=51.30,a01002-Avg=52.49,a01002-Max=53.52,a01002-Flag=N;a01006-Min=102.301,a01006-Avg=102.301,a01006-Max=102.303,a01006-Flag=N;a01007-Min=0.0,a01007-Avg=0.0,a01007-Max=0.0,a01007-Flag=N;a01008-Min=165,a01008-Avg=165,a01008-Max=166,a01008-Flag=N;a34001-Min=100.9,a34001-Avg=100.9,a34001-Max=100.9,a34001-Flag=N;LA-Min=38.4,LA-Avg=39.8,LA-Max=44.1,LA-Flag=N&&6240"
        ##0530QN=20241119170103194;ST=39;CN=2061;PW=123456;MN=ZR118220915203;Flag=5;CP=&&DataTime=20241119160000;a01001-Min=11.14,a01001-Avg=13.20,a01001-Max=15.22,a01001-Flag=N;a01002-Min=45.44,a01002-Avg=51.41,a01002-Max=57.99,a01002-Flag=N;a01006-Min=102.299,a01006-Avg=102.315,a01006-Max=102.349,a01006-Flag=N;a01007-Min=0.0,a01007-Avg=0.0,a01007-Max=0.0,a01007-Flag=N;a01008-Min=130,a01008-Avg=165,a01008-Max=197,a01008-Flag=N;LA-Min=37.3,LA-Avg=40.7,LA-Max=53.5,LA-Flag=N;a34001-Min=103.1,a34001-Avg=103.1,a34001-Max=103.1,a34001-Flag=N&&EA41
# 创建 socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((host, port))
    s.sendall(data.encode())

    # 接收服务器的响应
    response = s.recv(1024)
    print('服务器响应:', response.decode())


原文地址:https://blog.csdn.net/lovelry/article/details/143910960

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!