|
28 | 28 | from .const import ( |
29 | 29 | DOMAIN, |
30 | 30 | SUNSPEC_NOT_IMPL_UINT16, SUNSPEC_NOT_IMPL_INT16, SUNSPEC_NOT_IMPL_UINT32, |
31 | | - SUNSPEC_NOT_ACCUM_ACC32, SUNSPEC_ACCUM_LIMIT, SUNSPEC_SF_RANGE, |
32 | | - DEVICE_STATUS, DEVICE_STATUS_DESC, |
| 31 | + SUNSPEC_NOT_ACCUM_ACC32, SUNSPEC_ACCUM_LIMIT, SUNSPEC_SF_RANGE, SUNSPEC_NOT_IMPL_FLOAT32, |
| 32 | + DEVICE_STATUS, DEVICE_STATUS_DESC, BATTERY_STATUS, |
33 | 33 | VENDOR_STATUS, SUNSPEC_DID, METER_EVENTS, |
34 | 34 | ENERGY_VOLT_AMPERE_HOUR, ENERGY_VOLT_AMPERE_REACTIVE_HOUR, |
35 | 35 | ) |
@@ -171,10 +171,22 @@ async def async_setup_entry( |
171 | 171 | entities.append(SolarEdgeDevice(battery, config_entry)) |
172 | 172 | entities.append(Manufacturer(battery, config_entry)) |
173 | 173 | entities.append(Model(battery, config_entry)) |
174 | | - entities.append(Version(battery, config_entry)) |
175 | 174 | entities.append(SerialNumber(battery, config_entry)) |
176 | 175 | entities.append(DeviceAddress(battery, config_entry)) |
177 | 176 | entities.append(DeviceAddressParent(battery, config_entry)) |
| 177 | + entities.append(Version(battery, config_entry)) |
| 178 | + entities.append(SolarEdgeBatteryAvgTemp(battery, config_entry)) |
| 179 | + entities.append(SolarEdgeBatteryMaxTemp(battery, config_entry)) |
| 180 | + entities.append(SolarEdgeBatteryVoltage(battery, config_entry)) |
| 181 | + entities.append(SolarEdgeBatteryCurrent(battery, config_entry)) |
| 182 | + entities.append(SolarEdgeBatteryPower(battery, config_entry)) |
| 183 | + entities.append(SolarEdgeBatteryEnergyExport(battery, config_entry)) |
| 184 | + entities.append(SolarEdgeBatteryEnergyImport(battery, config_entry)) |
| 185 | + entities.append(SolarEdgeBatteryMaxEnergy(battery, config_entry)) |
| 186 | + entities.append(SolarEdgeBatteryAvailableEnergy(battery, config_entry)) |
| 187 | + entities.append(SolarEdgeBatterySOH(battery, config_entry)) |
| 188 | + entities.append(SolarEdgeBatterySOE(battery, config_entry)) |
| 189 | + entities.append(SolarEdgeBatteryStatus(battery, config_entry)) |
178 | 190 |
|
179 | 191 | if entities: |
180 | 192 | async_add_entities(entities) |
@@ -1254,3 +1266,326 @@ def native_value(self): |
1254 | 1266 |
|
1255 | 1267 | except TypeError: |
1256 | 1268 | return None |
| 1269 | + |
| 1270 | +class SolarEdgeBatteryAvgTemp(HeatSinkTemperature): |
| 1271 | + @property |
| 1272 | + def unique_id(self) -> str: |
| 1273 | + return f"{self._platform.model}_{self._platform.serial}_avg_temp" |
| 1274 | + |
| 1275 | + @property |
| 1276 | + def name(self) -> str: |
| 1277 | + return f"{self._platform._device_info['name']} Average Temperature" |
| 1278 | + |
| 1279 | + @property |
| 1280 | + def native_value(self): |
| 1281 | + try: |
| 1282 | + if ( |
| 1283 | + self._platform.decoded_model['B_Temp_Average'] == SUNSPEC_NOT_IMPL_FLOAT32 |
| 1284 | + or self._platform.decoded_model['B_Temp_Average'] == 0xFF7FFFFF |
| 1285 | + or self._platform.decoded_model['B_Temp_Average'] == 0x7F7FFFFF |
| 1286 | + ): |
| 1287 | + return None |
| 1288 | + |
| 1289 | + else: |
| 1290 | + return round(self._platform.decoded_model['B_Temp_Average'], 1) |
| 1291 | + |
| 1292 | + except TypeError: |
| 1293 | + return None |
| 1294 | + |
| 1295 | +class SolarEdgeBatteryMaxTemp(HeatSinkTemperature): |
| 1296 | + @property |
| 1297 | + def unique_id(self) -> str: |
| 1298 | + return f"{self._platform.model}_{self._platform.serial}_max_temp" |
| 1299 | + |
| 1300 | + @property |
| 1301 | + def name(self) -> str: |
| 1302 | + return f"{self._platform._device_info['name']} Max Temperature" |
| 1303 | + |
| 1304 | + @property |
| 1305 | + def native_value(self): |
| 1306 | + try: |
| 1307 | + if ( |
| 1308 | + self._platform.decoded_model['B_Temp_Max'] == SUNSPEC_NOT_IMPL_FLOAT32 |
| 1309 | + or self._platform.decoded_model['B_Temp_Max'] == 0xFF7FFFFF |
| 1310 | + or self._platform.decoded_model['B_Temp_Max'] == 0x7F7FFFFF |
| 1311 | + ): |
| 1312 | + return None |
| 1313 | + |
| 1314 | + else: |
| 1315 | + return round(self._platform.decoded_model['B_DC_Voltage'], 1) |
| 1316 | + |
| 1317 | + except TypeError: |
| 1318 | + return None |
| 1319 | + |
| 1320 | +class SolarEdgeBatteryVoltage(DCVoltage): |
| 1321 | + @property |
| 1322 | + def native_value(self): |
| 1323 | + try: |
| 1324 | + if ( |
| 1325 | + self._platform.decoded_model['B_DC_Voltage'] == SUNSPEC_NOT_IMPL_FLOAT32 |
| 1326 | + or self._platform.decoded_model['B_DC_Voltage'] == 0xFF7FFFFF |
| 1327 | + or self._platform.decoded_model['B_DC_Voltage'] == 0x7F7FFFFF |
| 1328 | + ): |
| 1329 | + return None |
| 1330 | + |
| 1331 | + elif self._platform.decoded_model['B_Status'] in [0]: |
| 1332 | + return None |
| 1333 | + |
| 1334 | + else: |
| 1335 | + return round(self._platform.decoded_model['B_DC_Voltage'], 2) |
| 1336 | + |
| 1337 | + except TypeError: |
| 1338 | + return None |
| 1339 | + |
| 1340 | +class SolarEdgeBatteryCurrent(DCCurrent): |
| 1341 | + @property |
| 1342 | + def native_value(self): |
| 1343 | + try: |
| 1344 | + if ( |
| 1345 | + self._platform.decoded_model['B_DC_Current'] == SUNSPEC_NOT_IMPL_FLOAT32 |
| 1346 | + or self._platform.decoded_model['B_DC_Current'] == 0xFF7FFFFF |
| 1347 | + or self._platform.decoded_model['B_DC_Current'] == 0x7F7FFFFF |
| 1348 | + ): |
| 1349 | + return None |
| 1350 | + |
| 1351 | + elif self._platform.decoded_model['B_Status'] in [0]: |
| 1352 | + return None |
| 1353 | + |
| 1354 | + else: |
| 1355 | + return round(self._platform.decoded_model['B_DC_Current'], 2) |
| 1356 | + |
| 1357 | + except TypeError: |
| 1358 | + return None |
| 1359 | + |
| 1360 | +class SolarEdgeBatteryPower(DCPower): |
| 1361 | + icon = 'mdi:lightning-bolt' |
| 1362 | + |
| 1363 | + @property |
| 1364 | + def native_value(self): |
| 1365 | + try: |
| 1366 | + if ( |
| 1367 | + self._platform.decoded_model['B_DC_Power'] == SUNSPEC_NOT_IMPL_FLOAT32 |
| 1368 | + or self._platform.decoded_model['B_DC_Power'] == 0xFF7FFFFF |
| 1369 | + or self._platform.decoded_model['B_DC_Power'] == 0x7F7FFFFF |
| 1370 | + ): |
| 1371 | + return None |
| 1372 | + |
| 1373 | + elif self._platform.decoded_model['B_Status'] in [0]: |
| 1374 | + return None |
| 1375 | + |
| 1376 | + else: |
| 1377 | + return round(self._platform.decoded_model['B_DC_Power'], 2) |
| 1378 | + |
| 1379 | + except TypeError: |
| 1380 | + return None |
| 1381 | + |
| 1382 | +class SolarEdgeBatteryEnergyExport(SolarEdgeSensorBase): |
| 1383 | + device_class = SensorDeviceClass.ENERGY |
| 1384 | + state_class = SensorStateClass.TOTAL_INCREASING |
| 1385 | + native_unit_of_measurement = ENERGY_KILO_WATT_HOUR |
| 1386 | + icon = 'mdi:transmission-tower-export' |
| 1387 | + |
| 1388 | + def __init__(self, platform, config_entry): |
| 1389 | + super().__init__(platform, config_entry) |
| 1390 | + """Initialize the sensor.""" |
| 1391 | + |
| 1392 | + @property |
| 1393 | + def unique_id(self) -> str: |
| 1394 | + return f"{self._platform.model}_{self._platform.serial}_energy_export" |
| 1395 | + |
| 1396 | + @property |
| 1397 | + def name(self) -> str: |
| 1398 | + return f"{self._platform._device_info['name']} Energy Export" |
| 1399 | + |
| 1400 | + @property |
| 1401 | + def native_value(self): |
| 1402 | + try: |
| 1403 | + if self._platform.decoded_model['B_Export_Energy_WH'] == 0xFFFFFFFFFFFFFFFF: |
| 1404 | + return None |
| 1405 | + |
| 1406 | + else: |
| 1407 | + try: |
| 1408 | + return watts_to_kilowatts(update_accum(self, self._platform.decoded_model['B_Export_Energy_WH'])) |
| 1409 | + except: |
| 1410 | + return None |
| 1411 | + |
| 1412 | + except TypeError: |
| 1413 | + return None |
| 1414 | + |
| 1415 | +class SolarEdgeBatteryEnergyImport(SolarEdgeSensorBase): |
| 1416 | + device_class = SensorDeviceClass.ENERGY |
| 1417 | + state_class = SensorStateClass.TOTAL_INCREASING |
| 1418 | + native_unit_of_measurement = ENERGY_KILO_WATT_HOUR |
| 1419 | + icon = 'mdi:transmission-tower-import' |
| 1420 | + |
| 1421 | + def __init__(self, platform, config_entry): |
| 1422 | + super().__init__(platform, config_entry) |
| 1423 | + """Initialize the sensor.""" |
| 1424 | + |
| 1425 | + @property |
| 1426 | + def unique_id(self) -> str: |
| 1427 | + return f"{self._platform.model}_{self._platform.serial}_energy_import" |
| 1428 | + |
| 1429 | + @property |
| 1430 | + def name(self) -> str: |
| 1431 | + return f"{self._platform._device_info['name']} Energy Import" |
| 1432 | + |
| 1433 | + @property |
| 1434 | + def native_value(self): |
| 1435 | + try: |
| 1436 | + if self._platform.decoded_model['B_Import_Energy_WH'] == 0xFFFFFFFFFFFFFFFF: |
| 1437 | + return None |
| 1438 | + |
| 1439 | + else: |
| 1440 | + try: |
| 1441 | + return watts_to_kilowatts(update_accum(self, self._platform.decoded_model['B_Import_Energy_WH'])) |
| 1442 | + except: |
| 1443 | + return None |
| 1444 | + |
| 1445 | + except TypeError: |
| 1446 | + return None |
| 1447 | + |
| 1448 | +class SolarEdgeBatteryMaxEnergy(SolarEdgeSensorBase): |
| 1449 | + device_class = SensorDeviceClass.ENERGY |
| 1450 | + state_class = SensorStateClass.MEASUREMENT |
| 1451 | + native_unit_of_measurement = ENERGY_KILO_WATT_HOUR |
| 1452 | + |
| 1453 | + def __init__(self, platform, config_entry): |
| 1454 | + super().__init__(platform, config_entry) |
| 1455 | + """Initialize the sensor.""" |
| 1456 | + |
| 1457 | + @property |
| 1458 | + def unique_id(self) -> str: |
| 1459 | + return f"{self._platform.model}_{self._platform.serial}_max_energy" |
| 1460 | + |
| 1461 | + @property |
| 1462 | + def name(self) -> str: |
| 1463 | + return f"{self._platform._device_info['name']} Maximum Energy" |
| 1464 | + |
| 1465 | + @property |
| 1466 | + def native_value(self): |
| 1467 | + if ( |
| 1468 | + self._platform.decoded_model['B_Energy_Max']== SUNSPEC_NOT_IMPL_FLOAT32 |
| 1469 | + or self._platform.decoded_model['B_Energy_Max'] == 0xFF7FFFFF |
| 1470 | + or self._platform.decoded_model['B_Energy_Max'] == 0x7F7FFFFF |
| 1471 | + ): |
| 1472 | + return None |
| 1473 | + |
| 1474 | + else: |
| 1475 | + return watts_to_kilowatts(self._platform.decoded_model['B_Energy_Max']) |
| 1476 | + |
| 1477 | +class SolarEdgeBatteryAvailableEnergy(SolarEdgeSensorBase): |
| 1478 | + device_class = SensorDeviceClass.ENERGY |
| 1479 | + state_class = SensorStateClass.MEASUREMENT |
| 1480 | + native_unit_of_measurement = ENERGY_KILO_WATT_HOUR |
| 1481 | + |
| 1482 | + def __init__(self, platform, config_entry): |
| 1483 | + super().__init__(platform, config_entry) |
| 1484 | + """Initialize the sensor.""" |
| 1485 | + |
| 1486 | + @property |
| 1487 | + def unique_id(self) -> str: |
| 1488 | + return f"{self._platform.model}_{self._platform.serial}_avail_energy" |
| 1489 | + |
| 1490 | + @property |
| 1491 | + def name(self) -> str: |
| 1492 | + return f"{self._platform._device_info['name']} Available Energy" |
| 1493 | + |
| 1494 | + @property |
| 1495 | + def native_value(self): |
| 1496 | + if ( |
| 1497 | + self._platform.decoded_model['B_Energy_Available']== SUNSPEC_NOT_IMPL_FLOAT32 |
| 1498 | + or self._platform.decoded_model['B_Energy_Available'] == 0xFF7FFFFF |
| 1499 | + or self._platform.decoded_model['B_Energy_Available'] == 0x7F7FFFFF |
| 1500 | + ): |
| 1501 | + return None |
| 1502 | + |
| 1503 | + else: |
| 1504 | + return watts_to_kilowatts(self._platform.decoded_model['B_Energy_Available']) |
| 1505 | + |
| 1506 | +class SolarEdgeBatterySOH(SolarEdgeSensorBase): |
| 1507 | + state_class = SensorStateClass.MEASUREMENT |
| 1508 | + native_unit_of_measurement = PERCENTAGE |
| 1509 | + entity_category = EntityCategory.DIAGNOSTIC |
| 1510 | + |
| 1511 | + def __init__(self, platform, config_entry): |
| 1512 | + super().__init__(platform, config_entry) |
| 1513 | + """Initialize the sensor.""" |
| 1514 | + |
| 1515 | + @property |
| 1516 | + def unique_id(self) -> str: |
| 1517 | + return f"{self._platform.model}_{self._platform.serial}_battery_soh" |
| 1518 | + |
| 1519 | + @property |
| 1520 | + def name(self) -> str: |
| 1521 | + return f"{self._platform._device_info['name']} State of Health" |
| 1522 | + |
| 1523 | + @property |
| 1524 | + def native_value(self): |
| 1525 | + if ( |
| 1526 | + self._platform.decoded_model['B_SOH']== SUNSPEC_NOT_IMPL_FLOAT32 |
| 1527 | + or self._platform.decoded_model['B_SOH'] == 0xFF7FFFFF |
| 1528 | + or self._platform.decoded_model['B_SOH'] == 0x7F7FFFFF |
| 1529 | + ): |
| 1530 | + return None |
| 1531 | + else: |
| 1532 | + return round(self._platform.decoded_model['B_SOH'], 0) |
| 1533 | + |
| 1534 | +class SolarEdgeBatterySOE(SolarEdgeSensorBase): |
| 1535 | + state_class = SensorStateClass.MEASUREMENT |
| 1536 | + native_unit_of_measurement = PERCENTAGE |
| 1537 | + entity_category = EntityCategory.DIAGNOSTIC |
| 1538 | + |
| 1539 | + def __init__(self, platform, config_entry): |
| 1540 | + super().__init__(platform, config_entry) |
| 1541 | + """Initialize the sensor.""" |
| 1542 | + |
| 1543 | + @property |
| 1544 | + def unique_id(self) -> str: |
| 1545 | + return f"{self._platform.model}_{self._platform.serial}_battery_soe" |
| 1546 | + |
| 1547 | + @property |
| 1548 | + def name(self) -> str: |
| 1549 | + return f"{self._platform._device_info['name']} State of Energy" |
| 1550 | + |
| 1551 | + @property |
| 1552 | + def native_value(self): |
| 1553 | + if ( |
| 1554 | + self._platform.decoded_model['B_SOE']== SUNSPEC_NOT_IMPL_FLOAT32 |
| 1555 | + or self._platform.decoded_model['B_SOE'] == 0xFF7FFFFF |
| 1556 | + or self._platform.decoded_model['B_SOE'] == 0x7F7FFFFF |
| 1557 | + ): |
| 1558 | + return None |
| 1559 | + else: |
| 1560 | + return round(self._platform.decoded_model['B_SOE'], 0) |
| 1561 | + |
| 1562 | +class SolarEdgeBatteryStatus(Status): |
| 1563 | + |
| 1564 | + def __init__(self, platform, config_entry): |
| 1565 | + super().__init__(platform, config_entry) |
| 1566 | + """Initialize the sensor.""" |
| 1567 | + |
| 1568 | + @property |
| 1569 | + def native_value(self): |
| 1570 | + try: |
| 1571 | + if (self._platform.decoded_model['B_Status'] == SUNSPEC_NOT_IMPL_UINT32): |
| 1572 | + return None |
| 1573 | + |
| 1574 | + else: |
| 1575 | + return str(self._platform.decoded_model['B_Status']) |
| 1576 | + |
| 1577 | + except TypeError: |
| 1578 | + return None |
| 1579 | + |
| 1580 | + @property |
| 1581 | + def extra_state_attributes(self): |
| 1582 | + attrs = {} |
| 1583 | + |
| 1584 | + try: |
| 1585 | + if self._platform.decoded_model['B_Status'] in BATTERY_STATUS: |
| 1586 | + attrs["status_text"] = BATTERY_STATUS[self._platform.decoded_model['B_Status']] |
| 1587 | + |
| 1588 | + except KeyError: |
| 1589 | + pass |
| 1590 | + |
| 1591 | + return attrs |
0 commit comments