import asyncio
import os
from datetime import datetime
from unittest import TestCase

from goodwe.dt import DT
from goodwe.exceptions import RequestFailedException, RequestRejectedException
from goodwe.modbus import ILLEGAL_DATA_ADDRESS
from goodwe.protocol import ProtocolCommand, ProtocolResponse


class DtMock(TestCase, DT):

    def __init__(self, methodName="runTest", port=8899):
        TestCase.__init__(self, methodName)
        DT.__init__(self, "localhost", port)
        self.sensor_map = {s.id_: s for s in self.sensors()}
        self._mock_responses = {}
        self.mock_response(self._READ_METER_VERSION_INFO, ILLEGAL_DATA_ADDRESS)
        self.mock_response(self._READ_DEVICE_MODEL, ILLEGAL_DATA_ADDRESS)

    def mock_response(self, command: ProtocolCommand, filename: str):
        self._mock_responses[command] = filename

    async def _read_from_socket(self, command: ProtocolCommand) -> ProtocolResponse:
        """Mock UDP communication"""
        root_dir = os.path.dirname(os.path.abspath(__file__))
        filename = self._mock_responses.get(command)
        if filename is not None:
            if ILLEGAL_DATA_ADDRESS == filename:
                raise RequestRejectedException(ILLEGAL_DATA_ADDRESS)
            if "NO RESPONSE" == filename:
                raise RequestFailedException()
            with open(root_dir + "/sample/dt/" + filename, "r") as f:
                response = bytes.fromhex(f.read())
                if not command.validator(response):
                    raise RequestFailedException
                return ProtocolResponse(response, command)
        else:
            self.request = command.request
            return ProtocolResponse(
                bytes.fromhex("aa557f00010203040506070809"), command
            )

    def assertSensor(self, sensor_name, expected_value, expected_unit, data):
        self.assertEqual(expected_value, data.get(sensor_name))
        sensor = self.sensor_map.get(sensor_name)
        self.assertEqual(expected_unit, sensor.unit)
        self.sensor_map.pop(sensor_name)

    @classmethod
    def setUpClass(cls):
        cls.loop = asyncio.new_event_loop()
        asyncio.set_event_loop(cls.loop)

    @classmethod
    def tearDownClass(cls):
        cls.loop.close()


class GW6000_DT_Test(DtMock):

    def __init__(self, methodName="runTest"):
        DtMock.__init__(self, methodName)
        self.mock_response(self._READ_RUNNING_DATA, "GW6000-DT_running_data.hex")
        self.mock_response(self._READ_METER_DATA, ILLEGAL_DATA_ADDRESS)

    def test_GW6000_DT_runtime_data(self):
        self.loop.run_until_complete(self.read_device_info())
        data = self.loop.run_until_complete(self.read_runtime_data())
        self.assertEqual(45, len(data))

        self.sensor_map = {s.id_: s for s in self.sensors()}

        self.assertSensor(
            "timestamp",
            datetime.strptime("2021-08-31 12:03:02", "%Y-%m-%d %H:%M:%S"),
            "",
            data,
        )
        self.assertSensor("vpv1", 320.8, "V", data)
        self.assertSensor("ipv1", 3.1, "A", data)
        self.assertSensor("ppv1", 994, "W", data)
        self.assertSensor("vpv2", 324.1, "V", data)
        self.assertSensor("ipv2", 3.2, "A", data)
        self.assertSensor("ppv2", 1037, "W", data)
        self.assertSensor("ppv", 2031, "W", data)
        self.assertSensor("vline1", 0, "V", data)
        self.assertSensor("vline2", 0, "V", data)
        self.assertSensor("vline3", 0, "V", data)
        self.assertSensor("vgrid1", 225.6, "V", data)
        self.assertSensor("vgrid2", 229.7, "V", data)
        self.assertSensor("vgrid3", 231.0, "V", data)
        self.assertSensor("igrid1", 2.7, "A", data)
        self.assertSensor("igrid2", 2.6, "A", data)
        self.assertSensor("igrid3", 2.7, "A", data)
        self.assertSensor("fgrid1", 49.98, "Hz", data)
        self.assertSensor("fgrid2", 49.98, "Hz", data)
        self.assertSensor("fgrid3", 49.98, "Hz", data)
        self.assertSensor("pgrid1", 609, "W", data)
        self.assertSensor("pgrid2", 597, "W", data)
        self.assertSensor("pgrid3", 624, "W", data)
        self.assertSensor("total_inverter_power", 1835, "W", data)
        self.assertSensor("work_mode", 1, "", data)
        self.assertSensor("work_mode_label", "Normal", "", data)
        self.assertSensor("error_codes", 0, "", data)
        self.assertSensor("warning_code", 0, "", data)
        self.assertSensor("apparent_power", -1, "VA", data),
        self.assertSensor("reactive_power", -1, "var", data),
        self.assertSensor("total_input_power", -1, "W", data)
        self.assertSensor("power_factor", 0.0, "", data),
        self.assertSensor("temperature", 41.3, "C", data)
        self.assertSensor("temperature_heatsink", None, "C", data)
        self.assertSensor("e_day", 6.0, "kWh", data)
        self.assertSensor("e_total", 13350.2, "kWh", data)
        self.assertSensor("h_total", 8451, "h", data)
        self.assertSensor("safety_country", 20, "", data)
        self.assertSensor("safety_country_label", "NL-A", "", data)
        self.assertSensor("funbit", 0, "", data)
        self.assertSensor("vbus", 601.2, "V", data)
        self.assertSensor("vnbus", 305.4, "V", data)
        self.assertSensor("derating_mode", 0, "", data)
        self.assertSensor("derating_mode_label", "", "", data)
        self.assertSensor("rssi", 100, "", data)

        self.assertFalse(
            self.sensor_map, f"Some sensors were not tested {self.sensor_map}"
        )

    def test_GW6000_DT_setting(self):
        self.assertEqual(11, len(self.settings()))
        settings = {s.id_: s for s in self.settings()}
        self.assertEqual("Timestamp", type(settings.get("time")).__name__)
        self.assertEqual("Integer", type(settings.get("grid_export")).__name__)
        self.assertEqual("Integer", type(settings.get("grid_export_limit")).__name__)

    def test_GW6000_DT_read_setting(self):
        self.loop.run_until_complete(self.read_setting("shadow_scan_pv1"))
        self.assertEqual("7f039d8600014051", self.request.hex())

    def test_GW6000_DT_write_setting(self):
        self.loop.run_until_complete(self.write_setting("shadow_scan_pv1", 1))
        self.assertEqual("7f069d8600018c51", self.request.hex())


class GW8K_DT_Test(DtMock):

    def __init__(self, methodName="runTest"):
        DtMock.__init__(self, methodName)
        self.mock_response(self._READ_DEVICE_VERSION_INFO, "GW8K-DT_device_info.hex")
        self.mock_response(self._READ_RUNNING_DATA, "GW8K-DT_running_data.hex")
        self.mock_response(self._READ_METER_DATA, ILLEGAL_DATA_ADDRESS)

    def test_GW8K_DT_device_info(self):
        self.loop.run_until_complete(self.read_device_info())
        self.assertEqual("GW8K-DT", self.model_name)
        self.assertEqual("00000DTS00000000", self.serial_number)
        self.assertEqual(1010, self.dsp1_version)
        self.assertEqual(1010, self.dsp2_version)
        self.assertEqual(728, self.dsp_svn_version)
        self.assertEqual(8, self.arm_version)
        self.assertEqual(49, self.arm_svn_version)
        self.assertEqual("1010.1010.08", self.firmware)

    def test_GW8K_DT_runtime_data(self):
        self.loop.run_until_complete(self.read_device_info())
        data = self.loop.run_until_complete(self.read_runtime_data())
        self.assertEqual(45, len(data))

        self.assertSensor(
            "timestamp",
            datetime.strptime("2021-08-24 16:43:27", "%Y-%m-%d %H:%M:%S"),
            "",
            data,
        )
        self.assertSensor("vpv1", 275.5, "V", data)
        self.assertSensor("ipv1", 0.6, "A", data)
        self.assertSensor("ppv1", 165, "W", data)
        self.assertSensor("vpv2", 510.8, "V", data)
        self.assertSensor("ipv2", 0.8, "A", data)
        self.assertSensor("ppv2", 409, "W", data)
        self.assertSensor("ppv", 574, "W", data)
        self.assertSensor("vline1", 413.7, "V", data)
        self.assertSensor("vline2", 413.0, "V", data)
        self.assertSensor("vline3", 408.0, "V", data)
        self.assertSensor("vgrid1", 237.2, "V", data)
        self.assertSensor("vgrid2", 240.5, "V", data)
        self.assertSensor("vgrid3", 235.2, "V", data)
        self.assertSensor("igrid1", 1.0, "A", data)
        self.assertSensor("igrid2", 1.0, "A", data)
        self.assertSensor("igrid3", 1.0, "A", data)
        self.assertSensor("fgrid1", 50.08, "Hz", data)
        self.assertSensor("fgrid2", 50.04, "Hz", data)
        self.assertSensor("fgrid3", 50.0, "Hz", data)
        self.assertSensor("pgrid1", 237, "W", data)
        self.assertSensor("pgrid2", 240, "W", data)
        self.assertSensor("pgrid3", 235, "W", data)
        self.assertSensor("total_inverter_power", 643, "W", data)
        self.assertSensor("work_mode", 1, "", data)
        self.assertSensor("work_mode_label", "Normal", "", data)
        self.assertSensor("error_codes", 0, "", data)
        self.assertSensor("warning_code", 0, "", data)
        self.assertSensor("apparent_power", 0, "VA", data),
        self.assertSensor("reactive_power", 0, "var", data),
        self.assertSensor("total_input_power", 0, "W", data)
        self.assertSensor("power_factor", 0.0, "", data),
        self.assertSensor("temperature", 45.3, "C", data)
        self.assertSensor("temperature_heatsink", None, "C", data)
        self.assertSensor("e_day", None, "kWh", data)
        self.assertSensor("e_total", None, "kWh", data)
        self.assertSensor("h_total", 0, "h", data)
        self.assertSensor("safety_country", 32, "", data)
        self.assertSensor("safety_country_label", "50Hz 230Vac Default", "", data)
        self.assertSensor("funbit", 512, "", data)
        self.assertSensor("vbus", 624.2, "V", data)
        self.assertSensor("vnbus", 316.8, "V", data)
        self.assertSensor("derating_mode", 0, "", data)
        self.assertSensor("derating_mode_label", "", "", data)

    def test_get_grid_export_limit(self):
        self.loop.run_until_complete(self.read_device_info())
        self.loop.run_until_complete(self.get_grid_export_limit())
        self.assertEqual("7f039d900001a195", self.request.hex())

    def test_set_grid_export_limit(self):
        self.loop.run_until_complete(self.read_device_info())
        self.loop.run_until_complete(self.set_grid_export_limit(100))
        self.assertEqual("7f069d900064adbe", self.request.hex())


class GW5000D_NS_Test(DtMock):

    def __init__(self, methodName="runTest"):
        DtMock.__init__(self, methodName)
        self.mock_response(self._READ_DEVICE_VERSION_INFO, "Mock_device_info.hex")
        self.mock_response(self._READ_RUNNING_DATA, "GW5000D-NS_running_data.hex")
        self.mock_response(self._READ_METER_DATA, ILLEGAL_DATA_ADDRESS)

    def test_GW5000D_NS_runtime_data(self):
        self.loop.run_until_complete(self.read_device_info())
        data = self.loop.run_until_complete(self.read_runtime_data())
        self.assertEqual(35, len(data))

        self.assertSensor(
            "timestamp",
            datetime.strptime("2021-09-06 06:56:01", "%Y-%m-%d %H:%M:%S"),
            "",
            data,
        )
        self.assertSensor("vpv1", 224.4, "V", data)
        self.assertSensor("ipv1", 0.0, "A", data)
        self.assertSensor("ppv1", 0, "W", data)
        self.assertSensor("vpv2", 291.8, "V", data)
        self.assertSensor("ipv2", 0, "A", data)
        self.assertSensor("ppv2", 0, "W", data)
        self.assertSensor("ppv", 0, "W", data)
        self.assertSensor("vline1", 0, "V", data)
        self.assertSensor("vgrid1", 240.5, "V", data)
        self.assertSensor("igrid1", 0.0, "A", data)
        self.assertSensor("fgrid1", 49.97, "Hz", data)
        self.assertSensor("pgrid1", 0, "W", data)
        self.assertSensor("total_inverter_power", 0, "W", data)
        self.assertSensor("work_mode", 0, "", data)
        self.assertSensor("work_mode_label", "Wait Mode", "", data)
        self.assertSensor("error_codes", 0, "", data)
        self.assertSensor("warning_code", 0, "", data)
        self.assertSensor("apparent_power", -1, "VA", data),
        self.assertSensor("reactive_power", -1, "var", data),
        self.assertSensor("total_input_power", -1, "W", data)
        self.assertSensor("power_factor", -0.001, "", data),
        self.assertSensor("temperature", 1.4, "C", data)
        self.assertSensor("temperature_heatsink", None, "C", data)
        self.assertSensor("e_day", 0, "kWh", data)
        self.assertSensor("e_total", 881.7, "kWh", data)
        self.assertSensor("h_total", 955, "h", data)
        self.assertSensor("safety_country", 73, "", data)
        self.assertSensor("safety_country_label", "Australia Victoria", "", data)
        self.assertSensor("funbit", 2400, "", data)
        self.assertSensor("vbus", 291.7, "V", data)
        self.assertSensor("vnbus", 0, "V", data)
        self.assertSensor("derating_mode", 0, "", data)
        self.assertSensor("derating_mode_label", "", "", data)

    def test_get_grid_export_limit(self):
        self.loop.run_until_complete(self.read_device_info())
        self.loop.run_until_complete(self.get_grid_export_limit())
        self.assertEqual("7f039d8800026193", self.request.hex())

    def test_set_grid_export_limit(self):
        self.loop.run_until_complete(self.read_device_info())
        self.loop.run_until_complete(self.set_grid_export_limit(5000))
        self.assertEqual("7f109d88000204000013889d80", self.request.hex())


class GW5000_MS_Test(DtMock):

    def __init__(self, methodName="runTest"):
        DtMock.__init__(self, methodName)
        self.mock_response(self._READ_DEVICE_VERSION_INFO, "GW5000-MS_device_info.hex")
        self.mock_response(self._READ_RUNNING_DATA, "GW5000-MS_running_data.hex")
        self.mock_response(self._READ_METER_DATA, ILLEGAL_DATA_ADDRESS)

    def test_GW6000_MS_device_info(self):
        self.loop.run_until_complete(self.read_device_info())
        self.assertEqual("GW5000-MS", self.model_name)
        self.assertEqual("00000MSU00000000", self.serial_number)
        self.assertEqual(12, self.dsp1_version)
        self.assertEqual(12, self.dsp2_version)
        self.assertEqual(65535, self.dsp_svn_version)
        self.assertEqual(16, self.arm_version)
        self.assertEqual(271, self.arm_svn_version)
        self.assertEqual("12.12.10", self.firmware)

    def test_GW5000_MS_runtime_data(self):
        self.loop.run_until_complete(self.read_device_info())
        data = self.loop.run_until_complete(self.read_runtime_data())
        self.assertEqual(38, len(data))

        self.assertSensor(
            "timestamp",
            datetime.strptime("2021-10-15 09:03:12", "%Y-%m-%d %H:%M:%S"),
            "",
            data,
        )
        self.assertSensor("vpv1", 319.6, "V", data)
        self.assertSensor("ipv1", 0.2, "A", data)
        self.assertSensor("ppv1", 64, "W", data)
        self.assertSensor("vpv2", 148.0, "V", data)
        self.assertSensor("ipv2", 0.3, "A", data)
        self.assertSensor("ppv2", 44, "W", data)
        self.assertSensor("vpv3", 143.2, "V", data)
        self.assertSensor("ipv3", 0.4, "A", data)
        self.assertSensor("ppv3", 57, "W", data)
        self.assertSensor("ppv", 165, "W", data)
        self.assertSensor("vline1", 0, "V", data)
        self.assertSensor("vgrid1", 240.1, "V", data)
        self.assertSensor("igrid1", 0.9, "A", data)
        self.assertSensor("fgrid1", 49.98, "Hz", data)
        self.assertSensor("pgrid1", 216, "W", data)
        self.assertSensor("total_inverter_power", 295, "W", data)
        self.assertSensor("work_mode", 1, "", data)
        self.assertSensor("work_mode_label", "Normal", "", data)
        self.assertSensor("error_codes", 0, "", data)
        self.assertSensor("warning_code", 0, "", data)
        self.assertSensor("apparent_power", -1, "VA", data),
        self.assertSensor("reactive_power", -1, "var", data),
        self.assertSensor("total_input_power", -1, "W", data)
        self.assertSensor("power_factor", -0.001, "", data),
        self.assertSensor("temperature", 10.7, "C", data)
        self.assertSensor("temperature_heatsink", None, "C", data)
        self.assertSensor("e_day", 0.4, "kWh", data)
        self.assertSensor("e_total", 6.8, "kWh", data)
        self.assertSensor("h_total", 7, "h", data)
        self.assertSensor("safety_country", 73, "", data)
        self.assertSensor("safety_country_label", "Australia Victoria", "", data)
        self.assertSensor("funbit", 2384, "", data)
        self.assertSensor("vbus", 393.9, "V", data)
        self.assertSensor("vnbus", 0, "V", data)
        self.assertSensor("derating_mode", 0, "", data)
        self.assertSensor("derating_mode_label", "", "", data)


class GW10K_MS_30_Test(DtMock):

    def __init__(self, methodName="runTest"):
        DtMock.__init__(self, methodName)
        self.mock_response(
            self._READ_DEVICE_VERSION_INFO, "GW10K-MS-30_device_info.hex"
        )
        self.mock_response(self._READ_RUNNING_DATA, "GW10K-MS-30_running_data.hex")
        self.mock_response(self._READ_METER_DATA, ILLEGAL_DATA_ADDRESS)

    def test_GW10K_MS_30_device_info(self):
        self.loop.run_until_complete(self.read_device_info())
        self.assertEqual(None, self.model_name)
        self.assertEqual("5010KMSC000W0000", self.serial_number)
        self.assertEqual(0, self.dsp1_version)
        self.assertEqual(0, self.dsp2_version)
        self.assertEqual(504, self.dsp_svn_version)
        self.assertEqual(2, self.arm_version)
        self.assertEqual(13, self.arm_svn_version)
        self.assertEqual("0.0.02", self.firmware)

    def test_GW10K_MS_30_runtime_data(self):
        self.loop.run_until_complete(self.read_device_info())
        data = self.loop.run_until_complete(self.read_runtime_data())
        self.assertEqual(38, len(data))

        self.assertSensor(
            "timestamp",
            datetime.strptime("2024-01-09 22:08:20", "%Y-%m-%d %H:%M:%S"),
            "",
            data,
        )
        self.assertSensor("vpv1", 0.0, "V", data)
        self.assertSensor("ipv1", 0.0, "A", data)
        self.assertSensor("ppv1", 0, "W", data)
        self.assertSensor("vpv2", 0.0, "V", data)
        self.assertSensor("ipv2", 0.0, "A", data)
        self.assertSensor("ppv2", 0, "W", data)
        self.assertSensor("vpv3", 0.0, "V", data)
        self.assertSensor("ipv3", 0.0, "A", data)
        self.assertSensor("ppv3", 0, "W", data)
        self.assertSensor("ppv", 0, "W", data)
        self.assertSensor("vline1", 0.0, "V", data)
        self.assertSensor("vgrid1", 236.2, "V", data)
        self.assertSensor("igrid1", 0.0, "A", data)
        self.assertSensor("fgrid1", 50.0, "Hz", data)
        self.assertSensor("pgrid1", 0, "W", data)
        self.assertSensor("total_inverter_power", 0, "W", data)
        self.assertSensor("work_mode", 0, "", data)
        self.assertSensor("work_mode_label", "Wait Mode", "", data)
        self.assertSensor("error_codes", 0, "", data)
        self.assertSensor("warning_code", 0, "", data)
        self.assertSensor("apparent_power", 0, "VA", data),
        self.assertSensor("reactive_power", 0, "var", data),
        self.assertSensor("total_input_power", 0, "W", data)
        self.assertSensor("power_factor", 0.0, "", data),
        self.assertSensor("temperature", 24.3, "C", data)
        self.assertSensor("temperature_heatsink", 0.0, "C", data)
        self.assertSensor("e_day", 71.8, "kWh", data)
        self.assertSensor("e_total", 3433.4, "kWh", data)
        self.assertSensor("h_total", 971, "h", data)
        self.assertSensor("safety_country", 9, "", data)
        self.assertSensor("safety_country_label", "Australia A", "", data)
        self.assertSensor("funbit", 0, "", data)
        self.assertSensor("vbus", 5.1, "V", data)
        self.assertSensor("vnbus", 0.0, "V", data)
        self.assertSensor("derating_mode", 0, "", data)
        self.assertSensor("derating_mode_label", "", "", data)


class GW10K_MS_TCP_Test(DtMock):

    def __init__(self, methodName="runTest"):
        DtMock.__init__(self, methodName, 502)
        self.mock_response(self._READ_RUNNING_DATA, "GW10K-MS-30_tcp_running_data.hex")
        self.mock_response(self._READ_METER_DATA, ILLEGAL_DATA_ADDRESS)

    def test_GW10K_MS_TCP_runtime_data(self):
        self.loop.run_until_complete(self.read_device_info())
        data = self.loop.run_until_complete(self.read_runtime_data())
        self.assertEqual(45, len(data))

        self.assertSensor(
            "timestamp",
            datetime.strptime("2024-06-02 09:07:17", "%Y-%m-%d %H:%M:%S"),
            "",
            data,
        )
        self.assertSensor("vpv1", 400.6, "V", data)
        self.assertSensor("ipv1", 6.9, "A", data)
        self.assertSensor("ppv1", 2764, "W", data)
        self.assertSensor("vpv2", 364.0, "V", data)
        self.assertSensor("ipv2", 3.6, "A", data)
        self.assertSensor("ppv2", 1310, "W", data)
        self.assertSensor("ppv", 6143, "W", data)
        self.assertSensor("vline1", 0, "V", data)
        self.assertSensor("vline2", 0, "V", data)
        self.assertSensor("vline3", 0, "V", data)
        self.assertSensor("vgrid1", 241.1, "V", data)
        self.assertSensor("vgrid2", 0, "V", data)
        self.assertSensor("vgrid3", 0, "V", data)
        self.assertSensor("igrid1", 24.7, "A", data)
        self.assertSensor("igrid2", 0, "A", data)
        self.assertSensor("igrid3", 0, "A", data)
        self.assertSensor("fgrid1", 49.98, "Hz", data)
        self.assertSensor("fgrid2", -0.01, "Hz", data)
        self.assertSensor("fgrid3", -0.01, "Hz", data)
        self.assertSensor("pgrid1", 5955, "W", data)
        self.assertSensor("pgrid2", 0, "W", data)
        self.assertSensor("pgrid3", 0, "W", data)
        self.assertSensor("total_inverter_power", 5914, "W", data)
        self.assertSensor("work_mode", 1, "", data)
        self.assertSensor("work_mode_label", "Normal", "", data)
        self.assertSensor("error_codes", 0, "", data)
        self.assertSensor("warning_code", 0, "", data)
        self.assertSensor("apparent_power", 5957, "VA", data)
        self.assertSensor("reactive_power", -6, "var", data)
        self.assertSensor("total_input_power", -1, "W", data)
        self.assertSensor("power_factor", 0.999, "", data),
        self.assertSensor("temperature", 36.0, "C", data)
        self.assertSensor("temperature_heatsink", None, "C", data)
        self.assertSensor("e_day", 4.3, "kWh", data)
        self.assertSensor("e_total", 998.2, "kWh", data)
        self.assertSensor("h_total", 246, "h", data)
        self.assertSensor("safety_country", 32, "", data)
        self.assertSensor("safety_country_label", "50Hz 230Vac Default", "", data)
        self.assertSensor("funbit", 0, "", data)
        self.assertSensor("vbus", 397.3, "V", data)
        self.assertSensor("vnbus", 0, "V", data)
        self.assertSensor("derating_mode", 0, "", data)
        self.assertSensor("derating_mode_label", "", "", data)


class GW20KAU_DT_Test(DtMock):

    def __init__(self, methodName="runTest"):
        DtMock.__init__(self, methodName)
        self.mock_response(self._READ_DEVICE_VERSION_INFO, "GW20KAU-DT_device_info.hex")
        self.mock_response(self._READ_RUNNING_DATA, "GW20KAU-DT_running_data.hex")
        self.mock_response(self._READ_METER_DATA, ILLEGAL_DATA_ADDRESS)

    def test_GW20KAU_DT_device_info(self):
        self.loop.run_until_complete(self.read_device_info())
        self.assertEqual("GW20KAU-DT", self.model_name)
        self.assertEqual("0000KDTA00000000", self.serial_number)
        self.assertEqual(15, self.dsp1_version)
        self.assertEqual(15, self.dsp2_version)
        self.assertEqual(1099, self.dsp_svn_version)
        self.assertEqual(16, self.arm_version)
        self.assertEqual(187, self.arm_svn_version)
        self.assertEqual("15.15.10", self.firmware)

    def test_GW20KAU_DT_runtime_data(self):
        self.loop.run_until_complete(self.read_device_info())
        data = self.loop.run_until_complete(self.read_runtime_data())
        self.assertEqual(45, len(data))

        self.assertSensor(
            "timestamp",
            datetime.strptime("2022-10-21 19:23:42", "%Y-%m-%d %H:%M:%S"),
            "",
            data,
        )
        self.assertSensor("vpv1", 390.5, "V", data)
        self.assertSensor("ipv1", 6.8, "A", data)
        self.assertSensor("ppv1", 2655, "W", data)
        self.assertSensor("vpv2", 351.6, "V", data)
        self.assertSensor("ipv2", 7.1, "A", data)
        self.assertSensor("ppv2", 2496, "W", data)
        self.assertSensor("ppv", 5151, "W", data)
        self.assertSensor("vline1", 388.5, "V", data)
        self.assertSensor("vline2", 391.7, "V", data)
        self.assertSensor("vline3", 394.5, "V", data)
        self.assertSensor("vgrid1", 226.1, "V", data)
        self.assertSensor("vgrid2", 223.6, "V", data)
        self.assertSensor("vgrid3", 228.3, "V", data)
        self.assertSensor("igrid1", 7.2, "A", data)
        self.assertSensor("igrid2", 7.4, "A", data)
        self.assertSensor("igrid3", 7.1, "A", data)
        self.assertSensor("fgrid1", 49.96, "Hz", data)
        self.assertSensor("fgrid2", 49.96, "Hz", data)
        self.assertSensor("fgrid3", 49.97, "Hz", data)
        self.assertSensor("pgrid1", 1628, "W", data)
        self.assertSensor("pgrid2", 1655, "W", data)
        self.assertSensor("pgrid3", 1621, "W", data)
        self.assertSensor("total_inverter_power", 4957, "W", data)
        self.assertSensor("work_mode", 1, "", data)
        self.assertSensor("work_mode_label", "Normal", "", data)
        self.assertSensor("error_codes", 0, "", data)
        self.assertSensor("warning_code", 0, "", data)
        self.assertSensor("apparent_power", 0, "VA", data),
        self.assertSensor("reactive_power", 205, "var", data),
        self.assertSensor("total_input_power", 0, "W", data)
        self.assertSensor("power_factor", 0.999, "", data),
        self.assertSensor("temperature", 36.4, "C", data)
        self.assertSensor("temperature_heatsink", None, "C", data)
        self.assertSensor("e_day", 19.8, "kWh", data)
        self.assertSensor("e_total", 4304.8, "kWh", data)
        self.assertSensor("h_total", 1139, "h", data)
        self.assertSensor("safety_country", 32, "", data)
        self.assertSensor("safety_country_label", "50Hz 230Vac Default", "", data)
        self.assertSensor("funbit", 0, "", data)
        self.assertSensor("vbus", 596.3, "V", data)
        self.assertSensor("vnbus", 298.9, "V", data)
        self.assertSensor("derating_mode", 4, "", data)
        self.assertSensor(
            "derating_mode_label", "Reactive power derating(PF/QU/FixQ)", "", data
        )


class GW17K_DT_Test(DtMock):

    def __init__(self, methodName="runTest"):
        DtMock.__init__(self, methodName)
        self.mock_response(self._READ_DEVICE_VERSION_INFO, "GW17K-DT_device_info.hex")
        self.mock_response(self._READ_RUNNING_DATA, "GW17K-DT_running_data.hex")
        self.mock_response(self._READ_METER_DATA, ILLEGAL_DATA_ADDRESS)

    def test_GW20KAU_DT_device_info(self):
        self.loop.run_until_complete(self.read_device_info())
        self.assertEqual("GW17KT-DT", self.model_name)
        self.assertEqual("5017KDTT00BW0000", self.serial_number)
        self.assertEqual(12, self.dsp1_version)
        self.assertEqual(12, self.dsp2_version)
        self.assertEqual(931, self.dsp_svn_version)
        self.assertEqual(13, self.arm_version)
        self.assertEqual(130, self.arm_svn_version)
        self.assertEqual("12.12.0d", self.firmware)

    def test_GW20KAU_DT_runtime_data(self):
        self.loop.run_until_complete(self.read_device_info())
        data = self.loop.run_until_complete(self.read_runtime_data())
        self.assertEqual(45, len(data))

        self.assertSensor(
            "timestamp",
            datetime.strptime("2024-05-20 10:35:55", "%Y-%m-%d %H:%M:%S"),
            "",
            data,
        )
        self.assertSensor("vpv1", 540.0, "V", data)
        self.assertSensor("ipv1", 10.5, "A", data)
        self.assertSensor("ppv1", 5670, "W", data)
        self.assertSensor("vpv2", 475.5, "V", data)
        self.assertSensor("ipv2", 14.8, "A", data)
        self.assertSensor("ppv2", 7037, "W", data)
        self.assertSensor("ppv", 12707, "W", data)
        self.assertSensor("vline1", 413.0, "V", data)
        self.assertSensor("vline2", 411.5, "V", data)
        self.assertSensor("vline3", 409.5, "V", data)
        self.assertSensor("vgrid1", 236.7, "V", data)
        self.assertSensor("vgrid2", 238.3, "V", data)
        self.assertSensor("vgrid3", 237.3, "V", data)
        self.assertSensor("igrid1", 17.6, "A", data)
        self.assertSensor("igrid2", 17.5, "A", data)
        self.assertSensor("igrid3", 17.5, "A", data)
        self.assertSensor("fgrid1", 50.02, "Hz", data)
        self.assertSensor("fgrid2", 50.02, "Hz", data)
        self.assertSensor("fgrid3", 50.02, "Hz", data)
        self.assertSensor("pgrid1", 4166, "W", data)
        self.assertSensor("pgrid2", 4170, "W", data)
        self.assertSensor("pgrid3", 4153, "W", data)
        self.assertSensor("total_inverter_power", 12470, "W", data)
        self.assertSensor("work_mode", 1, "", data)
        self.assertSensor("work_mode_label", "Normal", "", data)
        self.assertSensor("error_codes", 0, "", data)
        self.assertSensor("warning_code", 0, "", data)
        self.assertSensor("apparent_power", 0, "VA", data)
        self.assertSensor("reactive_power", 0, "var", data)
        self.assertSensor("total_input_power", 0, "W", data)
        self.assertSensor("power_factor", 0.0, "", data),
        self.assertSensor("temperature", 45.7, "C", data)
        self.assertSensor("temperature_heatsink", None, "C", data)
        self.assertSensor("e_day", 29.3, "kWh", data)
        self.assertSensor("e_total", 29984.4, "kWh", data)
        self.assertSensor("h_total", 8357, "h", data)
        self.assertSensor("safety_country", 1, "", data)
        self.assertSensor("safety_country_label", "CZ-A1", "", data)
        self.assertSensor("funbit", 546, "", data)
        self.assertSensor("vbus", 621.8, "V", data)
        self.assertSensor("vnbus", 314.2, "V", data)
        self.assertSensor("derating_mode", 4, "", data)
        self.assertSensor(
            "derating_mode_label", "Reactive power derating(PF/QU/FixQ)", "", data
        )


class GW50KS_MT_Test(DtMock):

    def __init__(self, methodName="runTest"):
        DtMock.__init__(self, methodName, 8899)
        self.mock_response(self._READ_DEVICE_VERSION_INFO, "GW50KS-MT_device_info.hex")
        self.mock_response(self._READ_RUNNING_DATA, "GW50KS-MT_running_data.hex")
        self.mock_response(self._READ_METER_DATA, ILLEGAL_DATA_ADDRESS)

    def test_GW50KS_MT_device_info(self):
        self.loop.run_until_complete(self.read_device_info())
        self.assertEqual("GW50KS-MT", self.model_name)
        self.assertEqual("5050KMTO233W0000", self.serial_number)
        self.assertEqual(4, self.dsp1_version)
        self.assertEqual(4, self.dsp2_version)
        self.assertEqual(168, self.dsp_svn_version)
        self.assertEqual(16, self.arm_version)
        self.assertEqual(345, self.arm_svn_version)
        self.assertEqual("4.4.10", self.firmware)

    def test_GW50KS_MT_runtime_data(self):
        self.loop.run_until_complete(self.read_device_info())
        data = self.loop.run_until_complete(self.read_runtime_data())
        self.assertEqual(51, len(data))

        for sensor in self.sensors():
            print(f"self.assertSensor('{sensor.id_}', {data[sensor.id_]}, '{self.sensor_map.get(sensor.id_).unit}', data)")

        self.assertSensor(
            "timestamp",
            datetime.strptime("2026-03-29 12:21:58", "%Y-%m-%d %H:%M:%S"),
            "",
            data,
        )

        self.assertSensor('vpv1', 708.0, 'V', data)
        self.assertSensor('ipv1', 16.4, 'A', data)
        self.assertSensor('ppv1', 11611, 'W', data)
        self.assertSensor('vpv2', 723.3, 'V', data)
        self.assertSensor('ipv2', 14.5, 'A', data)
        self.assertSensor('ppv2', 10488, 'W', data)
        self.assertSensor('vpv3', 740.2, 'V', data)
        self.assertSensor('ipv3', 17.9, 'A', data)
        self.assertSensor('ppv3', 13250, 'W', data)
        self.assertSensor('vpv4', 746.3, 'V', data)
        self.assertSensor('ipv4', 17.5, 'A', data)
        self.assertSensor('ppv4', 13060, 'W', data)
        self.assertSensor('ppv', 48409, 'W', data)
        self.assertSensor('vline1', 407.0, 'V', data)
        self.assertSensor('vline2', 405.2, 'V', data)
        self.assertSensor('vline3', 405.6, 'V', data)
        self.assertSensor('vgrid1', 235.0, 'V', data)
        self.assertSensor('vgrid2', 234.9, 'V', data)
        self.assertSensor('vgrid3', 232.9, 'V', data)
        self.assertSensor('igrid1', 80.6, 'A', data)
        self.assertSensor('igrid2', 80.7, 'A', data)
        self.assertSensor('igrid3', 80.6, 'A', data)
        self.assertSensor('fgrid1', 50.01, 'Hz', data)
        self.assertSensor('fgrid2', 50.02, 'Hz', data)
        self.assertSensor('fgrid3', 50.01, 'Hz', data)
        self.assertSensor('pgrid1', 18941, 'W', data)
        self.assertSensor('pgrid2', 18956, 'W', data)
        self.assertSensor('pgrid3', 18772, 'W', data)
        self.assertSensor('total_inverter_power', 47967, 'W', data)
        self.assertSensor('work_mode', 1, '', data)
        self.assertSensor('work_mode_label', "Normal", '', data)
        self.assertSensor('error_codes', 0, '', data)
        self.assertSensor('warning_code', 0, '', data)
        self.assertSensor('apparent_power', 56464, 'VA', data)
        self.assertSensor('reactive_power', -29840, 'var', data)
        self.assertSensor('total_input_power', 0, 'W', data)
        self.assertSensor('power_factor', 0.849, '', data)
        self.assertSensor('temperature', 34.2, 'C', data)
        self.assertSensor('temperature_heatsink', 37.7, 'C', data)
        self.assertSensor('e_day', 42.7, 'kWh', data)
        self.assertSensor('e_total', 8556.9, 'kWh', data)
        self.assertSensor('h_total', 1313, 'h', data)
        self.assertSensor('safety_country', 2, '', data)
        self.assertSensor('safety_country_label', "DE LV with PV", '', data)
        self.assertSensor('funbit', 66, '', data)
        self.assertSensor('vbus', 744.8, 'V', data)
        self.assertSensor('vnbus', 371.6, 'V', data)
        self.assertSensor('derating_mode', 256, '', data)
        self.assertSensor('derating_mode_label', "Maximum current derating", '', data)
        self.assertSensor('rssi', 37, '', data)

class GW20K_SDT_20_Test(DtMock):

    def __init__(self, methodName="runTest"):
        DtMock.__init__(self, methodName, 8899)
        self.mock_response(self._READ_DEVICE_VERSION_INFO, "GW20K-SDT-20_device_info.hex")
        self.mock_response(self._READ_RUNNING_DATA, "GW20K-SDT-20_running_data.hex")
        self.mock_response(self._READ_METER_DATA, ILLEGAL_DATA_ADDRESS)

    def test_GW20K_SDT_20_device_info(self):
        self.loop.run_until_complete(self.read_device_info())
        self.assertEqual("5020KDTB233W0000", self.serial_number)
        self.assertEqual(17, self.dsp1_version)
        self.assertEqual(17, self.dsp2_version)
        self.assertEqual(1156, self.dsp_svn_version)
        self.assertEqual(18, self.arm_version)
        self.assertEqual(246, self.arm_svn_version)
        self.assertEqual("17.17.12", self.firmware)


    def test_GW20K_SDT_20_runtime_data(self):
        self.loop.run_until_complete(self.read_device_info())
        data = self.loop.run_until_complete(self.read_runtime_data())
        self.assertEqual(51, len(data))

        self.assertSensor(
            "timestamp",
            datetime.strptime("2026-03-26 08:48:30", "%Y-%m-%d %H:%M:%S"),
            "",
            data,
        )
        self.assertSensor("vpv1", 677.1, "V", data)
        self.assertSensor("ipv1", 2.0, "A", data)
        self.assertSensor("ppv1", 1354, "W", data)
        self.assertSensor("vpv2", 688.8, "V", data)
        self.assertSensor("ipv2", 1.9, "A", data)
        self.assertSensor("ppv2", 1309, "W", data)
        self.assertSensor("vpv3", 711.3, "V", data)
        self.assertSensor("ipv3", 2.0, "A", data)
        self.assertSensor("ppv3", 1423, "W", data)
        self.assertSensor("vpv4", 728.7, "V", data)
        self.assertSensor("ipv4", 2.1, "A", data)
        self.assertSensor("ppv4", 1530, "W", data)
        self.assertSensor("ppv", 5616, "W", data)
        self.assertSensor("vline1", 402.6, "V", data)
        self.assertSensor("vline2", 402.6, "V", data)
        self.assertSensor("vline3", 402.4, "V", data)
        self.assertSensor("vgrid1", 232.4, "V", data)
        self.assertSensor("vgrid2", 233.3, "V", data)
        self.assertSensor("vgrid3", 231.4, "V", data)
        self.assertSensor("igrid1", 8.5, "A", data)
        self.assertSensor("igrid2", 8.7, "A", data)
        self.assertSensor("igrid3", 8.6, "A", data)
        self.assertSensor("fgrid1", 49.98, "Hz", data)
        self.assertSensor("fgrid2", 49.97, "Hz", data)
        self.assertSensor("fgrid3", 49.98, "Hz", data)
        self.assertSensor("pgrid1", 1975, "W", data)
        self.assertSensor("pgrid2", 2030, "W", data)
        self.assertSensor("pgrid3", 1990, "W", data)
        self.assertSensor("total_inverter_power", 4461, "W", data)
        self.assertSensor("work_mode", 1, "", data)
        self.assertSensor("work_mode_label", "Normal", "", data)
        self.assertSensor("error_codes", 0, "", data)
        self.assertSensor("warning_code", 0, "", data)
        self.assertSensor("apparent_power", 5840, "VA", data)
        self.assertSensor("reactive_power", -3793, "var", data)
        self.assertSensor("total_input_power", 0, "W", data)
        self.assertSensor("power_factor", 0.763, "", data)
        self.assertSensor("temperature", 34.3, "C", data)
        self.assertSensor("temperature_heatsink", 35.3, "C", data)
        self.assertSensor("e_day", 4.1, "kWh", data)
        self.assertSensor("e_total", 8096.4, "kWh", data)
        self.assertSensor("h_total", 1271, "h", data)
        self.assertSensor("safety_country", 2, "", data)
        self.assertSensor("safety_country_label", "DE LV with PV", "", data)
        self.assertSensor("funbit", 66, "", data)
        self.assertSensor("vbus", 727.9, "V", data)
        self.assertSensor("vnbus", 367.8, "V", data)
        self.assertSensor("derating_mode", 0, "", data)
        self.assertSensor("derating_mode_label", "", "", data)
        self.assertSensor("rssi", 35, "", data)
