Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
Update auf Version 0.1.0:
- Es können nun auch mehrere , verkettete Wechselrichter gelesen werden.
- Strukturell noch mal umgebaut
  • Loading branch information
CannonRS authored Nov 26, 2023
1 parent 3c5ce49 commit 576c14e
Show file tree
Hide file tree
Showing 2 changed files with 343 additions and 87 deletions.
151 changes: 90 additions & 61 deletions huawei_sun2000/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

from .webif import WebInterface

import time
from huawei_solar import AsyncHuaweiSolar, register_names as rn
import asyncio

Expand Down Expand Up @@ -57,17 +58,18 @@ def __init__(self, register, true_value, true_comparator, status=False):

READITEM_CYCLE_DEFAULT = 0
READITEM_CYCLE_STARTUP = -1

READITEM_DEFAULT_SLAVE = -1

class ReadItem:
def __init__(self, register, cycle=READITEM_CYCLE_DEFAULT, initialized=False):
def __init__(self, register, cycle=READITEM_CYCLE_DEFAULT, slave=READITEM_DEFAULT_SLAVE, initialized=False):
self.register = register
self.cycle = cycle
self.slave = slave
self.initialized = initialized


class Huawei_Sun2000(SmartPlugin):
PLUGIN_VERSION = '0.0.2' # (must match the version specified in plugin.yaml), use '1.0.0' for your initial plugin Release
PLUGIN_VERSION = '0.1.0' # (must match the version specified in plugin.yaml), use '1.0.0' for your initial plugin Release

def __init__(self, sh):
# Call init code of parent class (SmartPlugin)
Expand All @@ -81,8 +83,10 @@ def __init__(self, sh):

# global vars
self._read_item_dictionary = {}
self._slaves = [int(self._slave)]

asyncio.run(self.validate_equipment())
self._loop = asyncio.new_event_loop()
self._loop.run_until_complete(self.validate_equipment())

# On initialization error use:
# self._init_complete = False
Expand All @@ -94,75 +98,88 @@ def __init__(self, sh):
# self._init_complete = False
return

async def connect(self):
async def connect(self, slave):
try:
self.logger.debug(f"Connecting to {self._host}:{self._port}, slave_id {slave}")
client = await AsyncHuaweiSolar.create(self._host, self._port, self._slave)
except Exception as e:
self.logger.error(f"Error connecting {self._host}:{self._port}, slave_id {self._slave}: {e}.")
return None
if not client._client.connected:
client.stop()
self.logger.error(f"Error connecting {self._host}:{self._port}, slave_id {slave}: {e}")
return None
return client

async def read_from_inverter(self):
client = await self.connect()
if client is not None:
async def disconnect(self, client):
await client.stop()

async def inverter_read(self):
for slave in self._slaves:
try:
for item in self._read_item_dictionary:
# check for cycle
cycle = self._read_item_dictionary[item].cycle
initialized = self._read_item_dictionary[item].initialized
if not initialized or cycle == READITEM_CYCLE_DEFAULT or cycle != READITEM_CYCLE_STARTUP or cycle < item.property.last_update_age:
# get register and set item
result = await client.get(self._read_item_dictionary[item].register, self._slave)
item(result.value, self.get_shortname())
self._read_item_dictionary[item].initialized = True
client = await self.connect(slave)
if client is not None:
for item in self._read_item_dictionary:
# check for correct slave id
if self._read_item_dictionary[item].slave == slave:
# check for cycle
cycle = self._read_item_dictionary[item].cycle
initialized = self._read_item_dictionary[item].initialized
if not initialized or cycle == READITEM_CYCLE_DEFAULT or cycle != READITEM_CYCLE_STARTUP or cycle < item.property.last_update_age:
# get register and set item
result = await client.get(self._read_item_dictionary[item].register, slave)
item(result.value, self.get_shortname())
self._read_item_dictionary[item].initialized = True
await self.disconnect(client)
except Exception as e:
self.logger.error(f"Error reading register from {self._host}:{self._port}, slave_id {self._slave}: {e}.")
self.logger.error(f"inverter_read: Error reading register from {self._host}:{self._port}, slave_id {slave}: {e}")

async def write_to_inverter(self, register, value):
client = await self.connect()
if client is not None:
async def inverter_write(self, register, value):
for slave in self._slaves:
try:
await client.set(register, value, self._slave)
client = await self.connect(slave)
if client is not None:
await client.set(register, value, slave)
await self.disconnect(client)
except Exception as e:
self.logger.error(f"Error writing register '{register}' to {self._host}:{self._port}, slave_id {self._slave}: {e}.")
self.logger.error(f"Error writing register '{register}' to {self._host}:{self._port}, slave_id {slave}: {e}")

async def validate_equipment(self):
client = await self.connect()
if client is not None:
for slave in self._slaves:
try:
for equipment_key in EquipmentDictionary:
result = await client.get(EquipmentDictionary[equipment_key].register, self._slave)
if EquipmentDictionary[equipment_key].true_comparator == ">":
if result.value > EquipmentDictionary[equipment_key].true_value:
EquipmentDictionary[equipment_key].status = True
client = await self.connect(slave)
if client is not None:
for equipment_key in EquipmentDictionary:
result = await client.get(EquipmentDictionary[equipment_key].register, slave)
if EquipmentDictionary[equipment_key].true_comparator == ">":
if result.value > EquipmentDictionary[equipment_key].true_value:
EquipmentDictionary[equipment_key].status = True
else:
EquipmentDictionary[equipment_key].status = False
elif EquipmentDictionary[equipment_key].true_comparator == "<":
if result.value < EquipmentDictionary[equipment_key].true_value:
EquipmentDictionary[equipment_key].status = True
else:
EquipmentDictionary[equipment_key].status = False
else:
EquipmentDictionary[equipment_key].status = False
elif EquipmentDictionary[equipment_key].true_comparator == "<":
if result.value < EquipmentDictionary[equipment_key].true_value:
EquipmentDictionary[equipment_key].status = True
else:
EquipmentDictionary[equipment_key].status = False
else:
if result.value == EquipmentDictionary[equipment_key].true_value:
EquipmentDictionary[equipment_key].status = True
else:
EquipmentDictionary[equipment_key].status = False
if result.value == EquipmentDictionary[equipment_key].true_value:
EquipmentDictionary[equipment_key].status = True
else:
EquipmentDictionary[equipment_key].status = False
await self.disconnect(client)
except Exception as e:
self.logger.error(f"Error reading register from {self._host}:{self._port}, slave_id {self._slave}: {e}.")
self.logger.error(f"validate_equipment: Error reading register from {self._host}:{self._port}, slave_id {slave}: {e}")

def check_equipment(self, item):
if self.has_iattr(item.conf, 'equipment_part'):
equipment_key = self.get_iattr_value(item.conf, 'equipment_part')
if equipment_key in EquipmentDictionary:
self.logger.debug(f"Equipment status for item '{item.property.path}': {EquipmentDictionary[equipment_key].status}.")
self.logger.debug(f"Equipment status for item '{item.property.path}': {EquipmentDictionary[equipment_key].status}")
return EquipmentDictionary[equipment_key].status
else:
self.logger.warning(f"Invalid key for equipment_part '{equipment_key}' configured.")
self.logger.warning(f"Invalid key for equipment_part '{equipment_key}' configured")
return True

def update_slaves(self, slave: int):
if not slave in self._slaves and slave != READITEM_DEFAULT_SLAVE:
self._slaves.append(slave)

def string_to_seconds_special(self, timestring):
timestring = timestring.lower()
if timestring == "startup":
Expand Down Expand Up @@ -192,34 +209,42 @@ def string_to_seconds_special(self, timestring):
return 0

def run(self):
self.logger.debug("Run method called.")
self.logger.debug("Run method called")
self.scheduler_add('poll_device', self.poll_device, cycle=self._cycle)
self.alive = True

def stop(self):
self.logger.debug("Stop method called.")
self.logger.debug("Stop method called")
self.scheduler_remove('poll_device')
self.alive = False
self._loop.close()

def parse_item(self, item):
# check for attribute 'sun2000_read'
if self.has_iattr(item.conf, 'sun2000_read'):
self.logger.debug(f"Parse read item: {item}.")
self.logger.debug(f"Parse read item: {item}")
register = self.get_iattr_value(item.conf, 'sun2000_read')
if hasattr(rn, register):
# check equipment
if self.check_equipment(item):
self._read_item_dictionary.update({item: ReadItem(getattr(rn, register))})
# check for cycle_time
if self.has_iattr(item.conf, 'cycle_time'):
cycle = self.string_to_seconds_special(self.get_iattr_value(item.conf, 'cycle_time'))
# check for slave id
if self.has_iattr(item.conf, 'sun2000_slave'):
slave = int(self.get_iattr_value(item.conf, 'sun2000_slave'))
if slave == READITEM_DEFAULT_SLAVE:
slave = self._slave
self._read_item_dictionary[item].slave = slave
self.update_slaves(slave)
# check for sun2000_cycle
if self.has_iattr(item.conf, 'sun2000_cycle'):
cycle = self.string_to_seconds_special(self.get_iattr_value(item.conf, 'sun2000_cycle'))
self._read_item_dictionary[item].cycle = cycle
self.logger.debug(f"Item {item.property.path}, Zyklus {cycle}.")
self.logger.debug(f"Item {item.property.path}, Zyklus {cycle}")
self.logger.debug(f"Content of the dictionary _read_item_dictionary: '{self._read_item_dictionary}'")
else:
self.logger.debug(f"Equipment check skipped item '{item.property.path}'.")
self.logger.debug(f"Equipment check skipped item '{item.property.path}'")
else:
self.logger.warning(f"Invalid key for '{read_attr}' '{register}' configured.")
self.logger.warning(f"Invalid key for '{read_attr}' '{register}' configured")

def parse_logic(self, logic):
pass
Expand All @@ -231,11 +256,15 @@ def update_item(self, item, caller=None, source=None, dest=None):
register = self.get_iattr_value(item.conf, 'sun2000_write')
if hasattr(rn, register):
value = item()
asyncio.run(self.write_to_inverter(register, value))
self.logger.debug(f"Update_item was called with item {item.property.path} from caller {caller}, source {source} and dest {dest}.")
while self._loop.is_running():
time.sleep(1)
self._loop.run_until_complete(inverter_write(register, value))
self.logger.debug(f"Update_item was called with item {item.property.path} from caller {caller}, source {source} and dest {dest}")
else:
self.logger.warning(f"Invalid key for sun2000_write '{register}' configured.")
self.logger.warning(f"Invalid key for sun2000_write '{register}' configured")

def poll_device(self):
if self.alive:
asyncio.run(self.read_from_inverter())
self.logger.debug(f"List of all known slaves: {self._slaves}")
if not self._loop.is_running():
self._loop.run_until_complete(self.inverter_read())
Loading

0 comments on commit 576c14e

Please sign in to comment.