Version: 3.0
Author: ScooterCam
For: ScooterCam.net
Clean, discrete layers for buoy observations and forecast models – no more mixing yesterday’s data!
🎯 Why Layered Views?
The Problem with Hybrid
- Forecast data was bleeding into yesterday
- Timezone confusion between data sources
- Hard to see which data is which
- Mixed data = messy debugging
The Solution: Separate Layers
✅ Buoy layer = Past 48 hours of real observations
✅ Forecast layer = Next 48 hours of predictions
✅ No mixing = No timezone confusion
✅ Clear data source = Easy debugging
🌊 Three Shortcodes, Three Use Cases
1.
Loading buoy data...
– Buoy Observations Only
Shows: Past 48 hours of real buoy measurements
When to use: Historical data, validation, actual conditions
Data source: NDBC Buoy 45168 (South Haven)
24
72
[wave_buoy]
[wave_buoy hours="24"] // Last 24 hours only
[wave_buoy hours="72"] // Last 3 days
Features:
- ✅ Real measurements from 12 miles offshore
- ✅ Current wave stats (height, period, direction)
- ✅ Solid blue line
- ✅ Seasonal (April-October)
2.
Loading forecast data...
– Forecast Only
Shows: Next 48 hours of wave predictions
When to use: Planning, future conditions
Data source: Open-Meteo marine model
[wave_forecast]
[wave_forecast hours="24"] // Next 24 hours
[wave_forecast hours="72"] // Next 3 days
Features:
- ✅ Future predictions from now forward
- ✅ No historical/yesterday data
- ✅ Dashed orange line
- ✅ Year-round availability
3.
Loading buoy data...
Loading forecast data...
– Tabbed Interface
Shows: Both views with tab switcher
When to use: Complete conditions page
Data sources: Both buoy + forecast
[wave_layered]
Features:
- ✅ Tab 1: Buoy Observations (real data)
- ✅ Tab 2: Forecast Model (predictions)
- ✅ Single shortcode, both views
- ✅ Easy switching between layers
📦 Installation
File Structure
/wp-content/plugins/scootercam-wave-layered/
├── wave-height-layered.php
├── js/
│ └── wave-layered-chart.js
└── README.md
Upload & Activate
- Upload to
/wp-content/plugins/scootercam-wave-layered/
- WordPress Admin → Plugins → Activate
- Use any of the three shortcodes!
🎨 Visual Examples
Buoy Layer (Past Data)
Yesterday ←──────────────────── Now
48h of observations
Solid blue line
Real measurements
Forecast Layer (Future Data)
Now ────────────────────→ +48h
48h of predictions
Dashed orange line
Model forecasts
Layered View (Both)
┌─────────────────────────┐
│ 🌊 Buoy | 📊 Forecast │ ← Tabs
├─────────────────────────┤
│ │
│ [Active layer here] │
│ │
└─────────────────────────┘
🔧 How It Works
Separate AJAX Endpoints
Buoy Endpoint:
wp_ajax_get_buoy_data
→ Fetches NDBC 45168
→ Returns past X hours
→ Cached 30 minutes
Forecast Endpoint:
wp_ajax_get_forecast_data
→ Fetches Open-Meteo
→ Returns ONLY future data
→ Cached 1 hour
No More Timezone Issues!
Old hybrid approach:
// Mixed buoy (UTC) + forecast (Chicago)
// Comparison: time() vs strtotime()
// Result: Yesterday bleeds through ❌
New layered approach:
// Buoy: Shows past only
// Forecast: Shows future only
// No comparison needed ✅
🎯 Usage Examples
Main Conditions Page
<h1>Lake Michigan Wave Conditions</h1>
<h2>Current Observations</h2>
<h2>48-Hour Forecast</h2>
Tabbed Interface
<h1>Wave Data</h1>
Sidebar Widget
<h3>Current Waves</h3>
Blog Post Embed
<p>Check today's wave forecast:</p>
Comparison View
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
<div>
<h3>What Just Happened</h3>
</div> <div> <h3>What’s Coming</h3>
</div> </div>
📊 Data Specifications
Buoy Layer (45168)
Location: 42.397°N, 86.331°W
Distance: 12 miles west of South Haven
Active: April – October
Update: Hourly
Returns:
- Wave height (meters)
- Wave period (seconds)
- Wave direction (degrees)
- Timestamps in Chicago timezone
Behavior when offline:
- Shows friendly message
- Explains seasonal deployment
- No chart displayed
Forecast Layer
Location: 42.5593°N, 86.2359°W (South Haven)
Source: Open-Meteo marine model
Active: Year-round
Update: Every 6 hours
Returns:
- Wave height forecast (meters)
- Wave period forecast (seconds)
- Wave direction forecast (degrees)
- ONLY future timestamps
Filtering:
// Server-side filter
if ($timestamp <= $nowTimestamp) {
continue; // Skip past data
}
// Guaranteed: Only shows future
🐛 Troubleshooting
Issue: Forecast Still Shows Yesterday
This shouldn’t happen anymore! But if it does:
- Clear transients:
wp transient delete openmeteo_forecast
- Check server time:
echo date('Y-m-d H:i:s T'); // Should match reality
- Verify timezone:
WordPress Admin → Settings → General
Timezone: America/Chicago
- Hard refresh:
Ctrl+Shift+R (Windows/Linux)
Cmd+Shift+R (Mac)
Issue: Buoy Shows “Seasonal” Message
This is normal November-April!
The South Haven buoy is physically removed from the water in fall and redeployed in spring. This is expected behavior.
To verify it’s actually off-season:
- Check: https://www.ndbc.noaa.gov/station_page.php?station=45168
- Look for recent data (should be none)
Issue: Charts Not Loading
- Check browser console (F12):
// Look for errors like:
"Failed to fetch"
"Chart is not a constructor"
"waveLayeredData is not defined"
- Verify AJAX endpoints:
# Test buoy endpoint
curl -X POST https://scootercam.net/wp-admin/admin-ajax.php \
-d "action=get_buoy_data&nonce=..."
# Test forecast endpoint
curl -X POST https://scootercam.net/wp-admin/admin-ajax.php \
-d "action=get_forecast_data&nonce=..."
- Clear ALL caches:
wp transient delete --all
wp cache flush
🔄 Migration from Hybrid
If Currently Using Hybrid Plugin
Option 1: Run Both (Recommended)
- Keep hybrid plugin active
- Install layered plugin
- Test layered on separate page
- Gradually migrate
Option 2: Replace Entirely
Old: [wave_hybrid_chart]
New: [wave_layered]
Option 3: Separate Displays
Old: [wave_hybrid_chart]
New: [wave_buoy] + [wave_forecast]
Shortcode Conversion
Old Hybrid | New Layered |
---|---|
[wave_hybrid_chart] | |
[wave_hybrid_chart show_buoy="true" show_forecast="false"] | |
[wave_hybrid_chart show_buoy="false" show_forecast="true"] | |
🎨 Customization
Tab Colors
.wave-tab.active {
background: #10b981; /* Green instead of blue */
}
.wave-tab-badge {
background: rgba(255,255,255,0.3);
}
Chart Heights
.wave-chart-wrapper {
height: 500px !important; /* Taller charts */
}
Buoy Chart Color
// In wave-layered-chart.js
borderColor: '#0ea5e9', // Sky blue instead of blue
Forecast Chart Color
// In wave-layered-chart.js
borderColor: '#8b5cf6', // Purple instead of orange
📈 Performance
Cache Strategy
Buoy data: 30 minutes
- Real-time not critical
- Reduces NDBC server load
- Balances freshness vs performance
Forecast data: 1 hour
- Model updates every 6 hours
- No need for frequent checks
- Significant performance gain
Load Times
Single layer (buoy or forecast):
- Initial load: <1 second
- AJAX call: 1-2 seconds
- Chart render: <100ms
- Total: 2-3 seconds
Layered view (tabs):
- Both layers load on page load
- Slightly slower: 3-4 seconds
- But switching tabs is instant
✅ Advantages Over Hybrid
Data Integrity
- ✅ No mixed timeframes
- ✅ No timezone confusion
- ✅ Clear data boundaries
- ✅ Easy validation
Debugging
- ✅ Simple data flow
- ✅ Separate endpoints
- ✅ Clear error messages
- ✅ Isolated failures
User Experience
- ✅ Choose what to see
- ✅ Understand data source
- ✅ No confusing overlaps
- ✅ Clean visual separation
Maintenance
- ✅ Easier to update
- ✅ Independent caching
- ✅ Clearer code
- ✅ Better testability
🆚 When to Use Which
Use
Loading buoy data...
when:
- ✅ Want actual observed data
- ✅ Validating forecast accuracy
- ✅ Showing recent trends
- ✅ It’s buoy season (Apr-Oct)
Use
Loading forecast data...
when:
- ✅ Planning future activities
- ✅ Need predictions
- ✅ It’s off-season (Nov-Mar)
- ✅ Want clean forward-looking data
Use
Loading buoy data...
Loading forecast data...
when:
- ✅ Want complete picture
- ✅ Professional display
- ✅ Main conditions page
- ✅ Let users choose view
📝 Best Practices
Page Layout
Good:
<h1>Wave Conditions</h1>
<!– Single comprehensive view –>
Also Good:
<h2>Recent Observations</h2>
<h2>Upcoming Forecast</h2>
<!– Clear separation –>
Avoid:
[wave_layered]
Cache Management
During testing:
# Clear before each test
wp transient delete openmeteo_forecast
wp transient delete ndbc_buoy_45168
In production:
# Let caches work normally
# 30min/1hr is good balance
Seasonal Messaging
April-October (Active):
- Promote buoy data
- Show observed stats
- Highlight “real” measurements
November-March (Inactive):
- Default to forecast
- Explain seasonal nature
- Show “next deployment” date
🎉 Success Checklist
After deploying layered views:
- [ ] All three shortcodes work
- [ ] Buoy shows past data only
- [ ] Forecast shows future data only
- [ ] No “yesterday” in forecast
- [ ] Tabs switch properly (layered view)
- [ ] Current stats update (buoy view)
- [ ] Seasonal message shows correctly
- [ ] Mobile responsive
- [ ] No console errors
- [ ] Caching works
📞 Support
Quick Diagnostics
Test buoy data:
curl https://www.ndbc.noaa.gov/data/realtime2/45168.txt | head -5
Test forecast API:
curl "https://marine-api.open-meteo.com/v1/marine?latitude=42.5593&longitude=-86.2359&hourly=wave_height&timezone=America/Chicago&forecast_days=2" | jq
Check WordPress transients:
wp transient list | grep -E 'buoy|forecast'
🏆 Summary
Layered = Better than Hybrid because:
- Cleaner separation – No data mixing
- No timezone issues – Each layer independent
- Easier debugging – Isolated data flows
- Better UX – Users choose what to see
- More reliable – Simpler = fewer bugs
Three shortcodes for every use case:
- Loading buoy data...
- Loading forecast data...
- Loading buoy data...Loading forecast data...
The forecast layer guarantees future-only data! 🎯
Made with 🌊 for accurate wave forecasting