robertbeier.com — Operations Guide

Mach-E
Charging
Site Guide

Everything you need to add sessions, update rates, maintain files, and understand how your Jekyll + CloudCannon charging tracker works.

Adding Sessions Electricity Rates Gas Savings Odometer / Cost-per-Mile File Cleanup CloudCannon Git & GitHub

How the whole thing fits together

Add session
in CloudCannon
CloudCannon commits
.md file to GitHub
GitHub Actions
triggers Jekyll build
Site rebuilds at
robertbeier.com

An iPhone Shortcut alternative exists — see the Appendix (last slide) for migration steps when ready


Each charging session is a .md file in _charging/ with front matter:

--- date: "2026-04-18" location: "Work" vehicle: "2025 Mach-E GT" energy_kwh: 29.3 cost: 0.0 start_date: "2026-04-18" start_time: "07:42" end_time: "15:30" soc_start: 52 soc_end: 90 soc_added: 38 miles_added: 101 temperature_c: 12.4 temperature_f: 54.3 notes: "" ---
1

Jekyll reads _charging/

All .md files load as site.charging — iterated by dashboard, history, and analytics pages.

2

Analytics page enriches data in JS

Sessions are injected as JSON and enriched client-side — savings, CO₂, efficiency, temperature correlation.

3

Static HTML served free

No database, no server — GitHub Pages serves plain HTML. The site costs nothing to host.

Adding a session via CloudCannon

1

Open CloudCannon

Go to app.cloudcannon.com → your site → Charging Sessions in the left nav.

2

Click "+ Add" → Add Charging Session

A blank form opens. Fill in Date first — this controls the filename.

3

Fill in all fields

Location is a dropdown. Vehicle defaults to current car. Include start/end time, SOC start/end/added, and miles added from FordPass. Cost = 0 for free charging.

4

Save → site rebuilds in ~2 min

CloudCannon commits the file to GitHub. GitHub Actions builds the site. Run backfill_temperature.py periodically to fill in temperature data.

💡 Home charging cost
Leave cost as 0 for Home sessions — the analytics page calculates it using your configured electricity rate from _data/rates.yml.
⚠️ Date timezone
CloudCannon may show UTC time. If you charge after 8pm Eastern, the UTC date may show as the next day. Always verify the date and correct it if needed.
✓ Notes field
Anything in Notes appears as a 📝 tooltip on the history page. Good for logging trip context or unusual circumstances.
💡 Want to automate this?
An iPhone Shortcut that parses FordPass screenshots and pushes directly to GitHub is documented in the Appendix (last slide). Not currently in use but ready to build when wanted.

Location badges & charging networks

The site detects the charging network from the location string and colors the badge accordingly. The detection is keyword-based — the location just needs to contain the keyword.

Workcontains "work"
Homecontains "home"
Teslacontains "tesla"
ChargePointcontains "chargepoint"
Blinkcontains "blink"
Riviancontains "rivian"
Otheranything else

Adding a new location to the CloudCannon dropdown:

1

Open .cloudcannon/schemas/charging.md

In VS Code, find the values: list under location.

2

Add a new line

e.g. - "Tesla, Ann Arbor" — keep the quotes if the name has a comma.

3

Commit & push

New location appears in the dropdown for all future sessions after CloudCannon rebuilds.

Example: adding a new Tesla location
# in .cloudcannon/schemas/charging.md location: type: select options: values: - Home - Work - "Tesla, Lansing" - "Tesla, Ohio" - "Tesla, Ann Arbor" ← new
The badge color is automatic — "Tesla, Ann Arbor" contains "tesla" so it gets the red badge. No other changes needed.

Updating electricity rates in rates.yml

All electricity rates and gas savings assumptions now live in one place: _data/rates.yml. You never touch the charging .md pages for rate changes. Jekyll reads this file as real numbers so decimal rates work perfectly.

_data/rates.yml — the home_electricity section
home_electricity: - date: "2025-08-22" rate: 0.196 ← first period - date: "2025-09-18" rate: 0.191 - date: "2026-02-19" rate: 0.204 ← most recent — add new entries below this
1

Check your utility bill

Find "Energy Charge per kWh" on your DTE or Consumers Energy statement. Use your blended rate (total cost ÷ total kWh) if you have a tiered plan.

2

Open _data/rates.yml

Find the home_electricity: section. Add a new entry at the bottom with the date of your next Home session and the new rate.

3

Keep entries in date order

Always add at the bottom — earliest first. Each session uses the last entry whose date is on or before the session date. Never delete old entries.

4

Commit & push — one file only

Unlike before, you only edit _data/rates.yml. Both the dashboard and history page update automatically on the next build.

✓ One file replaces two
Previously you had to update both charging-dashboard.md AND charging-history.md in sync. Now you only edit _data/rates.yml — both pages read from it automatically.
💡 Non-home sessions
Work, Tesla, ChargePoint etc. always use the cost field stored in the session file. Enter those manually when you add the session in CloudCannon.
⚠️ Gas savings are here too
The gas_savings: section in the same file controls the gas comparison assumptions. Same pattern — add entries at the bottom when anything changes. See slide 6.

Managing gas savings periods

Gas savings use period-based rates from _data/rates.yml — each session is calculated with the rates that were current when it happened. The mpg field is your baseline (27 mpg). LRB's sessions automatically use 23 mpg via a per-vehicle override in the code — you don't need a separate rates.yml entry for this.

_data/rates.yml — the gas_savings section
gas_savings: - date: "2025-08-22" mpg: 27 ← your baseline; LRB's sessions override to 23 in code gas_price: 3.26 mi_per_kwh: 3.0 - date: "2025-09-01" ← winter: lower efficiency mpg: 27 gas_price: 3.29 mi_per_kwh: 2.5 - date: "2026-04-01" ← most recent — add new entries below mpg: 27 gas_price: 4.24 mi_per_kwh: 3.0

Field meaning

date

Start date of this period (YYYY-MM-DD). Each session uses the last entry whose date is on or before it.

mpg

Your baseline MPG (27 = your previous car). LRB's sessions always use 23 mpg regardless — this is a per-vehicle override in charging-dashboard.md and charging-analytics.md. Don't change this field to 23.

gas_price

Average gas price per gallon in dollars. Check GasBuddy for current Michigan average.

mi_per_kwh

Real-world EV efficiency. ~3.0 summer, ~2.5 winter. Check FordPass for your rolling average. Applied to both vehicles.

Per-vehicle MPG overrides (hardcoded)
These are set in the JS/Liquid code — do NOT try to manage them via rates.yml:

2025 Mach-E GT27 mpg
2026 Mach-E SR27 mpg
LRB's 2025 Mach-E GT23 mpg
LRB's 2026 Mach-E SR23 mpg
When to add a new period:
• Gas price shifts more than ~$0.25/gal
• Seasonal efficiency change (Nov → Mar)
• You want to update your baseline MPG
✓ The "see assumptions" link
On the live charging page, click "see assumptions ↕" to expand a table showing all periods, the per-vehicle MPG overrides, and the usable battery capacity for each car.

Usable Battery Capacity — also hardcoded per vehicle

2025 Mach-E GT
91.7 kWh
NCM Extended Range
2026 Mach-E SR
72.6 kWh
LFP Standard Range
LRB's 2025 / 2026
91.7 / 72.6
GT=91.7 · SR=72.6

These values live in VEHICLE_UBE in charging-analytics.md. Used to estimate battery degradation over time in the Session Detail section.

Odometer & cost-per-mile config

The odometer table — in charging-dashboard.md
{% assign odometer_entries = " 2025 Mach-E GT | 18500 | 2026-04-18 | 2025-08-22 | " | strip | split: " " %}

Column 1: Vehicle name

Must EXACTLY match the vehicle field in your charging files. Case-sensitive.

Column 2: Odometer miles

Current reading. Update this and column 3 regularly (monthly or whenever).

Column 3: Reading date

Only sessions ON OR BEFORE this date count toward this vehicle's cost/mile.

Column 4: First session date

Date of your very first session for this vehicle. Set once, don't change.

⚠️ When your 2026 Mach-E arrives
1. Add a new line to the table for 2026 Mach-E GT
2. Update the CloudCannon schema default vehicle
3. An "Overall" row auto-appears once you have 2+ vehicles
💡 How to update monthly
Check FordPass or your dashboard, then update just two numbers: odometer miles and the date. Commit and push.
Example with 2026 car added
2025 Mach-E GT | 32000 | 2027-01-01 | 2025-08-22 | 2026 Mach-E GT | 8500 | 2027-01-01 | 2026-10-15 |

Python maintenance scripts

fix_charging_files.py

🔧

Fix front matter

Strips timestamps from dates, fixes null notes, adds missing fields (SOC, miles_added, temperature_c/f), removes CloudCannon-injected keys.

📁

Rename files (optional)

Renames to YYYY-MM-DD-{slug}-N.md sorted chronologically. Preview before confirm.

# Fix front matter only (safe anytime) python3 fix_charging_files.py # Fix AND rename (shows preview first) python3 fix_charging_files.py --rename

backfill_temperature.py

🌡️

Fetches historical temperature for every session

Uses Open-Meteo ERA5 archive API — free, no API key. Looks up lat/lng from _data/locations.yml, fetches temperature at session start time, writes temperature_c and temperature_f to each session file.

Batches API calls efficiently

One API call per unique (location, date) — not per session. Skips sessions already populated. Requires lat/lng in _data/locations.yml for each location.

# Preview — no writes (do this first) python3 backfill_temperature.py # Write temperature to all session files python3 backfill_temperature.py --write # Then normalize field order python3 fix_charging_files.py
⚠️ When to run fix_charging_files.py
• After adding sessions via CloudCannon if dates look wrong
• After using the iPhone Shortcut (filenames use time suffix — fix normalizes)
• After running backfill_temperature.py
• Periodic housekeeping — monthly is fine
💡 When to run backfill_temperature.py
• Once after initial setup to backfill all historical sessions
• Monthly, on new sessions that don't have temperature yet
• After adding a new location to _data/locations.yml with lat/lng
• Skips already-populated sessions automatically
⚠️ Temperature requires coordinates
Every location in _data/locations.yml must have lat and lng set for the backfill to work. The preview run tells you which locations are missing coordinates.
✓ After running either script, always commit
git add _charging/
git commit -m "Backfill temperature / cleanup files"
git push

The git workflow for file edits

CloudCannon handles git automatically when you save there. For edits you make directly in VS Code, you need to commit and push manually.

Typical workflow after editing files in VS Code
# 1. Always pull first (CloudCannon may have pushed) git pull # 2. Make your edits, then stage everything git add . # 3. Commit with a descriptive message git commit -m "Update home rate to $0.19" # 4. Push to GitHub — triggers a site rebuild git push
💡 Use GitHub Desktop if preferred
GitHub Desktop does all of the above with a GUI. Either tool works — they talk to the same repo. Just remember to always pull before editing.

Branch rule of thumb

Commit to main directly

Adding sessions, updating odometer, tweaking rates — small routine changes. Fine on main.

Use a branch for big changes

Restructuring pages, adding new features, changing config files significantly. Create a branch so main stays live while you experiment.

Creating and using a branch
# Create and switch to new branch git checkout -b feature/new-vehicle # Work, commit as normal, then merge back git checkout main git merge feature/new-vehicle git push

Key config files explained

📄

cloudcannon.config.yml

Master CloudCannon config. Defines the Charging Sessions collection, the location dropdown values, field types (date, number, textarea), and the file naming template.

📄

.cloudcannon/schemas/charging.md

Template for new session files. Must be a .md file (not .yaml) so CloudCannon creates .md sessions. Contains default field values.

📄

_config.yml

Jekyll-only config. Site title, URL, timezone, theme, and the charging collection definition. No CloudCannon config here — keep them separate.

cloudcannon.config.yml — key sections
collections_config: charging: path: _charging default_content_type: md schemas: default: path: .cloudcannon/schemas/charging.md _inputs: ← field UI definitions date: type: date options: time_format: false ← no timestamp, plain date location: type: select ← dropdown of locations
⚠️ YAML indentation
These files are extremely sensitive to spaces. If CloudCannon stops working after an edit, check the indentation — use VS Code's yellow squiggles as a guide.

Analytics sections & trip notes

Analytics page sections (in order)

🌍

Perspective

8 hero cards — coast-to-coast trips, Earth %, home electricity months, trees, gas fill-ups, tanker trucks, iPhone charges, CO₂ balloons. Vehicle-filter aware.

🚗

Mileage & Fuel Rates

Odometer history, miles/month, gas price history, real efficiency (mi/kWh ↔ Wh/mi dual axis). Reads from _data/mileage.yml.

Gas Price Sensitivity

Interactive slider $2–$6/gal. Updates total savings, monthly avg, 5-yr projection, and cumulative chart in real time.

🕐

When Do I Charge

Hour × day-of-week heatmap. Color = dominant charging type, intensity = frequency. Only sessions with recorded start time.

🌡️

Temperature Charts

Efficiency vs. temp scatter (exclude-home toggle), monthly temp vs. efficiency dual-axis, monthly temp distribution. Hidden until 5+ sessions have temperature data.

Road trip cards — trip_notes.yml

💡 Auto-detected trips
Road trips are detected automatically from public charging sessions >50 miles from home, clustered in 5-day windows. No manual entry needed for detection.
✓ Enriching a trip card
1. Open _data/trip_notes.yml
2. Copy the template block at the bottom
3. Key = date of first charging session (YYYY-MM-DD)
4. Fill in destination, description, itinerary
5. If you photographed the Mach-E energy screen at trip end, add the energy_screen: true block with miles, efficiency, energy %, and driving scores
6. Commit and push
⚠️ Energy screen data
Use the Trip 2 tab on the car's energy screen (not "This Trip" — that resets too often). Photograph it at trip end before you reset it. Add data manually to trip_notes.yml within a day or two while you still have the photo.

The cheatsheet

Routine tasks

Add session: CloudCannon → Charging Sessions → + Add. Fill in date, location, vehicle, kWh, cost, start/end time, SOC start/end/added, and miles added from FordPass. Save → rebuilds in ~2 min.
🔌Update electricity rate: Add new entry to _data/rates.ymlhome_electricity: section, commit
Update gas price period: Add new entry to _data/rates.ymlgas_savings: section, commit
🚗Update odometer: Add new entry (newest first) to _data/mileage.yml with date, vehicle, odometer. Dashboard auto-reads. Commit.
🌡️Backfill temperature: python3 backfill_temperature.py (preview) then --write. Run monthly on new sessions. Requires lat/lng in locations.yml.
📍Add new location: Add to cloudcannon.config.yml dropdown AND _data/locations.yml with lat/lng AND iPhone Shortcut menu. Commit.
🗺Annotate road trip: Open _data/trip_notes.yml, copy template, fill in key (first session date YYYY-MM-DD), destination, description. Commit.
📊Add trip energy screen data: At trip end, photo the Mach-E "Where did my energy go?" screen (Trip 2 tab). Add energy_screen: true and the extracted fields to the trip entry in _data/trip_notes.yml. Shows energy breakdown bar + driving scores on the road trip card.
🧹Cleanup files: python3 fix_charging_files.py — adds missing fields, fixes dates, normalizes front matter. Run monthly or after bulk changes.

Annual car swap checklist

1Add final odometer entry for outgoing car to _data/mileage.yml
2Add first odometer entry for new car to _data/mileage.yml
3Update cloudcannon.config.yml vehicle dropdown with new car name
4Update iPhone Shortcut vehicle menu (Block C) — share updated link to LRB
5Update VEHICLE_MPG and VEHICLE_UBE in charging-analytics.md

Files & their purpose

📁_charging/*.md — one file per session (date, location, vehicle, kWh, cost, SOC, miles, temp)
📊_data/rates.yml — electricity rates & gas savings by date period
🚗_data/mileage.yml — odometer history, all vehicles, newest first
📍_data/locations.yml — lat/lng for map + temperature backfill
🗺_data/trip_notes.yml — road trip annotations: destination, itinerary, AND trip computer data (miles, efficiency, energy breakdown %, driving scores) from the Mach-E screen photo
📄charging-dashboard.md — /charging/ dashboard (reads mileage.yml automatically)
📄charging-analytics.md — /charging-analytics/ full analytics page
📄charging-history.md — /charging-history/ full session table
⚙️cloudcannon.config.yml — CloudCannon UI, location & vehicle dropdowns
🐍fix_charging_files.py — front matter cleanup & rename script
🌡️backfill_temperature.py — fetches historical temp from Open-Meteo for all sessions
📱manifest.json + sw.js — PWA manifest & service worker (repo root)
🖼️icons/ — PWA icons: apple-touch-icon.png, icon-192.png, icon-512.png, icon-maskable-512.png
💡 This guide is out of date?
Any time a new data file, Python script, field, or regular workflow is added — update charging-site-guide.html. The rule: if it requires user action regularly, it belongs in the cheatsheet.

Migrating to the iPhone Shortcut

Not currently in use — CloudCannon is the active workflow (slide 3). This appendix documents everything needed when you're ready to migrate. No data changes required — the session file format is identical either way.

What the shortcut does

📷

Parse FordPass screenshot automatically

Uses Apple Intelligence "Use Cloud model" to extract all session fields from a FordPass "Charge details" screenshot — date, kWh, cost, start/end time, SOC, miles. No manual typing.

✏️

Manual fallback also supported

If no screenshot is available, the Shortcut prompts for each field. Same end result.

📤

Pushes directly to GitHub

Creates the .md file via GitHub API — bypasses CloudCannon. Site rebuilds in ~60 seconds. Works entirely from your phone.

Migration checklist

1Open shortcut-guide.html from the repo — full build-from-scratch guide
2Generate a GitHub PAT: GitHub → Settings → Developer Settings → Personal Access Tokens → Fine-grained → repo write on robbertbeier-web
3Build the Shortcut on iPhone following the guide. Owner: RJBME · Repo: robbertbeier-web
4Update vehicle menu (Block C) to match current car names in cloudcannon.config.yml
5Test with a real FordPass screenshot — verify the .md file in GitHub looks correct
6Share Shortcut iCloud link to LRB's phone
7PAT tokens expire annually — regenerate and update the Text action block in the Shortcut
✓ No data migration
CloudCannon sessions and Shortcut sessions are identical .md files. Switch at any time — existing history is unaffected.
⚠️ After switching
Remove the CloudCannon step from your routine checklist and update this guide's slide 2 flow diagram back to "iPhone Shortcut → GitHub API" when you make the switch permanent.
arrow keys Space next slide Home first slide