@solidstudio.io/observability-ai-client
v0.0.1
Published
TypeScript SDK for Observability AI API - EV charging session anomaly detection
Downloads
431
Readme
@solidstudio.io/observability-ai-client
TypeScript SDK for the Observability AI API — EV charging session anomaly detection and predictive maintenance.
Installation
npm install @solidstudio.io/observability-ai-clientQuick Start
import { ObservabilityAIClient } from '@solidstudio.io/observability-ai-client';
const client = new ObservabilityAIClient({
token: 'your-api-key',
baseUrl: 'https://api.solidstudio.ai', // production (default)
});
// Create a charging session with OCPP meter values
const session = await client.sessions.create({
sessionId: 'sess-001',
chargingStationId: 'station-1',
connectorId: 'conn-1',
meterValues: [
{ timestamp: '2025-01-15T10:00:00Z', value: 100, measurand: 'Energy.Active.Import.Register', unit: 'Wh' },
{ timestamp: '2025-01-15T10:05:00Z', value: 200, measurand: 'Energy.Active.Import.Register', unit: 'Wh' },
{ timestamp: '2025-01-15T10:10:00Z', value: 300, measurand: 'Energy.Active.Import.Register', unit: 'Wh' },
],
});
console.log(session.status, session.anomalies);Configuration
const client = new ObservabilityAIClient({
token: 'your-api-key', // Required
baseUrl: 'https://api.solidstudio.ai', // Optional - production default
// baseUrl: 'https://api.dev.solidstudio.ai/api/saas', // dev environment
timeout: 30000, // Optional - request timeout in ms
timezone: 'Europe/Warsaw', // Optional - IANA timezone for responses
headers: { 'X-Custom': 'value' }, // Optional - additional headers
});API Resources
Sessions
// Create a session (auto-runs analysis pipeline if >= 3 meter values)
const session = await client.sessions.create({
sessionId: 'sess-001',
chargingStationId: 'station-1',
connectorId: 'conn-1',
evseId: 'evse-1',
metadata: { source: 'ocpp-gateway' },
meterValues: [
{ timestamp: '2025-01-15T10:00:00Z', value: 100, measurand: 'Energy.Active.Import.Register', unit: 'Wh' },
{ timestamp: '2025-01-15T10:05:00Z', value: 200, measurand: 'Energy.Active.Import.Register', unit: 'Wh' },
{ timestamp: '2025-01-15T10:10:00Z', value: 300, measurand: 'Energy.Active.Import.Register', unit: 'Wh' },
],
});
// Replace all meter values for a session
await client.sessions.replace('sess-001', {
meterValues: [/* new complete set of meter values */],
status: 'completed', // optional: mark session status
});
// Append/update meter values incrementally
await client.sessions.update('sess-001', {
meterValues: [
{ timestamp: '2025-01-15T10:15:00Z', value: 400, measurand: 'Energy.Active.Import.Register', unit: 'Wh' },
],
});
// List sessions with filters
const sessions = await client.sessions.list({
chargingStationId: 'station-1',
isAnomaly: true,
minScore: 0.5,
dateFrom: '2025-01-01',
dateTo: '2025-01-31',
page: 1,
pageSize: 20,
});
// Get full session details
const detail = await client.sessions.get('sess-001');LLM (Explain & Ask)
// Generate AI explanation of session anomalies
const explanation = await client.sessions.explain('sess-001', { lang: 'en' });
console.log(explanation.explanation);
// Get cached explanation (no tokens consumed)
const cached = await client.sessions.getExplanation('sess-001', { lang: 'en' });
// Ask a natural language question about a session
const answer = await client.sessions.ask('sess-001', {
question: 'What caused the energy pit anomaly?',
lang: 'en',
});
console.log(answer.answer);Batch Processing
// Submit multiple sessions for async analysis
const batch = await client.batches.submit({
sessions: [
{ sessionId: 'sess-001', chargingStationId: 'st-1', connectorId: 'c-1', meterValues: [/*...*/] },
{ sessionId: 'sess-002', chargingStationId: 'st-1', connectorId: 'c-2', meterValues: [/*...*/] },
],
});
console.log(batch.batchId, batch.status); // 'pending'
// Poll batch status (paginated results)
const status = await client.batches.getStatus(batch.batchId, { page: 1, pageSize: 50 });
console.log(status.status, status.processedSessions, status.totalSessions);
console.log(status.results); // SessionAnalysisResponse[] when completedStations
// List stations with aggregated anomaly statistics
const stations = await client.stations.list({ page: 1, pageSize: 20 });
// Lookup all station IDs
const ids = await client.stations.lookup();
// Get station details (connectors, sessions, anomaly counts)
const station = await client.stations.get('charging-station-id');
// Per-connector breakdown
const connectors = await client.stations.getConnectors('charging-station-id');
// Latest SHADE inference result
const inference = await client.stations.getInference('charging-station-id');
// Station anomaly history
const anomalies = await client.stations.listAnomalies('charging-station-id', { page: 1, pageSize: 20 });
// SHADE overview (energy timeline + anomaly markers)
const overview = await client.stations.getShadeOverview('charging-station-id');
console.log(overview.dayScore, overview.isAnomaly, overview.energyTimeline);Anomalies
// List anomalies with filters
const anomalies = await client.anomalies.list({
anomalyType: 'ENERGY_PIT',
chargingPointId: 'cp-uuid',
sortByScore: 'desc',
page: 1,
pageSize: 50,
});
// List anomaly sessions
const sessions = await client.anomalies.listSessions({
anomalyType: 'KWH_DECREASE',
occurrenceFrom: '2025-01-01T00:00:00Z',
});
// List anomaly connectors
const connectors = await client.anomalies.listConnectors({
sortBy: 'anomalyCount',
});
// Get anomaly detail for a specific session + category
const detail = await client.anomalies.getDetail('session-id', 'category-id');
// Update anomaly issue status
await client.anomalies.updateIssue('issue-id', {
status: 'RESOLVED',
assignedTo: 'user-uuid',
});Statistics
const stats = await client.statistics.get();
console.log(stats.totalSessions, stats.totalAnomaliesCount, stats.revenueAtRisk);Feedback
await client.feedback.submit({
category: 'GENERAL', // 'GENERAL' | 'ANOMALY_DETAIL' | 'SESSION_DETAIL' | 'LLM_EXPLANATION'
rating: 5,
comment: 'Great anomaly detection!',
referenceId: 'session-id', // optional: link feedback to a specific resource
});Error Handling
import {
ObservabilityAIError,
ObservabilityAIAuthError,
ObservabilityAINotFoundError,
ObservabilityAIPaymentRequiredError,
ObservabilityAIRateLimitError,
ObservabilityAIValidationError,
} from '@solidstudio.io/observability-ai-client';
try {
await client.sessions.explain('sess-001');
} catch (error) {
if (error instanceof ObservabilityAIAuthError) {
// 401/403 - invalid or missing token
} else if (error instanceof ObservabilityAIPaymentRequiredError) {
// 402 - insufficient tokens
} else if (error instanceof ObservabilityAINotFoundError) {
// 404 - resource not found
} else if (error instanceof ObservabilityAIRateLimitError) {
// 429 - rate limit exceeded
} else if (error instanceof ObservabilityAIValidationError) {
// 422 - validation error
console.log(error.details); // [{loc: [...], msg: '...', type: '...'}]
} else if (error instanceof ObservabilityAIError) {
// Other API errors (500, 503, etc.)
console.log(error.statusCode, error.message);
}
}Timezone Support
const client = new ObservabilityAIClient({
token: 'your-token',
timezone: 'Europe/Warsaw', // IANA timezone name
});
// All datetime fields in responses will use the specified timezoneAnomaly Categories
| Category | Description |
|---|---|
| CHARGING_EXPECTED | Charging expected but not occurring |
| KWH_DECREASE | Energy counter decreased |
| UNEXPECTED_KWH_ACCUMULATE | Unexpected energy accumulation |
| ENERGY_PIT | Sudden drop in energy delivery |
| INCORRECT_ACTIVE_POWER_REGISTER | Power register inconsistency |
| UNEXPECTED_CHARGE_LEVEL_CHANGES | Unexpected SoC changes |
| ZERO_SESSION | No energy delivered |
Requirements
- Node.js >= 18.0.0 (uses native
fetch) - Zero runtime dependencies
Development
npm install
cp .env.example .env # Configure API key and environment
npm run build # Build (ESM + CJS)
npm run test # Run unit tests
npm run verify # Run verification against live API (uses .env)
npm run typecheck # Type check
npm run lint # Lint
npm run format # FormatLicense
MIT
