You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Minimalmodbus清除PZEM 016能量计数器遇非法数据值错误

问题:Peacefair AC PZEM 016电能监测仪能量计数器清除失败,报错“Slave reported Illegal Data Value”

我正在尝试给Peacefair AC PZEM 016电能监测仪清除能量计数器,现有脚本可以正常读取寄存器数值,但用minimalmodbus库执行清除操作时一直报错,错误信息是Slave reported Illegal Data Value。设备文档里的“重置能量”功能在2.5章节,但操作始终无法成功。

以下是相关Python代码:

import minimalmodbus
import datetime
import time
import serial
import sys
import os
import threading
from crccheck.crc import Crc16

mb_address = 1 
clear_energy_command = 0x42
powark_sensor = minimalmodbus.Instrument('/dev/ttyUSB0',mb_address) 

powark_sensor.serial.baudrate = 9600
powark_sensor.serial.bytesize = 8
powark_sensor.serial.parity = minimalmodbus.serial.PARITY_NONE
powark_sensor.serial.stopbits = 1
powark_sensor.serial.timeout = 0.5
powark_sensor.mode = minimalmodbus.MODE_RTU

file_path = "/home/josiahferguson/Documents/powark/mb_powark_data.txt"

powark_sensor.clear_buffers_before_each_transaction = True
powark_sensor.close_port_after_each_call = True

print("")
print("Requesting Data From Powark...")
print("")
#single_data = powark.sensor.read_register(1, 1, 3, False)
#print(f"Single register data = {single_data}")

#function to read powark data
def read_sensor_data():
    data = powark_sensor.read_registers(0, 10, 4)

    volts = data[0] / 10
    ampslow = int(data[1]) / 1000
    ampshigh = int(data[2]) / 1000
    wattslow = int(data[3]) / 10
    wattshigh = int(data[4]) / 10
    watthourslow = int(data[5])
    watthourshigh = int(data[6])
    hertz = int(data[7]) / 10
    powerfactor = int(data[8]) / 100
    alarm = data[9]

    processed_data = {
        "volts": volts,
        "ampslow": ampslow,
        "ampshigh": ampshigh,
        "wattslow": wattslow,
        "wattshigh": wattshigh,
        "watthourslow": watthourslow,
        "watthourshigh": watthourshigh,
        "hertz": hertz,
        "powerfactor": powerfactor,
        "alarm": alarm,
    }

    return processed_data

powark_sensor_data = read_sensor_data()

#function to write sensor data to file
def write_data_to_file(powark_sensor_data, file_path):
    with open (file_path, "a") as file:
        timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
        file.write(f"{timestamp}: {powark_sensor_data}\n")

def low_byte(value):
    return value & 0xFF

def high_byte(value):
    return (value >> 8) & 0xFF

powark_sensor.write_long(mb_address, 0x42, False, 2)

# ~ powark_sensor.serial.open()
# ~ time.sleep(1)
# ~ # Calculate the CRC-16 using the CRC library
# ~ crc = Crc16.calc(bytearray([mb_address, clear_energy_command]))

# ~ # Send the slave address, reset command, and CRC-16
# ~ powark_sensor.serial.write(bytearray([mb_address, clear_energy_command, low_byte(crc), high_byte(crc)]))

# ~ # Wait for the energy monitor to process the command
# ~ time.sleep(0.26)

# ~ response = powark_sensor.serial.read(4)  # The expected response length is 4 bytes
# Check if the response is correct or an error reply
# ~ if len(response) == 0:
    # ~ print("No Response Received")
    # ~ print("")
# ~ elif response[0] == mb_address and response[1] == clear_energy_command:
    # ~ print("Energy Reset")
    # ~ print("")
# ~ elif response[0] == mb_address and response[1] == 0xC2:
    # ~ print("Error resetting energy. Abnormal code:", response[2])
    # ~ print("")
# ~ else:
    # ~ print("Unexpected response:", response)
    # ~ print("")


#fucntion to clear the energy data from the powark sensor
def clear_energy_used(port, mb_adrress):
    try:
        powark_sensor.write_register(clear_energy_command, 6)
        print("Energy data cleared successfully.")
    except Exception as e:
        print(f"Error clearing energy data: {e}")

#function to display sensor values to the console
def print_powark_values():
    print(f"Voltage: {powark_sensor_data['volts']} Volts")
    print("-------------------------")
    print(f"Current: {powark_sensor_data['ampslow']} Amps")
    print("-------------------------")

    #converts Watts to Kilowatts if the value exceeds 999.99
    if powark_sensor_data['wattslow'] >= 1000:
        print(f"Charging Rate: {powark_sensor_data['wattslow']/1000} Kilowatts")
    else:
        print(f"Charging Rate: {powark_sensor_data['wattslow']} Watts")
    print("-------------------------")

    #converts energy (watt hours) to Kilowatts if the value exceeds 999.99
    if powark_sensor_data['watthourslow'] >= 1000:
        print(f"Energy Added: {powark_sensor_data['watthourslow']/1000} Kilowatts")
    else:
        print(f"Energy Added: {powark_sensor_data['watthourslow']} Watts")

    print("-------------------------")
    print(f"Frequency: {powark_sensor_data['hertz']} Hz")
    print("")
    print(f"{powark_sensor_data['powerfactor']} Powerfactor")
    print("")
    print(f"{powark_sensor_data['alarm']}")
    print("")
    
print_powark_values()

print("Writing Data to mb_powark_data.txt File...")
write_data_to_file(powark_sensor_data, file_path)
print("")
print("Now Closing Serial Port")
powark_sensor.serial.close()
print("")

#
#user input handling to start logging data to the file
entered_value = input('Would you like to start a session?: y or n  ')
print("")

if entered_value == 'y':
    time.sleep(1)
    print("Your charging session has started!")
    print("")
    max_iterations = int(input("How many iterations would you like this to run?:  "))
    print("")
    iteration_count = 0

    while iteration_count <= max_iterations:
        # Read sensor data
        powark_sensor_data = read_sensor_data()
        # write_data_to_file(powark_sensor_data, file_path)
        write_data_to_file(powark_sensor_data, file_path)

    #print values to console
        print_powark_values()
        time.sleep(1)
    # Close the serial port
        powark_sensor.serial.close()
        iteration_count += 1
        if iteration_count >= max_iterations:
            print("")
            print("Ports now closed")
            print("")
            #print("Clearing Data")
            #clear_energy_used('/dev/ttyUSB0', mb_address)
            print("Thanks for using Powark!")
            break
    # Wait for the specified delay before the next iteration
else:
    print("Ports now closed")
    print("Thanks for using Powark!")

问题分析与解决方法

根据PZEM 016的Modbus协议规范,能量重置需要使用功能码0x42执行特殊写入操作,你的代码存在参数混淆的问题,具体修正如下:

1. 修正清除函数

替换原有的clear_energy_used函数,使用正确的Modbus参数:

# 修正后的能量清除函数
def clear_energy_used():
    try:
        # 功能码0x42,写入寄存器地址0x0000,固定值0x0000
        powark_sensor.write_register(registeraddress=0x0000, value=0x0000, functioncode=0x42)
        print("能量计数器已成功清除")
    except Exception as e:
        print(f"清除失败:{e}")

2. 错误原因说明

  • 原代码中write_long(mb_address, 0x42, False, 2)参数完全错误,write_long的参数顺序是寄存器地址、数值、字节序、功能码,不能把从站地址和功能码乱填。
  • clear_energy_used函数里的write_register(clear_energy_command, 6)错误地将功能码0x42当成了寄存器地址,这是触发“Illegal Data Value”错误的核心原因。

3. 调用示例

在会话结束后取消注释并调用修正后的函数:

if iteration_count >= max_iterations:
    print("")
    print("Ports now closed")
    print("")
    print("正在清除能量数据...")
    clear_energy_used()
    print("Thanks for using Powark!")
    break

额外注意事项

  • 执行清除操作前,确保设备通信正常(可以先读取一次数据验证)。
  • 操作后建议等待0.5秒再读取能量值,确认清除效果。

内容的提问来源于stack exchange,提问作者moosetinkerer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 00:44:53