Personalized Rebate & Savings Estimator

Estimate your total incentives, combining Federal IRA programs with State rebates.

Your Profile & Upgrades

🌎
1. Select Your State & Search Programs

Note: Only the California example uses the fixed data in Step 2 for calculation. Other states require manual input.

2. Select Your Upgrades

💰
3. Household Income Status

Higher rebates (like HEEHRA) are available for low-to-moderate income (LMI) households (generally under 150% AMI).

Total Estimated Incentives

Applied State: California (Sample Data)
$0

Breakdown of Estimated Savings:

Select upgrades and your income status to generate your personalized estimate.

📑 Incentive Lookup & Eligibility

Ask a question about specific program requirements, or search for incentives based on project type and location. **(Powered by Gemini Search)**

Ready to Start Your Electrification Journey?

Click below to schedule your free, no-obligation energy audit and take the first step toward a cleaner, more efficient home.

Schedule My Free Audit

Solenetec Project AI-Agent

Welcome! I'm your Solenetec Project Agent.
Please tell me your City, State, and Zip Code, a complete address unlocks a through project analysis.
What type of project are you're most interested in (e.g., Solar, Heat Pump, EV Charger)?

'); printWindow.document.close(); printWindow.print(); }); } // NEW EMAIL Listener if (emailAnalysisBtn) { emailAnalysisBtn.addEventListener('click', handleEmailResults); } updateRebates(); } function updateRebates() { let totalSavings = 0; let totalStateRebate = 0; const isIncomeQualified = incomeToggle.checked; const checkboxes = document.querySelectorAll('.upgrade-checkbox'); const selectedUpgrades = Array.from(checkboxes).filter(cb => cb.checked); const chartLabels = []; const stateData = []; const taxData = []; let breakdownHTML = ''; let upgradeList = []; let nonSolarTaxCreditTotal = 0; let finalTaxCreditSolar = 0; selectedUpgrades.forEach(cb => { const key = cb.dataset.key; const item = rebateData[key]; let stateRebateForThisItem = 0; let taxCreditForThisItem = 0; if (key === 'battery') { if (isIncomeQualified) { stateRebateForThisItem = item.state['SGIP Equity']; } taxCreditForThisItem = item.cost * 0.30; finalTaxCreditSolar = taxCreditForThisItem; } else { // Uses CA-specific example names if (isIncomeQualified) { stateRebateForThisItem = item.state['HEEHRA (LMI)'] || Math.max(item.state['TECH Clean CA'] || 0, item.state['Energy Smart Homes'] || 0); } else { stateRebateForThisItem = Math.max(item.state['TECH Clean CA'] || 0, item.state['Energy Smart Homes'] || 0); } taxCreditForThisItem = item.federalTax; nonSolarTaxCreditTotal += taxCreditForThisItem; } let combinedSavingsItem = stateRebateForThisItem + taxCreditForThisItem; totalStateRebate += stateRebateForThisItem; chartLabels.push(item.name); stateData.push(stateRebateForThisItem); taxData.push(taxCreditForThisItem); upgradeList.push({ name: item.name, total: combinedSavingsItem, state: stateRebateForThisItem, federal: taxCreditForThisItem }); // Text color to default (dark gray) on light background breakdownHTML += `
${item.name}:
$${combinedSavingsItem.toLocaleString()}($${stateRebateForThisItem.toLocaleString()} State + $${taxCreditForThisItem.toLocaleString()} Federal)
`; }); // Apply Non-Solar Tax Credit Cap ($3,200) const finalNonSolarTaxCredit = Math.min(nonSolarTaxCreditTotal, maxTaxCredit); const nonSolarDelta = nonSolarTaxCreditTotal - finalNonSolarTaxCredit; // Recalculate Tax Data in Chart/Breakdown for Cap const finalTaxData = taxData.map((tax, index) => { if (chartLabels[index] === rebateData.battery.name) { return tax; } else { const proportionalReduction = nonSolarDelta > 0 ? (tax / nonSolarTaxCreditTotal) * nonSolarDelta : 0; return tax - proportionalReduction; } }); const finalTotalTaxCredit = finalNonSolarTaxCredit + finalTaxCreditSolar; totalSavings = totalStateRebate + finalTotalTaxCredit; // Text color to blue-600 totalRebateAmountEl.textContent = '$' + totalSavings.toLocaleString(); if (selectedUpgrades.length === 0) { rebateBreakdownEl.innerHTML = `

Select upgrades and your income status to generate your personalized estimate.

`; } else { rebateBreakdownEl.innerHTML = breakdownHTML; // Border and text color to dark gray/white rebateBreakdownEl.innerHTML += `
Total Estimated Savings:$${totalSavings.toLocaleString()}

Disclaimer: Federal tax credits are subject to annual limits (up to $3,200 for non-solar efficiency) and your personal tax liability. This is an estimate only.

`; } rebateChartInstance.data.labels = chartLabels; rebateChartInstance.data.datasets[0].data = stateData; rebateChartInstance.data.datasets[1].data = finalTaxData; rebateChartInstance.update(); // Save state for Gemini currentRebateState = { totalSavings: totalSavings, isIncomeQualified: isIncomeQualified, selectedUpgrades: upgradeList.map(u => u.name), breakdown: `Federal Tax Credit portion: $${finalTotalTaxCredit.toLocaleString()}. State/Local Rebate portion: $${totalStateRebate.toLocaleString()}.` }; } // --- MODAL CONTROL --- function showModal(state) { modalStateName.textContent = state; stateModal.classList.add('show'); } function closeModal() { stateModal.classList.remove('show'); } // --- GEMINI API UTILITY --- async function exponentialBackoffFetch(url, options, retries = 5, delay = 1000) { for (let i = 0; i < retries; i++) { try { const response = await fetch(url, options); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { if (i === retries - 1) throw error; await new Promise(resolve => setTimeout(resolve, delay * 2 ** i)); } } } // --- GEMINI API LOGIC 3: STATE REBATE SEARCH (Search Grounding) --- async function searchStateRebates() { const selectedState = stateSelect.value; stateApiErrorSearchEl.classList.add('hidden'); stateSearchResultEl.textContent = 'Searching for major programs and compiling summary...'; stateCitationSourcesEl.innerHTML = ''; // Start loading state searchStateRebatesBtn.disabled = true; searchBtnText.textContent = `Searching for ${selectedState}...`; stateSearchSpinner.classList.remove('hidden'); const userQuery = `Find and summarize the major statewide residential energy efficiency and clean energy rebate programs available for homeowners in ${selectedState}. Include names of the programs.`; // UPDATED SYSTEM PROMPT: Forces a concise, high-level, bulleted list without dollar amounts. const systemPrompt = "Act as an expert on state-level energy rebates. For the specified state, provide a high-level summary. List the 3-5 major programs in a bulleted list, giving only the program name and a single sentence describing its primary goal (e.g., 'Heat Pump Water Heater Incentive: Provides rebates for high-efficiency water heating systems.'). DO NOT include dollar amounts in the text. Emphasize that full details are available in the cited sources."; const payload = { contents: [{ parts: [{ text: userQuery }] }], tools: [{ "google_search": {} }], // Enable Google Search grounding systemInstruction: { parts: [{ text: systemPrompt }] }, }; try { const result = await exponentialBackoffFetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const candidate = result.candidates?.[0]; const text = candidate?.content?.parts?.[0]?.text || "Error: Could not generate answer. Please try again or refine your question."; // 1. Extract sources let sources = []; const groundingMetadata = candidate?.groundingMetadata; // Check for groundingAttributions to exist if (groundingMetadata && groundingMetadata.groundingAttributions) { sources = groundingMetadata.groundingAttributions .map(attribution => ({ uri: attribution.web?.uri, title: attribution.web?.title, })) .filter(source => source.uri && source.title); } // 2. Display text in modal content area stateSearchResultEl.textContent = text; // 3. Display sources if (sources.length > 0) { let sourceHtml = 'Source(s): '; sources.forEach((source, index) => { sourceHtml += `${source.title}${index < sources.length - 1 ? ' | ' : ''}`; }); stateCitationSourcesEl.innerHTML = sourceHtml; } else { stateCitationSourcesEl.textContent = 'No specific web sources cited for this answer.'; } // 4. Show modal showModal(selectedState); // 5. Update Applied Filter Status (Fulfills user request) const isSample = selectedState === 'CA' ? ' (Sample Data)' : ''; appliedStateLabel.innerHTML = `Applied State: ${selectedState}${isSample}`; } catch (error) { // Handle error display in the modal area stateSearchResultEl.textContent = 'Failed to load program information.'; stateApiErrorSearchEl.textContent = `API Request Failed: The grounding service could not be reached. Please check your connection or try again.`; stateApiErrorSearchEl.classList.remove('hidden'); showModal(selectedState); // Show modal even on error } finally { searchStateRebatesBtn.disabled = false; searchBtnText.textContent = `Search Rebate Programs for ${selectedState}`; stateSearchSpinner.classList.add('hidden'); } } // --- GEMINI API LOGIC 2: INCENTIVE LOOKUP ASSISTANT (Search Grounding) --- async function getGroundedAnswer() { const userQuery = qaQueryEl.value.trim(); if (userQuery.length < 10) { qaApiErrorEl.textContent = 'Please ask a specific question (at least 10 characters long).'; qaApiErrorEl.classList.remove('hidden'); return; } qaApiErrorEl.classList.add('hidden'); // Start loading state getAnswerBtn.disabled = true; qaBtnText.textContent = "Searching for Answer..."; qaLoadingSpinner.classList.remove('hidden'); qaOutputCard.classList.add('hidden'); const systemPrompt = "You are a specialized assistant for home energy incentives. Use the provided search results to answer the user's question accurately and concisely. Include source citations at the end of the answer."; const payload = { contents: [{ parts: [{ text: userQuery }] }], tools: [{ "google_search": {} }], // Enable Google Search grounding systemInstruction: { parts: [{ text: systemPrompt }] }, }; try { const result = await exponentialBackoffFetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const candidate = result.candidates?.[0]; const text = candidate?.content?.parts?.[0]?.text || "Error: Could not generate answer. Please try again or refine your question."; // 1. Extract sources let sources = []; const groundingMetadata = candidate?.groundingMetadata; if (groundingMetadata && groundingMetadata.groundingAttributions) { sources = groundingMetadata.groundingAttributions .map(attribution => ({ uri: attribution.web?.uri, title: attribution.web?.title, })) .filter(source => source.uri && source.title); } // 2. Display text generatedAnswerEl.textContent = text; // 3. Display sources if (sources.length > 0) { let sourceHtml = 'Source(s): '; sources.forEach((source, index) => { sourceHtml += `${source.title}${index < sources.length - 1 ? ' | ' : ''}`; }); citationSourcesEl.innerHTML = sourceHtml; } else { citationSourcesEl.textContent = 'No specific web sources cited for this answer.'; } qaOutputCard.classList.remove('hidden'); } catch (error) { qaApiErrorEl.textContent = `API Request Failed: The grounding service could not be reached. Please check your query and try again.`; qaApiErrorEl.classList.remove('hidden'); } finally { getAnswerBtn.disabled = false; qaBtnText.textContent = "✨ Get Grounded Answer"; qaLoadingSpinner.classList.add('hidden'); } } // --- INITIALIZATION --- document.addEventListener('DOMContentLoaded', function () { initRebateSection(); });