From solar-skills
Use when the user asks to analyze solar data, review solar performance, get solar recommendations, check system sizing, compare EV vs non-EV days, or assess ROI on their PV system.
How this skill is triggered — by the user, by Claude, or both
Slash command
/solar-skills:analyzeThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Analyze hourly solar CSV data from `data/` and produce a consultant-style performance report with actionable recommendations.
Analyze hourly solar CSV data from data/ and produce a consultant-style performance report with actionable recommendations.
Data directory: Defaults to data/ (relative to the current working directory). If the SOLAR_DATA_DIR environment variable is set, use that directory instead — for every data/... path below (Glob input, the analysis_config.json you write, and the solar-analysis.md report). analyze.py reads SOLAR_DATA_DIR on its own; check it with echo "$SOLAR_DATA_DIR" and substitute it wherever data/ appears.
$ARGUMENTS — None required. Reads all solar_hourly_*.csv files from data/.
Files: data/solar_hourly_YYYY-MM.csv
Columns: Date, Hour, Readings, Avg_PV_W, PV_Energy_kWh, Avg_Battery_W, Battery_Energy_kWh, Avg_Grid_W, Grid_Energy_kWh, Avg_GridLoad_W, GridLoad_Energy_kWh, Avg_BackupLoad_W, BackupLoad_Energy_kWh, Avg_SOC_Pct, Min_SOC_Pct, Max_SOC_Pct
Sign conventions:
Use Glob to find all data/solar_hourly_*.csv files. If none exist, tell the user to export their solar data first (e.g., /export-hourly-soliscloud YYYY-MM for SolisCloud users, or /export-hourly-deye YYYY-MM for Deye/Solarman users).
Ask the user using AskUserQuestion:
If Codex is running in an environment where AskUserQuestion or equivalent structured prompt UI is unavailable, ask the same questions in plain chat one at a time instead of blocking. Keep the sequence interactive and continue once each required answer is provided.
pv_kwp / 1.3.kWh = voltage × Ah / 1000. This is the nominal capacity; usable capacity is estimated from data in step 3e. If no battery, skip battery-related analysis sections (3e, 3l, Battery Health, battery portions of anomaly detection).Build a JSON config from user parameters and run the analysis script. The script reads CSV files from data/ and outputs all metrics as JSON.
Build a config JSON with these keys from the user's answers:
{
"location": "Manila, Philippines",
"pv_kwp": 6.5,
"inverter_kw": 5.0,
"has_battery": true,
"battery_nominal_kwh": 14.336,
"has_ev": true,
"feedin_ratio": 0.5,
"additional_kwp": 0,
"seasonal_factors": {"1": 1.07, ...},
"grid_emission_factor": 0.68,
"tariff": {"type": "flat", "import_rate": 14},
"roi": {"total_cost": 400000, "battery_cost": 100000, "system_age_years": 0.25},
"currency": "₱"
}
Key notes:
location: user's city/province from Q1. Used to infer seasonal_factors, grid_emission_factor, and currency.inverter_kw: user-provided inverter AC capacity in kW. If unknown, use pv_kwp / 1.3 as fallback.has_battery: true if user has a battery, false otherwise. If false, set battery_nominal_kwh to 0 and skip battery analysis sections.battery_nominal_kwh: if user gave voltage + Ah, compute voltage * Ah / 1000seasonal_factors: infer from user's location/climate (see 3m below for factor tables)grid_emission_factor: infer from user's location (see 3o below for reference values)tariff.type: "flat", "tiered", or "tou". tariff.import_rate comes from Q7.tariff.tiers: [{"threshold": 200, "rate": 10}, {"threshold": 400, "rate": 12}, ...]tariff.tou: {"peak_hours": ["09:00", "10:00", ...], "peak_rate": 16, "offpeak_rate": 10}roi.battery_cost: cost of battery portion (only if has_battery is true); used for "without battery" ROI projectionroi: set to null if user declined ROI estimateWrite the config to data/analysis_config.json, then run:
python3 ${CLAUDE_PLUGIN_ROOT}/scripts/analyze.py data/analysis_config.json
The script outputs JSON to stdout with all computed metrics. Capture this output and use it to write the report in step 4.
The sections below document what the script computes. Use them as reference for interpreting the JSON output and writing the narrative report.
For each month, compute:
total_pv = sum(PV_Energy_kWh)total_load = sum(GridLoad_Energy_kWh) + sum(BackupLoad_Energy_kWh)grid_export = sum(Grid_Energy_kWh where > 0)grid_import = abs(sum(Grid_Energy_kWh where < 0))battery_charge = sum(Battery_Energy_kWh where > 0)battery_discharge = abs(sum(Battery_Energy_kWh where < 0))self_consumed = total_load - grid_import (measures actual solar offset of load; avoids inflating self-consumption by battery round-trip losses)self_consumption_rate = self_consumed / total_pv (guard: if total_pv == 0, report as 0%)self_sufficiency = 1 - (grid_import / total_load) (guard: if total_load == 0, report as N/A)max(8, average_daily_load * 0.3) kWh above mean — this catches both PHEV (smaller batteries) and full EV charging days relative to the household's baselinedaily_load > average_daily_load + threshold as EV dayscapacity_factor = avg_daily_pv / (pv_kwp * 24)peak_sun_hours = avg_daily_pv / pv_kwpinverter_kw (AC output rating). Check hours where Avg_PV_W > inverter_kw * 1000. If max observed PV output is within 5% of inverter capacity, flag as likely inverter-limited. Report DC/AC ratio (pv_kwp / inverter_kw), panel nameplate, and inverter capacity.discharge_kwh_in_that_window / (soc_start - soc_end) * 100. Take the median across days with >30% SOC swing in the deepest cycle. This avoids inflation from intra-day recharge cycles.discharge / charge — compute on monthly aggregates only (daily values are unreliable due to SOC imbalance between start and end of day)sum over hours of max(0, hourly_import - max(0, hourly_load - hourly_pv - hourly_battery_discharge_available)). This captures the temporal mismatch that daily totals miss. If hourly battery state is too complex to model, fall back to daily actual_import - max(0, load - pv) but note it is an upper-bound estimate.new_pv = pv * (total_kwp / current_kwp)abs(Avg_Grid_W) when importing (Grid_Energy_kWh < 0) as hourly grid drawtotal_load * import_rategrid_import * import_ratedaily_savings = from bill impact estimate (3i) if available, otherwise fall back to self_consumed_kwh * import_rate + exported_kwh * import_rate * feedin_ratioannual_savings = daily_savings * 365year_n_savings = annual_savings * (1 - 0.005)^n (0.5%/year panel degradation)cumulative_savings_at_year_n = sum(year_n_savings for n=0 to N)simple_payback = year where cumulative savings exceeds total cost (accounting for degradation)remaining_payback = max(0, simple_payback - system_age_years)has_battery is true): compute a parallel ROI using total_cost - battery_cost as the investment. For savings, remove battery's contribution: assume all solar energy not consumed in real-time is exported (no evening/night self-consumption from battery), so no_battery_savings = direct_solar_self_consumed * import_rate + (exported + battery_discharged_to_load) * import_rate * feedin_ratio. Where direct_solar_self_consumed = hours where PV > 0: min(pv, load) summed. Compare payback periods side-by-side to show the battery's incremental ROI.usable_capacity_pct = estimated_usable_kwh / nominal_kwh * 100 — compare to expected range for battery agedaily_discharge / usable_kwhdaily_equiv_cycles * 365(6000 - annual_cycles * system_age_years) / annual_cyclesyear_n_generation = projected_annual_pv * (1 - 0.005)^nprojected_annual_pv = adjusted_avg_daily_pv * 365projected_annual_savings = project from daily savings using the same seasonal adjustmentannual_co2_avoided = projected_annual_self_consumed * grid_emission_factor (in kg, convert to tonnes)Produce a narrative markdown report. Use ~ for approximate values in prose. Write like a solar consultant — explain causal chains (what → why → impact), not just numbers.
Style rules:
~ prefix for rounded values in prose (e.g. "~21 kWh", "~85% SOC")Report structure:
The report follows this order, designed so a homeowner who reads only the first page gets the most important information:
# Solar System Recommendations
Based on analysis of solar data from {month range} ({x} days).
## Executive Summary
{3–5 lines maximum. Lead with the single most important finding, then key number, then top action. This should be readable in 15 seconds.}
{Example: "The 6.5 kWp system is well-sized for household consumption and on track for a 4.5-year payback on $15k invested. Self-sufficiency improved from 60% to 73% as the dry season progressed. The single highest-impact optimization is shifting EV charging to morning hours (09:00–14:00), which could save an additional $400–700/year and reduce payback to ~3.8 years. No equipment faults detected, though two days of abnormally low generation warrant a check of inverter logs."}
{If anomalies requiring action were detected, mention them here: "Action needed: {date} showed near-zero PV output — check inverter logs to rule out equipment fault."}
{Include environmental headline if meaningful: "The system avoids ~{x} tonnes of CO₂ annually."}
## System Profile
- **PV capacity**: {kWp} kWp, inverter: {inverter_kw} kW AC (DC/AC ratio: {ratio})
- **Battery**: {nominal_kWh} kWh nominal, ~{usable_kWh} kWh usable (SOC range {min}%–{max}%)
- **EV/PHEV**: {present or not, charge frequency}
- **Tariff**: {flat / tiered / TOU} — {rate details}
- **Feed-in tariff**: {ratio}% of import rate
## Alerts
{Only include this section if anomalies were detected. If no anomalies, omit entirely — don't write "no alerts."}
{Prioritize equipment-related anomalies over weather. Anomalies that could indicate faults should be presented first with clear action items.}
### PV Generation Alerts
{If severe anomalies (>80% deviation) found:}
**Action required:** On {date}, PV generation was {x} kWh against an expected ~{x} kWh ({deviation}% below baseline). If this does not correspond to a known weather event or planned shutdown, check inverter logs and error codes for that date. Possible causes: inverter fault, tripped breaker, or grid outage preventing export.
{If moderate anomalies (40–80% deviation) found:}
| Date | Daily PV (kWh) | Expected (kWh) | Deviation |
|---|---|---|---|
| {date} | {x} | ~{x} | -{x}% |
{Narrative: "These days likely reflect heavy cloud cover or storms. If generation dips this severe recur without corresponding weather, investigate panel soiling or partial shading from new obstructions."}
### Load Alerts
{If load anomalies found:}
- {date}: {x} kWh consumed (expected ~{x} ± {x} kWh) — unusually high for a non-EV day. Possible causes: undetected EV charge below threshold, guest load, or appliance running abnormally. Worth investigating if this recurs.
### Battery Alerts
{If battery anomalies found:}
- {date}: round-trip efficiency {x}% (expected >85%) — may indicate BMS recalibration event or measurement error. Monitor for recurrence.
## Recommendations
### 1. {Highest impact action} (highest impact)
Paragraph 1: What's currently happening and its cost.
Paragraph 2: What to change, why it works, quantified benefit.
Paragraph 3: How to implement (e.g. EVSE scheduling, timer settings).
### 2. {Next action}
Similar multi-paragraph structure with data-backed reasoning.
(Continue numbered recommendations. Typical set: EV charge timing, overnight base load reduction, appliance scheduling, SOC floor assessment. Only include what the data supports. Tailor implementation advice to weekday vs weekend where relevant — e.g., "shifting loads is more practical on weekends when occupants are home; weekday optimization requires timer-based automation.")
### Not Recommended
{Fold into recommendations section as a closing subsection rather than a standalone top-level section.}
- **Grid-charging battery at off-peak**: {one-line explanation why it doesn't work with this tariff/efficiency}
- **Second battery**: {one-line explanation why export volume is too low to justify}
(Only include items relevant to the system.)
## Bill Impact
### Monthly Electricity Cost Comparison
| Month | Without Solar | With Solar | Feed-in Credit | Net Savings |
|---|---|---|---|---|
| {Mon} | {currency}{x} | {currency}{x} | {currency}{x} | {currency}{x} |
{For tiered tariffs: "Solar reduces monthly grid consumption from tier {x} ({rate}/kWh) to tier {y} ({rate}/kWh), saving an additional {currency}{x}/month beyond the raw kWh offset."}
{For TOU tariffs: "Solar generation peaks during {peak/off-peak} hours, offsetting {currency}{x}/month of {peak rate} electricity. Export credit during {peak/off-peak} hours adds {currency}{x}/month."}
- Estimated annual bill without solar: {currency}{x}
- Estimated annual bill with solar: {currency}{x}
- **Annual bill reduction: {currency}{x} ({x}%)**
## ROI Estimate
(Only if user requested. Placed immediately after Bill Impact for financial flow.)
| Metric | With Battery | Without Battery |
|---|---|---|
| System cost | {currency}{total_cost} | {currency}{total_cost - battery_cost} |
| Estimated annual savings (year 1) | {currency}{amount} | {currency}{amount} |
| **Simple payback** | **{x} years** | **{x} years** |
| Remaining payback | {x} years | {x} years |
| 25-year lifetime savings | {currency}{amount} | {currency}{amount} |
(If no battery, use a single-column table with just the system values — no "Without Battery" column.)
**Battery incremental ROI**: The battery cost {currency}{battery_cost} adds {currency}{battery_annual_benefit}/year in avoided import (energy shifted from export at feed-in rate to self-consumption at import rate). Battery-only payback: ~{x} years. {Narrative: whether the battery investment is justified given cycle life, or whether the panels alone carry most of the ROI.}
Note: "Total system cost" is the user-reported figure, which may include financing costs (e.g., loan interest) beyond hardware and installation. If the user indicated financing, note this in the narrative — e.g., "System cost includes financing; hardware-only cost would yield a shorter payback."
Narrative: payback context relative to panel lifespan (25+ years) and battery lifespan (from cycle life estimate). Note that degradation-adjusted payback is slightly longer than a naive calculation. If recommendations are implemented, estimated improved payback.
## Key Metrics
| Metric | Non-EV Days | EV Days |
|---|---|---|
| Daily PV generation | ~{x} kWh | ~{x} kWh |
| Daily consumption | ~{x} kWh | ~{x} kWh |
| Daily grid import | ~{x} kWh | ~{x} kWh |
| Daily grid export | ~{x} kWh | ~{x} kWh |
| Evening SOC | ~{x}% | ~{x}% |
(If no EV, use single-column table.)
Followed by narrative bullets:
- Self-consumption rate: {x}% ({Mon}), {x}% ({Mon})
- Self-sufficiency: {x}% ({Mon}), {x}% ({Mon})
- Grid export concentrated at {HH:MM}–{HH:MM} when battery is full (~{x}% SOC)
- Battery drains from ~{x}% to ~{x}% overnight on non-EV days (~{x}% drain)
- On EV days, battery depletes to {x}% by {HH:MM}, forcing heavy grid import
- Non-EV baseline load is well-matched to PV generation (~{x} kWh each)
### Hourly Patterns
5–7 narrative bullets summarizing:
- PV peak window and wattage range
- Non-EV load peak timing (typically after PV declines)
- EV charging window and surge wattage
- Battery charge taper timing and SOC level causing export
- Overnight grid import window and average kWh/day
### Weekday vs Weekend
{If self-sufficiency difference is ≥5pp or load difference is ≥15%, show the full table:}
| Metric | Weekdays | Weekends |
|---|---|---|
| Avg daily load | ~{x} kWh | ~{x} kWh |
| Avg daily grid import | ~{x} kWh | ~{x} kWh |
| Self-sufficiency | {x}% | {x}% |
{Narrative explaining the difference and its implications for recommendations.}
{If the difference is <5pp and <15% load difference, collapse to a single line:}
Weekday and weekend consumption patterns are similar (~{x} kWh each, {x}% vs {x}% self-sufficiency), with the main difference being {brief note on hourly shift if significant_hourly_diffs exist, or "no significant hourly differences" if none}.
### Peak Demand
- Peak grid draw: {x} kW on {date} at {hour} ({EV/non-EV day})
- Average daily peak: ~{x} kW (non-EV), ~{x} kW (EV days)
- Peak PV output: {x} kW on {date} at {hour} ({x}% of inverter capacity)
- {If near inverter capacity (>90%): "Peak PV output reached {x}% of inverter AC capacity ({inverter_kw} kW), suggesting the inverter may be limiting output during peak hours."}
## System Size Assessment
One-line intro about panel room availability.
### PV Array ({kWp} kWp): {correctly sized | undersized | oversized} for base load
Bullet list:
- Peak output reached {x}W ({x}% of nameplate, {x}% of inverter capacity)
- {If inverter-limited: "Output appears capped by inverter AC capacity ({inverter_kw} kW). With a higher-rated inverter, peak generation could increase by ~{x}%."}
- Peak sun hours per month
- Non-EV PV/load ratio and what it means
- EV day coverage percentage and deficit
- Clipping hours (panel nameplate and inverter) and what they indicate
### Battery ({kWh} kWh): {adequate | undersized}, {not the bottleneck | stretched on EV days}
Bullet list:
- Non-EV cycle depth, charge/discharge per day, headroom assessment, avoidable import
- EV cycle depth and why more battery wouldn't help (deficit is generation)
- Round-trip efficiency observed
### Verdict
Single paragraph: is the system well-sized? What would/wouldn't help? Where does optimization lie?
## Battery Health
- Nominal capacity: {nominal_kWh} kWh, estimated usable: ~{usable_kWh} kWh ({usable_pct}% of nominal)
- Round-trip efficiency: {efficiency}% (typical LFP range: 92–95%)
- Daily equivalent full cycles: ~{cycles} ({annual_cycles} per year)
- Estimated cycle life remaining: ~{years} years at current usage (based on 6,000-cycle LFP rating)
If ≥2 months of data: note any efficiency trend. If efficiency is declining, flag for monitoring.
If only baseline data: note that trends will be trackable in future reports.
## Month-over-Month Trends
(Only if ≥2 months of data.)
| Metric | {Mon1} | {Mon2} | Change |
|---|---|---|---|
| Avg daily PV | ~{x} kWh | ~{x} kWh | {+/-x}% |
| Avg daily load | ~{x} kWh | ~{x} kWh | {+/-x}% |
| Self-sufficiency | {x}% | {x}% | {+/-x}pp |
| Grid dependence | {x}% | {x}% | {+/-x}pp |
| Battery efficiency | {x}% | {x}% | {+/-x}pp |
Narrative explaining observed changes (seasonal shift, behavioral change, etc.).
## Annual Projection
- Data coverage: {n} months ({confidence}: low <3mo, moderate 3–6mo, high 6+mo)
- Seasonal context: {season months in data}, adjustment factor applied: {x}
- Projected annual generation: ~{x} kWh (year 1), ~{x} kWh (year 10), ~{x} kWh (year 25)
- Projected annual self-consumed: ~{x} kWh
- Projected annual grid export: ~{x} kWh
- Environmental impact: ~{x} tonnes CO₂ avoided annually (at {grid_emission_factor} kg CO₂/kWh), equivalent to ~{x} trees planted
Narrative on expected seasonal variation appropriate to the user's climate (inferred from location).
## Methodology Notes
This section documents the heuristics, assumptions, and caveats used in the analysis computations. All numerical results are produced by a deterministic script; the items below describe modelling choices that affect interpretation.
### Data Processing
- Energy values assume 1-hour buckets (each row = 1 hour). Days with ≤20 of 24 hourly rows are excluded from daily statistics as partial days.
- Self-consumed energy is calculated as `total_load - grid_import`, which measures actual solar offset and avoids inflating by battery round-trip losses. Can go slightly negative if metering errors cause import > load.
### EV Detection
- EV charging days are detected using a threshold of {threshold} kWh above the {avg_load} kWh daily average (formula: `max(8, avg_daily_load × 0.3)`). The 8 kWh floor catches PHEV charges; the 30% factor scales with household size.
- Days near the threshold may be misclassified. The heuristic cannot distinguish EV charging from other high-load events (guests, space heaters).
### Battery Analysis
- **Usable capacity** is estimated from the deepest monotonic SOC decline per day, using only days with >30% SOC swing. BMS-reported SOC may not be linear at extremes, which could bias the estimate.
- **Round-trip efficiency** is computed on monthly aggregates to smooth daily SOC imbalances. If SOC trends differently at month boundaries, the figure will be skewed.
- **Avoidable import** uses a daily upper-bound estimate that overstates savings — it ignores hourly timing mismatches between surplus generation and demand.
### Anomaly Detection
- **PV anomalies**: flags days with generation <60% of the rolling 14-day mean (first 3 days excluded). Cannot distinguish equipment faults from weather — heavy cloud cover triggers false positives.
- **Load anomalies**: flags non-EV days exceeding mean + 2 standard deviations (requires ≥5 non-EV days for baseline).
- **Battery anomalies**: flags days with round-trip efficiency <80% where start/end SOC are within 5% and charging exceeds 1 kWh.
### Financial Estimates
- Tiered tariff calculations treat tier thresholds as cumulative. Utilities using non-cumulative block structures would require different logic.
- Feed-in credit applies a flat rate regardless of TOU period. Time-differentiated feed-in tariffs are not modelled.
- ROI uses 0.5%/year panel degradation (industry standard for monocrystalline silicon). Does not model inverter replacement (~10-15 years), battery degradation beyond cycle count, or electricity price inflation.
- Battery cycle life uses a 6,000-cycle LFP rating. Actual life varies by manufacturer, depth of discharge, temperature, and charge rate. Calendar aging is not modelled.
### Projections
- Annual projection de-seasonalizes observed data using location-inferred seasonal factors, then re-applies all 12 months. Uses a fixed 30.44 days/month. With <3 months of data, confidence is low.
- Additional panels projection scales PV output linearly — assumes same orientation, tilt, and shading as existing panels. Does not model inverter clipping from additional capacity. {If clipping was detected: "Because inverter clipping was detected, this projection is optimistic."}
### Environmental
- Avoided CO₂ is computed as **self-consumed kWh × grid factor**, not gross PV × grid factor. This is conservative — exported kWh also displace fossil generation on the grid, and a gross-displacement convention would add roughly the export share (~10% in typical residential systems with high self-consumption). The self-consumption-only figure is what `analyze.py` returns by design.
- Carbon equivalents use fixed values: 22 kg CO₂/tree/year (mature deciduous tree, temperate climate), 0.21 kg CO₂/km (average passenger car). Actual values vary significantly by species, vehicle type, and conditions.
- {If feedin_ratio > 0: "Feed-in tariff assumed constant; regulatory changes could affect export revenue."}
## Appendix
### Best and Worst Days
**Best day: {date}** — PV: {x} kWh, Load: {x} kWh, Import: {x} kWh, Export: {x} kWh. {EV/non-EV}. {Brief explanation.} Self-sufficiency: {x}%.
**Worst day: {date}** — PV: {x} kWh, Load: {x} kWh, Import: {x} kWh, Export: {x} kWh. {EV/non-EV}. {Brief explanation.} Self-sufficiency: {x}%.
### Capacity Factor
| Month | Avg Daily kWh | Peak Sun Hours | Capacity Factor | Grid Dependence |
|---|---|---|---|---|
### Next Steps
- {If anomalies detected: "Check inverter logs for {date(s)} to rule out equipment faults"}
- Run this analysis again after {next month} to add wet/dry season data and improve projection confidence
- {If EV recommendation given: "Configure EVSE charging schedule per Recommendation 1 and compare next month's EV-day import"}
- {If overnight base load recommendation given: "Use a plug-in power meter to identify overnight loads and report findings for next analysis"}
- Monitor battery efficiency trend — current 93–97% range is healthy; flag if any month drops below 90%
### Disclaimer
This report was generated by an AI model. While the numerical computations are performed by a deterministic script (`analyze.py`), the narrative interpretation, recommendations, and contextual inferences (seasonal factors, grid emission factors, sizing assessments) are AI-generated and may contain inaccuracies. Verify critical findings — especially financial estimates and equipment diagnostics — against your own records, manufacturer specifications, or a qualified solar professional before making decisions based on this report.
### Data Sources
- `data/{filename}` — {x} days
data/solar-analysis.mddata/analysis_config.jsonnpx claudepluginhub marfillaster/solar-skills --plugin solar-skillsSearches MemPalace before answering questions about past work, people, projects, or prior decisions. Returns verbatim stored content instead of guessing from model memory.
Guides Payload CMS config (payload.config.ts), collections, fields, hooks, access control, APIs. Debugs validation errors, security, relationships, queries, transactions, hook behavior.
Implements vector databases with Pinecone, Weaviate, Qdrant, Milvus, pgvector for semantic search, RAG, recommendations, and similarity systems. Optimizes embeddings, indexing, and hybrid search.