将 Cyber​​power UPS 的 JSON 解析为 InfluxDB/Grafana

Posted

技术标签:

【中文标题】将 Cyber​​power UPS 的 JSON 解析为 InfluxDB/Grafana【英文标题】:Parse JSON for Cyberpower UPS into InfluxDB/Grafana 【发布时间】:2018-07-27 14:09:15 【问题描述】:

我正在尝试从 Cyber​​power UPS 代理解析 JSON(用于将数据导入 InfluxDB/Grafana)。除了电池状态之外,我能够解析我想要的所有内容。如下图所示,如果 UPS 与市电断开,状态为“正在放电”,但如果已连接,则该值包含逗号,“正常,充满电”....我无法找到解析数据的方法,因为我知道该值中可能有也可能没有逗号。如果值为“Discharging”,则工作正常,但由于 “Normal, Fully Charged” 中的逗号,grep 结果为 “Normal(显然缺少结束引号)。

单个值的 JSON:

"battery":"state":"Discharging",

用逗号和空格表示值的 JSON:

"battery":"state":"Normal, Fully Charged",

我的卷曲/greb。是否可以这样做来提取我想要的值中可能有也可能没有逗号的值?如果是这样,我做错了什么?

curl http://10.0.1.61:3052/agent/ppbe.js/init_status.js | grep -oP '(?<="battery":"state":)[^,]*' | head -1

放电时的完整 .js 页面:

var ppbeJsObj = 
    "status": 
        "communicationAvaiable": true,
        "onlyPhaseArch": false,
        "utility": 
            "state": "Blackout",
            "stateWarning": true,
            "voltage": "0",
            "frequency": "60.00",
            "voltages": null,
            "currents": null,
            "frequencies": null,
            "powerFactors": null
        ,
        "bypass": 
            "state": "Normal",
            "stateWarning": false,
            "voltage": null,
            "current": null,
            "frequency": null,
            "voltages": null,
            "currents": null,
            "frequencies": null,
            "powerFactors": null
        ,
        "output": 
            "state": "Normal",
            "stateWarning": false,
            "voltage": "120.0",
            "frequency": null,
            "load": 58,
            "watt": 522,
            "current": null,
            "outputLoadWarning": false,
            "outlet1": null,
            "outlet2": null,
            "activePower": null,
            "apparentPower": null,
            "reactivePower": null,
            "voltages": null,
            "currents": null,
            "frequencies": null,
            "powerFactors": null,
            "loads": null,
            "activePowers": null,
            "apparentPowers": null,
            "reactivePowers": null,
            "emergencyOff": null,
            "batteryExhausted": null
        ,
        "battery": 
            "state": "Discharging",
            "stateWarning": true,
            "voltage": null,
            "capacity": 99,
            "runtimeFormat": 1,
            "runtimeFormatWarning": false,
            "runtimeHour": 0,
            "runtimeMinute": 20,
            "chargetimeFormat": null,
            "chargetimeHour": null,
            "chargetimeMinute": null,
            "temperatureCelsius": null,
            "highVoltage": null,
            "lowVoltage": null,
            "highCurrent": null,
            "lowCurrent": null
        ,
        "upsSystem": 
            "state": "Normal",
            "stateWarning": false,
            "temperatureCelsius": null,
            "temperatureFahrenheit": null,
            "maintenanceBreak": null,
            "systemFaultDueBypass": null,
            "systemFaultDueBypassFan": null,
            "originalHardwareFaultCode": "0x8080"
        ,
        "modules": null,
        "deviceId": 0
    
;

【问题讨论】:

见:community.openhab.org/t/8334(我相信这是同一个问题。) 你需要解析JSON(使用jq '.battery.state')还是javascript。您将 JavaScript sn-p 作为输出,这与 JSON 完全不同。 @chepner - 我相信这里的目的是从 JavaScript 中提取对象,然后解析它。 对于 UPS 制造商而言,这是一个可怕的设计决策。 @eptesicus - 您是否尝试在 bash 中解析此 JavaScript? - 这可能对你有用。 (denlab.io/…) 【参考方案1】:

这应该可行:

grep -P -o '(?<="battery":"state":")[a-zA-Z, ]+'

问候!

编辑:由于 OP 评论而编辑。

$ cat test.txt
var ppbeJsObj="status":"communicationAvaiable":true,
"onlyPhaseArch":false,
"utility":"state":"Blackout",
"stateWarning":true,
"voltage":"0",
"frequency":"60.00",
"voltages":null,
"currents":null,
"frequencies":null,
"powerFactors":null,
"bypass":"state":"Normal",
"stateWarning":false,
"voltage":null,
"current":null,
"frequency":null,
"voltages":null,
"currents":null,
"frequencies":null,
"powerFactors":null,
"output":"state":"Normal",
"stateWarning":false,
"voltage":"120.0",
"frequency":null,
"load":58,
"watt":522,
"current":null,
"outputLoadWarning":false,
"outlet1":null,
"outlet2":null,
"activePower":null,
"apparentPower":null,
"reactivePower":null,
"voltages":null,
"currents":null,
"frequencies":null,
"powerFactors":null,
"loads":null,
"activePowers":null,
"apparentPowers":null,
"reactivePowers":null,
"emergencyOff":null,
"batteryExhausted":null,
"battery":"state":"Discharging",
"stateWarning":true,
"voltage":null,
"capacity":99,
"runtimeFormat":1,
"runtimeFormatWarning":false,
"runtimeHour":0,
"runtimeMinute":20,
"chargetimeFormat":null,
"chargetimeHour":null,
"chargetimeMinute":null,
"temperatureCelsius":null,
"highVoltage":null,
"lowVoltage":null,
"highCurrent":null,
"lowCurrent":null,
"upsSystem":"state":"Normal",
"stateWarning":false,
"temperatureCelsius":null,
"temperatureFahrenheit":null,
"maintenanceBreak":null,
"systemFaultDueBypass":null,
"systemFaultDueBypassFan":null,
"originalHardwareFaultCode":"0x8080",
"modules":null,
"deviceId":0;

$ grep -P -o '(?<="battery":"state":")[a-zA-Z, ]+' test.txt
Discharging

【讨论】:

这根据 regexr.com 工作,但是在我的服务器上执行操作时,没有返回任何内容。 卷曲10.0.1.61:3052/agent/ppbe.js/init_status.js | grep -oP '(? @eptesicus 添加 -P 和 -o 标志,如我的版本所示。【参考方案2】:

bash 解决方案:

你可以这样做:

curl http://10.0.1.61:3052/agent/ppbe.js/init_status.js | \
grep -oP '(?<="battery":\s*)([^]+)(?=)' | \
grep -oP '(?<="state": ")([^"]+)(?=")'

分解:

首先,正则表达式。

(?&lt;=) 是一个积极的群体。所以(?&lt;=aa)bb 将匹配前面有aa 的任何bb

(?=) 是一个正向前瞻组,因此,bb(?=aa) 将匹配任何 bb 后跟 aa

现在,命令,

获取文件:curl http://10.0.1.61:3052/agent/ppbe.js/init_status.js | \

找到battery 部分:grep -oP '(?&lt;="battery":\s*)([^]+)(?=)' | \ 这会将其转换为这种东西:

"state": "Normal, Fully Charged",
"stateWarning": true,
"voltage": null,
"capacity": 99,
"runtimeFormat": 1,
"runtimeFormatWarning": false,
"runtimeHour": 0,
"runtimeMinute": 20,
"chargetimeFormat": null,
"chargetimeHour": null,
"chargetimeMinute": null,
"temperatureCelsius": null,
"highVoltage": null,
"lowVoltage": null,
"highCurrent": null,
"lowCurrent": null

查找state 键/值:grep -oP '(?&lt;="state": ")([^"]+)(?=")' 然后这个将返回值:

Normal, Fully Charged

对于更高级的 JSON,您可以执行以下操作:

curl http://10.0.1.61:3052/agent/ppbe.js/init_status.js | \
grep -oP '(?<="battery":\s*)(([^]++|(?1))*)(?=)' | \
grep -oP '(?<="state": ")([^"]+)(?=")'

请参阅 (https://unix.stackexchange.com/a/147664) 了解其工作原理。


一个JS解决方案:

您可以去掉变量声明和分号,然后像普通 JSON 一样解析它。

// Here 'input' is your 'init_status.js' string
input = JSON.parse(input.replace(
    /(?:^[\s\S]*?(?=))|(?:;[^;]*?$)/g,
    ""
))

如果您还需要“获取”文件,那么您可以这样做:

const http = require('http');
http.get(
    'http://10.0.1.61:3052/agent/ppbe.js/init_status.js',
    response => 
        let body = '';

        // Read the data.
        response.on('data', chunk => body += chunk);

        // The file is complete, now we can use it.
        response.on('end', () => 
            const data = JSON.parse(
                body.replace(
                    /(?:^[\s\S]*?(?=))|(?:;[^;]*?$)/g,
                    ""
                )
            );

            // This logs the entire JSON object.
            console.log(data);

            // Getting the 'battery state'
            console.log(data.status.battery.state);
        );
    
);

【讨论】:

以上是关于将 Cyber​​power UPS 的 JSON 解析为 InfluxDB/Grafana的主要内容,如果未能解决你的问题,请参考以下文章

将 Cyber​​Panel 的所有内容迁移到不同 VPS 上的新 Cyber​​Panel

Power BI:通过记录行索引将 JSON 记录转换为列

如何将嵌套 JSON 有效负载的最深层元素转换为 Power Query 中的单独行?

Power Automate Flow:将 json 转换为可读的 PowerAutomate-Items

Rust 和 Cyber​​DWARF 可以一起使用吗?

Power 查询 JSON 动态 URL