Skip to content

Commit

Permalink
Merge pull request #51 from RustyDust/sru_work
Browse files Browse the repository at this point in the history
Fix `state_class` for newly created non-numeric sensors, closes #50
  • Loading branch information
RustyDust committed Mar 5, 2024
2 parents 81de577 + 688c58b commit 75a3e8c
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 52 deletions.
9 changes: 2 additions & 7 deletions custom_components/sonnenbatterie/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
"""The Sonnenbatterie integration."""
from .const import *
import json
import asyncio
import voluptuous as vol
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity import Entity
# from homeassistant.helpers import config_validation as cv
# from homeassistant.helpers.entity import Entity
from homeassistant.const import (
CONF_PASSWORD,
CONF_USERNAME,
Expand All @@ -13,7 +11,6 @@
)



async def async_setup(hass, config):
hass.data.setdefault(DOMAIN, {})
"""Set up a skeleton component."""
Expand Down Expand Up @@ -45,6 +42,4 @@ async def update_listener(hass, entry):
async def async_unload_entry(hass, entry):
"""Handle removal of an entry."""
return await hass.config_entries.async_forward_entry_unload(entry, 'sensor')



6 changes: 6 additions & 0 deletions custom_components/sonnenbatterie/mappings.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
`textmap`: Adds another sensor postfixed with _text to the
current sensor. The map needs to be specified in
PYTHON synatx, not JSON!
The state_class (see below) will be set to `None``
automatically.
`state_class`: Override the default state class `measurement`with
the value given here. For a list of valid classes see
https://developers.home-assistant.io/docs/core/entity/sensor/
"""

SBmap = {
Expand Down Expand Up @@ -213,6 +218,7 @@
"friendly_name": "System Status",
"unit": None,
"class": None,
"state_class": None,
},
"OperatingMode": {
"sensor": "operating_mode",
Expand Down
71 changes: 26 additions & 45 deletions custom_components/sonnenbatterie/sensor.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
import traceback
from datetime import datetime
import sys
# pylint: disable=unused-wildcard-import
from .const import *
from .mappings import SBmap

import ast
# pylint: enable=unused-wildcard-import
import threading
import time
from homeassistant.helpers import config_validation as cv
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.reload import async_setup_reload_service
#from homeassistant.helpers.device_registry import DeviceInfo ##this seems to be the way in some of the next updates...?
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
UpdateFailed,
)

from homeassistant.components.sensor import (
Expand Down Expand Up @@ -90,28 +84,20 @@ def generateDeviceInfo(configentry_id,systemdata):
devicename=devicename="{}_{}".format(DOMAIN, serial)

return DeviceInfo(
identifiers={(DOMAIN, configentry_id)},
manufacturer="Sonnen",
model=model,
name=devicename,
sw_version=version,
#identifiers={
# # Serial numbers are unique identifiers within a specific domain
# (DOMAIN, self._devicename)
#},
#name=self.name,
#manufacturer=self.light.manufacturername,
#model=self.light.productname,
#sw_version=self.light.swversion,
#via_device=(hue.DOMAIN, self.api.bridgeid),
identifiers = {(DOMAIN, configentry_id)},
manufacturer = "Sonnen",
model = model,
name = devicename,
sw_version = version,
)

class SonnenBatterieSensor(CoordinatorEntity,SensorEntity):
def __init__(self,id,deviceinfo,coordinator,name=None):

class SonnenBatterieSensor(CoordinatorEntity, SensorEntity):
def __init__(self, id, deviceinfo, coordinator, name=None):
self._attributes = {}
self._state = "0"
self._deviceinfo=deviceinfo
self.coordinator=coordinator
self._deviceinfo = deviceinfo
self.coordinator = coordinator
self.entity_id = id
if name is None:
name = id
Expand All @@ -124,8 +110,6 @@ def device_info(self) -> DeviceInfo:
"""Return the device info."""
return self._deviceinfo



def set_state(self, state):
"""Set the state."""
if self._state==state:
Expand Down Expand Up @@ -191,15 +175,15 @@ def state_class(self):
class SonnenBatterieCoordinator(DataUpdateCoordinator):
"""My custom coordinator."""

def __init__(self, hass, sbInst, async_add_entities, updateIntervalSeconds, debug_mode,device_id):
def __init__(self, hass, sbInst, async_add_entities, updateIntervalSeconds, debug_mode, device_id):
"""Initialize my coordinator."""
super().__init__(
hass,
_LOGGER,
# Name of the data. For logging purposes.
name="SonnenBatterieCoordinator",
name = "SonnenBatterieCoordinator",
# Polling interval. Will only be polled if there are subscribers.
update_interval=timedelta(seconds=updateIntervalSeconds),
update_interval = timedelta(seconds = updateIntervalSeconds),
)
self.sensor=None
self.hass = hass
Expand All @@ -225,6 +209,7 @@ def __init__(self, hass, sbInst, async_add_entities, updateIntervalSeconds, debu
self.serial = ""
self.allSensorsPrefix = ""
self.deviceName="to be set"

async def updateData(self):
try: ##ignore errors here, may be transient
self.latestData["battery"] = await self.hass.async_add_executor_job(self.sbInst.get_battery);
Expand All @@ -240,8 +225,6 @@ async def updateData(self):
if self.debug:
self.SendAllDataToLog();



async def _async_update_data(self):
"""Fetch data from API endpoint.
Expand All @@ -253,13 +236,12 @@ async def _async_update_data(self):

#Create/Update the Main Sensor, named after the battery serial
systemdata = self.latestData["systemdata"]
deviceinfo=generateDeviceInfo(self.device_id,systemdata)
deviceinfo = generateDeviceInfo(self.device_id, systemdata)
serial = systemdata["DE_Ticket_Number"]
if self.sensor is None:
self.sensor = SonnenBatterieSensor(id="sensor.{0}_{1}".format(DOMAIN, serial),deviceinfo=deviceinfo,coordinator=self,name=serial)
self.sensor = SonnenBatterieSensor(id="sensor.{0}_{1}".format(DOMAIN, serial), deviceinfo=deviceinfo, coordinator=self, name=serial)
self.async_add_entities([self.sensor])


statedisplay = "standby"
if self.latestData["status"]["BatteryCharging"]:
statedisplay = "charging"
Expand Down Expand Up @@ -289,7 +271,7 @@ def parse(self):

attr = {}
for meter in meters:
prefix = "{0}_{1}_{2}-".format(meter['direction'],meter['deviceid'],meter['channel'])
prefix = "{0}_{1}_{2}-".format(meter['direction'], meter['deviceid'], meter['channel'])
for name in meter:
parmName = prefix+name
attr[parmName] = meter[name]
Expand Down Expand Up @@ -329,7 +311,8 @@ def walkEntities(self, entities, parents=[], key=""):
entities["friendly_name"],
real_val,
entities["unit"],
entities["class"]
entities["class"],
entities["state_class"] if "state_class" in entities else "measurement"
)

# add alias names if needed
Expand Down Expand Up @@ -375,7 +358,8 @@ def walkEntities(self, entities, parents=[], key=""):
"{} (text)".format(entities["friendly_name"]),
tval,
entities["unit"],
entities["class"]
entities["class"],
None
)
else:
# recursively check deeper down
Expand All @@ -387,21 +371,21 @@ def walkEntities(self, entities, parents=[], key=""):
# pop path from stack to prevent ever growing path array
parents.remove(elem)

def _AddOrUpdateEntity(self,id,friendlyname,value,unit,device_class):
def _AddOrUpdateEntity(self, id, friendlyname, value, unit, device_class, state_class="measurement"):
if id in self.meterSensors:
sensor = self.meterSensors[id]
sensor.set_state(value)
else:
deviceinfo=generateDeviceInfo(self.device_id,self.latestData["systemdata"] )
deviceinfo = generateDeviceInfo(self.device_id, self.latestData["systemdata"] )


sensor = SonnenBatterieSensor(id=id,deviceinfo=deviceinfo,coordinator=self,name=friendlyname)
sensor = SonnenBatterieSensor(id=id, deviceinfo=deviceinfo, coordinator=self, name=friendlyname)
sensor.set_attributes(
{
"unit_of_measurement": unit,
"device_class": device_class,
"friendly_name": friendlyname,
"state_class": "measurement"
"state_class": state_class
}
)
self.async_add_entities([sensor])
Expand Down Expand Up @@ -468,7 +452,7 @@ def AddOrUpdateEntities(self):
if unitname == "V":
device_class = SensorDeviceClass.VOLTAGE
elif unitname == "A":
device_class=SensorDeviceClass.CURRENT
device_class = SensorDeviceClass.CURRENT
friendlyname = "{0} {1}".format(meter['direction'], sensormeter)
self._AddOrUpdateEntity(
sensorname,
Expand Down Expand Up @@ -497,6 +481,3 @@ def SendAllDataToLog(self):
LOGGER.warning("Battery:")
LOGGER.warning(self.latestData["battery"])
self.fullLogsAlreadySent = True



0 comments on commit 75a3e8c

Please sign in to comment.