Skip to main content
Glama
alexcz-a11y

Tessie MCP Server

by alexcz-a11y
trip-calculator.ts12.9 kB
import { TessieDrive } from './tessie-client.js'; export interface TripCostAnalysis { trip_summary: { distance_miles: number; duration_hours: number; battery_used_percent: number; energy_used_kwh: number; efficiency_miles_per_kwh: number; }; cost_breakdown: { electricity_cost: number; charging_stops_cost: number; total_cost: number; cost_per_mile: number; }; comparison: { vs_gas_vehicle: { gas_cost_estimate: number; savings: number; savings_percentage: number; }; vs_optimal_charging: { optimal_cost: number; current_cost: number; potential_savings: number; }; }; charging_strategy: string[]; environmental_impact: { co2_saved_lbs: number; trees_equivalent: number; }; } export class TripCalculator { private readonly BATTERY_CAPACITY_KWH = 75; // Typical Model 3/Y private readonly DEFAULT_HOME_RATE = 0.13; // $/kWh private readonly DEFAULT_SUPERCHARGER_RATE = 0.28; // $/kWh private readonly DEFAULT_GAS_PRICE = 4.50; // $/gallon private readonly DEFAULT_MPG = 30; // Comparison gas vehicle private readonly CO2_PER_GALLON = 19.6; // lbs CO2 per gallon of gas private readonly CO2_PER_KWH_GRID = 0.855; // lbs CO2 per kWh (US average) /** * Calculate the cost of a specific trip or set of drives */ calculateTripCost( drives: TessieDrive[], homeRate: number = this.DEFAULT_HOME_RATE, superchargerRate: number = this.DEFAULT_SUPERCHARGER_RATE, gasPrice: number = this.DEFAULT_GAS_PRICE ): TripCostAnalysis { if (drives.length === 0) { return this.emptyAnalysis(); } // Sort drives chronologically const sortedDrives = [...drives].sort((a, b) => a.started_at - b.started_at); // Calculate trip metrics const totalDistance = drives.reduce((sum, d) => sum + d.odometer_distance, 0); const totalDuration = this.calculateTotalDuration(sortedDrives); const totalBatteryUsed = this.calculateTotalBatteryUsed(sortedDrives); const totalEnergyKwh = (totalBatteryUsed / 100) * this.BATTERY_CAPACITY_KWH; const efficiency = totalEnergyKwh > 0 ? totalDistance / totalEnergyKwh : 0; // Calculate costs const chargingCosts = this.estimateChargingCosts( sortedDrives, totalEnergyKwh, homeRate, superchargerRate ); // Calculate gas comparison const gasComparison = this.calculateGasComparison(totalDistance, gasPrice); // Calculate optimal charging scenario const optimalCharging = this.calculateOptimalCharging(totalEnergyKwh, homeRate); // Generate charging strategy recommendations const strategy = this.generateChargingStrategy( sortedDrives, totalBatteryUsed, chargingCosts ); // Calculate environmental impact const environmental = this.calculateEnvironmentalImpact(totalDistance, totalEnergyKwh); return { trip_summary: { distance_miles: Math.round(totalDistance * 100) / 100, duration_hours: Math.round(totalDuration * 100) / 100, battery_used_percent: Math.round(totalBatteryUsed * 100) / 100, energy_used_kwh: Math.round(totalEnergyKwh * 100) / 100, efficiency_miles_per_kwh: Math.round(efficiency * 100) / 100 }, cost_breakdown: { electricity_cost: Math.round(chargingCosts.electricityCost * 100) / 100, charging_stops_cost: Math.round(chargingCosts.chargingStopsCost * 100) / 100, total_cost: Math.round(chargingCosts.totalCost * 100) / 100, cost_per_mile: Math.round((chargingCosts.totalCost / totalDistance) * 1000) / 1000 }, comparison: { vs_gas_vehicle: { gas_cost_estimate: Math.round(gasComparison.gasCost * 100) / 100, savings: Math.round(gasComparison.savings * 100) / 100, savings_percentage: Math.round(gasComparison.savingsPercent * 100) / 100 }, vs_optimal_charging: { optimal_cost: Math.round(optimalCharging.optimal * 100) / 100, current_cost: Math.round(chargingCosts.totalCost * 100) / 100, potential_savings: Math.round(optimalCharging.savings * 100) / 100 } }, charging_strategy: strategy, environmental_impact: { co2_saved_lbs: Math.round(environmental.co2Saved * 10) / 10, trees_equivalent: Math.round(environmental.treesEquivalent) } }; } private emptyAnalysis(): TripCostAnalysis { return { trip_summary: { distance_miles: 0, duration_hours: 0, battery_used_percent: 0, energy_used_kwh: 0, efficiency_miles_per_kwh: 0 }, cost_breakdown: { electricity_cost: 0, charging_stops_cost: 0, total_cost: 0, cost_per_mile: 0 }, comparison: { vs_gas_vehicle: { gas_cost_estimate: 0, savings: 0, savings_percentage: 0 }, vs_optimal_charging: { optimal_cost: 0, current_cost: 0, potential_savings: 0 } }, charging_strategy: ['No trip data available'], environmental_impact: { co2_saved_lbs: 0, trees_equivalent: 0 } }; } private calculateTotalDuration(drives: TessieDrive[]): number { if (drives.length === 0) return 0; const firstStart = drives[0].started_at; const lastEnd = drives[drives.length - 1].ended_at; return (lastEnd - firstStart) / 3600; // Convert to hours } private calculateTotalBatteryUsed(drives: TessieDrive[]): number { let totalUsed = 0; let lastEndingBattery = drives[0].starting_battery; for (const drive of drives) { // Account for charging between drives if (drive.starting_battery > lastEndingBattery) { // Battery increased - there was charging // Don't count this as usage } // Add battery used in this drive const driveUsage = drive.starting_battery - drive.ending_battery; if (driveUsage > 0) { totalUsed += driveUsage; } lastEndingBattery = drive.ending_battery; } return totalUsed; } private estimateChargingCosts( drives: TessieDrive[], totalEnergyKwh: number, homeRate: number, superchargerRate: number ): { electricityCost: number; chargingStopsCost: number; totalCost: number } { let homeCost = 0; let superchargerCost = 0; // Analyze charging patterns between drives for (let i = 1; i < drives.length; i++) { const prevDrive = drives[i - 1]; const currentDrive = drives[i]; const batteryGained = currentDrive.starting_battery - prevDrive.ending_battery; if (batteryGained > 2) { // Charging occurred const energyAdded = (batteryGained / 100) * this.BATTERY_CAPACITY_KWH; const gapHours = (currentDrive.started_at - prevDrive.ended_at) / 3600; // Estimate charging type based on duration and location if (gapHours < 1 && batteryGained > 30) { // Fast charging - likely Supercharger superchargerCost += energyAdded * superchargerRate; } else { // Slow charging - likely home homeCost += energyAdded * homeRate; } } } // If no charging detected in gaps, assume home charging for the energy used const detectedChargingKwh = (homeCost / homeRate) + (superchargerCost / superchargerRate); if (detectedChargingKwh < totalEnergyKwh * 0.5) { // Most energy not accounted for - assume home charging const unaccountedKwh = totalEnergyKwh - detectedChargingKwh; homeCost += unaccountedKwh * homeRate; } return { electricityCost: homeCost, chargingStopsCost: superchargerCost, totalCost: homeCost + superchargerCost }; } private calculateGasComparison( distance: number, gasPrice: number ): { gasCost: number; savings: number; savingsPercent: number } { const gallonsNeeded = distance / this.DEFAULT_MPG; const gasCost = gallonsNeeded * gasPrice; return { gasCost, savings: 0, // Will be calculated by caller savingsPercent: 0 // Will be calculated by caller }; } private calculateOptimalCharging( totalEnergyKwh: number, homeRate: number ): { optimal: number; savings: number } { // Optimal scenario: all charging at home during off-peak hours const offPeakRate = homeRate * 0.7; // Assume 30% discount for off-peak const optimal = totalEnergyKwh * offPeakRate; return { optimal, savings: 0 // Will be calculated by caller }; } private generateChargingStrategy( drives: TessieDrive[], totalBatteryUsed: number, costs: { electricityCost: number; chargingStopsCost: number; totalCost: number } ): string[] { const strategies: string[] = []; // Analyze Supercharger usage const superchargerPercent = (costs.chargingStopsCost / costs.totalCost) * 100; if (superchargerPercent > 40) { strategies.push( `⚡ High Supercharger usage (${Math.round(superchargerPercent)}%). Consider charging at home before long trips` ); } // Check if trip could be done with single charge if (totalBatteryUsed < 80) { strategies.push( `🔋 This trip could be completed with a single overnight charge at home` ); } // Recommend charging level for trip const optimalStartCharge = Math.min(90, totalBatteryUsed + 20); strategies.push( `📊 Optimal starting charge: ${Math.round(optimalStartCharge)}% for this trip distance` ); // Time-of-use recommendation if (costs.electricityCost > 0) { strategies.push( `🌙 Schedule home charging for off-peak hours (11pm-7am) to save 30-50% on electricity` ); } return strategies; } private calculateEnvironmentalImpact( distance: number, energyKwh: number ): { co2Saved: number; treesEquivalent: number } { // CO2 from equivalent gas vehicle const gallonsForGas = distance / this.DEFAULT_MPG; const co2FromGas = gallonsForGas * this.CO2_PER_GALLON; // CO2 from EV charging (grid average) const co2FromEV = energyKwh * this.CO2_PER_KWH_GRID; // Net savings const co2Saved = co2FromGas - co2FromEV; // Tree equivalent (1 tree absorbs ~48 lbs CO2/year) const treesEquivalent = co2Saved / 48; return { co2Saved: Math.max(0, co2Saved), treesEquivalent: Math.max(0, treesEquivalent) }; } /** * Calculate cost for a planned future trip */ estimateFutureTripCost( distanceMiles: number, currentBatteryPercent: number, homeRate: number = this.DEFAULT_HOME_RATE, superchargerRate: number = this.DEFAULT_SUPERCHARGER_RATE ): { estimated_cost: number; charging_needed: boolean; recommended_charge_level: number; charging_stops_needed: number; strategy: string; } { // Assume 4 miles/kWh efficiency const efficiencyMilesPerKwh = 4; const energyNeeded = distanceMiles / efficiencyMilesPerKwh; const batteryPercentNeeded = (energyNeeded / this.BATTERY_CAPACITY_KWH) * 100; // Add 15% buffer for safety const totalBatteryNeeded = batteryPercentNeeded * 1.15; // Calculate charging needs const chargingNeeded = totalBatteryNeeded > currentBatteryPercent; const chargeDeficit = Math.max(0, totalBatteryNeeded - currentBatteryPercent); // Estimate charging stops (assume 50% charge per Supercharger stop) const superchargerStopsNeeded = Math.ceil(chargeDeficit / 50); // Calculate cost let estimatedCost = 0; let strategy = ''; if (chargingNeeded) { if (chargeDeficit <= 60) { // Can charge at home const kwhNeeded = (chargeDeficit / 100) * this.BATTERY_CAPACITY_KWH; estimatedCost = kwhNeeded * homeRate; strategy = `Charge to ${Math.round(currentBatteryPercent + chargeDeficit)}% at home before departure`; } else { // Need Supercharger stops const homeChargeKwh = ((90 - currentBatteryPercent) / 100) * this.BATTERY_CAPACITY_KWH; const superchargerKwh = ((chargeDeficit - (90 - currentBatteryPercent)) / 100) * this.BATTERY_CAPACITY_KWH; estimatedCost = (homeChargeKwh * homeRate) + (superchargerKwh * superchargerRate); strategy = `Charge to 90% at home, then ${superchargerStopsNeeded} Supercharger stop${superchargerStopsNeeded > 1 ? 's' : ''} during trip`; } } else { strategy = `No charging needed - current ${currentBatteryPercent}% is sufficient`; } return { estimated_cost: Math.round(estimatedCost * 100) / 100, charging_needed: chargingNeeded, recommended_charge_level: Math.min(100, Math.round(currentBatteryPercent + chargeDeficit)), charging_stops_needed: superchargerStopsNeeded, strategy }; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/alexcz-a11y/tessie-mcp-fix'

If you have feedback or need assistance with the MCP directory API, please join our Discord server