npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@smartcar/signals

v1.1.0

Published

TypeScript SDK for parsing Smartcar vehicle signals

Readme

Signal Parsing Functions - Usage Examples

This document demonstrates how to use all the signal parsing functions available in @smartcar/signals.

Available Functions

  • getSignalByCode<T>(signals, code) - Get a single signal by its code
  • getSignalsByCodes<T>(signals, codes) - Get multiple signals by their codes
  • getSignalGroup<T>(signals, signalMap) - Get a group of signals with custom naming

1. Basic Single Signal Retrieval

Example: Get Current Charging Rate

import { 
  getSignalByCode, 
  type Signals,
  type ChargeAmperage 
} from '@smartcar/signals';

function getCurrentChargingAmperage(signals: Signals) {
  const amperageSignal: ChargeAmperage | undefined = getSignalByCode<ChargeAmperage>(signals, 'charge-amperage');
  
  if (amperageSignal) {
    if (amperageSignal.status.value === 'SUCCESS') {
        return {
            isCharging: amperageSignal.body.value > 0,
            rate: `${amperageSignal.body.value} ${amperageSignal.body.unit}`,
            timestamp: amperageSignal.meta.oemUpdatedAt,
            status: amperageSignal.status
        }
    } else {
        return {
            isCharging: null,
            rate: null,
            timestamp: amperageSignal.meta.oemUpdatedAt,
            status: amperageSignal.status
        }
    }
  }
  
  return { 
    isCharging: null, 
    rate: null, 
    timestamp: null,
    status: 'MISSING'
  };
}

2. Multiple Signals by Codes

Example: Battery Status Dashboard

import { 
  getSignalsByCodes, 
  type Signals,
  type ChargeIsCharging,
  type ChargeAmperage,
  type LowVoltageBatteryStateOfCharge,
  type LowVoltageBatteryStatus,
  type TractionBatteryStateOfCharge
} from '@smartcar/signals';

type BatterySignals = {
  chargingStatus: ChargeIsCharging;
  chargingAmperage: ChargeAmperage;
  lowVoltageSOC: LowVoltageBatteryStateOfCharge; 
  lowVoltageStatus: LowVoltageBatteryStatus;
  mainBatterySOC: TractionBatteryStateOfCharge;
};

function getBatteryStatus(signals: Signals) {
  const batteryData = getSignalsByCodes<BatterySignals>(signals, [
    'charge-ischarging',
    'charge-amperage',
    'lowvoltagebattery-stateofcharge', 
    'lowvoltagebattery-status',
    'tractionbattery-stateofcharge'
  ]);

  return {
    // Charging information
    isCharging: batteryData.chargingStatus?.body.value ?? false,
    chargingRate: batteryData.chargingAmperage ? 
      `${batteryData.chargingAmperage.body.value} ${batteryData.chargingAmperage.body.unit}` : 'N/A',
    
    // Low voltage battery (12V system)
    lowVoltageBattery: {
      stateOfCharge: batteryData.lowVoltageSOC?.body.value ?? null,
      status: batteryData.lowVoltageStatus?.body.value ?? 'unknown',
      unit: batteryData.lowVoltageSOC?.body.unit ?? ''
    },
    
    // Main traction battery (EV)
    mainBattery: {
      stateOfCharge: batteryData.mainBatterySOC?.body.value ?? null,
      unit: batteryData.mainBatterySOC?.body.unit ?? '%'
    },
    
    // Overall health check
    allSystemsHealthy: [
      batteryData.charging?.status,
      batteryData.lowVoltageSOC?.status, 
      batteryData.lowVoltageStatus?.status,
      batteryData.mainBatterySOC?.status
    ].every(status => status === 'success')
  };
}

Example: Vehicle Diagnostics Summary

import { 
  getSignalsByCodes, 
  type Signals,
  type DiagnosticsEVBatteryConditioning,
  type DiagnosticsEVHVBattery,
  type DiagnosticsOilLife,
  type DiagnosticsTirePressure,
  type DiagnosticsMIL
} from '@smartcar/signals';

type DiagnosticSignals = {
  batteryConditioning: DiagnosticsEVBatteryConditioning;
  hvBattery: DiagnosticsEVHVBattery;
  oilLife: DiagnosticsOilLife;
  tirePressure: DiagnosticsTirePressure;
  checkEngine: DiagnosticsMIL;
};

function getVehicleDiagnostics(signals: Signals) {
  const diagnostics = getSignalsByCodes<DiagnosticSignals>(signals, [
    'batteryConditioning',
    'hvBattery',
    'oilLife', 
    'tirePressure',
    'checkEngine'
  ]);

  const issues = [];
  const warnings = [];

  // Check each diagnostic signal
  if (diagnostics.batteryConditioning?.body.value !== 'normal') {
    issues.push('Battery conditioning system needs attention');
  }

  if (diagnostics.hvBattery?.body.value !== 'normal') {
    issues.push('High voltage battery system alert');
  }

  if (diagnostics.oilLife && diagnostics.oilLife.body.value < 20) {
    warnings.push(`Oil life low: ${diagnostics.oilLife.body.value}%`);
  }

  if (diagnostics.tirePressure?.body.value !== 'normal') {
    warnings.push('Tire pressure monitoring alert');
  }

  if (diagnostics.checkEngine?.body.value === true) {
    issues.push('Check engine light is on');
  }

  return {
    overallHealth: issues.length === 0 ? 'good' : 'needs_attention',
    criticalIssues: issues,
    warnings: warnings,
    lastChecked: Math.max(
      ...Object.values(diagnostics)
        .filter(signal => signal)
        .map(signal => signal!.meta.retrievedAt)
    )
  };
}

3. Signal Groups with Custom Naming

Example: Driver Dashboard

import { 
  getSignalGroup, 
  type Signals,
  type MotionCurrentSpeed,
  type OdometerTraveledDistance,
  type InternalCombustionEngineFuelLevel,
  type TractionBatteryStateOfCharge,
  type LocationPreciseLocation
} from '@smartcar/signals';

type DashboardSignals = {
  speed: MotionCurrentSpeed;
  odometer: OdometerTraveledDistance;
  fuelLevel: InternalCombustionEngineFuelLevel;
  batteryLevel: TractionBatteryStateOfCharge;
  location: LocationPreciseLocation;
};

function createDriverDashboard(signals: Signals) {
  // Map friendly names to actual signal codes
  const dashboard = getSignalGroup<DashboardSignals>(signals, {
    speed: 'motion-currentspeed',
    odometer: 'odometer-traveleddistance',
    fuelLevel: 'internalcombustionengine-fuellevel',
    batteryLevel: 'tractionbattery-stateofcharge',
    location: 'location-preciselocation'
  });

  return {
    // Speed information
    currentSpeed: dashboard.speed ? {
      value: dashboard.speed.body.value,
      unit: dashboard.speed.body.unit,
      display: `${dashboard.speed.body.value} ${dashboard.speed.body.unit}`
    } : null,
    
    // Distance traveled
    totalDistance: dashboard.odometer ? {
      value: dashboard.odometer.body.value,
      unit: dashboard.odometer.body.unit,
      display: `${dashboard.odometer.body.value.toLocaleString()} ${dashboard.odometer.body.unit}`
    } : null,
    
    // Energy levels (fuel or battery)
    energyLevel: {
      fuel: dashboard.fuelLevel ? {
        percentage: dashboard.fuelLevel.body.value,
        unit: dashboard.fuelLevel.body.unit
      } : null,
      battery: dashboard.batteryLevel ? {
        percentage: dashboard.batteryLevel.body.value,
        unit: dashboard.batteryLevel.body.unit
      } : null
    },
    
    // Current position
    position: dashboard.location ? {
      latitude: dashboard.location.body.latitude,
      longitude: dashboard.location.body.longitude,
      heading: dashboard.location.body.heading,
      coordinates: `${dashboard.location.body.latitude}, ${dashboard.location.body.longitude}`
    } : null,
    
    // Data freshness
    lastUpdated: Math.max(
      dashboard.speed?.meta.retrievedAt ?? 0,
      dashboard.odometer?.meta.retrievedAt ?? 0,
      dashboard.fuelLevel?.meta.retrievedAt ?? 0,
      dashboard.batteryLevel?.meta.retrievedAt ?? 0,
      dashboard.location?.meta.retrievedAt ?? 0
    )
  };
}

Example: Climate Control Status

import { 
  getSignalGroup, 
  type Signals,
  type ClimateInternalTemperature,
  type ClimateExternalTemperature,
  type HVACCabinTargetTemperature,
  type HVACIsCabinHVACActive,
  type HVACIsFrontDefrosterActive,
  type HVACIsRearDefrosterActive
} from '@smartcar/signals';

type ClimateSignals = {
  insideTemp: ClimateInternalTemperature;
  outsideTemp: ClimateExternalTemperature;
  targetTemp: HVACCabinTargetTemperature;
  hvacActive: HVACIsCabinHVACActive;
  frontDefroster: HVACIsFrontDefrosterActive;
  rearDefroster: HVACIsRearDefrosterActive;
};

function getClimateStatus(signals: Signals) {
  const climate = getSignalGroup<ClimateSignals>(signals, {
    insideTemp: 'climate-internaltemperature',
    outsideTemp: 'climate-externaltemperature', 
    targetTemp: 'hvac-cabintargettemperature',
    hvacActive: 'hvac-iscabinhvacactive',
    frontDefroster: 'hvac-isfrontdefrosteractive',
    rearDefroster: 'hvac-isreardefrosteractive'
  });

  return {
    temperatures: {
      inside: climate.insideTemp ? {
        value: climate.insideTemp.body.value,
        unit: climate.insideTemp.body.unit
      } : null,
      outside: climate.outsideTemp ? {
        value: climate.outsideTemp.body.value,
        unit: climate.outsideTemp.body.unit
      } : null,
      target: climate.targetTemp ? {
        value: climate.targetTemp.body.value,
        unit: climate.targetTemp.body.unit
      } : null
    },
    
    systems: {
      hvacRunning: climate.hvacActive?.body.value ?? false,
      frontDefrosterOn: climate.frontDefroster?.body.value ?? false,
      rearDefrosterOn: climate.rearDefroster?.body.value ?? false
    },
    
    // Calculate temperature difference
    temperatureDelta: (climate.insideTemp && climate.outsideTemp) ? 
      climate.insideTemp.body.value - climate.outsideTemp.body.value : null,
    
    // System status
    systemsActive: [
      climate.hvacActive?.body.value,
      climate.frontDefroster?.body.value,
      climate.rearDefroster?.body.value
    ].some(Boolean)
  };
}

4. Error Handling and Validation

Example: Robust Signal Processing

import { 
  getSignalsByCodes, 
  type Signals,
  type MotionCurrentSpeed,
  type TractionBatteryStateOfCharge
} from '@smartcar/signals';

function processSignalsWithValidation(signals: Signals) {
  type CriticalSignals = {
    speed: MotionCurrentSpeed;
    battery: TractionBatteryStateOfCharge;
  };

  const data = getSignalsByCodes<CriticalSignals>(signals, ['speed', 'battery']);

  // Validate signal availability
  const validation = {
    hasSpeed: data.speed !== undefined,
    hasBattery: data.battery !== undefined,
    speedStatus: data.speed?.status ?? 'missing',
    batteryStatus: data.battery?.status ?? 'missing'
  };

  // Check for critical missing signals
  const missingCritical = [];
  if (!validation.hasSpeed) missingCritical.push('speed');
  if (!validation.hasBattery) missingCritical.push('battery');
  
  if (missingCritical.length > 0) {
    throw new Error(`Missing critical signals: ${missingCritical.join(', ')}`);
  }

  // Check for stale data (older than 5 minutes)
  const fiveMinutesAgo = Date.now() / 1000 - 300;
  const staleSignals = [];
  
  if (data.speed!.meta.retrievedAt < fiveMinutesAgo) {
    staleSignals.push('speed');
  }
  if (data.battery!.meta.retrievedAt < fiveMinutesAgo) {
    staleSignals.push('battery');
  }

  return {
    data: {
      speed: data.speed!.body.value,
      speedUnit: data.speed!.body.unit,
      batteryLevel: data.battery!.body.value,
      batteryUnit: data.battery!.body.unit
    },
    validation: {
      ...validation,
      hasStaleData: staleSignals.length > 0,
      staleSignals,
      dataQuality: staleSignals.length === 0 ? 'fresh' : 'stale'
    },
    timestamps: {
      speed: data.speed!.meta.retrievedAt,
      battery: data.battery!.meta.retrievedAt,
      oldestData: Math.min(data.speed!.meta.retrievedAt, data.battery!.meta.retrievedAt)
    }
  };
}

Usage Summary

  1. getSignalByCode - Use when you need one specific signal
  2. getSignalsByCodes - Use when you need multiple related signals
  3. getSignalGroup - Use when you want custom naming for your signals
  4. Always handle undefined - Signals may not be available
  5. Check signal status - Verify data quality with signal.status
  6. Use timestamps - Check signal.meta.retrievedAt for data freshness