GPT Solar PV report

My first rule written with GPT, to feed the OpenHAB GPT binding to create reports about my solar pv systems.

I’m sure the code is janky, I had to make a few manual tweaks to make it work, and I think I can tweak his personality a bit more before I’m done, but it works!

I want to add the error logs, some of the Live Production values, weather, heat pump data and anything else that is difficult to see the big picture of.
Ideally we could get to a place where GPT just takes the entire events.log and openhab.log down it’s neck.

I don’t have much data yet, and the inverters have been on and off a lot recently while some work is being done in the house.

GPT Binding Chat System Message:

You are a smart home. I will give you stats and you will give me a report. make comparisons, note highs, lows, trends, and anomalies. ignore null or missing data. make it a conversational summary. Units are kWh. Uses relative dates eg 3 days ago. Round numbers to make them easier to read. Be entertaining in the delivery. Infer other data from the data provided and look for possible errors.

Javascript rule

rules.JSRule({
    name: "GPT - Report",
    description: "",
    triggers: [
      triggers.ItemStateChangeTrigger('GPT_GenerateReport', undefined, 'ON'),
  
    ],
    execute: (event) => {
        console.info('Generating Report')

        
    // Function to retrieve solar PV stats for a given day
    function getStatsForDay(date, totalImportItem, totalExportItem, totalProductionItem) {
        const startOfDay = date.withHour(0).withMinute(0).withSecond(0).withNano(0);
        const endOfDay = date.plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0); // Start of next day
        
        // Return the calculated stats for the day
        return {
            startOfPeriod: startOfDay.toString().replace('T00:00Z[SYSTEM]', '').replace('T00:00+01:00[SYSTEM]', ''),
            productionThisDay: totalProductionItem.history.deltaBetween(startOfDay, endOfDay),
            importThisDay: totalImportItem.history.deltaBetween(startOfDay, endOfDay),
            exportThisDay: totalExportItem.history.deltaBetween(startOfDay, endOfDay),
        };
    }

    // Function to retrieve solar PV stats for a given week
    function getStatsForWeek(date, totalImportItem, totalExportItem, totalProductionItem) {
        const dayOfWeek = date.dayOfWeek().value();
        const startOfWeek = date.withHour(0).withMinute(0).withSecond(0).withNano(0).minusDays(dayOfWeek - 1);
        const endOfWeek = startOfWeek.plusWeeks(1);
        
        // Return the calculated stats for the week
        return {
            startOfPeriod: startOfWeek.toString().replace('T00:00Z[SYSTEM]', '').replace('T00:00+01:00[SYSTEM]', ''),
            productionThisWeek: totalProductionItem.history.deltaBetween(startOfWeek, endOfWeek),
            importThisWeek: totalImportItem.history.deltaBetween(startOfWeek, endOfWeek),
            exportThisWeek: totalExportItem.history.deltaBetween(startOfWeek, endOfWeek),
        };
    }

    // Function to retrieve solar PV stats for a given month
    function getStatsForMonth(date, totalImportItem, totalExportItem, totalProductionItem) {
        const startOfMonth = date.withHour(0).withMinute(0).withSecond(0).withNano(0).withDayOfMonth(1);
        const endOfMonth = startOfMonth.plusMonths(1);
        
        let productionData = totalProductionItem.history.deltaBetween(startOfMonth, endOfMonth)
        let importData = totalImportItem.history.deltaBetween(startOfMonth, endOfMonth)
        let exportData = totalExportItem.history.deltaBetween(startOfMonth, endOfMonth)

        // Return the calculated stats for the month
        return {
            startOfPeriod: startOfMonth.toString().replace('T00:00Z[SYSTEM]', '').replace('T00:00+01:00[SYSTEM]', ''),
            productionThisMonth: totalProductionItem.history.deltaBetween(startOfMonth, endOfMonth),
            importThisMonth: totalImportItem.history.deltaBetween(startOfMonth, endOfMonth),
            exportThisMonth: totalExportItem.history.deltaBetween(startOfMonth, endOfMonth),
        };
    }

    // Function to retrieve solar PV stats for a given year
    function getStatsForYear(date, totalImportItem, totalExportItem, totalProductionItem) {
        const startOfYear = date.withHour(0).withMinute(0).withSecond(0).withNano(0).withDayOfYear(1);
        const endOfYear = startOfYear.plusYears(1);
        
        let productionData = totalProductionItem.history.deltaBetween(startOfYear, endOfYear)
        let importData = totalImportItem.history.deltaBetween(startOfYear, endOfYear)
        let exportData = totalExportItem.history.deltaBetween(startOfYear, endOfYear)

        // Return the calculated stats for the year
        return {
            startOfPeriod: startOfYear.toString().replace('T00:00Z[SYSTEM]', '').replace('T00:00+01:00[SYSTEM]', ''),
            productionThisYear: totalProductionItem.history.deltaBetween(startOfYear, endOfYear),
            importThisYear: totalImportItem.history.deltaBetween(startOfYear, endOfYear),
            exportThisYear: totalExportItem.history.deltaBetween(startOfYear, endOfYear)
        };
    }

    // Function to generate solar PV stats for the mixed approach
    function generateAllSolarStats(inverterNo) {
        const stats = [];
        const totalImportItem = items.getItem("H"+inverterNo+"_SolarEdge_AggregateLifetime_Import");
        const totalExportItem = items.getItem("H"+inverterNo+"_SolarEdge_AggregateLifetime_Export");
        const totalProductionItem = items.getItem("H"+inverterNo+"_SolarEdge_AggregateLifetime_Production");

        // Recent data (last 7 days)
        const recentData = [];
        const currentTime = time.toZDT();
        
        for (let i = 0; i < 7; i++) {
            const date = currentTime.minusDays(i); // Calculate date for each day in the past 30 days
            const dayStats = getStatsForDay(date, totalImportItem, totalExportItem, totalProductionItem); // Retrieve stats for the day
            recentData.push(dayStats);
        }
        stats.push({ duration: 'Recent Days', data: recentData });


        // Previous Weeks data
        const previousWeeksData = [];
        for (let i = 1; i <= 6; i++) { // Considering data for the last 6 Weeks
            let dayOfWeek = currentTime.dayOfWeek().value();
            const startOfPreviousWeek = currentTime.minusDays(dayOfWeek - 1).minusWeeks(i);
            const weekData = getStatsForWeek(startOfPreviousWeek, totalImportItem, totalExportItem, totalProductionItem); // Retrieve stats for the start of the Week
            previousWeeksData.push(weekData);
        }
        stats.push({ duration: 'Recent Weeks', data: previousWeeksData });

        // Previous months data
        const previousMonthsData = [];
        for (let i = 1; i <= 6; i++) { // Considering data for the last 6 months
            const startOfPreviousMonth = currentTime.withDayOfMonth(1).minusMonths(i);
            const monthData = getStatsForMonth(startOfPreviousMonth, totalImportItem, totalExportItem, totalProductionItem); // Retrieve stats for the start of the month
            previousMonthsData.push(monthData);
        }
        stats.push({ duration: 'Recent Months', data: previousMonthsData });

        // Previous years data
        const previousYearsData = [];
        for (let i = 1; i <= 5; i++) { // Considering data for the last 5 Years
            const startOfPreviousYear = currentTime.withDayOfYear(1).minusYears(i);
            const yearData = getStatsForYear(startOfPreviousYear, totalImportItem, totalExportItem, totalProductionItem); // Retrieve stats for the start of the Year
            previousYearsData.push(yearData);
        }
        stats.push({ duration: 'Recent Years', data: previousYearsData });

        return stats;
    }


    // Example usage:

    function generateReport(stats) {
        let report = "";

        // Iterate over each item in stats and append its properties to the report string
        stats.forEach((item, index) => {
            report += `Duration ${index + 1}: ${item.duration}\n`;
            item.data.forEach((data, dataIndex) => {
                report += `  Data ${dataIndex + 1}:\n`;
                Object.entries(data).forEach(([key, value]) => {
                    report += `    ${key}: ${value}\n`;
                });
            });
        });

        return report;
        
    }
    const solarStats1 = generateAllSolarStats("1");
    const solarStats2 = generateAllSolarStats("2");

    let Inverter1Report = generateReport(solarStats1)
    let Inverter2Report = generateReport(solarStats2)

    let gptMessage = "This is the data for Inverter 1: " + Inverter1Report + "This is the data for Inverter 2: " + Inverter2Report

    items.GPT_Report.sendCommand(gptMessage)

    }
});```

Overall there’s more repeated code than I usually like to see but over all I don’t see anything glaringly problematic. ChatGPT has come a long way. They must have injested more recent docs and examples. :smiley: