Skip to content

Commit 5e39055

Browse files
authored
Update solaredge_one_api.py
1 parent 8c810ee commit 5e39055

File tree

1 file changed

+25
-8
lines changed

1 file changed

+25
-8
lines changed

custom_components/solaredgeoptimizers/solaredge_one_api.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
"""
2-
SolarEdge One API client for Home Assistant integration.
2+
SolarEdge One portal API client: OAuth authentication and services/layout endpoints for site structure, optimizer live data, temperatures, and lifetime energy.
33
4-
This client is used by the dual API (api_dual.py) when Use SolarEdge One is enabled.
5-
Uses the SolarEdge One portal endpoints (monitoring.solaredge.com/services/...):
4+
Used by api_dual when Use SolarEdge One is enabled. Endpoints (monitoring.solaredge.com/services/...):
65
76
- **Site structure**: GET .../layout/logical/generic/v2/site/{siteId}?include-optimizers=true
87
- **Optimizer info + live data**: POST .../layout/information/optimizers (body: list of serials).
@@ -12,7 +11,7 @@
1211
- **Inverter information**: GET .../layout/information/inverters?inverter-serials=...
1312
Returns fullModel (e.g. SE5000H-RW000BNN4). 403 Forbidden is non-fatal; devices still work with position-based identity.
1413
- **Optimizer temperatures**: GET .../layout/energy/site/{siteId}/by-inverter?start-date=...&end-date=...&inverter-serials=...&include-max-temperature=true.
15-
Returns per-optimizer temperature (°C). Cached 15 min; merged into optimizer data.
14+
Returns per-optimizer temperature (may be °C or °F per temperatureUnit). Cached 15 min; merged into optimizer data (normalized to °C).
1615
- **Lifetime energy**: GET .../layout/energy-graph/site/{siteId}/optimizers?optimizer-serials=...&start-date=...&end-date=...
1716
One request per optimizer; when cache is cold, requests run in parallel (thread pool); cached 1 h.
1817
@@ -570,6 +569,7 @@ def get_optimizer_temperatures_cached(self):
570569
}
571570
data = self._get(path, params=params, timeout=30)
572571
result = {}
572+
fahrenheit_count = 0
573573
for inv_block in data.get("inverters") or []:
574574
for opt in inv_block.get("optimizers") or []:
575575
serial = (opt.get("serial") or "").strip()
@@ -578,15 +578,29 @@ def get_optimizer_temperatures_cached(self):
578578
t = temp_obj.get("temperature")
579579
if t is not None:
580580
try:
581-
result[serial] = round(float(t), 1)
581+
temp_val = float(t)
582+
unit = (temp_obj.get("temperatureUnit") or "CELSIUS").strip().upper()
583+
# Portal may send FAHRENHEIT or F (e.g. US). Convert to Celsius for storage.
584+
# F -> C: (x - 32) * 5/9 (e.g. 138°F -> 58.9°C). Do NOT use C->F formula.
585+
if unit in ("FAHRENHEIT", "F"):
586+
raw_f = temp_val
587+
temp_val = (temp_val - 32.0) * (5.0 / 9.0)
588+
fahrenheit_count += 1
589+
if _LOGGER.isEnabledFor(logging.DEBUG):
590+
_LOGGER.debug(
591+
"SolarEdge One: Temperature unit %s for optimizer %s: %.1f°F -> %.1f°C",
592+
unit, serial, raw_f, temp_val,
593+
)
594+
result[serial] = round(temp_val, 1)
582595
except (TypeError, ValueError):
583596
pass
584597
self._temperature_cache = result
585598
self._temperature_cache_time = now
586599
if _LOGGER.isEnabledFor(logging.DEBUG):
587600
_LOGGER.debug(
588-
"SolarEdge One: Refreshed optimizer temperature cache (%d optimizers)",
601+
"SolarEdge One: Refreshed optimizer temperature cache (%d optimizers%s)",
589602
len(result),
603+
f", {fahrenheit_count} in Fahrenheit (converted to °C)" if fahrenheit_count else "",
590604
)
591605
return result
592606
except Exception as e: # pylint: disable=broad-except
@@ -620,15 +634,18 @@ def _build_optimizer_data_from_response(self, item_id: str, live: dict, basic: d
620634
"""Build SolarEdgeOptimizerData from API live/basic dicts for one optimizer. Returns None on error."""
621635
last_measurement = live.get("lastMeasurement") or ""
622636
model = basic.get("model") or ""
637+
# Prefer API description (panel type e.g. 'SunPower SPR-MAX3-400') when present; else build from modules
638+
api_desc = (basic.get("description") or live.get("description") or "").strip()
639+
desc = api_desc if api_desc else self._description_from_basic(basic, item_id)
623640
if _LOGGER.isEnabledFor(logging.DEBUG):
624641
_LOGGER.debug(
625-
"SolarEdge One: Building optimizer data for %s model=%r last_measurement=%s has_live=%s",
642+
"SolarEdge One: Building optimizer data for %s model=%r panel_type=%r last_measurement=%s has_live=%s",
626643
item_id,
627644
model or "(none)",
645+
desc or "(none)",
628646
last_measurement or "(none)",
629647
bool(live),
630648
)
631-
desc = self._description_from_basic(basic, item_id)
632649
measurements = self._measurements_from_live(live)
633650
json_object = {
634651
"serialNumber": item_id,

0 commit comments

Comments
 (0)