Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 50 additions & 2 deletions src/em511/em511.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,12 @@ class Em511:
INPUT_MAX_VALUE_32 = 0x7FFFFFFF
INPUT_MAX_VALUE_16 = 0x7FFF

EM511_REGISTER_V = 0x0000
EM511_REGISTER_A = 0x0002
EM511_REGISTER_V = 0x0
EM511_REGISTER_A = 0x2
EM511_REGISTER_HZ = 0xF
EM511_REGISTER_PASSWORD = 0x1000
EM511_REGISTER_KWH_TOT = 0x10
EM511_REGISTER_KWH_PARTIAL = 0x14

SCALE_10 = 10
SCALE_100 = 100
Expand Down Expand Up @@ -151,6 +154,51 @@ def A(self) -> Decimal:
value = Decimal(self._unpack(regs, self.EM511_REGISTER_A)) / self.SCALE_1000
return round(value, 3)

@property
def Hz(self) -> Decimal:
"""Hertz (Hz).

Returns:
Decimal: Current hertz value.

Raises:
ValueError: If input is at max value or above.
ModbusException: If failed to read input register.
"""
regs = self._read_input_registers(self.EM511_REGISTER_HZ, self.INT16_REG_COUNT)
value = Decimal(self._unpack(regs, self.EM511_REGISTER_HZ)) / self.SCALE_10
return round(value, 1)

@property
def kWh_tot(self) -> Decimal:
"""Kilo watt hours in total (kWh).

Returns:
Decimal: Current total kWh value.

Raises:
ValueError: If input is at max value or above.
ModbusException: If failed to read input register.
"""
regs = self._read_input_registers(self.EM511_REGISTER_KWH_TOT, self.INT32_REG_COUNT)
value = Decimal(self._unpack(regs, self.EM511_REGISTER_KWH_TOT)) / self.SCALE_10
return round(value, 1)

@property
def kWh_partial(self) -> Decimal:
"""Kilo watt hours partial (kWh).

Returns:
Decimal: Current partial kWh value.

Raises:
ValueError: If input is at max value or above.
ModbusException: If failed to read input register.
"""
regs = self._read_input_registers(self.EM511_REGISTER_KWH_PARTIAL, self.INT32_REG_COUNT)
value = Decimal(self._unpack(regs, self.EM511_REGISTER_KWH_PARTIAL)) / self.SCALE_10
return round(value, 1)

@property
def password(self) -> int:
"""Password.
Expand Down
101 changes: 97 additions & 4 deletions src/em511/test_em511.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

"""Test file for driver."""

from decimal import Decimal
from unittest.mock import MagicMock

import pytest
Expand All @@ -20,13 +21,13 @@ def test_V() -> None:
mock_result.registers = [0x08FC, 0x0000]
client.read_input_registers.return_value = mock_result
value = meter.V
assert value == 230
assert value == Decimal("230.0")

"""Test 2: Should pass."""
mock_result.registers = [0x9A28, 0x0001]
client.read_input_registers.return_value = mock_result
value = meter.V
assert value == 10500
assert value == Decimal("10500.0")

"""Test 3: Should raise exception due to more registers in use than allowed."""
mock_result.registers = [0x1860, 0x0023, 0x4244]
Expand All @@ -52,13 +53,13 @@ def test_get_A() -> None:
mock_result.registers = [0x2904, 0x0000]
client.read_input_registers.return_value = mock_result
value = meter.A
assert value == 10.5
assert value == Decimal("10.5")

"""Test 2: Should pass."""
mock_result.registers = [0x1860, 0x0023]
client.read_input_registers.return_value = mock_result
value = meter.A
assert value == 2300
assert value == Decimal("2300.0")

"""Test 3: Should raise exception due to more registers in use than allowed."""
mock_result.registers = [0x1860, 0x0023, 0x4244]
Expand All @@ -72,6 +73,98 @@ def test_get_A() -> None:
with pytest.raises(ValueError, match="Input overflow EEE for 32-bit register: "):
_ = meter.A

def test_get_Hz() -> None:
"""Test Get HZ."""
client = MagicMock()
mock_result = MagicMock()
mock_result.isError.return_value = False
meter = Em511(1, client)

"""Test 1: should pass"""
mock_result.registers = [0x08FC]
client.read_input_registers.return_value = mock_result
value = meter.Hz
assert value == Decimal("230.0")

"""Test 2: Should pass."""
mock_result.registers = [0x9A28]
client.read_input_registers.return_value = mock_result
value = meter.Hz
assert value == Decimal("3946.4")

"""Test 3: Should raise exception due to more registers in use than allowed."""
mock_result.registers = [0x1860, 0x0023, 0x5743]
client.read_input_registers.return_value = mock_result
with pytest.raises(ValueError, match="Unexpected register count:"):
_ = meter.Hz

"""Test 6: Should raise exception if input value exceeds maximum value, display shows 'EEE', 16-bit register."""
mock_result.registers = [0x7FFF]
client.read_input_registers.return_value = mock_result
with pytest.raises(ValueError, match="Input overflow EEE for 16-bit register: "):
_ = meter.Hz

def test_kWh_tot() -> None:
"""Test Get total kWh."""
client = MagicMock()
mock_result = MagicMock()
mock_result.isError.return_value = False
meter = Em511(1, client)

"""Test 1: should pass"""
mock_result.registers = [0x08FC, 0x0000]
client.read_input_registers.return_value = mock_result
value = meter.kWh_tot
assert value == Decimal("230.0")

"""Test 2: Should pass."""
mock_result.registers = [0x9A28, 0x0001]
client.read_input_registers.return_value = mock_result
value = meter.kWh_tot
assert value == Decimal("10500.0")

"""Test 3: Should raise exception due to more registers in use than allowed."""
mock_result.registers = [0x1860, 0x0023, 0x4244]
client.read_input_registers.return_value = mock_result
with pytest.raises(ValueError, match="Unexpected register count:"):
_ = meter.kWh_tot

"""Test 6: Should raise exception if input value exceeds maximum value, display shows 'EEE', 32-bit register."""
mock_result.registers = [0xFFFF, 0x7FFF]
client.read_input_registers.return_value = mock_result
with pytest.raises(ValueError, match="Input overflow EEE for 32-bit register: "):
_ = meter.kWh_tot

def test_kWh_partial() -> None:
"""Test Get partial kWh."""
client = MagicMock()
mock_result = MagicMock()
mock_result.isError.return_value = False
meter = Em511(1, client)

"""Test 1: should pass"""
mock_result.registers = [0x08FC, 0x0000]
client.read_input_registers.return_value = mock_result
value = meter.kWh_partial
assert value == Decimal("230.0")

"""Test 2: Should pass."""
mock_result.registers = [0x9A28, 0x0001]
client.read_input_registers.return_value = mock_result
value = meter.kWh_partial
assert value == Decimal("10500.0")

"""Test 3: Should raise exception due to more registers in use than allowed."""
mock_result.registers = [0x1860, 0x0023, 0x4244]
client.read_input_registers.return_value = mock_result
with pytest.raises(ValueError, match="Unexpected register count:"):
_ = meter.kWh_partial

"""Test 6: Should raise exception if input value exceeds maximum value, display shows 'EEE', 32-bit register."""
mock_result.registers = [0xFFFF, 0x7FFF]
client.read_input_registers.return_value = mock_result
with pytest.raises(ValueError, match="Input overflow EEE for 32-bit register: "):
_ = meter.kWh_partial

def test_get_password() -> None:
"""Test Get password."""
Expand Down
Loading