mirror of
https://github.com/suaveolent/hoymiles-wifi.git
synced 2024-09-20 03:10:11 +00:00
Compare commits
8 Commits
61470d3161
...
d8dd357488
Author | SHA1 | Date | |
---|---|---|---|
|
d8dd357488 | ||
|
413886b8b0 | ||
|
c9aa65bf37 | ||
|
5bfecfdfc6 | ||
|
523b84132a | ||
|
1fae169c29 | ||
|
be21769efc | ||
|
d0c296b556 |
12
README.md
12
README.md
@ -27,7 +27,7 @@ You can integrate the library into your own project, or simply use it in the com
|
||||
### Command line:
|
||||
|
||||
```
|
||||
hoymiles-wifi [-h] --host HOST [--as-json] <command>
|
||||
hoymiles-wifi [-h] --host HOST [--local_addr IP_OF_INTERFACE_TO_USE] [--as-json] <command>
|
||||
|
||||
commands:
|
||||
get-real-data-new,
|
||||
@ -78,11 +78,11 @@ else:
|
||||
- `async_set_power_limit(power_limit)`: Set the power limit of the inverter (0-100%)
|
||||
- `async_set_wifi(wifi_ssid, wifi_password)`: Configure the wifi network
|
||||
- `async_firmware_update()`: Update to latest firmware
|
||||
- `async_restart_dtu`: Restart the DTU
|
||||
- `async_turn_on_inverter`: Turn the inverter on
|
||||
- `async_turn_off_inverter`: Turn the inverter off
|
||||
- `async_get_information_data`: Retrieve information data
|
||||
- `async_heartbeat`: Request a heartbeat message from the DTU
|
||||
- `async_restart_dtu()`: Restart the DTU
|
||||
- `async_turn_on_inverter()`: Turn the inverter on
|
||||
- `async_turn_off_inverter()`: Turn the inverter off
|
||||
- `async_get_information_data()`: Retrieve information data
|
||||
- `async_heartbeat()`: Request a heartbeat message from the DTU
|
||||
|
||||
## Note
|
||||
|
||||
|
@ -20,6 +20,7 @@ from hoymiles_wifi.hoymiles import (
|
||||
generate_version_string,
|
||||
get_dtu_model_name,
|
||||
get_inverter_model_name,
|
||||
get_meter_model_name,
|
||||
)
|
||||
from hoymiles_wifi.protobuf import (
|
||||
AppGetHistPower_pb2,
|
||||
@ -270,28 +271,44 @@ async def async_identify_dtu(dtu: DTU) -> str:
|
||||
"""Identify the DTU asynchronously."""
|
||||
|
||||
real_data = await async_get_real_data_new(dtu)
|
||||
return get_dtu_model_name(real_data.device_serial_number)
|
||||
dtu_model_name = get_dtu_model_name(real_data.device_serial_number)
|
||||
|
||||
return {real_data.device_serial_number: dtu_model_name}
|
||||
|
||||
|
||||
async def async_identify_inverters(dtu: DTU) -> list[str]:
|
||||
"""Identify the DTU asynchronously."""
|
||||
|
||||
inverter_models = []
|
||||
inverter_models = {}
|
||||
real_data = await async_get_real_data_new(dtu)
|
||||
if real_data:
|
||||
for sgs_data in real_data.sgs_data:
|
||||
serial_number = generate_inverter_serial_number(sgs_data.serial_number)
|
||||
inverter_model = get_inverter_model_name(serial_number)
|
||||
inverter_models.append(inverter_model)
|
||||
inverter_models[serial_number] = inverter_model
|
||||
|
||||
for tgs_data in real_data.tgs_data:
|
||||
serial_number = generate_inverter_serial_number(tgs_data.serial_number)
|
||||
inverter_model = get_inverter_model_name(serial_number)
|
||||
inverter_models.append(inverter_model)
|
||||
inverter_models[serial_number] = inverter_model
|
||||
|
||||
return inverter_models
|
||||
|
||||
|
||||
async def async_identify_meters(dtu: DTU) -> list[str]:
|
||||
"""Identify the meters asynchronously."""
|
||||
|
||||
meter_models = {}
|
||||
real_data = await async_get_real_data_new(dtu)
|
||||
if real_data:
|
||||
for meter_model in real_data.meter_data:
|
||||
serial_number = generate_inverter_serial_number(meter_model.serial_number)
|
||||
meter_model = get_meter_model_name(serial_number)
|
||||
meter_models[serial_number] = meter_model
|
||||
|
||||
return meter_models
|
||||
|
||||
|
||||
async def async_get_alarm_list(dtu: DTU) -> None:
|
||||
"""Get alarm list from the dtu asynchronously."""
|
||||
|
||||
@ -312,6 +329,12 @@ async def main() -> None:
|
||||
parser.add_argument(
|
||||
"--host", type=str, required=True, help="IP address or hostname of the DTU"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--local_addr",
|
||||
type=str,
|
||||
required=False,
|
||||
help="IP address of the interface to bind to",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--as-json",
|
||||
action="store_true",
|
||||
@ -339,13 +362,14 @@ async def main() -> None:
|
||||
"heartbeat",
|
||||
"identify-dtu",
|
||||
"identify-inverters",
|
||||
"identify-meters",
|
||||
"get-alarm-list",
|
||||
],
|
||||
help="Command to execute",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
dtu = DTU(args.host)
|
||||
dtu = DTU(args.host, args.local_addr)
|
||||
|
||||
# Execute the specified command using a switch case
|
||||
switch = {
|
||||
@ -366,6 +390,7 @@ async def main() -> None:
|
||||
"heartbeat": async_heatbeat,
|
||||
"identify-dtu": async_identify_dtu,
|
||||
"identify-inverters": async_identify_inverters,
|
||||
"identify-meters": async_identify_meters,
|
||||
"get-alarm-list": async_get_alarm_list,
|
||||
}
|
||||
|
||||
@ -376,15 +401,25 @@ async def main() -> None:
|
||||
if args.as_json:
|
||||
if isinstance(response, Message):
|
||||
print(MessageToJson(response)) # noqa: T201
|
||||
elif isinstance(response, dict):
|
||||
print(json.dumps(response, indent=4)) # noqa: T201
|
||||
else:
|
||||
print(json.dumps(asdict(response), indent=4)) # noqa: T201
|
||||
else:
|
||||
print(f"{args.command.capitalize()} Response: \n{response}") # noqa: T201
|
||||
else:
|
||||
print( # noqa: T201
|
||||
f"No response or unable to retrieve response for "
|
||||
f"{args.command.replace('_', ' ')}",
|
||||
)
|
||||
if args.as_json:
|
||||
print( # noqa: T201
|
||||
json.dumps(
|
||||
{"error": f"No response for {args.command.replace('_', ' ')}"},
|
||||
indent=4,
|
||||
)
|
||||
)
|
||||
else:
|
||||
print( # noqa: T201
|
||||
f"No response or unable to retrieve response for "
|
||||
f"{args.command.replace('_', ' ')}",
|
||||
)
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
|
@ -70,10 +70,11 @@ class NetworkState(Enum):
|
||||
class DTU:
|
||||
"""DTU class."""
|
||||
|
||||
def __init__(self, host: str):
|
||||
def __init__(self, host: str, local_addr: str = None):
|
||||
"""Initialize DTU class."""
|
||||
|
||||
self.host = host
|
||||
self.local_addr = local_addr
|
||||
self.state = NetworkState.Unknown
|
||||
self.sequence = 0
|
||||
self.mutex = asyncio.Lock()
|
||||
@ -365,11 +366,13 @@ class DTU:
|
||||
+ request_as_bytes
|
||||
)
|
||||
|
||||
address = (self.host, dtu_port)
|
||||
ip_to_bind = (self.local_addr, 0) if self.local_addr is not None else None
|
||||
|
||||
async with self.mutex:
|
||||
try:
|
||||
reader, writer = await asyncio.open_connection(*address)
|
||||
reader, writer = await asyncio.open_connection(
|
||||
host=self.host, port=dtu_port, local_addr=ip_to_bind
|
||||
)
|
||||
|
||||
writer.write(message)
|
||||
await writer.drain()
|
||||
|
@ -32,14 +32,11 @@ class InverterPower(Enum):
|
||||
P_400 = "400"
|
||||
P_500 = "500"
|
||||
P_600_700_800 = "600/700/800"
|
||||
P_800W = "800W"
|
||||
P_1000 = "1000"
|
||||
P_1000W = "1000W"
|
||||
P_800W_1000W = "800W/1000W"
|
||||
P_1000_1200_1500 = "1000/1200/1500"
|
||||
P_1200_1500 = "1200/1500"
|
||||
P_1600 = "1600"
|
||||
P_2000 = "2000"
|
||||
P_1600_2000 = "1600/2000"
|
||||
P_2250 = "2250"
|
||||
|
||||
|
||||
@ -56,7 +53,7 @@ power_mapping = {
|
||||
0x1060: InverterPower.P_1000,
|
||||
0x1061: InverterPower.P_1200_1500,
|
||||
0x1161: InverterPower.P_1000_1200_1500,
|
||||
0x1164: InverterPower.P_1600,
|
||||
0x1164: InverterPower.P_1600_2000,
|
||||
0x1412: InverterPower.P_800W_1000W,
|
||||
0x1382: InverterPower.P_2250,
|
||||
}
|
||||
@ -127,7 +124,7 @@ class MeterType(Enum):
|
||||
DTSU666 = "DTSU666"
|
||||
|
||||
|
||||
meter_mapping = {0x1123: MeterType.DDSU666}
|
||||
meter_mapping = {0x10C0: MeterType.DDSU666}
|
||||
|
||||
|
||||
def format_number(number: int) -> str:
|
||||
|
2
setup.py
2
setup.py
@ -6,7 +6,7 @@ setup(
|
||||
name="hoymiles-wifi",
|
||||
packages=["hoymiles_wifi", "hoymiles_wifi.protobuf"],
|
||||
install_requires=["protobuf", "crcmod"],
|
||||
version="0.2.3",
|
||||
version="0.2.4",
|
||||
description="A python library for interfacing with the Hoymiles DTUs and the HMS-XXXXW-2T series of micro-inverters using protobuf messages.",
|
||||
author="suaveolent",
|
||||
include_package_data=True,
|
||||
|
Loading…
Reference in New Issue
Block a user