culligan-iot
v1.0.0
Published
Node.js client for the Culligan IoT API
Maintainers
Readme
Culligan IoT API - Node.js Client
A TypeScript/JavaScript client for the Culligan IoT API. Control your Culligan smart water softeners programmatically.
Features
- 🔐 Authentication - Login with email/password, automatic token refresh
- 📱 Device Discovery - List all registered devices
- 🎛️ Device Control - Send commands to water softeners
- 🏖️ Vacation Mode - Start/stop vacation (away) mode
- 🔄 Bypass Mode - Control bypass mode (permanent or timed)
- 📊 Telemetry - Request device telemetry updates
- 💾 Token Persistence - Export/import auth state for session persistence
- 🚀 Zero Dependencies - Uses Node.js 18+ built-in
fetch
Requirements
- Node.js 18.0.0 or higher
Installation
npm install culligan-iotQuick Start
import { CulliganApi, isSoftener } from 'culligan-iot';
// Create API client
const api = new CulliganApi();
// Login
await api.login({
email: '[email protected]',
password: 'your-password'
});
console.log('Authenticated:', api.isAuthenticated());
// Get all devices
const devices = await api.getDevices();
for (const device of devices) {
console.log(`Device: ${device.name} (${device.serialNumber})`);
// Check if it's a water softener
if (isSoftener(device)) {
// Fetch device properties
await device.update();
console.log(' Salt Level:', device.saltLevel);
console.log(' Vacation Mode:', device.isVacationMode);
console.log(' Bypassed:', device.isBypassed);
// Control the softener
// await device.startVacationMode();
// await device.stopVacationMode();
// await device.startBypassMode();
// await device.startBypassMinutes(30);
// await device.stopBypassMode();
}
}API Reference
CulliganApi
Main API client for interacting with the Culligan IoT API.
const api = new CulliganApi(options?: ClientOptions);Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| baseUrl | string | Production URL | API base URL |
| appId | string | Culligan App ID | Application identifier |
| timeout | number | 30000 | Request timeout (ms) |
| autoRefresh | boolean | true | Auto-refresh expiring tokens |
| refreshBuffer | number | 600000 | Time before expiry to refresh (ms) |
Methods
Authentication
// Login with credentials
await api.login({ email: '[email protected]', password: 'secret' });
// Check authentication status
api.isAuthenticated(); // boolean
// Get time until token expires (ms)
api.getTimeUntilExpiry(); // number | null
// Manually refresh token
await api.refreshAccessToken();
// Logout (clear tokens)
api.logout();
// Export auth state for persistence
const state = api.exportAuth(); // AuthState | null
// Import previously exported auth state
api.importAuth(state);Devices
// Get raw device registry
const registry = await api.getDeviceRegistry();
// Get typed device instances
const devices = await api.getDevices();
// Get device properties
const data = await api.getDeviceData('SERIAL_NUMBER');
// Send a command
const response = await api.sendCommand('SERIAL_NUMBER', 'telemetry.get');User
// Get user profile
const profile = await api.getUserProfile();
// Get user metadata
const metadata = await api.getUserMetadata();CulliganDevice
Base class for all Culligan devices.
Properties
| Property | Type | Description |
|----------|------|-------------|
| serialNumber | string | Device serial number |
| name | string | Device name |
| model | string \| undefined | Device model |
| isOnline | boolean | Online status |
| properties | DeviceProperty[] | Device properties (after update) |
Methods
// Fetch fresh device properties
await device.update();
// Get a specific property value
const value = device.getPropertyValue<number>('saltLevel');
// Request telemetry update
await device.requestTelemetry();CulliganSoftener
Specialized class for water softeners (extends CulliganDevice).
Additional Properties
| Property | Type | Description |
|----------|------|-------------|
| saltLevel | number \| undefined | Current salt level |
| currentFlow | number \| undefined | Current water flow |
| waterUsageToday | number \| undefined | Water usage today |
| isBypassed | boolean | Bypass mode status |
| isVacationMode | boolean | Vacation mode status |
| lastRegeneration | string \| undefined | Last regeneration date |
| daysUntilRegeneration | number \| undefined | Days until next regen |
Methods
// Vacation mode
await softener.startVacationMode();
await softener.stopVacationMode();
// Bypass mode
await softener.startBypassMode(); // Permanent
await softener.startBypassTimedMode(3600); // Timed (seconds)
await softener.startBypassMinutes(30); // Convenience (minutes)
await softener.startBypassHours(2); // Convenience (hours)
await softener.stopBypassMode();Type Guard
import { isSoftener } from 'culligan-iot';
if (isSoftener(device)) {
// TypeScript knows this is a CulliganSoftener
await device.startVacationMode();
}Token Persistence
Save and restore authentication state between sessions:
import { CulliganApi } from 'culligan-iot';
import { readFileSync, writeFileSync } from 'fs';
const api = new CulliganApi();
// Try to restore previous session
try {
const saved = JSON.parse(readFileSync('auth.json', 'utf-8'));
api.importAuth(saved);
console.log('Restored session, expires in:', api.getTimeUntilExpiry(), 'ms');
} catch {
// No saved session, login fresh
await api.login({ email: process.env.EMAIL!, password: process.env.PASSWORD! });
}
// Save session for later
const state = api.exportAuth();
if (state) {
writeFileSync('auth.json', JSON.stringify(state));
}Error Handling
import {
CulliganApi,
CulliganAuthError,
CulliganNotAuthedError,
CulliganApiError,
} from 'culligan-iot';
try {
await api.login({ email, password });
} catch (error) {
if (error instanceof CulliganAuthError) {
console.error('Invalid credentials');
} else if (error instanceof CulliganNotAuthedError) {
console.error('Not logged in');
} else if (error instanceof CulliganApiError) {
console.error('API error:', error.statusCode, error.message);
}
}License
MIT
