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

procon-ip

v2.1.4

Published

Library for the ProCon.IP pool controller

Downloads

291

Readme

procon-ip

NPM

Package info
npm version GitHub GitHub issues Known Vulnerabilities
CI Workflow Docs CodeQL
Buy me a coffee

ProCon.IP TypeScript library

Migrating from 1.x? See CHANGELOG.md — v2.0.0 drops Node ≤ 18, replaces axios with native fetch, removes deep imports, and adds DMX512 support. Migration snippets are at the bottom of the changelog.

Overview


Introduction

procon-ip is a TypeScript client library for the ProCon.IP pool controller. It wraps the controller's small HTTP surface (/GetState.csv, /usrcfg.cgi, /Command.htm, /SetState.pl, /GetDmx.csv) in typed services with a clean error model and a read-mutate-write idiom for DMX512.

Feel free to ask questions on GitHub Issues — discussions there are searchable for everyone with a similar question.

Installation

Requires Node 22 LTS or newer.

pnpm add procon-ip
# or
npm install procon-ip
# or
yarn add procon-ip

The package ships dual ESM + CJS via the exports map — both import { GetStateService } from 'procon-ip' and const { GetStateService } = require('procon-ip') work.

Examples

The runnable forms of the snippets below live under examples/.

Requesting data

import { GetStateService, GetStateCategory, Logger } from 'procon-ip';

const logger = new Logger();
const config = {
  controllerUrl: 'http://192.168.2.3', // <-- your pool controller's address
  basicAuth: true,
  username: 'admin',
  password: 'admin',
  updateInterval: 5000,
  timeout: 5000,
  errorTolerance: 2,
};

const dataSource = new GetStateService(config, logger);

// One-shot fetch:
const data = await dataSource.update();
logger.info(`Uptime: ${data.sysInfo.uptime}`);

// Or poll continuously:
dataSource.start((data) => {
  for (const obj of data.getDataObjectsByCategory(GetStateCategory.ELECTRODES)) {
    logger.info(`${obj.label}: ${obj.displayValue}`);
  }
});

Switching relays

import {
  GetStateService,
  UsrcfgCgiService,
  RelayDataInterpreter,
  GetStateCategory,
  Logger,
} from 'procon-ip';

const logger = new Logger();
const config = {
  controllerUrl: 'http://192.168.2.3',
  basicAuth: true,
  username: 'admin',
  password: 'admin',
  timeout: 5000,
  updateInterval: 5000,
  errorTolerance: 2,
};

const dataSource = new GetStateService(config, logger);
const interpreter = new RelayDataInterpreter(logger);
const relays = new UsrcfgCgiService(config, logger, dataSource, interpreter);

await dataSource.update();

// Switch a known dosage relay off:
await relays.setOff(dataSource.data.getChlorineDosageControl());

// Or hand a relay back to the controller's automatic schedule by label:
for (const relay of dataSource.data.getDataObjectsByCategory(GetStateCategory.RELAYS)) {
  if (relay.label === 'Gartenlicht') await relays.setAuto(relay);
}

setOn / setOff / setAuto return Promise<void> in v2 — failures throw the typed error classes from 'procon-ip' instead of returning a numeric response code (see Error handling).

Manual dosage

import { CommandService, Logger } from 'procon-ip';

const svc = new CommandService(
  { controllerUrl: 'http://192.168.2.3', basicAuth: false, timeout: 5000 },
  new Logger(),
);

const seconds = await svc.setChlorineDosage(60); // dose for 60s
// `seconds` === 60 on success, -1 after three retries.

DMX512

import { GetDmxService, DmxService, Logger } from 'procon-ip';

const logger = new Logger();
const config = { controllerUrl: 'http://192.168.2.3', basicAuth: false, timeout: 5000 };

const reader = new GetDmxService(config, logger);
const writer = new DmxService(config, logger);

const dmx = await reader.update();
for (const ch of dmx) dmx.set(ch.index, (ch.value + 64) % 256); // shift each channel
await writer.set(dmx);

GetDmxData is iterable, indexable via at(index), mutable via set(index, value) (clamps to [0, 255]), and produces the controller's form payload via toPostData(). The controller only accepts full 16-channel writes, so DmxService.set always sends every channel.

Error handling

All HTTP calls throw typed errors from 'procon-ip':

import {
  BadCredentialsError,
  BadStatusCodeError,
  RequestTimeoutError,
  InvalidPayloadError,
  ProconIpError,
} from 'procon-ip';

try {
  await getStateService.update();
} catch (e) {
  if (e instanceof BadCredentialsError) console.error('check basicAuth');
  else if (e instanceof RequestTimeoutError) console.error(`timeout: ${e.timeoutMs}ms`);
  else if (e instanceof BadStatusCodeError) console.error(`HTTP ${e.status}`);
  else throw e;
}

Network-level failures (DNS, connection refused, etc.) propagate as native TypeError from fetch.

Full API docs

Auto-generated TypeDoc reference, deployed on every push to master: https://ylabonte.github.io/procon-ip/.

A brief description of the ProCon.IP pool controller

The ProCon.IP pool controller is a low-budget network-attached control unit for home swimming pools. With its software-switched relays it can drive multiple pumps (filter and dosage) either on a time schedule or based on sensor readings (i/o flow sensors, Dallas 1-Wire thermometers, redox / pH electrodes), and it can also switch arbitrary relays on demand for things like garden lighting. Its DMX512 extension drives 16 channels of lighting or other DMX-compatible gear.

Not all of its functionality is reachable via the documented HTTP API, so this library reverse-engineers the parts the web UI uses (/usrcfg.cgi for relay + DMX writes, /Command.htm for manual dosage, /SetState.pl for relay timers).

For more information (German only):

Changelog

See CHANGELOG.md.

Disclaimer

I have nothing to do with the development, sales, marketing, or support of the pool controller unit itself. This is a community library that originated from my own ioBroker integration, later split out for reuse.