Skip to content

Commit

Permalink
update api
Browse files Browse the repository at this point in the history
  • Loading branch information
austinmroczek committed Mar 24, 2023
1 parent 65b04f3 commit 2c6b5d9
Showing 1 changed file with 67 additions and 12 deletions.
79 changes: 67 additions & 12 deletions custom_components/neovolta/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
from pymodbus.client import AsyncModbusTcpClient
from pymodbus.exceptions import ConnectionException, ModbusIOException
from pymodbus.pdu import ExceptionResponse
from pymodbus import pymodbus_apply_logging_config

# logging.getLogger("pymodbus.logging").setLevel(logging.DEBUG)
pymodbus_apply_logging_config()

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -37,8 +41,25 @@ def __init__(
self._port = port
self._static_data_loaded = False
self.data = {}

self._client = AsyncModbusTcpClient(host=self._host, port=self._port)
self._stats = {
"async_get_data": 0,
"get_value": 0,
"TimeoutError": 0,
"ConnectionException": 0,
"ModbusIOException": 0,
"Exception": 0,
"isError": 0,
"ExceptionResponse": 0,
"tries": {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0},
}

self._client = AsyncModbusTcpClient(
host=self._host,
port=self._port,
close_comm_on_error=True,
reconnect_delay=1000,
retry_on_empty=True,
)

async def async_get_static_data(self) -> any:
"""Get static data only once."""
Expand All @@ -57,8 +78,7 @@ def _scaled_value(self, value, scale=1) -> any:

async def async_get_data(self) -> any:
"""Get data from the API."""
if not self._client.connected:
await self._client.connect()
self._stats["async_get_data"] += 1

if not self._static_data_loaded:
await self.async_get_static_data()
Expand Down Expand Up @@ -139,8 +159,7 @@ async def async_get_data(self) -> any:
self.data["voltage319"] = self._scaled_value(response[19], 0.1)
self.data["frequency4"] = self._scaled_value(response[44], 0.01)

# close after finished getting data (it will auto-connect on next call)
await self._client.close()
await self._calculate_stats()

async def _get_value(
self,
Expand All @@ -150,41 +169,77 @@ async def _get_value(
tries=1,
) -> any:
"""Get information from the API."""
self._stats["get_value"] += 1
self._stats["tries"][tries] += 1
if tries >= 10:
await self._calculate_stats()
raise NeovoltaApiClientCommunicationError(
f"Timeout fetching NeoVolta information",
)

if tries > 1:
_LOGGER.debug(f"Neovolta re-try # {tries} for register {address}")
await asyncio.sleep(tries)
# await asyncio.sleep(tries)
await asyncio.sleep(5)

try:
async with async_timeout.timeout(30):
response = await self._client.read_holding_registers(
address=address, count=size, slave=unit
)

except asyncio.TimeoutError:
_LOGGER.debug("Neovolta timeout")
except asyncio.TimeoutError as exception:
_LOGGER.debug(f"Neovolta timeout: {exception}")
self._stats["TimeoutError"] += 1
return await self._get_value(address, size, unit, tries + 1)
except ConnectionException:
_LOGGER.debug("Neovolta connection problem")
except ConnectionException as exception:
_LOGGER.debug(f"Neovolta connection problem: {exception}")
self._stats["ConnectionException"] += 1
return await self._get_value(address, size, unit, tries + 1)
except ModbusIOException as exception:
_LOGGER.error(f"Neovolta ModbusIOException: {exception.message}")
_LOGGER.debug(f"Neovolta ModbusIOException: {exception.message}")
self._stats["ModbusIOException"] += 1
self._client.close()
return await self._get_value(address, size, unit, tries + 1)
except Exception as exception: # pylint: disable=broad-except
self._stats["Exception"] += 1
await self._calculate_stats()
raise NeovoltaApiClientError(
"Something really wrong happened!"
) from exception

if response.isError():
self._stats["isError"] += 1
_LOGGER.debug(f"NeoVolta MODBUS response error: {response}")
return await self._get_value(address, size, unit, tries + 1)

if isinstance(response, ExceptionResponse):
self._stats["ExceptionResponse"] += 1
_LOGGER.debug(f"NeoVolta device rejected MODBUS request: {response}")
return await self._get_value(address, size, unit, tries + 1)

return response.registers

async def _calculate_stats(self):
"""Calculate stats."""

stats = (
f"\nNeoVolta Integration Debug STATS:\n"
f"async_get_data {self._stats['async_get_data']}\t"
f"get_value {self._stats['get_value']}\n"
f"TimeoutError {self._stats['TimeoutError']}\t"
f"ConnectionException {self._stats['ConnectionException']}\t"
f"ModbusIOException {self._stats['ModbusIOException']}\n"
f"Exception {self._stats['Exception']}\t"
f"isError {self._stats['isError']}\t"
f"ExceptionResponse {self._stats['ExceptionResponse']}\n"
)

tries = "tries - "
i = 1
for i in range(1, 11):
tries = tries + f"{i}: {self._stats['tries'][i]}\t"

stats = stats + tries

_LOGGER.debug(stats)

0 comments on commit 2c6b5d9

Please sign in to comment.