Skip to content

Commit

Permalink
make sure that senec switches will "show" updated data - inlc. häcks
Browse files Browse the repository at this point in the history
  • Loading branch information
marq24 committed Oct 14, 2023
1 parent 5a5fe48 commit 327b78a
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 19 deletions.
10 changes: 8 additions & 2 deletions custom_components/senec/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ class ExtBinarySensorEntityDescription(BinarySensorEntityDescription):
icon_off: str | None = None
senec_lala_section: str | None = None

@dataclass
class ExtSwitchEntityDescription(SwitchEntityDescription):
update_after_switch_delay_in_sec: int = 0

"""Supported number implementations"""
WEB_NUMBER_SENYOR_TYPES = [
NumberEntityDescription(
Expand All @@ -123,16 +127,18 @@ class ExtBinarySensorEntityDescription(BinarySensorEntityDescription):

"""Supported main unit switch types."""
MAIN_SWITCH_TYPES = [
SwitchEntityDescription(
ExtSwitchEntityDescription(
key="safe_charge",
name="Load Battery",
icon="mdi:battery-charging-high",
update_after_switch_delay_in_sec=2,
),
SwitchEntityDescription(
ExtSwitchEntityDescription(
entity_registry_enabled_default=False,
key="li_storage_mode",
name="Lithium Storage Mode - PV OFF",
icon="mdi:solar-power",
update_after_switch_delay_in_sec=2,
),
]

Expand Down
55 changes: 41 additions & 14 deletions custom_components/senec/pysenec_ha/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ def __init__(self, host, use_https, websession, lang: str = "en", options: dict
else:
self.url = f"http://{host}/lala.cgi"

# evil HACK - since SENEC does not switch the property fast enough...
# so for five seconds after the switch take place we will return
# the 'faked' value
self._LI_STORAGE_MODE_RUNNING_OVERWRITE_TS = 0
self._SAFE_CHARGE_RUNNING_OVERWRITE_TS = 0

@property
def device_id(self) -> str:
return self._rawVer[SENEC_SECTION_FACTORY]["DEVICE_ID"]
Expand Down Expand Up @@ -1510,16 +1516,25 @@ async def read_senec_energy(self):
@property
def safe_charge(self) -> bool:
if hasattr(self, '_raw'):
return self._raw[SENEC_SECTION_ENERGY]["SAFE_CHARGE_RUNNING"] == 1
# if it just has been switched on/off we provide a FAKE value for 5 sec...
# since senec unit do not react 'instant' on some requests...
if self._SAFE_CHARGE_RUNNING_OVERWRITE_TS + 5 > time():
return self._SAFE_CHARGE_RUNNING_OVERWRITE_VALUE
else:
return self._raw[SENEC_SECTION_ENERGY]["SAFE_CHARGE_RUNNING"] == 1

async def switch_safe_charge(self, value):
async def switch_safe_charge(self, value: bool):
self._SAFE_CHARGE_RUNNING_OVERWRITE_VALUE = value
self._SAFE_CHARGE_RUNNING_OVERWRITE_TS = time()
postdata = {}
if (value):
self._raw[SENEC_SECTION_ENERGY]["SAFE_CHARGE_RUNNING"] = 1
postdata = {SENEC_SECTION_ENERGY: {"SAFE_CHARGE_FORCE": "u8_01", "SAFE_CHARGE_PROHIBIT": "",
"SAFE_CHARGE_RUNNING": "",
"LI_STORAGE_MODE_START": "", "LI_STORAGE_MODE_STOP": "",
"LI_STORAGE_MODE_RUNNING": ""}}
else:
self._raw[SENEC_SECTION_ENERGY]["SAFE_CHARGE_RUNNING"] = 0
postdata = {SENEC_SECTION_ENERGY: {"SAFE_CHARGE_FORCE": "", "SAFE_CHARGE_PROHIBIT": "u8_01",
"SAFE_CHARGE_RUNNING": "",
"LI_STORAGE_MODE_START": "", "LI_STORAGE_MODE_STOP": "",
Expand All @@ -1530,16 +1545,25 @@ async def switch_safe_charge(self, value):
@property
def li_storage_mode(self) -> bool:
if hasattr(self, '_raw'):
return self._raw[SENEC_SECTION_ENERGY]["LI_STORAGE_MODE_RUNNING"] == 1
# if it just has been switched on/off we provide a FAKE value for 5 sec...
# since senec unit do not react 'instant' on some requests...
if self._LI_STORAGE_MODE_RUNNING_OVERWRITE_TS + 5 > time():
return self._LI_STORAGE_MODE_RUNNING_OVERWRITE_VALUE
else:
return self._raw[SENEC_SECTION_ENERGY]["LI_STORAGE_MODE_RUNNING"] == 1

async def switch_li_storage_mode(self, value):
async def switch_li_storage_mode(self, value: bool):
self._LI_STORAGE_MODE_RUNNING_OVERWRITE_VALUE = value
self._LI_STORAGE_MODE_RUNNING_OVERWRITE_TS = time()
postdata = {}
if (value):
self._raw[SENEC_SECTION_ENERGY]["LI_STORAGE_MODE_RUNNING"] = 1
postdata = {
SENEC_SECTION_ENERGY: {"SAFE_CHARGE_FORCE": "", "SAFE_CHARGE_PROHIBIT": "", "SAFE_CHARGE_RUNNING": "",
"LI_STORAGE_MODE_START": "u8_01", "LI_STORAGE_MODE_STOP": "",
"LI_STORAGE_MODE_RUNNING": ""}}
else:
self._raw[SENEC_SECTION_ENERGY]["LI_STORAGE_MODE_RUNNING"] = 0
postdata = {
SENEC_SECTION_ENERGY: {"SAFE_CHARGE_FORCE": "", "SAFE_CHARGE_PROHIBIT": "", "SAFE_CHARGE_RUNNING": "",
"LI_STORAGE_MODE_START": "", "LI_STORAGE_MODE_STOP": "u8_01",
Expand All @@ -1556,7 +1580,7 @@ async def write(self, data):
async def write_senec_v31(self, data):
async with self.websession.post(self.url, json=data, ssl=False) as res:
res.raise_for_status()
self._raw = parse(await res.json())
self._rawPost = parse(await res.json())


class Inverter:
Expand Down Expand Up @@ -1693,14 +1717,14 @@ def device_serial(self) -> str:
def device_netbiosname(self) -> str:
return self._rawVer["root"]["Device"]["@NetBiosName"]

#@property
#def measurements(self) -> dict:
# @property
# def measurements(self) -> dict:
# if ('Measurements' in self._raw["root"]["Device"] and "Measurement" in self._raw["root"]["Device"][
# "Measurements"]):
# return self._raw["root"]["Device"]["Measurements"]["Measurement"]

#@property
#def versions(self) -> dict:
# @property
# def versions(self) -> dict:
# if ('Versions' in self._rawVer["root"]["Device"] and 'Software' in self._rawVer["root"]["Device"]["Versions"]):
# return self._rawVer["root"]["Device"]["Versions"]["Software"]

Expand Down Expand Up @@ -2039,21 +2063,24 @@ async def update_now_kW_stats(self):
entity_now_name = str(key + "_now")
self._battery_entities[entity_now_name] = value_now
else:
_LOGGER.info(f"No 'now' for key: '{key}' in json: {r_json} when requesting: {a_url}")
_LOGGER.info(
f"No 'now' for key: '{key}' in json: {r_json} when requesting: {a_url}")
else:
if "now" in r_json[key]:
value_now = r_json[key]["now"]
entity_now_name = str(key + "_now")
self._power_entities[entity_now_name] = value_now
else:
_LOGGER.info(f"No 'now' for key: '{key}' in json: {r_json} when requesting: {a_url}")
_LOGGER.info(
f"No 'now' for key: '{key}' in json: {r_json} when requesting: {a_url}")

if "today" in r_json[key]:
value_today = r_json[key]["today"]
entity_today_name = str(key + "_today")
self._energy_entities[entity_today_name] = value_today
else:
_LOGGER.info(f"No 'today' for key: '{key}' in json: {r_json} when requesting: {a_url}")
_LOGGER.info(
f"No 'today' for key: '{key}' in json: {r_json} when requesting: {a_url}")

else:
_LOGGER.info(f"No '{key}' in json: {r_json} when requesting: {a_url}")
Expand Down Expand Up @@ -2196,8 +2223,8 @@ def zone_id(self) -> str:
if hasattr(self, '_zone_id'):
return str(self._zone_id)

#@property
#def firmwareVersion(self) -> str:
# @property
# def firmwareVersion(self) -> str:
# if hasattr(self, '_raw') and "firmwareVersion" in self._raw:
# return str(self._raw["firmwareVersion"])

Expand Down
16 changes: 13 additions & 3 deletions custom_components/senec/switch.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
"""Platform for Senec Switches."""
import asyncio
import logging

from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.util import slugify
from homeassistant.const import STATE_ON, STATE_OFF, CONF_TYPE

from typing import Literal
from . import SenecDataUpdateCoordinator, SenecEntity
from .const import DOMAIN, MAIN_SWITCH_TYPES, CONF_SYSTYPE_INVERTER, CONF_SYSTYPE_WEB
from .const import DOMAIN, MAIN_SWITCH_TYPES, CONF_SYSTYPE_INVERTER, CONF_SYSTYPE_WEB, ExtSwitchEntityDescription

_LOGGER = logging.getLogger(__name__)
_LANG = None
Expand Down Expand Up @@ -37,7 +38,7 @@ class SenecSwitch(SenecEntity, SwitchEntity):
def __init__(
self,
coordinator: SenecDataUpdateCoordinator,
description: SwitchEntityDescription
description: ExtSwitchEntityDescription
):
"""Initialize a singular value sensor."""
super().__init__(coordinator=coordinator, description=description)
Expand All @@ -61,6 +62,11 @@ async def async_turn_on(self, **kwargs): # pylint: disable=unused-argument
try:
await self.coordinator._async_switch_to_state(self.entity_description.key, True)
self.async_schedule_update_ha_state(force_refresh=True)
if hasattr(self.entity_description, 'update_after_switch_delay_in_sec') and self.entity_description.update_after_switch_delay_in_sec > 0:
await asyncio.sleep(self.entity_description.update_after_switch_delay_in_sec)
self.async_schedule_update_ha_state(force_refresh=True)


except ValueError:
return "unavailable"

Expand All @@ -69,6 +75,10 @@ async def async_turn_off(self, **kwargs): # pylint: disable=unused-argument
try:
await self.coordinator._async_switch_to_state(self.entity_description.key, False)
self.async_schedule_update_ha_state(force_refresh=True)
if hasattr(self.entity_description, 'update_after_switch_delay_in_sec') and self.entity_description.update_after_switch_delay_in_sec > 0:
await asyncio.sleep(self.entity_description.update_after_switch_delay_in_sec)
self.async_schedule_update_ha_state(force_refresh=True)

except ValueError:
return "unavailable"

Expand Down

0 comments on commit 327b78a

Please sign in to comment.