Skip to main content
Glama
alexcz-a11y

Tessie MCP Server

by alexcz-a11y
charging-reminder.ts13.3 kB
import { TessieVehicleState } from './tessie-client.js'; export interface ChargingReminder { priority: 'urgent' | 'high' | 'medium' | 'low'; type: 'range_warning' | 'optimal_charge' | 'time_of_use' | 'weather_prep' | 'trip_prep' | 'maintenance'; title: string; message: string; action_required: boolean; estimated_savings?: string; time_sensitive?: boolean; deadline?: string; } export interface ChargingStrategy { current_status: { battery_level: number; charging_state: string; range_miles: number; plugged_in: boolean; }; recommendations: ChargingReminder[]; charging_schedule: { optimal_start_time: string; optimal_end_time: string; off_peak_window: string; estimated_cost_savings: number; }; range_analysis: { comfort_range: boolean; emergency_range: boolean; recommended_charge_level: number; next_charge_needed: string; }; smart_insights: string[]; } export class ChargingReminderSystem { private readonly COMFORT_RANGE_THRESHOLD = 50; // miles private readonly EMERGENCY_RANGE_THRESHOLD = 20; // miles private readonly OPTIMAL_CHARGE_LEVEL = 80; // % private readonly DAILY_CHARGE_LEVEL = 90; // % private readonly COLD_WEATHER_THRESHOLD = 32; // °F private readonly HOT_WEATHER_THRESHOLD = 85; // °F private readonly OFF_PEAK_START = 23; // 11 PM private readonly OFF_PEAK_END = 7; // 7 AM private readonly PEAK_RATE = 0.35; // $/kWh private readonly OFF_PEAK_RATE = 0.13; // $/kWh /** * Generate intelligent charging reminders and strategy */ generateChargingStrategy( vehicleState: TessieVehicleState, dailyMiles: number = 40, nextTripDistance?: number, weatherTemp?: number ): ChargingStrategy { const batteryLevel = vehicleState.battery_level || 0; const rangeMiles = vehicleState.battery_range || 0; const chargingState = vehicleState.charging_state || 'Disconnected'; const pluggedIn = chargingState !== 'Disconnected' && chargingState !== 'Complete'; // Generate reminders based on current state const recommendations = this.generateReminders( vehicleState, dailyMiles, nextTripDistance, weatherTemp ); // Calculate optimal charging schedule const chargingSchedule = this.calculateOptimalSchedule(batteryLevel, dailyMiles); // Analyze range situation const rangeAnalysis = this.analyzeRange(batteryLevel, rangeMiles, dailyMiles, nextTripDistance); // Generate smart insights const smartInsights = this.generateSmartInsights( vehicleState, batteryLevel, rangeMiles, dailyMiles, weatherTemp ); return { current_status: { battery_level: batteryLevel, charging_state: chargingState, range_miles: Math.round(rangeMiles), plugged_in: pluggedIn }, recommendations: recommendations.sort((a, b) => this.getPriorityWeight(a.priority) - this.getPriorityWeight(b.priority)), charging_schedule: chargingSchedule, range_analysis: rangeAnalysis, smart_insights: smartInsights }; } private generateReminders( vehicleState: TessieVehicleState, dailyMiles: number, nextTripDistance?: number, weatherTemp?: number ): ChargingReminder[] { const reminders: ChargingReminder[] = []; const batteryLevel = vehicleState.battery_level || 0; const rangeMiles = vehicleState.battery_range || 0; const chargingState = vehicleState.charging_state || 'Disconnected'; const isHome = this.isHomeLocation(vehicleState); // Critical range warnings if (rangeMiles < this.EMERGENCY_RANGE_THRESHOLD) { reminders.push({ priority: 'urgent', type: 'range_warning', title: '🚨 Critical Range Alert', message: `Only ${Math.round(rangeMiles)} miles remaining. Find charging immediately!`, action_required: true, time_sensitive: true, deadline: 'ASAP' }); } else if (rangeMiles < this.COMFORT_RANGE_THRESHOLD) { reminders.push({ priority: 'high', type: 'range_warning', title: '⚠️ Low Range Warning', message: `${Math.round(rangeMiles)} miles remaining. Plan charging for today.`, action_required: true, time_sensitive: true, deadline: 'Today' }); } // Optimal charging reminders if (isHome && chargingState === 'Disconnected' && batteryLevel < this.OPTIMAL_CHARGE_LEVEL) { const chargeNeeded = this.OPTIMAL_CHARGE_LEVEL - batteryLevel; const savings = this.calculateOffPeakSavings(chargeNeeded); reminders.push({ priority: batteryLevel < 30 ? 'high' : 'medium', type: 'optimal_charge', title: '🔌 Plug In Recommended', message: `Battery at ${batteryLevel}%. Charge to ${this.OPTIMAL_CHARGE_LEVEL}% during off-peak hours.`, action_required: true, estimated_savings: `$${savings.toFixed(2)}/charge`, time_sensitive: false }); } // Time-of-use optimization if (chargingState === 'Charging' && this.isDuringPeakHours()) { const savings = this.calculateOffPeakSavings(20); // Assume 20% charge reminders.push({ priority: 'medium', type: 'time_of_use', title: '💰 Peak Hour Charging Alert', message: 'Currently charging during peak rates. Consider scheduling for off-peak hours.', action_required: false, estimated_savings: `$${savings.toFixed(2)}/session`, time_sensitive: true }); } // Weather preparation if (weatherTemp !== undefined) { if (weatherTemp < this.COLD_WEATHER_THRESHOLD && batteryLevel < 90) { reminders.push({ priority: 'medium', type: 'weather_prep', title: '❄️ Cold Weather Prep', message: `Freezing weather ahead (${weatherTemp}°F). Charge to 90% and precondition cabin.`, action_required: true, time_sensitive: true, deadline: 'Before tomorrow' }); } else if (weatherTemp > this.HOT_WEATHER_THRESHOLD && batteryLevel < 85) { reminders.push({ priority: 'medium', type: 'weather_prep', title: '🔥 Hot Weather Prep', message: `High temperatures forecast (${weatherTemp}°F). Charge to 85% and precondition.`, action_required: true, time_sensitive: true, deadline: 'Before peak heat' }); } } // Trip preparation if (nextTripDistance && nextTripDistance > 0) { const requiredRange = nextTripDistance * 1.3; // 30% buffer if (rangeMiles < requiredRange) { const chargeNeeded = Math.ceil((requiredRange - rangeMiles) / 3); // ~3 miles per % reminders.push({ priority: 'high', type: 'trip_prep', title: '🛣️ Trip Charging Required', message: `${nextTripDistance}-mile trip needs ${chargeNeeded}% more charge. Plan charging stops if needed.`, action_required: true, time_sensitive: true, deadline: 'Before departure' }); } } // Daily routine reminders const rangeForTomorrow = rangeMiles - dailyMiles; if (rangeForTomorrow < this.COMFORT_RANGE_THRESHOLD && isHome) { reminders.push({ priority: 'medium', type: 'optimal_charge', title: '🌅 Daily Routine Charging', message: `Tomorrow's commute (~${dailyMiles} mi) will leave ${Math.round(rangeForTomorrow)} miles. Plug in tonight.`, action_required: true, time_sensitive: false }); } // Maintenance reminders if (batteryLevel === 100 && chargingState === 'Complete') { reminders.push({ priority: 'low', type: 'maintenance', title: '🔋 Battery Health Tip', message: 'Avoid keeping battery at 100% unless needed for long trips. Consider setting daily limit to 80%.', action_required: false, time_sensitive: false }); } return reminders; } private calculateOptimalSchedule(batteryLevel: number, dailyMiles: number): ChargingStrategy['charging_schedule'] { // Calculate charge needed for daily routine plus buffer const rangeNeeded = dailyMiles * 1.5; // 50% buffer const chargeNeeded = Math.max(0, this.OPTIMAL_CHARGE_LEVEL - batteryLevel); // Estimate charging time (assume Level 2 charging ~25 miles/hour) const chargingHours = Math.ceil(chargeNeeded * 3 / 25); // Rough estimate // Calculate optimal off-peak window const optimalStart = Math.max(this.OFF_PEAK_START, 23); const optimalEnd = Math.min(this.OFF_PEAK_END + chargingHours, 7); const savings = this.calculateOffPeakSavings(chargeNeeded); return { optimal_start_time: `${optimalStart === 23 ? 11 : optimalStart}:00 PM`, optimal_end_time: `${optimalEnd}:00 AM`, off_peak_window: `11:00 PM - 7:00 AM`, estimated_cost_savings: Math.round(savings * 100) / 100 }; } private analyzeRange( batteryLevel: number, rangeMiles: number, dailyMiles: number, nextTripDistance?: number ): ChargingStrategy['range_analysis'] { const comfortRange = rangeMiles > this.COMFORT_RANGE_THRESHOLD; const emergencyRange = rangeMiles < this.EMERGENCY_RANGE_THRESHOLD; // Calculate recommended charge level let recommendedLevel = this.OPTIMAL_CHARGE_LEVEL; if (nextTripDistance && nextTripDistance > 200) { recommendedLevel = Math.min(100, 90); // Long trip preparation } else if (dailyMiles > 60) { recommendedLevel = this.DAILY_CHARGE_LEVEL; // High daily usage } // Estimate when next charge is needed const rangeAfterDailyDriving = rangeMiles - dailyMiles; let nextChargeNeeded = 'Not needed'; if (rangeAfterDailyDriving < this.COMFORT_RANGE_THRESHOLD) { nextChargeNeeded = 'Tonight'; } else if (rangeAfterDailyDriving < dailyMiles * 2) { nextChargeNeeded = 'Tomorrow evening'; } else { const daysUntilCharge = Math.floor(rangeAfterDailyDriving / dailyMiles); nextChargeNeeded = `In ${daysUntilCharge} days`; } return { comfort_range: comfortRange, emergency_range: emergencyRange, recommended_charge_level: recommendedLevel, next_charge_needed: nextChargeNeeded }; } private generateSmartInsights( vehicleState: TessieVehicleState, batteryLevel: number, rangeMiles: number, dailyMiles: number, weatherTemp?: number ): string[] { const insights: string[] = []; const chargingState = vehicleState.charging_state || 'Disconnected'; // Charging efficiency insights if (chargingState === 'Charging') { if (this.isDuringPeakHours()) { insights.push('💸 Charging during peak hours costs ~170% more than off-peak rates'); } else { insights.push('💚 Great timing! Off-peak charging saves $2-5 per session'); } } // Battery level insights if (batteryLevel > 95) { insights.push('🔋 Consider setting daily charge limit to 80% to optimize battery longevity'); } else if (batteryLevel < 20) { insights.push('⚡ Low battery increases phantom drain - charge soon to maintain efficiency'); } // Range vs usage insights const daysOfRange = Math.floor(rangeMiles / dailyMiles); if (daysOfRange >= 5) { insights.push(`🎯 Current range covers ${daysOfRange} days of typical driving - you're well prepared`); } else if (daysOfRange <= 1) { insights.push('📅 Less than 2 days of range remaining - plan charging today'); } // Weather impact insights if (weatherTemp !== undefined) { if (weatherTemp < 32) { insights.push('❄️ Cold weather reduces range ~20-30% - factor this into trip planning'); } else if (weatherTemp > 85) { insights.push('🌡️ Hot weather increases A/C usage - expect 10-15% range reduction'); } else { insights.push('🌤️ Mild weather conditions optimal for efficiency and range'); } } // Charging pattern insights if (batteryLevel < 50 && chargingState === 'Disconnected') { insights.push('🔌 Plugging in now would complete charging during off-peak hours tonight'); } return insights; } private isHomeLocation(vehicleState: TessieVehicleState): boolean { // Simple heuristic: if the car is parked and not at a known charging location // In a real implementation, this would check against user's home coordinates const speed = vehicleState.speed || 0; return speed === 0; // Simplified - assume stationary = home } private isDuringPeakHours(): boolean { const hour = new Date().getHours(); return hour >= 16 && hour <= 21; // 4 PM - 9 PM peak hours } private calculateOffPeakSavings(chargePercent: number): number { // Estimate kWh for charge percentage (assuming 75kWh battery) const kwhNeeded = (chargePercent / 100) * 75; const peakCost = kwhNeeded * this.PEAK_RATE; const offPeakCost = kwhNeeded * this.OFF_PEAK_RATE; return peakCost - offPeakCost; } private getPriorityWeight(priority: ChargingReminder['priority']): number { const weights = { urgent: 1, high: 2, medium: 3, low: 4 }; return weights[priority]; } }

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