Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 0 additions & 73 deletions packages/modules/common/tasmota.py

This file was deleted.

68 changes: 68 additions & 0 deletions packages/modules/devices/tasmota/tasmota/bat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env python3
from typing import Any, TypedDict
import logging

from modules.devices.tasmota.tasmota.config import TasmotaBatSetup
from modules.common.abstract_device import AbstractBat
from modules.common.component_type import ComponentDescriptor
from modules.common.fault_state import ComponentInfo, FaultState
from modules.common.store import get_bat_value_store
from modules.common.simcount import SimCounter
from modules.common import req
from modules.common.component_state import BatState

log = logging.getLogger(__name__)


class KwargsDict(TypedDict):
device_id: int
ip_address: str
phase: int


class TasmotaBat(AbstractBat):
def __init__(self, component_config: TasmotaBatSetup, **kwargs: Any) -> None:
self.component_config = component_config
self.kwargs: KwargsDict = kwargs

def initialize(self) -> None:
self.__device_id: int = self.kwargs['device_id']
self.__ip_address: str = self.kwargs['ip_address']
self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="speicher")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simcount und device_id wird nicht benötigt oder?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eine der Tasmota Zählervarianten gibt nur einen Gesamtzählerstand aus. Bisher war das als Import Zählerwert implementiert. Der Simcount wird für den Export Zählerstand benötigt.
Ob ['StatusSNS']['ENERGY']['Total'] den Importwert oder eine Kombination aus Im- und Export wiedergibt ist nicht bekannt.
Möglicherweise wäre auch hier der SimCount besser...

self.__phase: int = self.kwargs['phase']
self.store = get_bat_value_store(self.component_config.id)
self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config))

def update(self):
url = "http://" + self.__ip_address + "/cm?cmnd=Status%208"
response = req.get_http_session().get(url, timeout=5).json()

if 'ENERGY' in response['StatusSNS']:
currents = [0.0, 0.0, 0.0]

power = float(response['StatusSNS']['ENERGY']['Power'])
currents[self.__phase-1] = (response['StatusSNS']['ENERGY']['Current']), 0.0, 0.0
imported = float(response['StatusSNS']['ENERGY']['Total']*1000)
_, exported = self.sim_counter.sim_count(power)

bat_state = BatState(
power=power,
currents=currents,
imported=imported,
exported=exported
)
else:
power = float(response['StatusSNS']['Itron']['Power'])
imported = float(response['StatusSNS']['Itron']['E_in']*1000)
exported = float(response['StatusSNS']['Itron']['E_out']*1000)

bat_state = BatState(
power=power,
imported=imported,
exported=exported
)

self.store.set(bat_state)


component_descriptor = ComponentDescriptor(configuration_factory=TasmotaBatSetup)
28 changes: 28 additions & 0 deletions packages/modules/devices/tasmota/tasmota/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,31 @@ def __init__(self,
id: int = 0,
configuration: TasmotaCounterConfiguration = None) -> None:
super().__init__(name, type, id, configuration or TasmotaCounterConfiguration())


class TasmotaInverterConfiguration:
def __init__(self):
pass


class TasmotaInverterSetup(ComponentSetup[TasmotaInverterConfiguration]):
def __init__(self,
name: str = "Tasmota Wechselrichterzähler",
type: str = "inverter",
id: int = 0,
configuration: TasmotaInverterConfiguration = None) -> None:
super().__init__(name, type, id, configuration or TasmotaInverterConfiguration())


class TasmotaBatConfiguration:
def __init__(self):
pass


class TasmotaBatSetup(ComponentSetup[TasmotaBatConfiguration]):
def __init__(self,
name: str = "Tasmota Speicherzähler",
type: str = "bat",
id: int = 0,
configuration: TasmotaBatConfiguration = None) -> None:
super().__init__(name, type, id, configuration or TasmotaBatConfiguration())
45 changes: 41 additions & 4 deletions packages/modules/devices/tasmota/tasmota/counter.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

from modules.devices.tasmota.tasmota.config import TasmotaCounterSetup
from modules.common.abstract_device import AbstractCounter
from modules.common.tasmota import Tasmota
from modules.common.component_type import ComponentDescriptor
from modules.common.fault_state import ComponentInfo, FaultState
from modules.common.store import get_counter_value_store
from modules.common.simcount import SimCounter
from modules.common import req
from modules.common.component_state import CounterState

log = logging.getLogger(__name__)

Expand All @@ -26,14 +28,49 @@ def __init__(self, component_config: TasmotaCounterSetup, **kwargs: Any) -> None
def initialize(self) -> None:
self.__device_id: int = self.kwargs['device_id']
self.__ip_address: str = self.kwargs['ip_address']
self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="bezug")
self.__phase: int = self.kwargs['phase']
self.store = get_counter_value_store(self.component_config.id)
self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config))
self.__tasmota = Tasmota(self.__device_id, self.__ip_address, self.__phase)

def update(self):
log.debug("tasmota.counter.update: " + self.__ip_address)
counter_state = self.__tasmota.get_CounterState()
url = "http://" + self.__ip_address + "/cm?cmnd=Status%208"
response = req.get_http_session().get(url, timeout=5).json()

if 'ENERGY' in response['StatusSNS']:
voltages = [0.0, 0.0, 0.0]
powers = [0.0, 0.0, 0.0]
currents = [0.0, 0.0, 0.0]
power_factors = [0.0, 0.0, 0.0]

power = float(response['StatusSNS']['ENERGY']['Power'])
voltages[self.__phase-1] = float(response['StatusSNS']['ENERGY']['Voltage'])
powers[self.__phase-1] = float(response['StatusSNS']['ENERGY']['Power'])
currents[self.__phase-1] = float(response['StatusSNS']['ENERGY']['Current'])
power_factors[self.__phase-1] = float(response['StatusSNS']['ENERGY']['Factor'])
imported = float(response['StatusSNS']['ENERGY']['Total']*1000)
_, exported = self.sim_counter.sim_count(power)

counter_state = CounterState(
power=power,
voltages=voltages,
currents=currents,
powers=powers,
power_factors=power_factors,
imported=imported,
exported=exported
)
else:
power = float(response['StatusSNS']['Itron']['Power'])
imported = float(response['StatusSNS']['Itron']['E_in']*1000)
exported = float(response['StatusSNS']['Itron']['E_out']*1000)

counter_state = CounterState(
power=power,
imported=imported,
exported=exported
)

self.store.set(counter_state)


Expand Down
18 changes: 17 additions & 1 deletion packages/modules/devices/tasmota/tasmota/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
import logging

from modules.common.configurable_device import ComponentFactoryByType, ConfigurableDevice, IndependentComponentUpdater
from modules.devices.tasmota.tasmota.config import Tasmota, TasmotaCounterSetup
from modules.devices.tasmota.tasmota.config import Tasmota, TasmotaCounterSetup, TasmotaInverterSetup, TasmotaBatSetup
from modules.common.abstract_device import DeviceDescriptor
from modules.devices.tasmota.tasmota.counter import TasmotaCounter
from modules.devices.tasmota.tasmota.inverter import TasmotaInverter
from modules.devices.tasmota.tasmota.bat import TasmotaBat

log = logging.getLogger(__name__)

Expand All @@ -16,10 +18,24 @@ def create_counter_component(component_config: TasmotaCounterSetup):
ip_address=device_config.configuration.ip_address,
phase=int(device_config.configuration.phase))

def create_inverter_component(component_config: TasmotaInverterSetup):
return TasmotaInverter(component_config,
device_id=device_config.id,
ip_address=device_config.configuration.ip_address,
phase=int(device_config.configuration.phase))

def create_bat_component(component_config: TasmotaBatSetup):
return TasmotaBat(component_config,
device_id=device_config.id,
ip_address=device_config.configuration.ip_address,
phase=int(device_config.configuration.phase))

return ConfigurableDevice(
device_config=device_config,
component_factory=ComponentFactoryByType(
counter=create_counter_component,
inverter=create_inverter_component,
bat=create_bat_component
),
component_updater=IndependentComponentUpdater(lambda component: component.update())
)
Expand Down
64 changes: 64 additions & 0 deletions packages/modules/devices/tasmota/tasmota/inverter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env python3
from typing import Any, TypedDict
import logging

from modules.devices.tasmota.tasmota.config import TasmotaInverterSetup
from modules.common.abstract_device import AbstractInverter
from modules.common.component_type import ComponentDescriptor
from modules.common.fault_state import ComponentInfo, FaultState
from modules.common.store import get_inverter_value_store
from modules.common.simcount import SimCounter
from modules.common import req
from modules.common.component_state import InverterState

log = logging.getLogger(__name__)


class KwargsDict(TypedDict):
device_id: int
ip_address: str
phase: int


class TasmotaInverter(AbstractInverter):
def __init__(self, component_config: TasmotaInverterSetup, **kwargs: Any) -> None:
self.component_config = component_config
self.kwargs: KwargsDict = kwargs

def initialize(self) -> None:
self.__device_id: int = self.kwargs['device_id']
self.__ip_address: str = self.kwargs['ip_address']
self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="pv")
self.__phase: int = self.kwargs['phase']
self.store = get_inverter_value_store(self.component_config.id)
self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config))

def update(self):
url = "http://" + self.__ip_address + "/cm?cmnd=Status%208"
response = req.get_http_session().get(url, timeout=5).json()

if 'ENERGY' in response['StatusSNS']:
currents = [0.0, 0.0, 0.0]

power = float(response['StatusSNS']['ENERGY']['Power']) * -1
currents[self.__phase-1] = (response['StatusSNS']['ENERGY']['Current']), 0.0, 0.0
_, exported = self.sim_counter.sim_count(power)

inverter_state = InverterState(
power=power,
currents=currents,
exported=exported
)
else:
power = float(response['StatusSNS']['Itron']['Power']) * -1
exported = float(response['StatusSNS']['Itron']['E_out']*1000)

inverter_state = InverterState(
power=power,
exported=exported
)

self.store.set(inverter_state)


component_descriptor = ComponentDescriptor(configuration_factory=TasmotaInverterSetup)