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)
}
});```