from aurorapy.client import AuroraTCPClient, AuroraError
import json
from datetime import datetime, timedelta
import time

# Konfiguration
TARGET_IP = "192.168.250.245"
TARGET_PORT = 5000
INVERTER_ADDRESS = 2  # Slave-ID deines Wechselrichters

def measure_with_retry(client, code, retries=2):
    for attempt in range(retries + 1):
        try:
            value = client.measure(code)
            # Filtere nur extrem kleine oder extrem große Werte, die offensichtlich unplausibel sind
            if (abs(value) < 1e-30 and value != 0.0) or abs(value) > 1e10:
                return "Wert unplausibel"
            return value
        except AuroraError as e:
            if "Reading Timeout" in str(e) and attempt < retries:
                time.sleep(1)  # Warte 1 Sekunde vor dem nächsten Versuch
                continue
            return f"Fehler: {str(e)}"
    return "Maximale Anzahl von Wiederholungen erreicht"

def test_comprehensive_data_all_measures():
    try:
        client = AuroraTCPClient(ip=TARGET_IP, port=TARGET_PORT, address=INVERTER_ADDRESS, timeout=10)
        client.connect()

        # Daten abfragen
        data = {}

        # 50: State Request
        try:
            data["global_state"] = client.state(1)
        except AttributeError:
            data["global_state"] = "Methode nicht verfügbar"

        try:
            data["inverter_state"] = client.state(2)
        except AttributeError:
            data["inverter_state"] = "Methode nicht verfügbar"

        try:
            data["DCDC_ch1_state"] = client.state(3)
        except AttributeError:
            data["DCDC_ch1_state"] = "Methode nicht verfügbar"

        try:
            data["DCDC_ch2_state"] = client.state(4)
        except AttributeError:
            data["DCDC_ch2_state"] = "Methode nicht verfügbar"

        try:
            data["alarm_state"] = client.state(5)
        except AttributeError:
            data["alarm_state"] = "Methode nicht verfügbar"

        # 58: Version Reading
        try:
            data["version"] = client.version()
        except AttributeError:
            data["version"] = "Methode nicht verfügbar"

        # 63: Serial Number Reading
        try:
            data["serial_number"] = client.serial_number()
        except AttributeError:
            data["serial_number"] = "Methode nicht verfügbar"

        # 65: Manufacturing Week and Year
        try:
            data["manufacturing_week_year"] = client.manufacturing_week_year()
        except AttributeError:
            try:
                data["manufacturing_week_year"] = client.manufacturing_date()
            except AttributeError:
                data["manufacturing_week_year"] = "Methode nicht verfügbar"

        # 68: Cumulated Float Energy Readings
        try:
            data["daily_energy_float"] = client.cumulated_energy(period=1)
            data["week_energy_float"] = client.cumulated_energy(period=2)
            data["month_energy_float"] = client.cumulated_energy(period=3)
        except AttributeError:
            data["cumulated_float_energy"] = "Methode nicht verfügbar"

        # 70: Time/Date Reading
        try:
            seconds_since_2000 = client.time_date()
            data["time_date"] = (datetime(2000, 1, 1) + timedelta(seconds=seconds_since_2000)).strftime("%Y-%m-%d %H:%M:%S")
        except AttributeError:
            data["time_date"] = "Methode nicht verfügbar"

        # 72: Firmware Release Reading
        try:
            data["firmware_micro_release_C"] = client.firmware(3)
        except AttributeError:
            data["firmware_micro_release_C"] = "Methode nicht verfügbar"

        # 78: Cumulated Energy Readings
        try:
            data["daily_energy"] = client.cumulated_energy(1)
            data["week_energy"] = client.cumulated_energy(2)
            data["month_energy"] = client.cumulated_energy(3)
            data["year_energy"] = client.cumulated_energy(4)
            data["total_energy"] = client.cumulated_energy(5)
        except AttributeError:
            data["cumulated_energy"] = "Methode nicht verfügbar"

        # 86: Last Four Alarms
        try:
            data["last_four_alarms"] = client.alarms()
        except AttributeError:
            data["last_four_alarms"] = "Methode nicht verfügbar"

        # 59: Measure Requests
        measure_codes = {
            1: "grid_voltage",
            2: "grid_current",
            3: "grid_power",
            4: "frequency",
            5: "vbulk",
            6: "ileak_dc_dc",
            7: "ileak_inverter",
            8: "pin1",
            9: "pin2",
            21: "inverter_temperature",
            22: "booster_temperature",
            23: "input_1_voltage",
            25: "input_1_current",
            26: "input_2_voltage",
            27: "input_2_current",
            28: "grid_voltage_dc_dc",
            29: "grid_frequency_dc_dc",
            30: "isolation_resistance",
            31: "vbulk_dc_dc",
            32: "average_grid_voltage",
            33: "vbulk_mid",
            34: "power_peak",
            35: "power_peak_today",
            36: "grid_voltage_neutral",
            37: "wind_generator_frequency",
            38: "grid_voltage_neutral_phase",
            39: "grid_current_phase_r",
            40: "grid_current_phase_s",
            41: "grid_current_phase_t",
            42: "frequency_phase_r",
            43: "frequency_phase_s",
            44: "frequency_phase_t",
            45: "vbulk_plus",
            46: "vbulk_minus",
            47: "supervisor_temperature",
            48: "alim_temperature",
            49: "heat_sink_temperature",
            50: "temperature_1",
            51: "temperature_2",
            52: "temperature_3",
            53: "fan_1_speed",
            54: "fan_2_speed",
            55: "fan_3_speed",
            56: "fan_4_speed",
            57: "fan_5_speed",
            58: "power_saturation_limit",
            59: "riferimento_anello_bulk",
            60: "vpanel_micro",
            61: "grid_voltage_phase_r",
            62: "grid_voltage_phase_s",
            63: "grid_voltage_phase_t"
        }

        for code, name in measure_codes.items():
            try:
                data[name] = measure_with_retry(client, code)
            except AttributeError:
                data[name] = "Methode nicht verfügbar"
            except Exception as e:
                data[name] = f"Fehler: {str(e)}"

        client.close()

        # Daten als JSON speichern
        with open('comprehensive_data_all_measures.json', 'w') as f:
            json.dump(data, f, indent=4)

        print("Daten erfolgreich in 'comprehensive_data_all_measures.json' gespeichert.")

    except AuroraError as e:
        print(f"Fehler bei der Kommunikation: {str(e)}")
    except Exception as e:
        print(f"Allgemeiner Fehler: {str(e)}")

def test_all_sensor_parameters():
    """Testet alle Parameter aus sensor.py, sortiert nach Kategorien."""
    try:
        client = AuroraTCPClient(ip=TARGET_IP, port=TARGET_PORT, address=INVERTER_ADDRESS, timeout=10)
        client.connect()

        # Symbol-Mapping für die Ausgabe
        icon_mapping = {
            "DSP_GRID_POWER": "🌞",
            "DSP_DAILY_ENERGY": "🌞",
            "DSP_TOTAL_ENERGY": "📊",
            "DSP_DC_POWER": "🌞",
            "DSP_MPPT_POWER": "🌞",
            "DSP_POWER_PEAK": "🌞",
            "DSP_POWER_PEAK_TODAY": "🌞",
            "DSP_PIN1": "🌞",
            "DSP_PIN2": "🌞",
            "DSP_GRID_VOLTAGE": "⚡",
            "DSP_GRID_CURRENT": "🔌",
            "DSP_GRID_FREQUENCY": "🔄",
            "DSP_PF": "🔄",
            "DSP_AVERAGE_GRID_VOLTAGE": "⚡",
            "DSP_DC_VOLTAGE": "⚡",
            "DSP_DC_CURRENT": "🔌",
            "DSP_INPUT_2_VOLTAGE": "⚡",
            "DSP_INPUT_2_CURRENT": "🔌",
            "DSP_VBULK": "⚡",
            "DSP_VBULK_DC_DC": "⚡",
            "DSP_VBULK_MID": "⚡",
            "DSP_VBULK_PLUS": "⚡",
            "DSP_VBULK_MINUS": "⚡",
            "DSP_GRID_VOLTAGE_DC_DC": "⚡",
            "DSP_GRID_VOLTAGE_NEUTRAL": "⚡",
            "DSP_GRID_VOLTAGE_NEUTRAL_PHASE": "⚡",
            "DSP_VPANEL_MICRO": "⚡",
            "DSP_GRID_CURRENT_PHASE_R": "🔌",
            "DSP_GRID_CURRENT_PHASE_S": "🔌",
            "DSP_GRID_CURRENT_PHASE_T": "🔌",
            "DSP_FREQUENCY_PHASE_R": "🔄",
            "DSP_FREQUENCY_PHASE_S": "🔄",
            "DSP_FREQUENCY_PHASE_T": "🔄",
            "DSP_GRID_VOLTAGE_PHASE_R": "⚡",
            "DSP_GRID_VOLTAGE_PHASE_S": "⚡",
            "DSP_GRID_VOLTAGE_PHASE_T": "⚡",
            "DSP_TEMPERATURE": "🌡️",
            "DSP_RADIATOR_TEMP": "🌡️",
            "DSP_AMBIENT_TEMP": "🌡️",
            "DSP_SUPERVISOR_TEMPERATURE": "🌡️",
            "DSP_ALIM_TEMPERATURE": "🌡️",
            "DSP_HEAT_SINK_TEMPERATURE": "🌡️",
            "DSP_TEMPERATURE_1": "🌡️",
            "DSP_TEMPERATURE_2": "🌡️",
            "DSP_TEMPERATURE_3": "🌡️",
            "DSP_FAN_1_SPEED": "💨",
            "DSP_FAN_2_SPEED": "💨",
            "DSP_FAN_3_SPEED": "💨",
            "DSP_FAN_4_SPEED": "💨",
            "DSP_FAN_5_SPEED": "💨",
            "DSP_ILEAK_DC_DC": "🔌",
            "DSP_ILEAK_INVERTER": "🔌",
            "DSP_ISOLATION": "🔌",
            "DSP_OPERATING_HOURS": "⏱️",
            "DSP_POWER_SATURATION_LIMIT": "🌞",
            "DSP_RIFERIMENTO_ANELLO_BULK": "🔄",
            "DSP_ALARMS": "⚠️",
            "DSP_FAULT_CODE": "⚠️",
            "DSP_STATUS": "ℹ️",
            "DSP_EVENTS": "ℹ️",
            "DSP_LAST_ERROR": "⚠️",
            "DSP_SERIAL_NUMBER": "🆔",
            "DSP_MODEL": "📋",
            "DSP_VERSION": "📋",
            "DSP_GRID_FREQUENCY_DC_DC": "🔄",
            "DSP_WIND_GENERATOR_FREQUENCY": "🔄",
        }

        # Strukturierte Daten nach Kategorien
        structured_data = {
            "1. Leistung und Energie": {},
            "2. Netzparameter": {},
            "3. Gleichstromkreis": {},
            "4. Spannungen": {},
            "5. Phasenbezogene Werte": {},
            "6. Temperaturen": {},
            "7. Lüftergeschwindigkeiten": {},
            "8. Leckströme": {},
            "9. Diagnose": {},
            "10. Status und Alarme": {},
            "11. Metadaten": {},
        }

        # 1. Leistung und Energie
        structured_data["1. Leistung und Energie"]["DSP_GRID_POWER"] = measure_with_retry(client, 3)
        structured_data["1. Leistung und Energie"]["DSP_DAILY_ENERGY"] = client.cumulated_energy(0)
        structured_data["1. Leistung und Energie"]["DSP_TOTAL_ENERGY"] = client.cumulated_energy(1) * 0.1
        structured_data["1. Leistung und Energie"]["DSP_DC_POWER"] = measure_with_retry(client, 12)
        structured_data["1. Leistung und Energie"]["DSP_MPPT_POWER"] = measure_with_retry(client, 16)
        structured_data["1. Leistung und Energie"]["DSP_POWER_PEAK"] = measure_with_retry(client, 34)
        structured_data["1. Leistung und Energie"]["DSP_POWER_PEAK_TODAY"] = measure_with_retry(client, 35)
        structured_data["1. Leistung und Energie"]["DSP_PIN1"] = measure_with_retry(client, 8)
        structured_data["1. Leistung und Energie"]["DSP_PIN2"] = measure_with_retry(client, 9)

        # 2. Netzparameter
        structured_data["2. Netzparameter"]["DSP_GRID_VOLTAGE"] = measure_with_retry(client, 1)
        structured_data["2. Netzparameter"]["DSP_GRID_CURRENT"] = measure_with_retry(client, 2)
        structured_data["2. Netzparameter"]["DSP_GRID_FREQUENCY"] = measure_with_retry(client, 4)
        structured_data["2. Netzparameter"]["DSP_PF"] = measure_with_retry(client, 9)
        structured_data["2. Netzparameter"]["DSP_AVERAGE_GRID_VOLTAGE"] = measure_with_retry(client, 32)

        # 3. Gleichstromkreis
        structured_data["3. Gleichstromkreis"]["DSP_DC_VOLTAGE"] = measure_with_retry(client, 23)
        structured_data["3. Gleichstromkreis"]["DSP_DC_CURRENT"] = measure_with_retry(client, 25)
        structured_data["3. Gleichstromkreis"]["DSP_INPUT_2_VOLTAGE"] = measure_with_retry(client, 26)
        structured_data["3. Gleichstromkreis"]["DSP_INPUT_2_CURRENT"] = measure_with_retry(client, 27)

        # 4. Spannungen
        structured_data["4. Spannungen"]["DSP_VBULK"] = measure_with_retry(client, 5)
        structured_data["4. Spannungen"]["DSP_VBULK_DC_DC"] = measure_with_retry(client, 31)
        structured_data["4. Spannungen"]["DSP_VBULK_MID"] = measure_with_retry(client, 33)
        structured_data["4. Spannungen"]["DSP_VBULK_PLUS"] = measure_with_retry(client, 45)
        structured_data["4. Spannungen"]["DSP_VBULK_MINUS"] = measure_with_retry(client, 46)
        structured_data["4. Spannungen"]["DSP_GRID_VOLTAGE_DC_DC"] = measure_with_retry(client, 28)
        structured_data["4. Spannungen"]["DSP_GRID_VOLTAGE_NEUTRAL"] = measure_with_retry(client, 36)
        structured_data["4. Spannungen"]["DSP_GRID_VOLTAGE_NEUTRAL_PHASE"] = measure_with_retry(client, 38)
        structured_data["4. Spannungen"]["DSP_VPANEL_MICRO"] = measure_with_retry(client, 60)

        # 5. Phasenbezogene Werte
        structured_data["5. Phasenbezogene Werte"]["DSP_GRID_CURRENT_PHASE_R"] = measure_with_retry(client, 39)
        structured_data["5. Phasenbezogene Werte"]["DSP_GRID_CURRENT_PHASE_S"] = measure_with_retry(client, 40)
        structured_data["5. Phasenbezogene Werte"]["DSP_GRID_CURRENT_PHASE_T"] = measure_with_retry(client, 41)
        structured_data["5. Phasenbezogene Werte"]["DSP_FREQUENCY_PHASE_R"] = measure_with_retry(client, 42)
        structured_data["5. Phasenbezogene Werte"]["DSP_FREQUENCY_PHASE_S"] = measure_with_retry(client, 43)
        structured_data["5. Phasenbezogene Werte"]["DSP_FREQUENCY_PHASE_T"] = measure_with_retry(client, 44)
        structured_data["5. Phasenbezogene Werte"]["DSP_GRID_VOLTAGE_PHASE_R"] = measure_with_retry(client, 61)
        structured_data["5. Phasenbezogene Werte"]["DSP_GRID_VOLTAGE_PHASE_S"] = measure_with_retry(client, 62)
        structured_data["5. Phasenbezogene Werte"]["DSP_GRID_VOLTAGE_PHASE_T"] = measure_with_retry(client, 63)

        # 6. Temperaturen
        structured_data["6. Temperaturen"]["DSP_TEMPERATURE"] = measure_with_retry(client, 21)
        structured_data["6. Temperaturen"]["DSP_RADIATOR_TEMP"] = measure_with_retry(client, 22)
        structured_data["6. Temperaturen"]["DSP_AMBIENT_TEMP"] = measure_with_retry(client, 15)
        structured_data["6. Temperaturen"]["DSP_SUPERVISOR_TEMPERATURE"] = measure_with_retry(client, 47)
        structured_data["6. Temperaturen"]["DSP_ALIM_TEMPERATURE"] = measure_with_retry(client, 48)
        structured_data["6. Temperaturen"]["DSP_HEAT_SINK_TEMPERATURE"] = measure_with_retry(client, 49)
        structured_data["6. Temperaturen"]["DSP_TEMPERATURE_1"] = measure_with_retry(client, 50)
        structured_data["6. Temperaturen"]["DSP_TEMPERATURE_2"] = measure_with_retry(client, 51)
        structured_data["6. Temperaturen"]["DSP_TEMPERATURE_3"] = measure_with_retry(client, 52)

        # 7. Lüftergeschwindigkeiten
        structured_data["7. Lüftergeschwindigkeiten"]["DSP_FAN_1_SPEED"] = measure_with_retry(client, 53)
        structured_data["7. Lüftergeschwindigkeiten"]["DSP_FAN_2_SPEED"] = measure_with_retry(client, 54)
        structured_data["7. Lüftergeschwindigkeiten"]["DSP_FAN_3_SPEED"] = measure_with_retry(client, 55)
        structured_data["7. Lüftergeschwindigkeiten"]["DSP_FAN_4_SPEED"] = measure_with_retry(client, 56)
        structured_data["7. Lüftergeschwindigkeiten"]["DSP_FAN_5_SPEED"] = measure_with_retry(client, 57)

        # 8. Leckströme
        structured_data["8. Leckströme"]["DSP_ILEAK_DC_DC"] = measure_with_retry(client, 6)
        structured_data["8. Leckströme"]["DSP_ILEAK_INVERTER"] = measure_with_retry(client, 7)

        # 9. Diagnose
        structured_data["9. Diagnose"]["DSP_ISOLATION"] = measure_with_retry(client, 30)
        structured_data["9. Diagnose"]["DSP_OPERATING_HOURS"] = measure_with_retry(client, 18)
        structured_data["9. Diagnose"]["DSP_POWER_SATURATION_LIMIT"] = measure_with_retry(client, 58)
        structured_data["9. Diagnose"]["DSP_RIFERIMENTO_ANELLO_BULK"] = measure_with_retry(client, 59)

        # 10. Status und Alarme
        structured_data["10. Status und Alarme"]["DSP_ALARMS"] = client.alarms()
        structured_data["10. Status und Alarme"]["DSP_FAULT_CODE"] = measure_with_retry(client, 20)
        structured_data["10. Status und Alarme"]["DSP_STATUS"] = measure_with_retry(client, 23)
        structured_data["10. Status und Alarme"]["DSP_EVENTS"] = measure_with_retry(client, 21)
        structured_data["10. Status und Alarme"]["DSP_LAST_ERROR"] = measure_with_retry(client, 22)

        # 11. Metadaten
        structured_data["11. Metadaten"]["DSP_SERIAL_NUMBER"] = client.serial_number()
        structured_data["11. Metadaten"]["DSP_MODEL"] = client.version()
        structured_data["11. Metadaten"]["DSP_VERSION"] = client.version()
        structured_data["11. Metadaten"]["DSP_GRID_FREQUENCY_DC_DC"] = measure_with_retry(client, 29)
        structured_data["11. Metadaten"]["DSP_WIND_GENERATOR_FREQUENCY"] = measure_with_retry(client, 37)

        client.close()

        # Speichere die Daten in einer strukturierten JSON-Datei
        with open('all_sensor_parameters_structured.json', 'w') as f:
            json.dump(structured_data, f, indent=4)

        # Erstelle eine lesbare Ausgabe mit Symbolen
        print("\n" + "="*80)
        print("Aurora Wechselrichter - Alle Sensorparameter")
        print("="*80 + "\n")

        for category, values in structured_data.items():
            print(f"{category}")
            print("-" * len(category))
            for key, value in values.items():
                icon = icon_mapping.get(key, "🔹")
                print(f"  {icon} {key}: {value}")
            print()

        print("="*80)
        print("Daten wurden in 'all_sensor_parameters_structured.json' gespeichert.")
        print("="*80 + "\n")

    except AuroraError as e:
        print(f"Fehler bei der Kommunikation: {str(e)}")
    except Exception as e:
        print(f"Allgemeiner Fehler: {str(e)}")

if __name__ == "__main__":
    test_all_sensor_parameters()
