update to 1.0.2

This commit is contained in:
Norbert
2024-07-12 12:13:55 +02:00
parent 3a0fc1f9cd
commit 577596d9f3
44 changed files with 5860 additions and 1957 deletions

View File

@@ -1,108 +0,0 @@
from datetime import datetime, timedelta
from pymodbus.client import ModbusSerialClient
from solaxx3.rs485 import SolaxX3
import mysql.connector
s = SolaxX3(port="/dev/ttyUSB0", baudrate=115200)
database_ip = "172.17.7.77"
if s.connect():
s.read_all_registers()
# read the stats from the inverter
battery_capacity = s.read("battery_capacity")[0]
feed_in_today = s.read("feed_in_energy_today")[0]
consumtion_today = s.read("consumption_energy_today")[0]
battery_charging = s.read("battery_power_charge1")[0]
grid_voltage_r = s.read("grid_voltage_r")[0]
grid_voltage_s = s.read("grid_voltage_s")[0]
grid_voltage_t = s.read("grid_voltage_t")[0]
run_mode = s.read("run_mode")[0]
time_count_down = s.read("time_count_down")[0]
inverter_ac_power = s.read("grid_power")[0]
etoday_togrid = s.read("energy_to_grid_today")[0]
solar_energy_today = s.read("solar_energy_today")[0]
echarge_today = s.read("echarge_today")[0]
energy_from_grid = s.read("energy_from_grid_meter")[0]
energy_to_grid = s.read("energy_to_grid_meter")[0]
power_to_ev = s.read("power_to_ev")[0]
feed_in_power = s.read("feed_in_power")[0]
output_energy_charge = s.read("output_energy_charge")[0]
output_energy_today = s.read("output_energy_charge_today")[0]
input_energy_today = s.read("input_energy_charge_today")[0]
power_dc1 = s.read("power_dc1")[0]
power_dc2 = s.read("power_dc2")[0]
total_power = power_dc1 + power_dc2
uploadTime = s.read("rtc_datetime")[0]
uploadDate = uploadTime.date()
timezone_difference_from_utc = 2
uploadTime = uploadTime - timedelta(hours=timezone_difference_from_utc, minutes=0)
# store the stats in the database
mydb = mysql.connector.connect(
host=database_ip, user="root", passwd="rootroot", database="solax"
)
mycursor = mydb.cursor()
try:
# create the sql statement
sql = """REPLACE INTO solax_local (
uploadTime,
inverter_status,
dc_solar_power,
grid_voltage_r,
grid_voltage_s,
grid_voltage_t,
battery_capacity,
battery_power,
feed_in_power,
time_count_down,
inverter_ac_power,
consumeenergy,
feedinenergy,
power_dc1,
power_dc2
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
"""
values = (
uploadTime,
run_mode,
total_power,
grid_voltage_r,
grid_voltage_s,
grid_voltage_t,
battery_capacity,
battery_charging,
feed_in_power,
time_count_down,
inverter_ac_power,
energy_from_grid,
energy_to_grid,
power_dc1,
power_dc2,
)
mycursor.execute(sql, values)
mydb.commit()
# update daily values
sql = """REPLACE INTO solax_daily (
uploadDate,
feed_in,
total_yield
) VALUES (%s, %s, %s)
"""
values = (uploadDate, feed_in_today, etoday_togrid)
mycursor.execute(sql, values)
mydb.commit()
except mysql.connector.Error as error:
print("parameterized query failed {}".format(error))
else:
print("Cannot connect to the Modbus Server/Slave")
exit()

View File

@@ -0,0 +1,19 @@
"""Module containing an abstract class."""
from abc import ABC, abstractmethod
class DataSourceDb(ABC):
"""Abstract class representing a data source."""
@abstractmethod
def save_record(self):
"""Transfer some data."""
raise NotImplementedError
@abstractmethod
def bulk_save(self):
"""Transfer multiple records of data."""
raise NotImplementedError

View File

@@ -0,0 +1,89 @@
from typing import Any, Dict, List, Tuple
import mysql.connector
from .data_source_db import DataSourceDb
class MySQLDataSource(DataSourceDb):
def __init__(self, mysql_connection_info: Dict[str, str]) -> None:
self.user = mysql_connection_info["user"]
self.host = mysql_connection_info["host"]
self.password = mysql_connection_info["password"]
def save_record(
self,
database: str,
tablename: str,
data: Dict[str, Any],
use_obj_connection: bool = False,
close_obj_connection: bool = True,
):
query, values = self.create_query(tablename, data)
if use_obj_connection:
try:
self.cursor.execute(query, values)
if close_obj_connection:
self.db.commit()
self.db.close()
except mysql.connector.Error:
self.db.commit()
self.db.close()
raise
else:
db = mysql.connector.connect(
user=self.user,
host=self.host,
password=self.password,
database=database,
)
try:
cursor = db.cursor()
cursor.execute(query, values)
db.commit()
db.close()
except mysql.connector.Error:
db.close()
raise
def bulk_save(self, export_data: List[Dict[str, Any]]) -> None:
for index, unit in enumerate(export_data):
database, table_name, data = unit.values()
if (
not hasattr(self, "db")
or not hasattr(self, "cursor")
or not self.db.is_connected()
):
self.db = mysql.connector.connect(
user=self.user,
host=self.host,
password=self.password,
database=database,
)
try:
self.cursor = self.db.cursor()
except:
self.db.close()
raise
self.save_record(
database, table_name, data, True, index + 1 == len(export_data)
)
def create_query(self, table_name: str, data: dict) -> Tuple[str, list]:
columns = list(data.keys())
values = list(data.values())
query = (
f"REPLACE INTO {table_name} ("
+ ", ".join(columns)
+ ") VALUES ("
+ ", ".join(["%s"] * len(columns))
+ ")"
)
return (query, values)

View File

@@ -0,0 +1,93 @@
"""Example of reading and saving some inverter registers."""
import sys
from datetime import datetime, timedelta
from os import environ
from solaxx3.solaxx3 import SolaxX3
from .mysql_data_source import MySQLDataSource
def _get_datetime(inverter_time: datetime) -> datetime:
return inverter_time - timedelta(hours=TIMEZONE_OFFSET)
MYSQL_CONNECTION_INFO = {
"user": environ["MYSQL_DB_USERNAME"],
"host": environ["MYSQL_DB_HOST_IP"],
"password": environ["MYSQL_DB_PASSWORD"],
}
DATABASE = environ["MYSQL_DB_DATABASE"]
TIMEZONE_OFFSET = 2
s = SolaxX3(port="/dev/ttyUSB0", baudrate=115200)
if not s.connect():
print("Could not connect to inverter")
sys.exit(1)
s.read_all_registers()
mysql_export_data = [
{
"database": DATABASE,
"table": "solax_local",
"data": {
"uploadTime": _get_datetime(s.read("rtc_datetime")[0]),
"inverter_status": s.read("run_mode")[0],
"dc_solar_power": s.read("power_dc1")[0] + s.read("power_dc2")[0],
"grid_voltage_r": s.read("grid_voltage_r")[0],
"grid_voltage_s": s.read("grid_voltage_s")[0],
"grid_voltage_t": s.read("grid_voltage_t")[0],
"battery_capacity": s.read("battery_capacity")[0],
"battery_power": s.read("battery_power_charge1")[0],
"feed_in_power": s.read("feed_in_power")[0],
"time_count_down": s.read("time_count_down")[0],
"inverter_ac_power": s.read("grid_power")[0],
"consumeenergy": s.read("energy_from_grid_meter")[0],
"feedinenergy": s.read("energy_to_grid_meter")[0],
"power_dc1": s.read("power_dc1")[0],
"power_dc2": s.read("power_dc2")[0],
"inv_volt_r": s.read("inv_volt_r")[0],
"inv_volt_s": s.read("inv_volt_s")[0],
"inv_volt_t": s.read("inv_volt_t")[0],
"off_grid_power_active_r": s.read("off_grid_power_active_r")[0],
"off_grid_power_active_s": s.read("off_grid_power_active_s")[0],
"off_grid_power_active_t": s.read("off_grid_power_active_t")[0],
"grid_power_r": s.read("grid_power_r")[0],
"grid_power_s": s.read("grid_power_s")[0],
"grid_power_t": s.read("grid_power_t")[0],
},
},
{
"database": DATABASE,
"table": "solax_daily",
"data": {
"uploadDate": _get_datetime(s.read("rtc_datetime")[0]).date(),
"feed_in": s.read("feed_in_energy_today")[0],
"total_yield": s.read("energy_to_grid_today")[0],
},
},
]
mysql_data_source = MySQLDataSource(MYSQL_CONNECTION_INFO)
def bulk_save():
"""Save collected data."""
mysql_data_source.bulk_save(mysql_export_data)
def _transfer(index: int, **extras) -> None:
"""Save a record of collected data."""
data_record = mysql_export_data[index]
database, tablename = data_record["database"], data_record["table"]
data = data_record["data"]
mysql_data_source.save_record(database, tablename, data, **extras)
save = bulk_save
if __name__ == "__main__":
save()

View File

@@ -1,25 +1,36 @@
CREATE TABLE `solax_daily` (
`uploadDate` date NOT NULL,
`feed_in` float(6,1) DEFAULT NULL,
`total_yield` float(6,1) DEFAULT NULL,
PRIMARY KEY (`uploadDate`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE solax_daily (
uploadDate DATE NOT NULL,
feed_in FLOAT NULL,
total_yield FLOAT NULL
)
ENGINE=InnoDB
DEFAULT CHARSET=latin1;
CREATE TABLE `solax_local` (
`uploadTime` datetime NOT NULL,
`inverter_status` tinyint(4) DEFAULT NULL,
`dc_solar_power` smallint(6) DEFAULT NULL,
`grid_voltage_r` smallint(6) DEFAULT NULL,
`grid_voltage_s` smallint(6) DEFAULT NULL,
`grid_voltage_t` smallint(6) DEFAULT NULL,
`battery_capacity` tinyint(4) DEFAULT NULL,
`battery_power` smallint(6) DEFAULT NULL,
`feed_in_power` smallint(6) DEFAULT NULL,
`time_count_down` smallint(6) DEFAULT NULL,
`inverter_ac_power` smallint(6) DEFAULT NULL,
`consumeenergy` float(7,1) DEFAULT NULL,
`feedinenergy` float(7,1) DEFAULT NULL,
`power_dc1` smallint(6) DEFAULT NULL,
`power_dc2` smallint(6) DEFAULT NULL,
PRIMARY KEY (`uploadTime`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE solax_local (
uploadTime DATETIME NOT NULL,
inverter_status TINYINT NULL,
dc_solar_power SMALLINT NULL,
grid_voltage_r SMALLINT NULL,
grid_voltage_s SMALLINT NULL,
grid_voltage_t SMALLINT NULL,
battery_capacity TINYINT NULL,
battery_power SMALLINT NULL,
feed_in_power SMALLINT NULL,
time_count_down SMALLINT NULL,
inverter_ac_power SMALLINT NULL,
consumeenergy FLOAT NULL,
feedinenergy FLOAT NULL,
power_dc1 SMALLINT NULL,
power_dc2 SMALLINT NULL,
inv_volt_r SMALLINT NULL,
inv_volt_s SMALLINT NULL,
inv_volt_t SMALLINT NULL,
off_grid_power_active_r INTEGER NULL,
off_grid_power_active_s INTEGER NULL,
off_grid_power_active_t INTEGER NULL,
grid_power_r INTEGER NULL,
grid_power_s INTEGER NULL,
grid_power_t INTEGER NULL
)
ENGINE=InnoDB
DEFAULT CHARSET=latin1;