commit 46f208349000745c824c081f256d9991932c0453 Author: Daniel Häfliger Date: Fri Apr 12 16:52:15 2024 +0200 Initial commit, Json formatting, engine, user, producer und meter erstellt. diff --git a/__pycache__/energyuser.cpython-39.pyc b/__pycache__/energyuser.cpython-39.pyc new file mode 100644 index 0000000..2e4aaa2 Binary files /dev/null and b/__pycache__/energyuser.cpython-39.pyc differ diff --git a/client/Energydistributer.py b/client/Energydistributer.py new file mode 100644 index 0000000..90c1ba6 --- /dev/null +++ b/client/Energydistributer.py @@ -0,0 +1,54 @@ + + +class Energydistributer(): + @staticmethod + def distribute_energy(energy_users, current_power): + remaining_power = current_power - sum(user.current_delta_power for user in energy_users) + + # Filtere Benutzer mit idle = True + idle_energy_users = [user for user in energy_users if user.idle] + + # Erweitere die Schritte für modulare Benutzer + for user in idle_energy_users: + if user.modular: + user.powersteps = list(range(min(user.powersteps), max(user.powersteps) + 1)) + + # Sortiere die Benutzer nach ihrer Priorität und dann nach ihrer ID + idle_energy_users.sort(key=lambda x: (x.user_prio, x.used_energy)) + + # Schleife durch alle Prioritäten + priorities = set(user.user_prio for user in idle_energy_users) + for priority in priorities: + # Benutzer mit gleicher Priorität sammeln + same_priority_users = [u for u in idle_energy_users if u.user_prio == priority] + if not same_priority_users: + continue + + # Sammle alle Schritte der Benutzer in einem Array + all_steps = [] + for user in same_priority_users: + all_steps.extend([(user, step) for step in user.powersteps]) + + # Sortiere die Schritte nach Größe + all_steps.sort(key=lambda x: x[1]) + + # Variable zur Verfolgung der bereitgestellten Energie für jeden Benutzer + user_energy_prov = {user: 0 for user in same_priority_users} + + # Iteriere durch alle Schritte + for user, powerstep in all_steps: + # Überprüfe, ob noch genügend verbleibende Energie für den nächsten Schritt vorhanden ist + if remaining_power >= powerstep - user_energy_prov[user]: + # Aktualisiere die verbleibende Energie und die bereitgestellte Energie für den Benutzer + remaining_power -= (powerstep - user_energy_prov[user]) + user_energy_prov[user] = powerstep + + # Verteile die bereitgestellte Energie auf die Benutzer + for user in same_priority_users: + user.use_energy(user_energy_prov[user]) + + print("Final state after distributing power:") + for user in energy_users: + print(f"{user.ID}: {user.used_energy}") + + \ No newline at end of file diff --git a/client/JsonHandling.py b/client/JsonHandling.py new file mode 100644 index 0000000..677ba62 --- /dev/null +++ b/client/JsonHandling.py @@ -0,0 +1,79 @@ +import json +import os +import serverrequests as serverrequests +import JsonHandling +import energymeter +import energyproducer +import energyuser +import datetime + +class JsonHandling: + + @staticmethod + def check_config_has_changed(json_data): + data = json.loads(json_data) + return data["metadata"]["config_has_changed"] == "1" + + +class DataCollector: + def __init__(self): + self.data = {"timestamps": []} + self.now = datetime.datetime.now() + + + def collect_and_store_data(self, producer_values, meter_values, user_values): + + print("a") + if self.now.minute == datetime.datetime.now().minute: + print("b") + + return + self.now = datetime.datetime.now() + print("cccccccc") + + timestamp = self.now.strftime("%Y-%m-%d %H:%M") + self.data["timestamps"].append(timestamp) + # Werte für Produzenten hinzufügen + for producer_id, values in producer_values.items(): + if producer_id not in self.data: + self.data[producer_id] = {} + self.data[producer_id]["values"] = self.update_values(self.data[producer_id].get("values", {}), values) + + # Werte für Meter hinzufügen + for meter_id, values in meter_values.items(): + if meter_id not in self.data: + self.data[meter_id] = {} + self.data[meter_id]["values"] = self.update_values(self.data[meter_id].get("values", {}), values) + + # Werte für Benutzer hinzufügen + for user_id, values in user_values.items(): + if user_id not in self.data: + self.data[user_id] = {} + self.data[user_id]["values"] = self.update_values(self.data[user_id].get("values", {}), values) + + # Begrenzung der Daten auf die letzten 24 Stunden (1440 Minuten) + if len(self.data["timestamps"]) > 1440: + self.data["timestamps"].pop(0) + for key in self.data.keys(): + if key != "timestamps": + for value_key in self.data[key]["values"]: + self.data[key]["values"][value_key].pop(0) + + + if os.path.exists("data.json"): + with open("data.json", "r") as file: + existing_data = json.load(file) + existing_data.update(self.data) + self.data = existing_data + + # Daten als JSON speichern + with open("data.json", "w") as file: + json.dump(self.data, file) + + + def update_values(self, current_values, new_values): + for key, value in new_values.items(): + if key not in current_values: + current_values[key] = [] + current_values[key].append(value) + return current_values \ No newline at end of file diff --git a/client/__pycache__/JsonHandling.cpython-39.pyc b/client/__pycache__/JsonHandling.cpython-39.pyc new file mode 100644 index 0000000..6c36a3b Binary files /dev/null and b/client/__pycache__/JsonHandling.cpython-39.pyc differ diff --git a/client/__pycache__/energymeter.cpython-39.pyc b/client/__pycache__/energymeter.cpython-39.pyc new file mode 100644 index 0000000..d160761 Binary files /dev/null and b/client/__pycache__/energymeter.cpython-39.pyc differ diff --git a/client/__pycache__/energyproducer.cpython-39.pyc b/client/__pycache__/energyproducer.cpython-39.pyc new file mode 100644 index 0000000..5f3849a Binary files /dev/null and b/client/__pycache__/energyproducer.cpython-39.pyc differ diff --git a/client/__pycache__/energyuser.cpython-39.pyc b/client/__pycache__/energyuser.cpython-39.pyc new file mode 100644 index 0000000..36ec9f0 Binary files /dev/null and b/client/__pycache__/energyuser.cpython-39.pyc differ diff --git a/client/__pycache__/main.cpython-39.pyc b/client/__pycache__/main.cpython-39.pyc new file mode 100644 index 0000000..4f98529 Binary files /dev/null and b/client/__pycache__/main.cpython-39.pyc differ diff --git a/client/__pycache__/serverrequests.cpython-39.pyc b/client/__pycache__/serverrequests.cpython-39.pyc new file mode 100644 index 0000000..709e4a9 Binary files /dev/null and b/client/__pycache__/serverrequests.cpython-39.pyc differ diff --git a/client/config.txt b/client/config.txt new file mode 100644 index 0000000..b2e86ef --- /dev/null +++ b/client/config.txt @@ -0,0 +1,20 @@ + { + "metadata":{"config_has_changed" : "1"}, + "users": [ + {"type": "User1", "config": {"ID":"Umod1","user_prio":1,"lock_prio":2}}, + {"type": "User1", "config": {"ID":"Umod3","user_prio":3,"lock_prio":4}}, + {"type": "User1", "config": {"ID":"Umod2.0","user_prio":2,"lock_prio":3}}, + {"type": "User1", "config": {"ID":"Umod2.1","user_prio":2,"lock_prio":3}}, + {"type": "User1", "config": {"ID":"Umod2.2","user_prio":2,"lock_prio":3}}, + {"type": "User1", "config": {"ID":"Umod2.3","user_prio":2,"lock_prio":3}}, + {"type": "User2", "config": {"ID":"Usta2.0","user_prio":2,"lock_prio":6}}, + {"type": "Boiler_1Stufig_Shelly", "config": {"ID":"shelly_Boiler","user_prio":2,"lock_prio":6, "shelly_ip" : "192.168.20.233", "boilerpower": 5000, "temperatur": 38}} + ], + "producers": [ + {"type": "Fronius", "config": {"ID":"Fronius_15kW","IP":"192.168.20.51","Adr":1}}, + {"type": "Fronius", "config": {"ID":"Fronius_20kW","IP":"192.168.20.51","Adr":2}} + ], + "meters": [ + {"type": "Fronius", "config": {"ID":"Meter_Fronius","IP":"192.168.20.51","Adr":1}} + ] + } \ No newline at end of file diff --git a/client/data.json b/client/data.json new file mode 100644 index 0000000..41d7638 --- /dev/null +++ b/client/data.json @@ -0,0 +1 @@ +{"timestamps": ["2024-04-12 16:43"], "Producer_sum": {"values": {"success": [true], "day_energy": [205790], "pac": [19349], "total_energy": [58877902], "year_energy": [7792097]}}, "Fronius_15kW": {"values": {"success": [true], "day_energy": [84970], "pac": [8075], "total_energy": [30943902], "year_energy": [3146688]}}, "Fronius_20kW": {"values": {"success": [true], "day_energy": [120820], "pac": [11274], "total_energy": [27934000], "year_energy": [4645409]}}, "Meter_Sum": {"values": {"success": [true], "Current_AC_Phase_1": [-10.55], "Current_AC_Phase_2": [-21.65], "Current_AC_Phase_3": [-19.2], "PowerReal_P_Sum": [-11792.6]}}, "Meter_Fronius": {"values": {"success": [true], "Current_AC_Phase_1": [-10.55], "Current_AC_Phase_2": [-21.65], "Current_AC_Phase_3": [-19.2], "PowerReal_P_Sum": [-11792.6]}}, "User_data": {"values": {"Current_Power": [0], "Used_Energy": [0], "Current_Prio": [0], "Current_deltaPower": [0], "measured_Temp": [0]}}, "Umod1": {"values": {"Current_Power": [0], "Used_Energy": [6], "Current_Prio": [1], "Current_deltaPower": [0], "measured_Temp": [0]}}, "Umod3": {"values": {"Current_Power": [0], "Used_Energy": [6], "Current_Prio": [3], "Current_deltaPower": [0], "measured_Temp": [0]}}, "Umod2.0": {"values": {"Current_Power": [0], "Used_Energy": [6], "Current_Prio": [2], "Current_deltaPower": [0], "measured_Temp": [0]}}, "Umod2.1": {"values": {"Current_Power": [0], "Used_Energy": [6], "Current_Prio": [2], "Current_deltaPower": [0], "measured_Temp": [0]}}, "Umod2.2": {"values": {"Current_Power": [0], "Used_Energy": [6], "Current_Prio": [2], "Current_deltaPower": [0], "measured_Temp": [0]}}, "Umod2.3": {"values": {"Current_Power": [0], "Used_Energy": [6], "Current_Prio": [2], "Current_deltaPower": [0], "measured_Temp": [0]}}, "Usta2.0": {"values": {"Current_Power": [0], "Used_Energy": [4], "Current_Prio": [2], "Current_deltaPower": [0], "measured_Temp": [0]}}, "Usta2.1": {"values": {"Current_Power": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "Used_Energy": [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], "Current_Prio": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], "Current_deltaPower": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}}, "shelly_Boiler": {"values": {"Current_Power": [0], "Used_Energy": [0], "Current_Prio": [2], "Current_deltaPower": [0], "measured_Temp": [25.19]}}} \ No newline at end of file diff --git a/client/energymeter.py b/client/energymeter.py new file mode 100644 index 0000000..dc1d760 --- /dev/null +++ b/client/energymeter.py @@ -0,0 +1,116 @@ +import sys +import json +import requests + +class EnergyMeter: + def __init__(self, config): + self.ID = config.get("ID") + self.IP = config.get("IP") + self.Adr = config.get("Adr") + + + def get_current_value(self): + raise NotImplementedError("Subclasses must implement use_energy method") + + + + @staticmethod + def create_meterlist_from_json(json_data): + subclasses = [cls for cls in sys.modules[__name__].__dict__.values() if isinstance(cls, type) and issubclass(cls, EnergyMeter) and cls != EnergyMeter] + + energy_meters = [] + data = json.loads(json_data) + + for user_data in data["meters"]: + user_type = user_data["type"] + user_config = user_data["config"] + for subclass in subclasses: + if user_type in subclass.__name__: + energy_meters.append(subclass(user_config)) + + return energy_meters + + @staticmethod + def get_all_current_values(meters): + data = {"Meter_Sum": {"success": True, "Current_AC_Phase_1": 0, "Current_AC_Phase_2": 0, "Current_AC_Phase_3": 0, "PowerReal_P_Sum": 0}} + for meter in meters: + if isinstance(meter, EnergyMeter): + current_value = meter.get_current_value() + meter_data = { + "success": current_value["success"], + "Current_AC_Phase_1": current_value.get("Current_AC_Phase_1", 0), + "Current_AC_Phase_2": current_value.get("Current_AC_Phase_2", 0), + "Current_AC_Phase_3": current_value.get("Current_AC_Phase_3", 0), + "PowerReal_P_Sum": current_value.get("PowerReal_P_Sum", 0) + } + data[meter.ID] = meter_data + if current_value["success"]: + data["Meter_Sum"]["success"] &= True + data["Meter_Sum"]["Current_AC_Phase_1"] += meter_data["Current_AC_Phase_1"] + data["Meter_Sum"]["Current_AC_Phase_2"] += meter_data["Current_AC_Phase_2"] + data["Meter_Sum"]["Current_AC_Phase_3"] += meter_data["Current_AC_Phase_3"] + data["Meter_Sum"]["PowerReal_P_Sum"] += meter_data["PowerReal_P_Sum"] + else: + data["Meter_Sum"]["success"] &= False + return data + + + +class Meter1(EnergyMeter): + + def __init__(self, config): + self.ID = config.get("ID") + self.IP = config.get("IP") + self.Adr = config.get("Adr") + + + def get_current_value(self): + raise NotImplementedError("Subclasses must implement use_energy method") + +class Meter2(EnergyMeter): + + def __init__(self, config): + self.ID = config.get("ID") + self.IP = config.get("IP") + self.Adr = config.get("Adr") + + + + def get_current_value(self): + + raise NotImplementedError("Subclasses must implement use_energy method") + + +class Fronius(EnergyMeter): + + def __init__(self, config): + self.ID = config.get("ID") + self.IP = config.get("IP") + self.Adr = config.get("Adr") + + + def get_current_value(self): + url = f"http://{self.IP}/solar_api/v1/GetMeterRealtimeData.cgi?Scope=System" + try: + response = requests.get(url) + if response.status_code == 200: + data = response.json() + if "Body" in data and "Data" in data["Body"]: + meter_data = data["Body"]["Data"] + if str(self.Adr) in meter_data: + meter_values = meter_data[str(self.Adr)] + current_ac_phase_1 = meter_values.get("Current_AC_Phase_1", 0) + current_ac_phase_2 = meter_values.get("Current_AC_Phase_2", 0) + current_ac_phase_3 = meter_values.get("Current_AC_Phase_3", 0) + power_real_p_sum = meter_values.get("PowerReal_P_Sum", 0) + return {"success": True, + "Current_AC_Phase_1": current_ac_phase_1, + "Current_AC_Phase_2": current_ac_phase_2, + "Current_AC_Phase_3": current_ac_phase_3, + "PowerReal_P_Sum": power_real_p_sum} + return {"success": False} + else: + return {"success": False} + except Exception as e: + print(f"An error occurred: {str(e)}") + return {"success": False} \ No newline at end of file diff --git a/client/energyproducer.py b/client/energyproducer.py new file mode 100644 index 0000000..1aec05d --- /dev/null +++ b/client/energyproducer.py @@ -0,0 +1,126 @@ +import sys +import json +import requests + +class EnergyProducer: + def __init__(self, config): + self.ID = config.get("ID") + self.IP = config.get("IP") + self.Adr = config.get("Adr") + + def get_current_value(self): + raise NotImplementedError("Subclasses must implement use_energy method") + + + @staticmethod + def create_producerlist_from_json(json_data): + subclasses = [cls for cls in sys.modules[__name__].__dict__.values() if isinstance(cls, type) and issubclass(cls, EnergyProducer) and cls != EnergyProducer] + + energy_producers = [] + data = json.loads(json_data) + + for user_data in data["producers"]: + user_type = user_data["type"] + user_config = user_data["config"] + for subclass in subclasses: + if user_type in subclass.__name__: + energy_producers.append(subclass(user_config)) + return energy_producers + + @staticmethod + def get_all_current_values(producers): + data = {"Producer_sum": {"success": True, "day_energy": 0, "pac": 0, "total_energy": 0, "year_energy": 0}} + for producer in producers: + if isinstance(producer, EnergyProducer): + current_value = producer.get_current_value() + producer_data = { + "success": current_value["success"], + "day_energy": current_value.get("day_energy", 0), + "pac": current_value.get("pac", 0), + "total_energy": current_value.get("total_energy", 0), + "year_energy": current_value.get("year_energy", 0) + } + data[producer.ID] = producer_data + if current_value["success"]: + data["Producer_sum"]["success"] &= True + data["Producer_sum"]["day_energy"] += producer_data["day_energy"] + data["Producer_sum"]["pac"] += producer_data["pac"] + data["Producer_sum"]["total_energy"] += producer_data["total_energy"] + data["Producer_sum"]["year_energy"] += producer_data["year_energy"] + else: + data["Producer_sum"]["success"] &= False + return data + +class Producer1(EnergyProducer): + + def __init__(self, config): + self.ID = config.get("ID") + self.IP = config.get("IP") + self.Adr = config.get("Adr") + + + def get_current_value(self): + raise NotImplementedError("Subclasses must implement use_energy method") + + + +class Producer2(EnergyProducer): + + def __init__(self, config): + self.ID = config.get("ID") + self.IP = config.get("IP") + self.Adr = config.get("Adr") + + + + def get_current_value(self): + raise NotImplementedError("Subclasses must implement use_energy method") + + +class Fronius(EnergyProducer): + + def __init__(self, config): + self.ID = config.get("ID") + self.IP = config.get("IP") + self.Adr = config.get("Adr") + + + def get_current_value(self): + url = f"http://{self.IP}/solar_api/v1/GetInverterRealtimeData.cgi?Scope=System" + + try: + response = requests.get(url) + + success = response.status_code == 200 + data = response.json() if success else None + + if data: + day_energy = data.get("Body", {}).get("Data", {}).get("DAY_ENERGY", {}).get("Values", {}).get(str(self.Adr)) + pac = data.get("Body", {}).get("Data", {}).get("PAC", {}).get("Values", {}).get(str(self.Adr)) + total_energy = data.get("Body", {}).get("Data", {}).get("TOTAL_ENERGY", {}).get("Values", {}).get(str(self.Adr)) + year_energy = data.get("Body", {}).get("Data", {}).get("YEAR_ENERGY", {}).get("Values", {}).get(str(self.Adr)) + return { + "success": success, + "day_energy": day_energy, + "pac": pac, + "total_energy": total_energy, + "year_energy": year_energy + } + else: + return { + "success": success, + "day_energy": None, + "pac": None, + "total_energy": None, + "year_energy": None + } + except: + return { + "success": False, + "day_energy": None, + "pac": None, + "total_energy": None, + "year_energy": None + } + + \ No newline at end of file diff --git a/client/energyuser.py b/client/energyuser.py new file mode 100644 index 0000000..f79db3b --- /dev/null +++ b/client/energyuser.py @@ -0,0 +1,222 @@ +import random +import sys +import json +import requests +class EnergyUser: + def __init__(self, config): + self.ID = config.get("ID") + self.user_prio = config.get("user_prio", 0) + self.lock_prio = config.get("lock_prio", 0) + self.idle = True + self.used_energy = 0 + self.current_power = 0 + self.current_delta_power = 0 + + self.modular = False + self.powersteps = [] + + def calc_used_power(self): + raise NotImplementedError("Subclasses must implement use_energy method") + + + + def use_energy(self, amount): + raise NotImplementedError("Subclasses must implement use_energy method") + + + + + def get_current_values(self): + raise NotImplementedError("Subclasses must implement use_energy method") + + + def get_requested_power(self): + + max_power = max(self.powersteps) + return max_power if random.choice([True, False]) else max_power + return 0 + + + + + @staticmethod + def create_userlist_from_json(json_data): + subclasses = [cls for cls in sys.modules[__name__].__dict__.values() if isinstance(cls, type) and issubclass(cls, EnergyUser) and cls != EnergyUser] + + energy_users = [] + data = json.loads(json_data) + + for user_data in data["users"]: + user_type = user_data["type"] + user_config = user_data["config"] + for subclass in subclasses: + if user_type in subclass.__name__: + energy_users.append(subclass(user_config)) + + return energy_users + + + + @staticmethod + def get_all_current_values(users): + data = {"User_data": { "Current_Power": 0, "Used_Energy": 0, "Current_Prio": 0, "Current_deltaPower": 0, "measured_Temp": 0}} + for user in users: + current_value = user.get_current_value() + userdata = { + "Current_Power": current_value.get("Current_Power", 0), + "Used_Energy": current_value.get("Used_Energy", 0), + "Current_Prio": current_value.get("Current_Prio", 0), + "Current_deltaPower": current_value.get("Current_deltaPower", 0), + "measured_Temp": current_value.get("measured_Temp", 0) + } + + data[user.ID] = userdata + return data + + + +class User1(EnergyUser): + + def __init__(self, config): + self.ID = config.get("ID") + self.user_prio = config.get("user_prio", 0) + self.lock_prio = config.get("lock_prio", 0) + self.idle = True + self.used_energy = 6 + self.current_power = 0 + self.current_delta_power = 0 + + self.modular = False + self.powersteps = [100, 600] + + + def calc_used_power(self): + pass + + + def use_energy(self, amount): + print(f"Using energy as {self.ID} with amount {amount}") + # Hier kannst du die spezifische Logik für User 1 implementieren + + def get_current_value(self): + return {"Current_Power": self.current_power, + "Used_Energy": self.used_energy, + "Current_Prio": self.user_prio, + "Idle": self.idle, + "Current_deltaPower": self.current_delta_power} + + + + + +class User2(EnergyUser): + modular = False + powersteps = [200, 400] + + def __init__(self, config): + self.ID = config.get("ID") + self.user_prio = config.get("user_prio", 0) + self.lock_prio = config.get("lock_prio", 0) + self.idle = True + self.used_energy = 4 + self.current_power = 0 + self.current_delta_power = 0 + + self.modular = False + self.powersteps = [0] + + + def calc_used_power(self): + pass + + + def use_energy(self, amount): + print(f"Using energy as {self.ID} with amount {amount}") + # Hier kannst du die spezifische Logik für User 2 implementieren + + def get_current_value(self): + return {"Current_Power": self.current_power, + "Used_Energy": self.used_energy, + "Current_Prio": self.user_prio, + "Current_deltaPower": self.current_delta_power} + + + + +class Boiler_1Stufig_Shelly(EnergyUser): + + def __init__(self, config): + self.ID = config.get("ID") + self.user_prio = config.get("user_prio", 0) + self.lock_prio = config.get("lock_prio", 0) + self.idle = True + self.used_energy = 0 + self.current_power = 0 + self.current_delta_power = 0 + + self.modular = False + self.powersteps = [0] + + self.measured_Temp =0 + # userdefinierte Variablen + self.boilerleistung = config.get("boilerpower", 0) + self.temperatur = config.get("temperatur", 0) + self.shelly_ip = config.get("shelly_ip") + + + def get_shelly_temperature(self): + try: + url = f"http://{self.shelly_ip}/status" + response = requests.get(url) + if response.status_code == 200: + data = response.json() + temperature = data.get("ext_temperature", {}).get("0", {}).get("tC") + self.measured_Temp =temperature + + return temperature + else: + print("Failed to get temperature from Shelly.") + self.measured_Temp = 0 + + return None + except Exception as e: + print(f"Error occurred while getting temperature from Shelly: {e}") + return None + + def set_shelly_output(self, state): + try: + url = f"http://{self.shelly_ip}/relay/0?turn={'on' if state else 'off'}" + response = requests.get(url) + if response.status_code != 200: + print("Failed to set Shelly output state.") + except Exception as e: + print(f"Error occurred while setting Shelly output state: {e}") + + def calc_used_power(self): + + temperature = self.get_shelly_temperature() + if temperature is not None and temperature < self.temperatur: + self.powersteps[0] = self.boilerleistung + else: + self.current_power = 0 + + def use_energy(self, amount): + if amount == self.boilerleistung: + self.set_shelly_output(True) + else: + self.set_shelly_output(False) + print(f"Using energy as {self.ID} with amount {amount}") + + def get_current_value(self): + return {"Current_Power": self.current_power, + "Used_Energy": self.used_energy, + "Current_Prio": self.user_prio, + "measured_Temp": self.measured_Temp, + + "Idle": self.idle, + "Current_deltaPower": self.current_delta_power} + + + + + diff --git a/client/engine.py b/client/engine.py new file mode 100644 index 0000000..8a6528f --- /dev/null +++ b/client/engine.py @@ -0,0 +1,54 @@ + +import serverrequests as serverrequests +import JsonHandling +import energymeter +import energyproducer +import energyuser +import time +import datetime +import json +import main +# Gehe in eine Dauerschlaufe + +ID = "SRING_TO_DEFINE" + +producer_values = [] +producers =[] + +meter_values = [] +meter = [] + +user_values = [] +users = [] + +Collector = JsonHandling.DataCollector() +data = {} + +def calcSomeStuff(): + return + + + +while True: + + # Neue Konfig holen + config = serverrequests.update_config_on_server(ID, data) + if JsonHandling.JsonHandling.check_config_has_changed(config): + producers = energyproducer.EnergyProducer.create_producerlist_from_json(config) + meter = energymeter.EnergyMeter.create_meterlist_from_json(config) + users = energyuser.EnergyUser.create_userlist_from_json(config) + + producer_values = energyproducer.EnergyProducer.get_all_current_values(producers) + meter_values = energymeter.EnergyMeter.get_all_current_values(meter) + + calcSomeStuff() + for user in users: + user.calc_used_power() + + main.EnergyUserFactory.distribute_energy(users, meter_values["Meter_Sum"]["PowerReal_P_Sum"]) + + user_values = energyuser.EnergyUser.get_all_current_values(users) + + Collector.collect_and_store_data(producer_values, meter_values, user_values) + data = Collector.data + time.sleep(5) \ No newline at end of file diff --git a/client/hey.html b/client/hey.html new file mode 100644 index 0000000..449fe32 --- /dev/null +++ b/client/hey.html @@ -0,0 +1,112 @@ + + + + + + Highcharts Line Chart + + + + + + +
+ +
+ PAC Values +
+ Success Values + + + + + diff --git a/client/main.py b/client/main.py new file mode 100644 index 0000000..a649e13 --- /dev/null +++ b/client/main.py @@ -0,0 +1,164 @@ +import json +import sys +import random +import JsonHandling as JsonHandling +from collections import defaultdict +import energyuser as energyuser +import random + +class EnergyUser: + def __init__(self, config): + self.ID = config.get("ID") + self.user_prio = config.get("user_prio", 0) + self.lock_prio = config.get("lock_prio", 0) + self.idle = True + self.used_energy = 0 + self.current_power = 0 + self.current_delta_power = 0 + + def use_energy(self, amount): + raise NotImplementedError("Subclasses must implement use_energy method") + + modular = False + powersteps = [] + + def get_requested_power(self): + + max_power = max(self.powersteps) + return max_power if random.choice([True, False]) else max_power + return 0 + +class User1(EnergyUser): + modular = True + powersteps = [100, 600] + + def __init__(self, config): + self.ID = config.get("ID") + self.user_prio = config.get("user_prio", 0) + self.lock_prio = config.get("lock_prio", 0) + self.idle = True + self.used_energy = 6 + self.current_power = 0 + self.current_delta_power = 0 + + def use_energy(self, amount): + print(f"Using energy as {self.ID} with amount {amount}") + # Hier kannst du die spezifische Logik für User 1 implementieren + + + +class User2(EnergyUser): + modular = False + powersteps = [200, 400] + + def __init__(self, config): + self.ID = config.get("ID") + self.user_prio = config.get("user_prio", 0) + self.lock_prio = config.get("lock_prio", 0) + self.idle = True + self.used_energy = 4 + self.current_power = 0 + self.current_delta_power = 0 + + + def use_energy(self, amount): + print(f"Using energy as {self.ID} with amount {amount}") + # Hier kannst du die spezifische Logik für User 2 implementieren + + + +class EnergyUserFactory: + @staticmethod + def create_from_json(json_data): + subclasses = [cls for cls in sys.modules[__name__].__dict__.values() if isinstance(cls, type) and issubclass(cls, EnergyUser) and cls != EnergyUser] + + energy_users = [] + data = json.loads(json_data) + + for user_data in data["users"]: + user_type = user_data["type"] + user_config = user_data["config"] + for subclass in subclasses: + if user_type in subclass.__name__: + energy_users.append(subclass(user_config)) + + return energy_users + + + + + @staticmethod + def get_current_available_power(): + a = random.randint(0,3000) + print(a) + return a + + @staticmethod + def distribute_energy(energy_users, current_power): + remaining_power = current_power - sum(user.current_delta_power for user in energy_users) + print(remaining_power) + # Filtere Benutzer mit idle = True + idle_energy_users = [user for user in energy_users if user.idle] + + # Erweitere die Schritte für modulare Benutzer + for user in idle_energy_users: + if user.modular: + user.powersteps = list(range(min(user.powersteps), max(user.powersteps) + 1)) + + # Sortiere die Benutzer nach ihrer Priorität und dann nach ihrer ID + idle_energy_users.sort(key=lambda x: (x.user_prio, x.used_energy)) + + # Schleife durch alle Prioritäten + priorities = set(user.user_prio for user in idle_energy_users) + for priority in priorities: + # Benutzer mit gleicher Priorität sammeln + same_priority_users = [u for u in idle_energy_users if u.user_prio == priority] + if not same_priority_users: + continue + + # Sammle alle Schritte der Benutzer in einem Array + all_steps = [] + for user in same_priority_users: + all_steps.extend([(user, step) for step in user.powersteps]) + + # Sortiere die Schritte nach Größe + all_steps.sort(key=lambda x: x[1]) + + # Variable zur Verfolgung der bereitgestellten Energie für jeden Benutzer + user_energy_prov = {user: 0 for user in same_priority_users} + + # Iteriere durch alle Schritte + for user, powerstep in all_steps: + # Überprüfe, ob noch genügend verbleibende Energie für den nächsten Schritt vorhanden ist + if remaining_power >= powerstep - user_energy_prov[user]: + # Aktualisiere die verbleibende Energie und die bereitgestellte Energie für den Benutzer + remaining_power -= (powerstep - user_energy_prov[user]) + user_energy_prov[user] = powerstep + + # Verteile die bereitgestellte Energie auf die Benutzer + for user in same_priority_users: + user.use_energy(user_energy_prov[user]) + + print("Final state after distributing power:") + for user in energy_users: + print(f"{user.ID}: {user.used_energy}") + +# Beispielverwendung +json_data = ''' +{ + "metadata":{"config_has_changed" : "0"}, + "users": [ + {"type": "User1", "config": {"ID":"Umod1","user_prio":1,"lock_prio":2}}, + {"type": "User1", "config": {"ID":"Umod3","user_prio":3,"lock_prio":4}}, + {"type": "User1", "config": {"ID":"Umod2","user_prio":2,"lock_prio":3}}, + {"type": "User1", "config": {"ID":"Umod2","user_prio":2,"lock_prio":3}}, + {"type": "User1", "config": {"ID":"Umod2","user_prio":2,"lock_prio":3}}, + {"type": "User1", "config": {"ID":"Umod2","user_prio":2,"lock_prio":3}}, + {"type": "User2", "config": {"ID":"Usta2","user_prio":2,"lock_prio":6}}, + {"type": "User2", "config": {"ID":"Usta2","user_prio":2,"lock_prio":6}} + ] +} + +''' + +# \ No newline at end of file diff --git a/client/serverrequests.py b/client/serverrequests.py new file mode 100644 index 0000000..3d5664d --- /dev/null +++ b/client/serverrequests.py @@ -0,0 +1,23 @@ +import requests + +def update_config_on_server(token, config): + ## For developement now just return json from here + with open("config.txt", 'r') as file: + json_data = file.read() + + return json_data + + + ## For server later + response = requests.post(f'http://your_server_ip:5000/update_config?token={token}', json=config) + if response.status_code == 200: + print('Config updated successfully.') + else: + print('Failed to update config.') + return response + +if __name__ == '__main__': + # Beispiel für die Verwendung der Funktion update_config_on_server + token = 'your_token' + config = {'key1': 'new_value1', 'key2': 'new_value2'} + update_config_on_server(token, config) \ No newline at end of file diff --git a/server/main.py b/server/main.py new file mode 100644 index 0000000..703b94d --- /dev/null +++ b/server/main.py @@ -0,0 +1,56 @@ +from flask import Flask, request, jsonify, abort +import os + +app = Flask(__name__) + +TOKENS_FILE = "tokens.txt" +CONFIG_DIR = "configs" + +@app.route('/getconfig', methods=['POST']) +def get_config(): + # Überprüfe, ob die erforderlichen Daten im Request vorhanden sind + if not request.json or 'token' not in request.json or 'data' not in request.json: + abort(400, 'Bad request. JSON data with "token" and "data" is required.') + + token = request.json['token'] + data = request.json['data'] + + # Überprüfe, ob der Token gültig ist + if not is_valid_token(token): + abort(401, 'Unauthorized. Invalid token.') + + # Speichere die Daten in einem Datei für das entsprechende Token + save_data(token, data) + + # Lade die Konfigurationsdatei für das Token + config = load_config(token) + + return jsonify(config) + +def is_valid_token(token): + # Überprüfe, ob der Token in der tokens.txt Datei vorhanden ist + with open(TOKENS_FILE, 'r') as file: + tokens = file.read().splitlines() + return token in tokens + +def save_data(token, data): + # Erstelle das Verzeichnis für die Konfigurationsdateien, falls es nicht existiert + if not os.path.exists(CONFIG_DIR): + os.makedirs(CONFIG_DIR) + + # Speichere die Daten in einer Datei für das entsprechende Token + with open(os.path.join(CONFIG_DIR, f'{token}.json'), 'w') as file: + file.write(jsonify(data)) + +def load_config(token): + config_file = os.path.join(CONFIG_DIR, f'{token}.json') + + # Lade die Konfigurationsdatei für das Token + if os.path.exists(config_file): + with open(config_file, 'r') as file: + return json.load(file) + else: + return {} + +if __name__ == '__main__': + app.run(debug=True)