### Login usage example Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-base.md Example of calling the login method with installer credentials. ```python await device.login("installer", "00000a") ``` -------------------------------- ### login Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-base.md Performs the installer login sequence. Acquires locks, calls client.login, and starts the heartbeat on success. Raises InvalidCredentials if credentials are rejected. ```APIDOC ## login ### Description Performs the installer login sequence. Acquires update_lock and login_lock, calls client.login, and starts the heartbeat on success. Raises InvalidCredentials if the device rejects the credentials. ### Method async def login(self, username: str, password: str) -> bool ### Parameters - **username** (str) - Required - The installer username. - **password** (str) - Required - The installer password. ### Returns - **bool** - Always True on success. ### Errors - **InvalidCredentials** - Raised when the device rejects the credentials. ### Example ```python await device.login("installer", "00000a") ``` ### Error Handling Example ```python try: await device.login(username, password) except InvalidCredentials: print("Bad credentials for installer login") ``` ``` -------------------------------- ### Usage example: read and write TOU schedule Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-periods.md Shows how to create a client and device, login, read the current TOU schedule, and write a new schedule. The example includes a placeholder comment for merging and validating periods. ```python from huawei_solar import create_device_instance, create_tcp_client from huawei_solar import register_names as rn from huawei_solar.register_definitions import ( HUAWEI_LUNA2000_TimeOfUsePeriod, HUAWEI_LUNA2000_TimeOfUseRegisters, ChargeFlag, ) client = create_tcp_client(host="192.168.1.1") device = await create_device_instance(client) await device.login("installer", "00000a") # Read the current TOU schedule result = await device.get(rn.STORAGE_HUAWEI_LUNA2000_TIME_OF_USE_CHARGING_AND_DISCHARGING_PERIODS) periods: list[HUAWEI_LUNA2000_TimeOfUsePeriod] = result.value print(periods[0].start_time, periods[0].charge_flag) # Write a schedule: charge 02:00-04:00 every day new_periods = [ HUAWEI_LUNA2000_TimeOfUsePeriod( start_time=120, end_time=240, charge_flag=ChargeFlag.CHARGE, days_effective=(True, True, True, True, True, True, True), ), ] result = await device.get(rn.STORAGE_HUAWEI_LUNA2000_TIME_OF_USE_CHARGING_AND_DISCHARGING_PERIODS) current: list[HUAWEI_LUNA2000_TimeOfUsePeriod] = result.value # merge and validate ... ``` -------------------------------- ### get_file usage example Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/modbus-client.md Example call to get_file to read the Optimizer System Information file (0x45). ```python file_data = await client.get_file(0x45) # Optimizer System Information file ``` -------------------------------- ### login method signature Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-base.md Performs the installer login sequence. Acquires update_lock and login_lock, calls client.login, and raises InvalidCredentials on rejection. Returns True on success and starts the heartbeat. ```python async def login(self, username: str, password: str) -> bool: ``` -------------------------------- ### Using detect_device_type Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-factories.md Example of creating a TCP client and calling detect_device_type to get the device class and model name. ```python from huawei_solar.device import detect_device_type client = create_tcp_client(host="192.168.1.1") device_class, model_name = await detect_device_type(client) print(device_class.__name__, model_name) ``` -------------------------------- ### Usage example for device discovery Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-discovery.md Shows how to create a TCP client and use get_device_identifiers and get_device_infos to retrieve device information. ```python from huawei_solar import create_tcp_client, get_device_identifiers, get_device_infos client = create_tcp_client(host="192.168.1.1") identifiers = await get_device_identifiers(client) print(identifiers.vendor, identifiers.product_code, identifiers.main_revision_version) for info in await get_device_infos(client): print(info.model, info.esn, info.software_version) ``` -------------------------------- ### Example usage of get_optimizer_system_information_data Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-subclasses.md Example that calls get_optimizer_system_information_data and prints each optimizer's address, online status, model, and serial number. ```python optimizers = await device.get_optimizer_system_information_data() for address, info in optimizers.items(): print(address, info.online_status, info.model, info.sn) ``` -------------------------------- ### Error handling example for device discovery Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-discovery.md Shows how to handle ReadException and ConnectionInterruptedException when calling get_device_infos. ```python try: infos = await get_device_infos(client) except ReadException as err: print("Device identification failed, modbus code:", err.modbus_exception_code) except ConnectionInterruptedException: print("Connection lost during identification") ``` -------------------------------- ### Usage example for create_sub_device_instance Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-factories.md Shows how to create a sub-device instance for a battery with unit_id=1. Raises the same detection errors as create_device_instance. ```python battery = await create_sub_device_instance(device, unit_id=1) ``` -------------------------------- ### stop usage example Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-base.md Example of stopping the device. ```python await device.stop() ``` -------------------------------- ### set usage example Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-base.md Example of setting the active power fixed value derating to 500 W to limit export. ```python await device.set(rn.ACTIVE_POWER_FIXED_VALUE_DERATING, 500) # limit export to 500 W ``` -------------------------------- ### Usage Example: Defining and Using a Custom Register Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-definitions.md Example showing how to define a U16Register with a unit and gain, decode raw values, and encode values for writing. ```APIDOC ## Usage Example: Defining and Using a Custom Register ### Description Demonstrates defining a U16Register with unit 'W' and gain 10, decoding a raw value, and encoding a value for writing. ### Code ```python from huawei_solar.register_definitions import U16Register, Result # A register with unit 'W' and gain 10: raw value 1234 decodes to 123.4 reg = U16Register("W", 10, 31000) decoded: Result[int | None] = reg.decode((1234,)) print(decoded) # Result(value=123.4, unit='W') # Encoding back for writing print(reg.encode(123.4)) # (1234,) ``` ``` -------------------------------- ### Usage example for create_device_instance Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-factories.md Shows how to create a TCP client and then call create_device_instance to obtain a device instance. Prints the device type name, serial number, and model name. ```python from huawei_solar import create_device_instance, create_tcp_client client = create_tcp_client(host="192.168.1.1", port=503) device = await create_device_instance(client) print(type(device).__name__, device.serial_number, device.model_name) ``` -------------------------------- ### Connect and retrieve optimizer data with huawei-solar-lib Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/files.md Shows how to create a device instance, log in, and use high-level helpers to get optimizer history and system information. Also demonstrates manual parsing of a raw data file using the low-level API. ```python from huawei_solar import SUN2000Device, create_device_instance, create_tcp_client device = await create_device_instance(create_tcp_client(host="192.168.1.1")) assert isinstance(device, SUN2000Device) await device.login("installer", "00000a") # High-level helpers (see device-subclasses.md) latest = await device.get_latest_optimizer_history_data() for addr, opt in latest.items(): print(addr, opt.output_power, opt.alarm, opt.running_status) system_info = await device.get_optimizer_system_information_data() for addr, info in system_info.items(): print(addr, info.online_status, info.model, info.sn) # Manual parsing with the low-level API raw = await device.read_file(0x44, OptimizerRealTimeDataFile.query_within_timespan(0, 0)) parsed = OptimizerRealTimeDataFile(raw) print(parsed.data_units[0].time, len(parsed.data_units[0].optimizers)) ``` -------------------------------- ### Sub-device creation example Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-subclasses.md Shows how to create a sub-device (e.g., battery or meter) behind a SmartLogger using create_sub_device_instance. Raises ValueError if unit_id equals the primary device's unit_id. ```python battery = await create_sub_device_instance(device, unit_id=1) print(battery.model_name) ``` -------------------------------- ### batch_update usage example Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-base.md Example of calling batch_update with two register names and the resulting dictionary. ```python result = await device.batch_update([rn.INPUT_POWER, rn.LINE_VOLTAGE_A_B]) # result: {'input_power': Result(value=82, unit='W'), 'line_voltage_A_B': Result(value=233.4, unit='V')} ``` -------------------------------- ### Combine create_device_instance and create_sub_device_instance Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-factories.md Use this snippet to create a TCP client, then a device instance for the SmartLogger at unit 0, and a sub-device instance for the meter at unit 1. The example prints the model name and serial number of the two devices. ```python import asyncio from huawei_solar import create_device_instance, create_sub_device_instance, create_tcp_client async def main() -> None: client = create_tcp_client(host="192.168.1.1", port=503) meter = await create_device_instance(client) # SmartLogger at unit 0 sub_meter = await create_sub_device_instance(meter, unit_id=1) # meter at unit 1 print(meter.model_name, sub_meter.serial_number) asyncio.run(main()) ``` -------------------------------- ### Recommended catch strategy in consumer code Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/errors.md Python example showing how to catch and handle various exceptions thrown by the huawei-solar library during login, batch_update, and set operations. ```APIDOC ## Recommended catch strategy in consumer code ### Description This code snippet demonstrates the recommended way to catch and handle exceptions when using the huawei-solar library. It shows how to handle invalid credentials, read/write failures, connection interruptions, and any other library errors. ### Code ```python from huawei_solar import ( ConnectionInterruptedException, DecodeError, HuaweiSolarException, InvalidCredentials, ReadException, WriteException, ) try: await device.login("installer", "00000a") values = await device.batch_update([rn.ACTIVE_POWER]) await device.set(rn.ACTIVE_POWER_FIXED_VALUE_DERATING, 500) except InvalidCredentials: print("Wrong installer credentials") except (ReadException, DecodeError) as err: print("Read failed, modbus exception code:", getattr(err, "modbus_exception_code", None)) except WriteException as err: print("Write failed, modbus exception code:", getattr(err, "modbus_exception_code", None)) except ConnectionInterruptedException: print("Connection dropped — reconnect and retry") except HuaweiSolarException: print("Any other library error") ``` ### Exceptions Handled - **InvalidCredentials**: Raised when the installer credentials are incorrect. - **ReadException**: Raised when a read operation fails. Contains `modbus_exception_code` attribute. - **DecodeError**: Raised when decoding of a response fails. Contains `modbus_exception_code` attribute. - **WriteException**: Raised when a write operation fails. Contains `modbus_exception_code` attribute. - **ConnectionInterruptedException**: Raised when the connection is dropped during an operation. - **HuaweiSolarException**: Base exception for any other library error. ### Related Documentation Detailed error documentation is available in the context of each API page: - `device-base.md` - `modbus-client.md` - `register-client.md` - `register-periods.md` - `files.md` - `device-discovery.md` ``` -------------------------------- ### Usage example: Read and write TOU schedules Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-periods.md Demonstrates how to read the current time-of-use schedule and write a new schedule using the device API. Includes error handling for invalid schedules. ```APIDOC ## Usage example ### Description Example of reading and writing time-of-use (TOU) schedules on a Huawei Luna2000 device. ### Prerequisites - Import required modules: `create_device_instance`, `create_tcp_client`, `register_names`, `HUAWEI_LUNA2000_TimeOfUsePeriod`, `HUAWEI_LUNA2000_TimeOfUseRegisters`, `ChargeFlag`. ### Steps 1. Create a TCP client and device instance. 2. Login with installer credentials. 3. Read the current TOU schedule using `device.get(rn.STORAGE_HUAWEI_LUNA2000_TIME_OF_USE_CHARGING_AND_DISCHARGING_PERIODS)`. 4. Write a new schedule by setting a list of `HUAWEI_LUNA2000_TimeOfUsePeriod` objects. ### Error Handling - `TimeOfUsePeriodsException` - raised for invalid schedules. - `EncodeError` - raised for encoding issues. - `PeakPeriodsValidationError` - raised for peak period validation failures. ### Example Code ```python from huawei_solar import create_device_instance, create_tcp_client from huawei_solar import register_names as rn from huawei_solar.register_definitions import ( HUAWEI_LUNA2000_TimeOfUsePeriod, HUAWEI_LUNA2000_TimeOfUseRegisters, ChargeFlag, ) client = create_tcp_client(host="192.168.1.1") device = await create_device_instance(client) await device.login("installer", "00000a") # Read the current TOU schedule result = await device.get(rn.STORAGE_HUAWEI_LUNA2000_TIME_OF_USE_CHARGING_AND_DISCHARGING_PERIODS) periods: list[HUAWEI_LUNA2000_TimeOfUsePeriod] = result.value print(periods[0].start_time, periods[0].charge_flag) # Write a schedule: charge 02:00-04:00 every day new_periods = [ HUAWEI_LUNA2000_TimeOfUsePeriod( start_time=120, end_time=240, charge_flag=ChargeFlag.CHARGE, days_effective=(True, True, True, True, True, True, True), ), ] result = await device.get(rn.STORAGE_HUAWEI_LUNA2000_TIME_OF_USE_CHARGING_AND_DISCHARGING_PERIODS) current: list[HUAWEI_LUNA2000_TimeOfUsePeriod] = result.value # merge and validate ... ``` ### Error Handling Example ```python try: await device.set(rn.STORAGE_LG_RESU_TIME_OF_USE_PRICE_PERIODS, overlapping_periods) except TimeOfUsePeriodsException as err: print("Invalid schedule:", err) ``` ``` -------------------------------- ### Usage example: batch_update and set Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-names.md Shows how to create a client and device, perform a batch_update to read multiple registers, print a value and unit, and set a register value. Note that set on an unknown name raises ValueError("Invalid Register Name"). ```python from huawei_solar import create_device_instance, create_tcp_client from huawei_solar import register_names as rn client = create_tcp_client(host="192.168.1.1") device = await create_device_instance(client) values = await device.batch_update([ rn.INPUT_POWER, rn.ACTIVE_POWER, rn.ACCUMULATED_YIELD_ENERGY, rn.DEVICE_STATUS, ]) print(values[rn.ACTIVE_POWER].value, values[rn.ACTIVE_POWER].unit) await device.set(rn.ACTIVE_POWER_FIXED_VALUE_DERATING, 500) ``` -------------------------------- ### HuaweiSolarDevice.get(name) / .set(name, value) Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/types.md Gets or sets a single register value on a device instance. ```APIDOC ## HuaweiSolarDevice.get(name) / .set(name, value) ### Description Gets or sets a single register value on a device instance. ### Method GET / SET ### Parameters - **name** (RegisterName) - Required - The register name. - **value** (Any) - Required for set - The value to set. ### Return Type Result[Any] for get, bool for set ``` -------------------------------- ### Usage example: defining and using a custom register Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-definitions.md Shows how to create a U16Register with unit 'W' and gain 10, decode a raw value, and encode back for writing. ```python from huawei_solar.register_definitions import U16Register, Result # A register with unit 'W' and gain 10: raw value 1234 decodes to 123.4 reg = U16Register("W", 10, 31000) decoded: Result[int | None] = reg.decode((1234,)) print(decoded) # Result(value=123.4, unit='W') # Encoding back for writing print(reg.encode(123.4)) # (1234,) ``` -------------------------------- ### Read and write registers with huawei-solar client Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-client.md Shows how to create a TCP client, read a single register, read multiple registers in one request, get values as a dict, and write a register. The get_multiple method requires registers to be close together. ```python from huawei_solar import create_tcp_client from huawei_solar import register_names as rn client = create_tcp_client(host="192.168.1.1") # single register result = await client.get(rn.INPUT_POWER) # multiple registers in one request (must be close together) values = await client.get_multiple([rn.INPUT_POWER, rn.ACTIVE_POWER]) # as dict values_dict = await client.get_multiple_as_dict([rn.INPUT_POWER, rn.ACTIVE_POWER]) print(values_dict[rn.INPUT_POWER].value) # write a register ok = await client.set(rn.ACTIVE_POWER_FIXED_VALUE_DERATING, 500) print(ok) ``` -------------------------------- ### login method definition Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/modbus-client.md Logs into the inverter by sending challenge and login PDUs. Installs a re-login handler on reconnection. ```python async def login(self, username: str, password: str) -> bool: """Login onto the inverter.""" ``` -------------------------------- ### SUN2000Device.supports_device classmethod Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-subclasses.md Checks if the SUN2000Device class supports a given device model name. Returns True if the model name starts with any of the listed prefixes. ```python @classmethod def supports_device(cls, model_name: str) -> bool: """Check if this class support the given device.""" return model_name.startswith( ( "SUN", "EDF ESS", "Powershifter", "SWI300", ), ) ``` -------------------------------- ### Create TCP client, login, read register, and disconnect Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/modbus-client.md Connects to a Huawei inverter over Modbus TCP, logs in with installer credentials, performs a heartbeat, reads the INPUT_POWER register, prints the result, and disconnects. Requires the huawei_solar library and an accessible device at the specified host and port. ```python from huawei_solar import create_tcp_client from huawei_solar import register_names as rn client = create_tcp_client(host="192.168.1.1", port=502, unit_id=0, timeout=10) await client.login("installer", "00000a") heartbeat_ok = await client.heartbeat() result = await client.get(rn.INPUT_POWER) print(result) # Result(value=82, unit='W') await client.disconnect() ``` -------------------------------- ### StringRegister.__init__ Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-definitions.md Constructor for the StringRegister class. Creates a string register definition with a starting register address, length in registers, and optional flags for writeability, readability, and target device. ```APIDOC ## StringRegister.__init__ ### Description Creates a StringRegister instance representing a UTF-8 string spanning multiple registers. ### Method Constructor ### Signature ```python def __init__( self, register: int, length: int, *, writeable: bool = False, readable: bool = True, target_device: TargetDevice = TargetDevice.SUN2000, ) -> None ``` ### Parameters - **register** (int) - Required - Starting register address. - **length** (int) - Required - Number of registers the string spans. - **writeable** (bool) - Optional - Whether the register is writeable. Defaults to False. - **readable** (bool) - Optional - Whether the register is readable. Defaults to True. - **target_device** (TargetDevice) - Optional - Target device type. Defaults to TargetDevice.SUN2000. ### Attributes - **length** (int) - Number of registers. - **format** (str) - Format string for struct packing, e.g., f"{length * 2}s" (every register has two bytes). ``` -------------------------------- ### SDongleDevice.supports_device class method Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-subclasses.md Class method that checks if a model name starts with 'SDongle' to determine if the device is an SDongle device. ```python @classmethod def supports_device(cls, model_name: str) -> bool: return model_name.startswith("SDongle") ``` -------------------------------- ### Read inverter registers with SUN2000Device Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/README.md Example of using the high-level Devices interface to create a TCP client, create a device instance, and batch read registers. The output shows the printed result with values and units. ```python import asyncio from huawei_solar import ( SUN2000Device, create_device_instance, create_tcp_client, ) from huawei_solar import register_names as rn async def test() -> None: """Run test.""" client = create_tcp_client(host="192.168.1.1", port=503) device = await create_device_instance(client) assert isinstance(device, SUN2000Device) print( await device.batch_update( [ rn.INPUT_POWER, rn.LINE_VOLTAGE_A_B, rn.LINE_VOLTAGE_B_C, rn.LINE_VOLTAGE_C_A, ] ), ) if __name__ == "__main__": asyncio.run(main()) ``` ```text {'input_power': Result(value=82, unit='W'), 'line_voltage_A_B': Result(value=233.4, unit='V'), 'line_voltage_B_C': Result(value=0.0, unit='V'), 'line_voltage_C_A': Result(value=0.0, unit='V')} ``` -------------------------------- ### Register definition styles in REGISTERS Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/registers-catalog.md Shows how registers are defined in the REGISTERS dict using definition classes. Includes examples for string, numeric, status, timestamp, and bitfield registers. Notable addresses covered by the base (SUN2000) section are listed. ```python rn.MODEL_NAME: StringRegister(30000, 15, target_device=TargetDevice.SUN2000 | TargetDevice.EMMA | TargetDevice.SCHARGER | TargetDevice.SDONGLE | TargetDevice.SMARTLOGGER), rn.SERIAL_NUMBER: StringRegister(30015, 10, target_device=TargetDevice.SUN2000 | TargetDevice.EMMA | TargetDevice.SDONGLE | TargetDevice.SMARTLOGGER), rn.INPUT_POWER: I32Register("W", 1, 32064), rn.GRID_VOLTAGE: U16Register("V", 10, 32066), rn.GRID_CURRENT: I32Register("A", 1000, 32072), rn.DEVICE_STATUS: U16Register(rv.DEVICE_STATUS_DEFINITIONS, 1, 32089), rn.STARTUP_TIME: TimestampRegister(32091), rn.ALARM_1: U16Register(partial(bitfield_decoder, rv.ALARM_CODES_1), 1, 32008, ignore_invalid=True), ``` -------------------------------- ### Common device usage pattern Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-subclasses.md Shows how to create a TCP client, create a device instance, login, batch update registers, check power meter status, and stop the device. ```python client = create_tcp_client(host="192.168.1.1", port=503) device = await create_device_instance(client) assert isinstance(device, SUN2000Device) await device.login("installer", "00000a") values = await device.batch_update([rn.ACTIVE_POWER, rn.ACCUMULATED_YIELD_ENERGY]) if device.power_meter_online: print("meter type:", device.power_meter_type) await device.stop() ``` -------------------------------- ### batch_update error handling example Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-base.md Example of catching ReadException when calling batch_update and printing the modbus exception code. ```python try: result = await device.batch_update([rn.ACTIVE_POWER, rn.METER_STATUS]) except ReadException as exc: print(f"Read failed with modbus exception code {exc.modbus_exception_code}") ``` -------------------------------- ### Register name constant examples Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-names.md Examples of register-name constants following the naming convention: UPPER_SNAKE_CASE identifiers with snake_case string values. ```python MODEL_NAME = RegisterName("model_name") SERIAL_NUMBER = RegisterName("serial_number") INPUT_POWER = RegisterName("input_power") LINE_VOLTAGE_A_B = RegisterName("line_voltage_A_B") STORAGE_CAPACITY_CONTROL_MODE = RegisterName("storage_capacity_control_mode") EMMA_LOCAL_TIME = RegisterName("emma_local_time") ``` -------------------------------- ### create_device_instance(client) Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/types.md Creates a device instance from an AsyncHuaweiSolarClient. ```APIDOC ## create_device_instance(client) ### Description Creates a device instance from an AsyncHuaweiSolarClient. ### Method CREATE ### Parameters - **client** (AsyncHuaweiSolarClient) - Required - The client to use. ### Return Type HuaweiSolarDevice ``` -------------------------------- ### get method signature Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-client.md Signature of the `get` method that reads a single named register. Returns a `Result[Any]` containing `.value` and `.unit`. Raises `ValueError` for unknown names and `ReadException`/`ConnectionInterruptedException` on failures. ```python async def get(self, name: rn.RegisterName) -> "Result[Any]": """Get named register from device.""" ``` -------------------------------- ### HuaweiSolarDevice.create Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-base.md Class method to instantiate a HuaweiSolarDevice. It is the recommended way to create a device instance, as the constructor should not be used directly. ```APIDOC ## create (classmethod) ### Description Instantiates the class and calls `_populate_additional_fields()`. Returns the populated device. This is used internally by `create_device_instance` / `create_sub_device_instance`. ### Method create ### Signature ```python @classmethod async def create( cls, client: "AsyncHuaweiSolarClient", *, model_name: str, primary_device: "HuaweiSolarDevice | None" = None, ) -> Self: ``` ### Parameters - **client** (AsyncHuaweiSolarClient) - Required - Low-level Modbus client - **model_name** (str) - Required - Device model string - **primary_device** (HuaweiSolarDevice | None) - Optional - Parent device when creating a sub-device ### Returns - **Self** - The populated device instance ``` -------------------------------- ### Handling DeviceDetectionError Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-factories.md Example of catching DeviceDetectionError when detection fails. ```python try: device_class, model_name = await detect_device_type(client) except DeviceDetectionError as err: print("Could not identify the device:", err) ``` -------------------------------- ### Constructor Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-base.md Initializes a HuaweiSolarDeviceWithLogin instance with the given client and model name, plus optional primary device. Sets up internal locks and heartbeat state. ```APIDOC ## Constructor ### Description Initializes a HuaweiSolarDeviceWithLogin instance. ### Signature ```python def __init__( self, client: "AsyncHuaweiSolarClient", model_name: str, *, primary_device: "HuaweiSolarDevice | None" = None, ) -> None: ``` ### Parameters - **client** (AsyncHuaweiSolarClient) - Required - The client used for communication. - **model_name** (str) - Required - The model name of the device. - **primary_device** (HuaweiSolarDevice | None) - Optional - The primary device, if any. ### Returns None ``` -------------------------------- ### SChargerDevice.supports_device classmethod Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-subclasses.md Checks if a model name starts with 'FusionCharge' to identify SCharger devices. ```python @classmethod def supports_device(cls, model_name: str) -> bool: return model_name.startswith("FusionCharge") ``` -------------------------------- ### EMMADevice.supports_device classmethod Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-subclasses.md Checks if a model name starts with 'SmartHEMS' to identify EMMA devices. ```python @classmethod def supports_device(cls, model_name: str) -> bool: return model_name.startswith("SmartHEMS") ``` -------------------------------- ### Import HuaweiSolarDevice and HuaweiSolarDeviceWithLogin Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-base.md Import the two abstract base classes from the huawei_solar package. ```python from huawei_solar import HuaweiSolarDevice, HuaweiSolarDeviceWithLogin ``` -------------------------------- ### ChargeDischargePeriod dataclass Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-periods.md Defines a charge or discharge period with start time, end time, and power in watts. ```APIDOC ## ChargeDischargePeriod ### Description Represents a charge or discharge period. ### Fields - **start_time** (int) - Minutes since midnight. - **end_time** (int) - Minutes since midnight. - **power** (int) - Power in watts. ### Example ```python @dataclass(frozen=True, slots=True) class ChargeDischargePeriod: """Charge or Discharge Period.""" start_time: int # minutes since midnight end_time: int # minutes since midnight power: int # power in watts ``` ``` -------------------------------- ### Import AsyncHuaweiSolarClient and client factories Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/modbus-client.md Import the main client class and the factory functions for creating TCP, RTU, and scanning clients. ```python from huawei_solar import AsyncHuaweiSolarClient, create_tcp_client, create_rtu_client from huawei_solar.modbus_client import create_client, create_scan_client, create_scan_tcp_client, create_scan_rtu_client ``` -------------------------------- ### MeterDevice.supports_device classmethod Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-subclasses.md Checks if a model name starts with 'PowerMeter' or 'Meter' to identify power meter devices. ```python @classmethod def supports_device(cls, model_name: str) -> bool: return model_name.startswith(("PowerMeter", "Meter")) ``` -------------------------------- ### Import path for device discovery functions Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-discovery.md Import the necessary classes and functions for device discovery. ```python from huawei_solar import DeviceIdentifier, DeviceInfo, get_device_identifiers, get_device_infos ``` -------------------------------- ### RegisterDefinition.__init__ Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-definitions.md Create a RegisterDefinition instance. The constructor initializes the register address and optional flags for writeability, readability, and target device. ```APIDOC ## RegisterDefinition.__init__ ### Description Create a RegisterDefinition instance. The constructor initializes the register address and optional flags for writeability, readability, and target device. ### Method Constructor ### Signature ```python def __init__( self, register: int, *, writeable: bool = False, readable: bool = True, target_device: TargetDevice = TargetDevice.SUN2000, ) -> None: ``` ### Parameters - `register` (int) - Required - First Modbus register address - `writeable` (bool) - Optional - Whether `set` is allowed (default: `False`) - `readable` (bool) - Optional - Whether reads are allowed (default: `True`) - `target_device` (TargetDevice) - Optional - Device family mask (default: `TargetDevice.SUN2000`) ### Notes - `__post_init__` asserts `struct.calcsize(f">{self.format}") == self.length * 2`. ``` -------------------------------- ### PeakSettingPeriod dataclass Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-periods.md Defines a peak setting period with start time, end time, power, and days effective. ```APIDOC ## PeakSettingPeriod ### Description Represents a peak setting period. ### Fields - **start_time** (int) - Minutes since midnight. - **end_time** (int) - Minutes since midnight. - **power** (int) - Power in watts. - **days_effective** (tuple[bool, bool, bool, bool, bool, bool, bool]) - Valid on days Sunday to Saturday. ### Example ```python @dataclass(frozen=True, slots=True) class PeakSettingPeriod: """Peak Setting Period.""" start_time: int # minutes since midnight end_time: int # minutes since midnight power: int # power in watts days_effective: tuple[ bool, bool, bool, bool, bool, bool, bool, ] # Valid on days Sunday to ``` ``` -------------------------------- ### start_heartbeat Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-base.md Starts the background task that keeps the session alive. Raises RuntimeError if called outside the login lock. ```APIDOC ## start_heartbeat ### Description Starts the background task that keeps the session alive. The task loops while heartbeat is enabled, acquiring update_lock, calling client.heartbeat(), and sleeping HEARTBEAT_INTERVAL (15 seconds). ### Method def start_heartbeat(self) -> None ### Returns None ### Errors - **RuntimeError** - Raised when invoked outside the login_lock. ``` -------------------------------- ### SmartLoggerDevice.supports_device class method Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-subclasses.md Class method that checks if a model name starts with 'SmartLogger' to determine if the device is a SmartLogger device. ```python @classmethod def supports_device(cls, model_name: str) -> bool: return model_name.startswith("SmartLogger") ``` -------------------------------- ### Import RegisterAwareModbusClient and AsyncHuaweiSolarClient Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-client.md Shows the import path for the main client class and the direct import for RegisterAwareModbusClient. Use the first import for normal usage through AsyncHuaweiSolarClient. ```python from huawei_solar.modbus_client import AsyncHuaweiSolarClient # or directly: from huawei_solar.register_client import RegisterAwareModbusClient ``` -------------------------------- ### get method signature Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-base.md Reads a single named register. Acquires update_lock, then delegates to _raw_get, which must only be called while holding the lock. ```python async def get(self, name: rn.RegisterName) -> "Result[Any]": ``` -------------------------------- ### OptimizerRealTimeDataFile.__init__ Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/files.md Constructor that parses raw file data (bytes) into a list of OptimizerHistoryRealTimeDataUnit objects. The file data is expected to be the result of read_file(0x44, ...). ```APIDOC ## OptimizerRealTimeDataFile.__init__ ### Description Creates an OptimizerRealTimeDataFile instance from the byte representation of a real-time data file (file type 0x44). Parses the file into `self.data_units`, a list of `OptimizerHistoryRealTimeDataUnit` objects. An empty file (shorter than the header) results in an empty list. ### Method Constructor ### Signature ```python def __init__(self, file_data: bytes) -> None: ``` ### Parameters - **file_data** (bytes) - Required - The raw byte data of the file, typically obtained from `read_file(0x44, ...)`. ### Returns None (initializes the instance) ### Attributes - **data_units** (list[OptimizerHistoryRealTimeDataUnit]) - Parsed data units, each containing a timestamp and a list of optimizer data. ### Exceptions - **DecodeError** - Raised if the file contents are corrupted (struct.error). ### Notes - Raw integer values are scaled: power /10, currents /100, temperature /10, energy /1000. - The file format uses the following struct formats: - HEADER = "<4s8x" - OPTIMIZER_DATA_UNIT = " None: ``` ### Parameters - **file_data** (bytes) - Required - The binary contents of the optimizer system information data file. ### Behavior - Parses the file header and version. - Supports file versions `b"V102"` and `b"V103"`. - For V102, reads: optimizer address, online status, string number, position, serial number, software version, alias, and model. - For V103, additionally reads: one_to_more, rated_power, and cpu_type. - Raises `DecodeError` for unsupported versions or corrupted data. ### Exceptions - **DecodeError** - Raised if the file version is not `b"V102"` or `b"V103"`, or if the data is corrupted (struct.error). ### Example ```python from huawei_solar_lib.optimizer_system_information import OptimizerSystemInformationDataFile file_data = b"..." # binary data parser = OptimizerSystemInformationDataFile(file_data) print(parser.optimizers) print(parser.file_version) ``` ``` -------------------------------- ### LG_RESU_TimeOfUsePeriod dataclass Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-periods.md Defines a time-of-use period for LG RESU batteries with start and end times in minutes since midnight and an electricity price. ```python @dataclass(frozen=True, slots=True) class LG_RESU_TimeOfUsePeriod: """Time of use period of LG RESU.""" start_time: int # minutes since midnight end_time: int # minutes since midnight electricity_price: float ``` -------------------------------- ### StartFileUploadPDU Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/modbus-pdu.md Modbus file upload request. Encodes a request to start a file upload and decodes the response containing file upload details. ```APIDOC ## StartFileUploadPDU ### Description Modbus file upload request. Encodes a request to start a file upload and decodes the response containing file upload details. ### Fields - **file_type** (int) - File type identifier - **customised_data** (bytes) - Customized data (default: empty bytes) ### Methods #### encode_request(self) -> bytes `>BBBB` header (data_length = 1 + len(customised_data)) followed by the raw customized data. #### decode_response(self, response: bytes) -> StartFileUpload Unpacks `>BBBBLB` (function, sub-function, data_length, file_type, file_length, data_frame_length); validates the data length and the echoed file type; returns `StartFileUpload`. ### Response Data (StartFileUpload) - **file_length** (int) - Total file length in bytes - **data_frame_length** (int) - Bytes per frame - **customised_data** (bytes) - Echoed customized data ``` -------------------------------- ### get Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-client.md Reads a single named register from the device. Equivalent to (await self.get_multiple([name]))[0]. Returns a Result object containing the value and unit. ```APIDOC ## get ### Description Reads a single named register from the device. Equivalent to `(await self.get_multiple([name]))[0]`. Returns a `Result[Any]` containing `.value` and `.unit`. ### Method async def get(self, name: rn.RegisterName) -> "Result[Any]" ### Parameters - **name** (rn.RegisterName) - Required - The name of the register to read. ### Returns - **Result[Any]** - The result containing the register value and unit. ### Exceptions - **ValueError** - When the name is unknown (from `_get_register_definitions`). - **ReadException** / **ConnectionInterruptedException** - On Modbus/transport failure. ``` -------------------------------- ### create_sub_device_instance Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-factories.md Creates a HuaweiSolarDevice instance for extra servers accessible as subdevices via an existing device. Raises ValueError if the unit_id is the same as the primary device's. ```APIDOC ## create_sub_device_instance ### Description Create a HuaweiSolarDevice instance for extra servers accessible as subdevices via an existing device. ### Signature ```python async def create_sub_device_instance( primary_device: HuaweiSolarDevice, unit_id: int, ) -> HuaweiSolarDevice ``` ### Parameters - **primary_device** (HuaweiSolarDevice) - Required - The existing primary device instance. - **unit_id** (int) - Required - The unit ID of the sub-device. ### Returns - **HuaweiSolarDevice** - The created sub-device instance. ### Raises - **ValueError** - If `primary_device.client.unit_id == unit_id` (message: "The unit_id for the sub-device must be different from the primary device's unit_id."). - Same detection errors as `create_device_instance`. ### Behavior - Creates a derived client via `primary_device.client.for_unit_id(unit_id)` (same transport, different unit ID). - Detects the sub-device type and creates it with `primary_device=primary_device` (links `update_lock` and `stop()` behavior). ### Example ```python battery = await create_sub_device_instance(device, unit_id=1) ``` ``` -------------------------------- ### Import register definition classes Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-definitions.md Import the register definition classes from huawei_solar.register_definitions. Result is also re-exported at the top level from huawei_solar. ```python from huawei_solar.register_definitions import ( Result, RegisterDefinition, TargetDevice, I16Register, I32Register, I32AbsoluteValueRegister, I64Register, U16Register, U32Register, U64Register, TimestampRegister, StringRegister, ) # Result is also re-exported at the top level: from huawei_solar import Result ``` -------------------------------- ### ensure_logged_in Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-base.md Checks whether login is needed and performs it. If force is set, stops any running heartbeat; if credentials exist but no heartbeat is running, re-runs client.login and starts the heartbeat. ```APIDOC ## ensure_logged_in ### Description Checks whether login is needed and performs it. Under login_lock: if force is set, stops any running heartbeat; if credentials exist but no heartbeat is running, re-runs client.login and starts the heartbeat. ### Method async def ensure_logged_in(self, *, force: bool = False) -> bool ### Parameters - **force** (bool) - Optional - If True, forces a re-login even if already logged in. ### Returns - **bool** - Always True on success. ### Errors - **InvalidCredentials** - Raised if the stored password is missing or the login fails. ``` -------------------------------- ### create_device_instance function definition Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-factories.md Async factory that detects the connected device and creates the appropriate primary-device instance. It runs detect_device_type(client) and then device_type.create(client, model_name=model_name, primary_device=None). Returns the populated HuaweiSolarDevice subclass. ```python async def create_device_instance(client: AsyncHuaweiSolarClient) -> HuaweiSolarDevice: """Detect the connected device and create the appropriate instance.""" ``` -------------------------------- ### RegisterDefinition __init__ Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/register-definitions.md Constructor for RegisterDefinition. Parameters include register (required), writeable, readable, and target_device with defaults. The __post_init__ asserts that struct.calcsize(f">{self.format}") equals self.length * 2. ```python def __init__( self, register: int, *, writeable: bool = False, readable: bool = True, target_device: TargetDevice = TargetDevice.SUN2000, ) -> None: """Create RegisterDefinition.""" ``` -------------------------------- ### Import device factory and detection helpers Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-factories.md Import the main factory functions and detection helpers from the huawei-solar package. ```python from huawei_solar import create_device_instance, create_sub_device_instance # or, for the detection helpers: from huawei_solar.device import detect_device_type, get_device_class_for_model ``` -------------------------------- ### SUN2000Device.supports_device Source: https://github.com/wlcrs/huawei-solar-lib/blob/develop/_autodocs/api-reference/device-subclasses.md Class method to check if the SUN2000Device class supports a given device model name. Returns True if the model name starts with 'SUN', 'EDF ESS', 'Powershifter', or 'SWI300'. ```APIDOC ## supports_device ### Description Class method to check if this class supports the given device model name. ### Method Class method (Python) ### Signature ```python @classmethod def supports_device(cls, model_name: str) -> bool: ``` ### Parameters - **model_name** (str) - Required - The device model name to check. ### Returns - **bool** - True if the model name starts with 'SUN', 'EDF ESS', 'Powershifter', or 'SWI300'. ### Example ```python supported = SUN2000Device.supports_device("SUN2000-10KTL") ``` ```