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. [wave_buoy] – 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)
[wave_buoy]
24
[wave_buoy hours=”24″]
72
[wave_buoy hours=”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. [wave_forecast] – 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″]
[wave_forecast hours=”72″]
[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. [wave_layered] – Tabbed Interface
Shows: Both views with tab switcher
When to use: Complete conditions page
Data sources: Both buoy + forecast
[wave_layered]
[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>
[wave_buoy hours=”48″]
<h2>48-Hour Forecast</h2>
[wave_forecast hours=”48″]
Tabbed Interface
<h1>Wave Data</h1>
[wave_layered]
Sidebar Widget
<h3>Current Waves</h3>
[wave_buoy hours=”6″]
Blog Post Embed
<p>Check today's wave forecast:</p>
[wave_forecast hours=”24″]
Comparison View
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
<div>
<h3>What Just Happened</h3>
[wave_buoy hours=”24″]
</div> <div> <h3>What’s Coming</h3>
[wave_forecast hours=”24″]
</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_layered] |
[wave_hybrid_chart show_buoy="true" show_forecast="false"] | [wave_buoy] |
[wave_hybrid_chart show_buoy="false" show_forecast="true"] | [wave_forecast] |
๐จ 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 [wave_buoy] when:
- โ Want actual observed data
- โ Validating forecast accuracy
- โ Showing recent trends
- โ It’s buoy season (Apr-Oct)
Use [wave_forecast] when:
- โ Planning future activities
- โ Need predictions
- โ It’s off-season (Nov-Mar)
- โ Want clean forward-looking data
Use [wave_layered] when:
- โ Want complete picture
- โ Professional display
- โ Main conditions page
- โ Let users choose view
๐ Best Practices
Page Layout
Good:
<h1>Wave Conditions</h1>
[wave_layered]
<!– Single comprehensive view –>
Also Good:
<h2>Recent Observations</h2>
[wave_buoy hours=”24″]
<h2>Upcoming Forecast</h2>
[wave_forecast hours=”48″]
<!– Clear separation –>
Avoid:
[wave_layered]
[wave_buoy]
[wave_forecast] <!– Too much! Pick one approach –>
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:
[wave_buoy]โ Past observations[wave_forecast]โ Future predictions[wave_layered]โ Both in tabs
The forecast layer guarantees future-only data! ๐ฏ
Made with ๐ for accurate wave forecasting