1 """Support for SolarEdge-local Monitoring API."""
3 from __future__
import annotations
5 from contextlib
import suppress
7 from datetime
import timedelta
11 from requests.exceptions
import ConnectTimeout, HTTPError
12 from solaredge_local
import SolarEdge
13 import voluptuous
as vol
16 PLATFORM_SCHEMA
as SENSOR_PLATFORM_SCHEMA,
19 SensorEntityDescription,
24 UnitOfElectricCurrent,
25 UnitOfElectricPotential,
37 DOMAIN =
"solaredge_local"
54 @dataclasses.dataclass(frozen=True)
56 """Describes SolarEdge-local sensor entity."""
58 extra_attribute: str |
None =
None
61 SENSOR_TYPES: tuple[SolarEdgeLocalSensorEntityDescription, ...] = (
65 native_unit_of_measurement=UnitOfElectricPotential.VOLT,
66 device_class=SensorDeviceClass.VOLTAGE,
67 icon=
"mdi:current-ac",
72 native_unit_of_measurement=UnitOfElectricPotential.VOLT,
73 device_class=SensorDeviceClass.VOLTAGE,
74 icon=
"mdi:current-dc",
78 name=
"Grid Frequency",
79 native_unit_of_measurement=UnitOfFrequency.HERTZ,
80 device_class=SensorDeviceClass.FREQUENCY,
85 native_unit_of_measurement=UnitOfPower.WATT,
86 device_class=SensorDeviceClass.POWER,
87 icon=
"mdi:solar-power",
90 key=
"energyThisMonth",
91 name=
"Energy This Month",
92 native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
93 device_class=SensorDeviceClass.ENERGY,
94 icon=
"mdi:solar-power",
98 name=
"Energy This Year",
99 native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
100 device_class=SensorDeviceClass.ENERGY,
101 icon=
"mdi:solar-power",
106 native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
107 device_class=SensorDeviceClass.ENERGY,
108 icon=
"mdi:solar-power",
112 name=
"Lifetime Energy",
113 native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
114 device_class=SensorDeviceClass.ENERGY,
115 icon=
"mdi:solar-power",
119 name=
"Optimizers Online",
120 native_unit_of_measurement=
"optimizers",
121 icon=
"mdi:solar-panel",
122 extra_attribute=
"optimizers_connected",
125 key=
"optimizercurrent",
126 name=
"Average Optimizer Current",
127 native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
128 device_class=SensorDeviceClass.CURRENT,
129 icon=
"mdi:solar-panel",
132 key=
"optimizerpower",
133 name=
"Average Optimizer Power",
134 native_unit_of_measurement=UnitOfPower.WATT,
135 device_class=SensorDeviceClass.POWER,
136 icon=
"mdi:solar-panel",
139 key=
"optimizertemperature",
140 name=
"Average Optimizer Temperature",
141 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
142 icon=
"mdi:solar-panel",
143 device_class=SensorDeviceClass.TEMPERATURE,
146 key=
"optimizervoltage",
147 name=
"Average Optimizer Voltage",
148 native_unit_of_measurement=UnitOfElectricPotential.VOLT,
149 device_class=SensorDeviceClass.VOLTAGE,
150 icon=
"mdi:solar-panel",
155 key=
"invertertemperature",
156 name=
"Inverter Temperature",
157 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
158 extra_attribute=
"operating_mode",
159 device_class=SensorDeviceClass.TEMPERATURE,
162 SENSOR_TYPES_ENERGY_IMPORT: tuple[SolarEdgeLocalSensorEntityDescription, ...] = (
164 key=
"currentPowerimport",
165 name=
"current import Power",
166 native_unit_of_measurement=UnitOfPower.WATT,
167 device_class=SensorDeviceClass.POWER,
168 icon=
"mdi:arrow-collapse-down",
171 key=
"totalEnergyimport",
172 name=
"total import Energy",
173 native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
174 device_class=SensorDeviceClass.ENERGY,
179 SENSOR_TYPES_ENERGY_EXPORT: tuple[SolarEdgeLocalSensorEntityDescription, ...] = (
181 key=
"currentPowerexport",
182 name=
"current export Power",
183 native_unit_of_measurement=UnitOfPower.WATT,
184 device_class=SensorDeviceClass.POWER,
185 icon=
"mdi:arrow-expand-up",
188 key=
"totalEnergyexport",
189 name=
"total export Energy",
190 native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
191 device_class=SensorDeviceClass.ENERGY,
196 PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
198 vol.Required(CONF_IP_ADDRESS): cv.string,
199 vol.Optional(CONF_NAME, default=
"SolarEdge"): cv.string,
203 _LOGGER = logging.getLogger(__name__)
209 add_entities: AddEntitiesCallback,
210 discovery_info: DiscoveryInfoType |
None =
None,
212 """Create the SolarEdge Monitoring API sensor."""
213 ip_address = config[CONF_IP_ADDRESS]
214 platform_name = config[CONF_NAME]
217 api = SolarEdge(f
"http://{ip_address}/")
221 status = api.get_status()
222 _LOGGER.debug(
"Credentials correct and site is active")
223 except AttributeError:
224 _LOGGER.error(
"Missing details data in solaredge status")
226 except (ConnectTimeout, HTTPError):
227 _LOGGER.error(
"Could not retrieve details from SolarEdge API")
234 inverter_temp_description = SENSOR_TYPE_INVERTER_TEMPERATURE
236 status.inverters.primary.temperature.units.farenheit
238 inverter_temp_description = dataclasses.replace(
239 inverter_temp_description,
240 native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT,
246 for description
in (*SENSOR_TYPES, inverter_temp_description)
250 if status.metersList[0]:
254 for description
in SENSOR_TYPES_ENERGY_IMPORT
258 _LOGGER.debug(
"Import meter sensors are not created")
261 if status.metersList[1]:
265 for description
in SENSOR_TYPES_ENERGY_EXPORT
269 _LOGGER.debug(
"Export meter sensors are not created")
275 """Representation of an SolarEdge Monitoring API sensor."""
277 entity_description: SolarEdgeLocalSensorEntityDescription
283 description: SolarEdgeLocalSensorEntityDescription,
285 """Initialize the sensor."""
289 self.
_attr_name_attr_name = f
"{platform_name} ({description.name})"
293 """Return the state attributes."""
302 """Get the latest data from the sensor and update the state."""
308 """Get and update the latest data."""
311 """Initialize the data object."""
317 @Throttle(UPDATE_DELAY)
319 """Update the data from the SolarEdge Monitoring API."""
322 _LOGGER.debug(
"Status from SolarEdge: %s", status)
323 except ConnectTimeout:
324 _LOGGER.error(
"Connection timeout, skipping update")
327 _LOGGER.error(
"Could not retrieve status, skipping update")
331 maintenance = self.
apiapi.get_maintenance()
332 _LOGGER.debug(
"Maintenance from SolarEdge: %s", maintenance)
333 except ConnectTimeout:
334 _LOGGER.error(
"Connection timeout, skipping update")
337 _LOGGER.error(
"Could not retrieve maintenance, skipping update")
345 for optimizer
in maintenance.diagnostics.inverters.primary.optimizer:
346 if not optimizer.online:
348 temperature.append(optimizer.temperature.value)
349 voltage.append(optimizer.inputV)
350 current.append(optimizer.inputC)
353 temperature.append(0)
357 power = statistics.mean(voltage) * statistics.mean(current)
360 self.
datadata[
"energyTotal"] = round(status.energy.total, 2)
361 self.
datadata[
"energyThisYear"] = round(status.energy.thisYear, 2)
362 self.
datadata[
"energyThisMonth"] = round(status.energy.thisMonth, 2)
363 self.
datadata[
"energyToday"] = round(status.energy.today, 2)
364 self.
datadata[
"currentPower"] = round(status.powerWatt, 2)
365 self.
datadata[
"invertertemperature"] = round(
366 status.inverters.primary.temperature.value, 2
368 self.
datadata[
"dcvoltage"] = round(status.inverters.primary.voltage, 2)
369 self.
datadata[
"gridfrequency"] = round(status.frequencyHz, 2)
370 self.
datadata[
"gridvoltage"] = round(status.voltage, 2)
371 self.
datadata[
"optimizers"] = status.optimizersStatus.online
373 self.
infoinfo[
"optimizers"] = status.optimizersStatus.total
374 self.
infoinfo[
"invertertemperature"] = INVERTER_MODES[status.status]
376 with suppress(IndexError):
377 if status.metersList[1]:
378 self.
datadata[
"currentPowerimport"] = status.metersList[1].currentPower
379 self.
datadata[
"totalEnergyimport"] = status.metersList[1].totalEnergy
381 with suppress(IndexError):
382 if status.metersList[0]:
383 self.
datadata[
"currentPowerexport"] = status.metersList[0].currentPower
384 self.
datadata[
"totalEnergyexport"] = status.metersList[0].totalEnergy
386 if maintenance.system.name:
387 self.
datadata[
"optimizertemperature"] = round(statistics.mean(temperature), 2)
388 self.
datadata[
"optimizervoltage"] = round(statistics.mean(voltage), 2)
389 self.
datadata[
"optimizercurrent"] = round(statistics.mean(current), 2)
390 self.
datadata[
"optimizerpower"] = round(power, 2)
def __init__(self, hass, api)
def extra_state_attributes(self)
None __init__(self, platform_name, data, SolarEdgeLocalSensorEntityDescription description)
def add_entities(account, async_add_entities, tracked)
def get_status(hass, host, port)
None setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback add_entities, DiscoveryInfoType|None discovery_info=None)