diff --git a/src/em511/em511.py b/src/em511/em511.py index 4da7c7e..520697e 100644 --- a/src/em511/em511.py +++ b/src/em511/em511.py @@ -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 @@ -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. diff --git a/src/em511/test_em511.py b/src/em511/test_em511.py index 8c8bac5..5442c1c 100644 --- a/src/em511/test_em511.py +++ b/src/em511/test_em511.py @@ -2,6 +2,7 @@ """Test file for driver.""" +from decimal import Decimal from unittest.mock import MagicMock import pytest @@ -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] @@ -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] @@ -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."""