Skip to content

Commit

Permalink
feat: Add scaling modifier + Reverted Deye Hybrid scaling
Browse files Browse the repository at this point in the history
  • Loading branch information
davidrapan committed Dec 6, 2024
1 parent 3d1183a commit b0ae389
Show file tree
Hide file tree
Showing 8 changed files with 30 additions and 14 deletions.
3 changes: 3 additions & 0 deletions custom_components/solarman/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
bulk_delete(new_data, CONF_OLD_SERIAL)
bulk_delete(new_options, CONF_OLD_SERIAL, "inverter_host", "inverter_port", CONF_BATTERY_NOMINAL_VOLTAGE, CONF_BATTERY_LIFE_CYCLE_RATING)

if not new_options.get(CONF_ADDITIONAL_OPTIONS):
del new_options[CONF_ADDITIONAL_OPTIONS]

hass.config_entries.async_update_entry(config_entry, options = new_options, minor_version = ConfigFlowHandler.MINOR_VERSION, version = ConfigFlowHandler.VERSION)

_LOGGER.debug("Migration to configuration version %s.%s successful", config_entry.version, config_entry.minor_version)
Expand Down
8 changes: 7 additions & 1 deletion custom_components/solarman/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,20 @@ def is_ethernet_frame(frame):
def format_exception(e):
return re.sub(r"\s+", " ", f"{type(e).__name__}{f': {e}' if f'{e}' else ''}")

def process_descriptions(item, group, table, code):
def process_descriptions(item, group, table, code, mod):
bulk_inherit(item, group, *(REQUEST_UPDATE_INTERVAL, REQUEST_CODE) if "registers" in item else REQUEST_UPDATE_INTERVAL)
if not REQUEST_CODE in item and (r := item.get("registers")) is not None and (addr := min(r)) is not None:
item[REQUEST_CODE] = table.get(addr, code)
if (c := item.get("scale")) is not None and isinstance(c, list):
item["scale"] = c[mod]
if (sensors := item.get("sensors")) is not None:
for s in sensors:
if (c := s.get("scale")) is not None and isinstance(c, list):
s["scale"] = c[mod]
bulk_inherit(s, item, REQUEST_CODE, "scale")
if (m := item.get("multiply")) is not None:
if (c := m.get("scale")) is not None and isinstance(c, list):
m["scale"] = c[mod]
bulk_inherit(m, s, REQUEST_CODE, "scale")
return item

Expand Down
3 changes: 2 additions & 1 deletion custom_components/solarman/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
vol.Required(CONF_ADDITIONAL_OPTIONS): section(
vol.Schema(
{
vol.Optional(CONF_MOD, default = DEFAULT_TABLE[CONF_MOD], description = {"suggested_value": DEFAULT_TABLE[CONF_MOD]}): bool,
vol.Optional(CONF_MPPT, default = DEFAULT_TABLE[CONF_MPPT], description = {"suggested_value": DEFAULT_TABLE[CONF_MPPT]}): vol.All(vol.Coerce(int), vol.Range(min = 1, max = 12)),
vol.Optional(CONF_PHASE, default = DEFAULT_TABLE[CONF_PHASE], description = {"suggested_value": DEFAULT_TABLE[CONF_PHASE]}): vol.All(vol.Coerce(int), vol.Range(min = 1, max = 3)),
vol.Optional(CONF_BATTERY_NOMINAL_VOLTAGE, default = DEFAULT_TABLE[CONF_BATTERY_NOMINAL_VOLTAGE], description = {"suggested_value": DEFAULT_TABLE[CONF_BATTERY_NOMINAL_VOLTAGE]}): cv.positive_int,
Expand Down Expand Up @@ -87,7 +88,7 @@ def remove_defaults(user_input: dict[str, Any]):
return user_input

class ConfigFlowHandler(ConfigFlow, domain = DOMAIN):
MINOR_VERSION = 3
MINOR_VERSION = 4
VERSION = 1

async def _async_set_and_abort_if_unique_id_configured(self, suffix: str):
Expand Down
2 changes: 2 additions & 0 deletions custom_components/solarman/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
CONF_ADDITIONAL_OPTIONS = "additional_options"
CONF_MPPT = "mppt"
CONF_PHASE = "phase"
CONF_MOD = "mod"
CONF_BATTERY_NOMINAL_VOLTAGE = "battery_nominal_voltage"
CONF_BATTERY_LIFE_CYCLE_RATING = "battery_life_cycle_rating"
CONF_MB_SLAVE_ID = "mb_slave_id"
Expand All @@ -49,6 +50,7 @@
CONF_LOOKUP_FILE: "Auto",
CONF_MPPT: 4,
CONF_PHASE: 3,
CONF_MOD: False,
CONF_BATTERY_NOMINAL_VOLTAGE: 48,
CONF_BATTERY_LIFE_CYCLE_RATING: 6000,
UPDATE_INTERVAL: 60,
Expand Down
18 changes: 9 additions & 9 deletions custom_components/solarman/inverter_definitions/deye_hybrid.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ parameters:
state_class: "measurement"
uom: "W"
rule: 2
scale: 10 # out of date docs
scale: [1, 10] # out of date docs
registers: [0x00A7]
icon: "mdi:transmission-tower"

Expand All @@ -668,7 +668,7 @@ parameters:
state_class: "measurement"
uom: "W"
rule: 2
scale: 10 # out of date docs
scale: [1, 10] # out of date docs
registers: [0x00A8]
icon: "mdi:transmission-tower"

Expand All @@ -678,7 +678,7 @@ parameters:
state_class: "measurement"
uom: "W"
rule: 2
scale: 10 # out of date docs
scale: [1, 10] # out of date docs
registers: [0x00A9]
icon: "mdi:transmission-tower"
attributes: [inverse]
Expand Down Expand Up @@ -709,7 +709,7 @@ parameters:
state_class: "measurement"
uom: "W"
rule: 2
scale: 10 # out of date docs
scale: [1, 10] # out of date docs
registers: [0x00AA]
icon: "mdi:transmission-tower"

Expand All @@ -719,7 +719,7 @@ parameters:
state_class: "measurement"
uom: "W"
rule: 2
scale: 10 # out of date docs
scale: [1, 10] # out of date docs
registers: [0x00AB]
icon: "mdi:transmission-tower"

Expand All @@ -729,7 +729,7 @@ parameters:
state_class: "measurement"
uom: "W"
rule: 2
scale: 10 # out of date docs
scale: [1, 10] # out of date docs
registers: [0x00AC]
icon: "mdi:transmission-tower"

Expand Down Expand Up @@ -759,7 +759,7 @@ parameters:
state_class: "measurement"
uom: "W"
rule: 2
scale: 10 # out of date docs
scale: [1, 10] # out of date docs
registers: [0x00B0]

- name: "Load L2 Power"
Expand All @@ -768,7 +768,7 @@ parameters:
state_class: "measurement"
uom: "W"
rule: 2
scale: 10 # out of date docs
scale: [1, 10] # out of date docs
registers: [0x00B1]

- name: "Load Power"
Expand All @@ -777,7 +777,7 @@ parameters:
state_class: "measurement"
uom: "W"
rule: 2
scale: 10 # out of date docs
scale: [1, 10] # out of date docs
registers: [0x00B2]

- name: "Load L1 Current"
Expand Down
2 changes: 1 addition & 1 deletion custom_components/solarman/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"iot_class": "local_polling",
"issue_tracker": "https://github.com/davidrapan/ha-solarman/issues",
"requirements": ["ipaddress", "pyyaml", "umodbus", "pysolarmanv5>=3.0.4"],
"version": "24.12.06_3"
"version": "24.12.06_4"
}
2 changes: 1 addition & 1 deletion custom_components/solarman/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def __init__(self, profile, attr):

table = {r: get_request_code(pr) for pr in profile["requests"] for r in range(pr[REQUEST_START], pr[REQUEST_END] + 1)} if "requests" in profile and not "requests_fine_control" in profile else {}

self._items = sorted([process_descriptions(item, group, table, self._code) for group in profile["parameters"] for item in group["items"] if len((a := item.keys() & attr.keys())) == 0 or ((k := next(iter(a))) and item[k] <= attr[k])], key = lambda x: (get_code(x, "read", self._code), max(x["registers"])) if "registers" in x else (-1, -1))
self._items = sorted([process_descriptions(item, group, table, self._code, attr["mod"]) for group in profile["parameters"] for item in group["items"] if len((a := item.keys() & attr.keys())) == 0 or ((k := next(iter(a))) and item[k] <= attr[k])], key = lambda x: (get_code(x, "read", self._code), max(x["registers"])) if "registers" in x else (-1, -1))

if (items_codes := [get_code(i, "read", self._code) for i in self._items if "registers" in i]) and (is_single_code := all_same(items_codes)):
self._is_single_code = is_single_code
Expand Down
6 changes: 5 additions & 1 deletion custom_components/solarman/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,11 @@ def auto(self) -> bool:
@cached_property
def attributes(self) -> str:
#return {k: v for k, v in self.additional if k in XXX}
return {ATTR_MPPT: self._additional_options.get(CONF_MPPT, DEFAULT_TABLE[CONF_MPPT]), ATTR_PHASE: self._additional_options.get(CONF_PHASE, DEFAULT_TABLE[CONF_PHASE])}
return {
CONF_MOD: int(self._additional_options.get(CONF_MOD, DEFAULT_TABLE[CONF_MOD])),
ATTR_MPPT: self._additional_options.get(CONF_MPPT, DEFAULT_TABLE[CONF_MPPT]),
ATTR_PHASE: self._additional_options.get(CONF_PHASE, DEFAULT_TABLE[CONF_PHASE])
}

async def resolve(self, request: Callable[[], Awaitable[None]] | None = None):
_LOGGER.debug(f"Device autodetection is {"enabled" if self.auto and request else f"disabled. Selected profile: {self.filename}"}")
Expand Down

0 comments on commit b0ae389

Please sign in to comment.