175 lines
7.7 KiB
TypeScript
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));
|
|
}
|
|
}
|