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

@gasolinaradar/ocm-collector

v1.1.1

Published

Collector for OpenChargeMap (OCM) electric vehicle charging stations (Spain) returning normalized EV stations

Readme

@gasolinaradar/ocm-collector

A Node.js collector for electric-vehicle charging stations in Spain sourced from OpenChargeMap (OCM). It queries the OCM API v3 /poi endpoint, paginates the full Spain dataset, and returns a normalized, ready-to-use array of stations following the shared Station contract.

Features / Características

  • Official OpenChargeMap API (open data only via opendata=true).
  • Paginates past OCM's per-request result cap to collect all stations (countrycode=ES, maxresults=10000).
  • Maps OCM ConnectionTypeIDs to OCPI connector types (OCM_TO_OCPI_CONNECTOR).
  • Maps OCM StatusTypeIDs to a canonical status (AVAILABLE / UNKNOWN / OUTOFORDER).
  • Classifies OCM UsageTypeIDs into a usageRestrictions object (access + payAtLocation / membershipRequired / accessKeyRequired) from the official OCM UsageTypes table.
  • Built-in retry with exponential backoff.
  • Injectable logger, HTTP client, and URL resolver.
  • Progress reporting hook for long runs.
  • API key read from the OCM_API_KEY environment variable.

Installation / Instalación

npm install @gasolinaradar/ocm-collector

Quick start / Inicio rápido

export OCM_API_KEY=your_key_here
const { fetchStations } = require('@gasolinaradar/ocm-collector');

async function main() {
  const stations = await fetchStations();
  console.log(`Fetched ${stations.length} charging stations`);
  console.log(stations[0]);
}

main();

API

fetchStations(options?) → Promise<Station[]>

Downloads the full Spain OCM dataset and returns normalized stations in one step.

const { fetchStations } = require('@gasolinaradar/ocm-collector');

const stations = await fetchStations({
  apiKey: process.env.OCM_API_KEY,
  logger: console,
  timeout: 15000,
  retries: 3,
});

The API key is also read automatically from the OCM_API_KEY environment variable when options.apiKey is omitted.

createOcmCollector(options?) → Collector

Returns an object matching the common collector contract used by ingestion pipelines:

{ name: 'ocm', country: 'ES', fetch(context) }
const { createOcmCollector } = require('@gasolinaradar/ocm-collector');

const ocmCollector = createOcmCollector({ logger });

const stations = await ocmCollector.fetch({
  reportProgress(percent, metadata = {}) {
    console.log(`${percent}%`, metadata);
  },
});

Options / Opciones

| Option | Type | Default | Description | | ------------ | ---------------------- | ------------------ | ----------------------------------------------------------------- | | url | string | OCM v3 /poi URL | API endpoint. | | apiKey | string | OCM_API_KEY env | OCM API key. | | timeout | number | 15000 | HTTP timeout in milliseconds. | | retries | number | 3 | Retry attempts before failing. | | logger | { info, warn } | console | Injectable logger. | | httpClient | { get(url, opts) } | axios | Injectable HTTP client (useful for tests). |

Output schema / Esquema de salida

Each normalized station matches the shared EV Station contract:

{
  source: 'ocm',
  country: 'ES',
  sourceStationId: 'ocm-200352',
  name: 'Mardy Street',
  address: 'Calle Mayor 1',
  municipality: 'Madrid',
  province: 'Madrid',
  postalCode: '28013',
  location: { type: 'Point', coordinates: [-3.70379, 40.416775] }, // [lon, lat]
  connectorTypeKeys: ['28'],
  connectors: [
    {
      type: 'IEC_62196_T2',
      format: null,
      mode: null,
      maxPowerKw: 7.4,
      voltageV: 230,
      maxCurrentA: 32,
      typeKey: '28',
    },
  ],
  operator: { name: 'Opcharge', website: 'https://opcharge.example' },
  status: 'AVAILABLE',
  services: ['ev_charging'],
  typeOfSite: undefined, // never set for OCM points (that key carries dgtEv semantics)
  usageRestrictions: {
    access: 'unknown', // 'public' | 'private' | 'unknown'
    title: '(Unknown)', // real OCM UsageTypes title
    payAtLocation: false,
    membershipRequired: false,
    accessKeyRequired: false,
  },
  lastUpdated: Date, // timestamp of the normalization
}

Notes / Notas:

  • Coordinates are [longitude, latitude] (GeoJSON order).
  • status is derived from OCM StatusTypeID: 10/50 → AVAILABLE, 20 → UNKNOWN, 75 → OUTOFORDER, 150 → UNKNOWN.
  • usageRestrictions is derived from OCM UsageTypeID via the official UsageTypes referencedata table (1 → public, 2/3/6 → private, 4 → public + membershipRequired + accessKeyRequired, 5 → public + payAtLocation, 7 → public, 0/missing → unknown). It is always present.
  • typeOfSite is never populated for OCM points; use usageRestrictions.access instead.
  • A POI without a matching connector table entry or operator is handled gracefully (connector type UNKNOWN, operator: undefined).

Tests

npm test   # unit tests (mocked HTTP)

License / Licencia

MIT. See LICENSE. The underlying OCM data is subject to OCM's own terms and is filtered to open data via opendata=true.