Skip to content

Commit b2ee18c

Browse files
authored
Merge pull request #79 from Monitor-My-Solar/monitormysolarDEV
Bug fix on energy dash for some users, added more combined entities f…
2 parents a89faf2 + cf05864 commit b2ee18c

4 files changed

Lines changed: 118 additions & 3 deletions

File tree

custom_components/monitormysolar/config_flow.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,30 @@ class InverterMQTTFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
1414

1515
VERSION = 1
1616

17+
def _normalize_dongle_id(self, dongle_id):
18+
"""Normalize dongle ID to format: dongle-XX:XX:XX:XX:XX:XX."""
19+
if not dongle_id:
20+
return ""
21+
22+
# Remove any whitespace
23+
dongle_id = dongle_id.strip()
24+
25+
# Extract MAC address part (everything after 'dongle-' or the whole string if no prefix)
26+
if dongle_id.lower().startswith("dongle-"):
27+
mac_part = dongle_id[7:] # Remove 'dongle-' prefix
28+
else:
29+
mac_part = dongle_id
30+
31+
# Normalize MAC address: remove non-alphanumeric chars and ensure uppercase
32+
mac_part = ''.join(c for c in mac_part if c.isalnum()).upper()
33+
34+
# Insert colons if not present (assuming 12 character MAC)
35+
if len(mac_part) == 12 and ':' not in mac_part:
36+
mac_part = ':'.join(mac_part[i:i+2] for i in range(0, 12, 2))
37+
38+
# Return normalized format
39+
return f"dongle-{mac_part}"
40+
1741
def _get_inverter_title(self, brand, dongle_count=1):
1842
"""Generate a proper title based on brand and number of dongles."""
1943
# Map brand codes to proper names
@@ -40,6 +64,9 @@ async def async_step_user(self, user_input=None):
4064
if user_input is not None:
4165
_LOGGER.debug("User input received: %s", user_input)
4266

67+
# Normalize the dongle ID
68+
user_input["dongle_id"] = self._normalize_dongle_id(user_input["dongle_id"])
69+
4370
# If parallel inverters is selected, store the data and move to the parallel step
4471
if user_input.get("parallel_inverters", False):
4572
self.initial_data = user_input
@@ -90,7 +117,9 @@ async def async_step_parallel(self, user_input=None):
90117
for i in range(1, 4): # Check for dongle_id_2, dongle_id_3, dongle_id_4
91118
additional_dongle = user_input.get(f"dongle_id_{i+1}")
92119
if additional_dongle and additional_dongle.strip():
93-
dongle_ids.append(additional_dongle)
120+
# Normalize the additional dongle ID
121+
normalized_dongle = self._normalize_dongle_id(additional_dongle)
122+
dongle_ids.append(normalized_dongle)
94123
# Get corresponding IP or empty string
95124
additional_ip = user_input.get(f"dongle_ip_{i+1}", "")
96125
dongle_ips.append(additional_ip)
@@ -141,6 +170,30 @@ def config_entry(self):
141170
"""Return the config entry."""
142171
return self._config_entry
143172

173+
def _normalize_dongle_id(self, dongle_id):
174+
"""Normalize dongle ID to format: dongle-XX:XX:XX:XX:XX:XX."""
175+
if not dongle_id:
176+
return ""
177+
178+
# Remove any whitespace
179+
dongle_id = dongle_id.strip()
180+
181+
# Extract MAC address part (everything after 'dongle-' or the whole string if no prefix)
182+
if dongle_id.lower().startswith("dongle-"):
183+
mac_part = dongle_id[7:] # Remove 'dongle-' prefix
184+
else:
185+
mac_part = dongle_id
186+
187+
# Normalize MAC address: remove non-alphanumeric chars and ensure uppercase
188+
mac_part = ''.join(c for c in mac_part if c.isalnum()).upper()
189+
190+
# Insert colons if not present (assuming 12 character MAC)
191+
if len(mac_part) == 12 and ':' not in mac_part:
192+
mac_part = ':'.join(mac_part[i:i+2] for i in range(0, 12, 2))
193+
194+
# Return normalized format
195+
return f"dongle-{mac_part}"
196+
144197
def _get_inverter_title(self, brand, dongle_count=1):
145198
"""Generate a proper title based on brand and number of dongles."""
146199
# Map brand codes to proper names
@@ -198,7 +251,8 @@ async def async_step_add_dongle(self, user_input=None):
198251
errors = {}
199252

200253
if user_input is not None:
201-
new_dongle_id = user_input["dongle_id"]
254+
# Normalize the new dongle ID
255+
new_dongle_id = self._normalize_dongle_id(user_input["dongle_id"])
202256
new_dongle_ip = user_input.get("dongle_ip", "")
203257

204258
# Get current data

custom_components/monitormysolar/const.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,11 @@
473473
,
474474
"combined": [
475475
{"name": "Combined PV Power Total", "type": "sensor", "unique_id": "combined_pv_power", "state_class": SensorStateClass.MEASUREMENT, "device_class": SensorDeviceClass.POWER, "unit_of_measurement": UnitOfPower.WATT, "calculation": {"operation": "addition", "source_entity": "pall"}},
476+
{"name": "Combined House Power Load", "type": "sensor", "unique_id": "combined_house_power_load", "state_class": SensorStateClass.MEASUREMENT, "device_class": SensorDeviceClass.POWER, "unit_of_measurement": UnitOfPower.WATT, "calculation": {"operation": "addition", "source_entity": "pload"}},
477+
{"name": "Combined Energy To Grid Day", "type": "sensor", "unique_id": "combined_energy_to_grid_day", "state_class": SensorStateClass.TOTAL_INCREASING, "unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR, "device_class": SensorDeviceClass.ENERGY, "calculation": {"operation": "addition", "source_entity": "etogrid_day"}},
478+
{"name": "Combined Energy To User Day", "type": "sensor", "unique_id": "combined_energy_to_user_day", "state_class": SensorStateClass.TOTAL_INCREASING, "unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR, "device_class": SensorDeviceClass.ENERGY, "calculation": {"operation": "addition", "source_entity": "etouser_day"}},
479+
{"name": "Combined Energy To Grid (live)", "type": "sensor", "unique_id": "combined_energy_to_grid_live", "state_class": SensorStateClass.MEASUREMENT, "device_class": SensorDeviceClass.POWER, "unit_of_measurement": UnitOfPower.WATT, "calculation": {"operation": "addition", "source_entity": "ptogrid"}},
480+
{"name": "Combined Energy To User (live)", "type": "sensor", "unique_id": "combined_energy_to_user_live", "state_class": SensorStateClass.MEASUREMENT, "device_class": SensorDeviceClass.POWER, "unit_of_measurement": UnitOfPower.WATT, "calculation": {"operation": "addition", "source_entity": "ptouser"}},
476481
{"name": "Combined Discharge", "type": "sensor", "unique_id": "combined_discharge", "state_class": SensorStateClass.MEASUREMENT, "device_class": SensorDeviceClass.POWER, "unit_of_measurement": UnitOfPower.WATT, "calculation": {"operation": "addition", "source_entity": "pdischarge"}},
477482
{"name": "Combined Charge", "type": "sensor", "unique_id": "combined_charge", "state_class": SensorStateClass.MEASUREMENT, "device_class": SensorDeviceClass.POWER, "unit_of_measurement": UnitOfPower.WATT, "calculation": {"operation": "addition", "source_entity": "pcharge"}},
478483
{"name": "Combined SOC", "type": "sensor", "unique_id": "combined_soc", "state_class": SensorStateClass.MEASUREMENT, "device_class": SensorDeviceClass.BATTERY, "unit_of_measurement": PERCENTAGE, "calculation": {"operation": "average", "source_entity": "soc"}},

custom_components/monitormysolar/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
"issue_tracker": "https://github.com/Monitor-My-Solar/monitormysolar",
1111
"loggers": [],
1212
"requirements": [],
13-
"version": "3.0.3"
13+
"version": "3.0.4"
1414
}
1515

custom_components/monitormysolar/sensor.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,13 @@ def unit_of_measurement(self):
168168
@property
169169
def device_class(self):
170170
return self.sensor_info.get("device_class")
171+
172+
@property
173+
def suggested_display_precision(self):
174+
"""Return the suggested display precision for energy sensors."""
175+
if self.device_class == SensorDeviceClass.ENERGY:
176+
return 2
177+
return None
171178

172179
@property
173180
def last_reset(self):
@@ -305,6 +312,13 @@ def unit_of_measurement(self):
305312
@property
306313
def device_class(self):
307314
return self.sensor_info.get("device_class")
315+
316+
@property
317+
def suggested_display_precision(self):
318+
"""Return the suggested display precision for energy sensors."""
319+
if self.device_class == SensorDeviceClass.ENERGY:
320+
return 2
321+
return None
308322

309323
@property
310324
def extra_state_attributes(self):
@@ -382,6 +396,13 @@ def unit_of_measurement(self):
382396
@property
383397
def device_class(self):
384398
return self.sensor_info.get("device_class")
399+
400+
@property
401+
def suggested_display_precision(self):
402+
"""Return the suggested display precision for energy sensors."""
403+
if self.device_class == SensorDeviceClass.ENERGY:
404+
return 2
405+
return None
385406

386407

387408
@property
@@ -459,6 +480,13 @@ def unit_of_measurement(self):
459480
@property
460481
def device_class(self):
461482
return self.sensor_info.get("device_class")
483+
484+
@property
485+
def suggested_display_precision(self):
486+
"""Return the suggested display precision for energy sensors."""
487+
if self.device_class == SensorDeviceClass.ENERGY:
488+
return 2
489+
return None
462490

463491

464492
@property
@@ -531,6 +559,13 @@ def state(self):
531559
@property
532560
def device_class(self):
533561
return self.sensor_info.get("device_class")
562+
563+
@property
564+
def suggested_display_precision(self):
565+
"""Return the suggested display precision for energy sensors."""
566+
if self.device_class == SensorDeviceClass.ENERGY:
567+
return 2
568+
return None
534569

535570
@property
536571
def extra_state_attributes(self):
@@ -711,6 +746,13 @@ def unit_of_measurement(self):
711746
@property
712747
def device_class(self):
713748
return self.sensor_info.get("device_class")
749+
750+
@property
751+
def suggested_display_precision(self):
752+
"""Return the suggested display precision for energy sensors."""
753+
if self.device_class == SensorDeviceClass.ENERGY:
754+
return 2
755+
return None
714756

715757
@property
716758
def device_info(self):
@@ -840,6 +882,13 @@ def unit_of_measurement(self):
840882
@property
841883
def device_class(self):
842884
return self.sensor_info.get("device_class")
885+
886+
@property
887+
def suggested_display_precision(self):
888+
"""Return the suggested display precision for energy sensors."""
889+
if self.device_class == SensorDeviceClass.ENERGY:
890+
return 2
891+
return None
843892

844893
@property
845894
def last_reset(self):
@@ -1004,6 +1053,13 @@ def unit_of_measurement(self):
10041053
@property
10051054
def device_class(self):
10061055
return self.sensor_info.get("device_class")
1056+
1057+
@property
1058+
def suggested_display_precision(self):
1059+
"""Return the suggested display precision for energy sensors."""
1060+
if self.device_class == SensorDeviceClass.ENERGY:
1061+
return 2
1062+
return None
10071063

10081064
@property
10091065
def available(self):

0 commit comments

Comments
 (0)