Skip to content

Commit a050b19

Browse files
authored
修复异步和循环问题
1 parent 85708cb commit a050b19

File tree

5 files changed

+138
-67
lines changed

5 files changed

+138
-67
lines changed

custom_components/peacefair_energy/__init__.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import voluptuous as vol
44
import os
55
from datetime import timedelta
6+
import asyncio
67
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
78
from homeassistant.core import HomeAssistant
89
from .const import(
@@ -72,7 +73,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry):
7273
await hass.config_entries.async_forward_entry_setups(config_entry, ["sensor"])
7374
hass.data[config_entry.entry_id][UN_SUBDISCRIPT] = config_entry.add_update_listener(update_listener)
7475

75-
def service_handle(service):
76+
async def async_service_handle(service):
7677
entity_id = service.data[ATTR_ENTITY_ID]
7778
energy_sensor = next(
7879
(sensor for sensor in hass.data[DOMAIN][ENERGY_SENSOR] if sensor.entity_id == entity_id),
@@ -85,20 +86,19 @@ def service_handle(service):
8586
coordinator = hass.data[config_entry.entry_id][COORDINATOR]
8687
if coordinator is not None:
8788
coordinator.reset_energy()
88-
energy_sensor.reset()
89+
await energy_sensor.reset() # 等待异步方法完成
8990

9091
hass.services.async_register(
9192
DOMAIN,
9293
SERVICE_RESET_ENERGY,
93-
service_handle,
94+
async_service_handle,
9495
schema=RESET_ENERGY_SCHEMA,
9596
)
9697

9798
return True
9899

99100

100101
async def async_unload_entry(hass: HomeAssistant, config_entry):
101-
102102
await hass.config_entries.async_forward_entry_unloads(config_entry, ["sensor"])
103103

104104
host = config_entry.data[CONF_HOST]
@@ -113,15 +113,22 @@ async def async_unload_entry(hass: HomeAssistant, config_entry):
113113
if unsub is not None:
114114
unsub()
115115
hass.data.pop(config_entry.entry_id)
116+
117+
# 异步执行文件操作
116118
storage_path = hass.config.path(f"{STORAGE_PATH}")
117119
record_file = hass.config.path(f"{STORAGE_PATH}/{config_entry.entry_id}_state.json")
118120
reset_file = hass.config.path(f"{STORAGE_PATH}/{DOMAIN}_reset.json")
119-
if os.path.exists(record_file):
120-
os.remove(record_file)
121-
if os.path.exists(reset_file):
122-
os.remove(reset_file)
123-
if len(os.listdir(storage_path)) == 0:
124-
os.rmdir(storage_path)
121+
122+
def remove_files():
123+
if os.path.exists(record_file):
124+
os.remove(record_file)
125+
if os.path.exists(reset_file):
126+
os.remove(reset_file)
127+
if len(os.listdir(storage_path)) == 0:
128+
os.rmdir(storage_path)
129+
130+
await hass.async_add_executor_job(remove_files)
131+
125132
return True
126133

127134

@@ -156,5 +163,9 @@ async def _async_update_data(self):
156163
data = data_update
157164
_LOGGER.debug(f"Got Data {data}")
158165
if self._updates is not None:
159-
self._updates()
166+
# 确保异步方法被正确调用
167+
if asyncio.iscoroutinefunction(self._updates):
168+
await self._updates()
169+
else:
170+
self._updates()
160171
return data

custom_components/peacefair_energy/const.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
UN_SUBDISCRIPT = "un_subdiscript"
99
DEVICE_CLASS_FREQUENCY = "frequency"
1010
DEVICES = "devices"
11-
VERSION = "0.7.0"
11+
VERSION = "3.11.1"
1212
GATHER_TIME = "gather_time"
1313
PROTOCOLS = {
1414
"ModbusRTU Over UDP/IP": "rtuoverudp",
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
{
22
"domain": "peacefair_energy",
33
"name": "Peacefair Energy Monitor",
4-
"version": "v0.7.5",
4+
"version": "v3.11.1",
55
"config_flow": true,
66
"documentation": "https://github.com/georgezhao2010/peacefair_energy",
77
"issue_tracker": "https://github.com/georgezhao2010/peacefair_energy/issue",
88
"iot_class": "local_polling",
99
"dependencies": [],
1010
"codeowners": ["@georgezhao2010"],
11-
"requirements": ["pymodbus==3.6.9"]
11+
"requirements": ["pymodbus"]
1212
}

custom_components/peacefair_energy/modbus.py

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import logging
22
import asyncio
33
from pymodbus.client import ModbusTcpClient, ModbusUdpClient
4-
from pymodbus.transaction import ModbusRtuFramer, ModbusIOException
5-
from pymodbus.pdu import ModbusRequest
4+
from pymodbus.framer.rtu import FramerRTU
5+
from pymodbus.transaction.transaction import ModbusIOException
6+
from pymodbus.pdu import ModbusPDU
7+
#from pymodbus.exceptions import ModbusException
68
import threading
79

810
try:
@@ -35,6 +37,29 @@
3537

3638
_LOGGER = logging.getLogger(__name__)
3739

40+
class ModbusRequest(ModbusPDU):
41+
"""Base class for a modbus request PDU."""
42+
43+
function_code = -1
44+
45+
def __init__(self, slave, transaction, skip_encode):
46+
"""Proxy to the lower level initializer.
47+
48+
:param slave: Modbus slave slave ID
49+
"""
50+
super().__init__(slave, transaction, skip_encode)
51+
self.fut = None
52+
53+
def doException(self, exception):
54+
"""Build an error response based on the function.
55+
56+
:param exception: The exception to return
57+
:raises: An exception response
58+
"""
59+
exc = ExceptionResponse(self.function_code, exception)
60+
Log.error("Exception response {}", exc)
61+
return exc
62+
3863
class ModbusResetEnergyRequest(ModbusRequest):
3964
_rtu_frame_size = 4
4065
function_code = 0x42
@@ -58,19 +83,19 @@ def __init__(self, protocol, host, port, slave):
5883
self._client = ModbusTcpClient(
5984
host=host,
6085
port=port,
61-
framer=ModbusRtuFramer,
86+
framer='rtu',
6287
timeout=2,
63-
retry_on_empty=True,
64-
retry_on_invalid=False
88+
#retry_on_empty=True,
89+
#retry_on_invalid=False
6590
)
6691
elif protocol == "rtuoverudp":
6792
self._client = ModbusUdpClient(
6893
host=host,
6994
port=port,
70-
framer=ModbusRtuFramer,
95+
framer='rtu',
7196
timeout=2,
72-
retry_on_empty=False,
73-
retry_on_invalid=False
97+
#retry_on_empty=False,
98+
#retry_on_invalid=False
7499
)
75100

76101
def connect(self):
@@ -81,27 +106,27 @@ def close(self):
81106
with self._lock:
82107
self._client.close()
83108

84-
# 新增同步版本,供线程池调用
85-
def read_input_registers_sync(self, address, count):
86-
with self._lock:
87-
kwargs = {"slave": self._slave}
88-
return self._client.read_input_registers(address, count, **kwargs)
89-
90-
# 异步版本,交给线程池执行,避免阻塞事件循环
91-
async def read_input_registers(self, address, count):
92-
loop = asyncio.get_running_loop()
93-
return await loop.run_in_executor(
94-
None,
95-
self.read_input_registers_sync,
96-
address,
97-
count
98-
)
99-
100-
def reset_energy(self):
101-
with self._lock:
102-
kwargs = {"slave": self._slave}
103-
request = ModbusResetEnergyRequest(**kwargs)
104-
self._client.execute(request)
109+
# 新增同步版本,供线程池调用
110+
def read_input_registers_sync(self, address, count):
111+
with self._lock:
112+
kwargs = {"device_id": self._slave}
113+
return self._client.read_input_registers(address=address, count=count, **kwargs)
114+
115+
# 异步版本,交给线程池执行,避免阻塞事件循环
116+
async def read_input_registers(self, address, count):
117+
loop = asyncio.get_running_loop()
118+
return await loop.run_in_executor(
119+
None,
120+
self.read_input_registers_sync,
121+
address,
122+
count
123+
)
124+
125+
def reset_energy(self):
126+
with self._lock:
127+
kwargs = {"slave": self._slave}
128+
request = ModbusResetEnergyRequest(**kwargs)
129+
self._client.execute(request)
105130

106131
# 异步版本info_gather
107132
async def info_gather(self):

0 commit comments

Comments
 (0)