Files
integrations/ts/integrations/ipp/ipp.mapper.ts
T

175 lines
7.7 KiB
TypeScript

import * as plugins from '../../plugins.js';
import type { IIntegrationEntity } from '../../core/types.js';
import type { IIppJobInfo, IIppMarkerInfo, IIppSnapshot } from './ipp.types.js';
const ippDomain = 'ipp';
export class IppMapper {
public static toDevices(snapshotArg: IIppSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
const updatedAt = snapshotArg.updatedAt || new Date().toISOString();
const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
{ id: 'status', capability: 'sensor', name: 'Printer status', readable: true, writable: false },
{ id: 'queued_jobs', capability: 'sensor', name: 'Queued jobs', readable: true, writable: false },
{ id: 'accepting_jobs', capability: 'sensor', name: 'Accepting jobs', readable: true, writable: false },
];
const state: plugins.shxInterfaces.data.IDeviceState[] = [
{ featureId: 'status', value: snapshotArg.status.printerState, updatedAt },
{ featureId: 'queued_jobs', value: snapshotArg.status.queuedJobCount ?? null, updatedAt },
{ featureId: 'accepting_jobs', value: snapshotArg.status.acceptingJobs ?? null, updatedAt },
];
for (const marker of snapshotArg.markers) {
const featureId = `marker_${marker.index}`;
features.push({ id: featureId, capability: 'sensor', name: marker.name, readable: true, writable: false, unit: '%' });
state.push({ featureId, value: marker.level ?? null, updatedAt });
}
for (const job of snapshotArg.jobs) {
const featureId = `job_${this.slug(job.id)}`;
features.push({ id: featureId, capability: 'sensor', name: job.name || `Job ${job.id}`, readable: true, writable: false });
state.push({ featureId, value: job.state || null, updatedAt });
}
return [{
id: this.printerDeviceId(snapshotArg),
integrationDomain: ippDomain,
name: this.printerName(snapshotArg),
protocol: 'http',
manufacturer: snapshotArg.printer.manufacturer || 'Unknown',
model: snapshotArg.printer.model || snapshotArg.printer.makeAndModel || 'IPP printer',
online: snapshotArg.online,
features,
state,
metadata: this.cleanAttributes({
serialNumber: snapshotArg.printer.serialNumber,
uuid: snapshotArg.printer.uuid,
location: snapshotArg.printer.location,
info: snapshotArg.printer.info,
moreInfo: snapshotArg.printer.moreInfo,
commandSet: snapshotArg.printer.commandSet,
uriSupported: snapshotArg.printer.uriSupported,
host: snapshotArg.printer.host,
port: snapshotArg.printer.port,
basePath: snapshotArg.printer.basePath,
tls: snapshotArg.printer.tls,
source: snapshotArg.source,
stateReasons: snapshotArg.status.stateReasons,
markerCount: snapshotArg.markers.length,
jobCount: snapshotArg.jobs.length,
error: snapshotArg.error,
}),
}];
}
public static toEntities(snapshotArg: IIppSnapshot): IIntegrationEntity[] {
const deviceId = this.printerDeviceId(snapshotArg);
const uniqueBase = this.uniqueBase(snapshotArg);
const baseName = this.printerName(snapshotArg);
const entities: IIntegrationEntity[] = [];
entities.push(this.entity('sensor', 'printer', `${baseName} Status`, snapshotArg.status.printerState, deviceId, uniqueBase, snapshotArg.online, {
deviceClass: 'enum',
options: ['idle', 'printing', 'stopped'],
info: snapshotArg.printer.info,
serial: snapshotArg.printer.serialNumber,
uuid: snapshotArg.printer.uuid,
location: snapshotArg.printer.location,
stateMessage: snapshotArg.status.stateMessage,
stateReason: snapshotArg.status.stateReasons,
commandSet: snapshotArg.printer.commandSet,
uriSupported: snapshotArg.printer.uriSupported?.join(','),
manufacturer: snapshotArg.printer.manufacturer,
model: snapshotArg.printer.model,
source: snapshotArg.source,
error: snapshotArg.error,
}));
if (snapshotArg.status.bootedAt) {
entities.push(this.entity('sensor', 'uptime', `${baseName} Uptime`, snapshotArg.status.bootedAt, deviceId, uniqueBase, snapshotArg.online, {
deviceClass: 'timestamp',
entityCategory: 'diagnostic',
}));
}
if (snapshotArg.status.queuedJobCount !== undefined) {
entities.push(this.entity('sensor', 'queued_jobs', `${baseName} Queued Jobs`, snapshotArg.status.queuedJobCount, deviceId, uniqueBase, snapshotArg.online, {
stateClass: 'measurement',
}));
}
if (snapshotArg.status.acceptingJobs !== undefined) {
entities.push(this.entity('binary_sensor', 'accepting_jobs', `${baseName} Accepting Jobs`, snapshotArg.status.acceptingJobs ? 'on' : 'off', deviceId, uniqueBase, snapshotArg.online, {
deviceClass: 'running',
}));
}
for (const marker of snapshotArg.markers) {
entities.push(this.markerEntity(marker, deviceId, uniqueBase, snapshotArg.online));
}
for (const job of snapshotArg.jobs) {
entities.push(this.jobEntity(job, deviceId, uniqueBase, baseName, snapshotArg.online));
}
return entities;
}
public static printerDeviceId(snapshotArg: IIppSnapshot): string {
return `ipp.printer.${this.uniqueBase(snapshotArg)}`;
}
public static slug(valueArg: string): string {
return valueArg.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '') || 'ipp';
}
private static markerEntity(markerArg: IIppMarkerInfo, deviceIdArg: string, uniqueBaseArg: string, availableArg: boolean): IIntegrationEntity {
return this.entity('sensor', `marker_${markerArg.index}`, markerArg.name, markerArg.level ?? null, deviceIdArg, uniqueBaseArg, availableArg, {
unit: '%',
stateClass: 'measurement',
markerType: markerArg.type,
markerKind: markerArg.kind,
markerColor: markerArg.color,
markerLowLevel: markerArg.lowLevel,
markerHighLevel: markerArg.highLevel,
});
}
private static jobEntity(jobArg: IIppJobInfo, deviceIdArg: string, uniqueBaseArg: string, baseNameArg: string, availableArg: boolean): IIntegrationEntity {
return this.entity('sensor', `job_${this.slug(jobArg.id)}`, jobArg.name || `${baseNameArg} Job ${jobArg.id}`, jobArg.state || 'unknown', deviceIdArg, uniqueBaseArg, availableArg, {
jobId: jobArg.id,
owner: jobArg.owner,
impressionsCompleted: jobArg.impressionsCompleted,
createdAt: jobArg.createdAt,
processingAt: jobArg.processingAt,
completedAt: jobArg.completedAt,
...jobArg.attributes,
});
}
private static entity(platformArg: IIntegrationEntity['platform'], keyArg: string, nameArg: string, stateArg: unknown, deviceIdArg: string, uniqueBaseArg: string, availableArg: boolean, attributesArg: Record<string, unknown>): IIntegrationEntity {
return {
id: `${platformArg}.${this.slug(nameArg)}`,
uniqueId: `ipp_${uniqueBaseArg}_${keyArg}`,
integrationDomain: ippDomain,
deviceId: deviceIdArg,
platform: platformArg,
name: nameArg,
state: stateArg,
attributes: this.cleanAttributes(attributesArg),
available: availableArg,
};
}
private static printerName(snapshotArg: IIppSnapshot): string {
return snapshotArg.printer.name || snapshotArg.printer.model || snapshotArg.printer.host || 'IPP printer';
}
private static uniqueBase(snapshotArg: IIppSnapshot): string {
return this.slug(snapshotArg.printer.uuid || snapshotArg.printer.serialNumber || snapshotArg.printer.id || snapshotArg.printer.host || this.printerName(snapshotArg));
}
private static cleanAttributes(attributesArg: Record<string, unknown>): Record<string, unknown> {
return Object.fromEntries(Object.entries(attributesArg).filter(([, valueArg]) => valueArg !== undefined));
}
}