iobroker.lovelace
Version:
With this adapter you can build visualization for ioBroker with Home Assistant Lovelace UI
236 lines (235 loc) • 9.83 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var converter_exports = {};
__export(converter_exports, {
Converter: () => Converter,
Entity: () => import_baseEntity.BaseEntity,
default: () => converter_default
});
module.exports = __toCommonJS(converter_exports);
var import_indicators = require("./indicators");
var import_entity_id = require("../entities/entity_id");
var import_baseEntity = require("../entities/baseEntity");
const entityData = require("../../../lib/dataSingleton");
class Converter {
/**
* Registry of TypeScript converter subclasses keyed by device type.
* Populated by each subclass module at load time.
*/
static converters = {};
/**
* Tracks duplicate-iob-id reports already logged this run so we don't spam
* the log on every redetection pass.
*/
static _loggedDuplicateIobIds = /* @__PURE__ */ new Set();
/**
* Override in subclasses to return the HA entities for this device type.
* Called by the base class convert() after resolving forcedEntityId.
*
* @param _params - conversion parameters with a single controls PatternControl
* @returns array of created entities (may be empty, may be async)
*/
static convertEntities(_params) {
return [];
}
/**
* Template method — do not override in subclasses.
* Calls this.convertEntities(), adds indicator entities, handles duplicates.
*
* @param params - conversion parameters (controls is a single PatternControl)
*/
static convert(params) {
const entities = this.convertEntities(params);
Converter._processEntities(entities, params);
}
/**
* Main entry point called from server.js.
* Iterates over all detected controls and dispatches each one to the right converter.
* Dispatches each control to the matching TypeScript converter subclass.
*
* @param controls - array of PatternControls returned by type-detector
* @param baseParams - all parameters except 'controls'
*/
static convertAll(controls, baseParams) {
var _a, _b;
const { adapter } = baseParams;
for (const control of controls) {
const params = { ...baseParams, controls: control };
const ConverterClass = Converter.converters[control.type];
if (ConverterClass) {
ConverterClass.convert(params);
continue;
}
adapter.log.debug(
`[Type-Detector] device ${(_b = (_a = control.states) == null ? void 0 : _a.find((e) => e == null ? void 0 : e.id)) == null ? void 0 : _b.id} - ${control.type} - ${baseParams.id} is not yet supported`
);
}
}
/**
* Shared post-processing for a batch of entities produced by a single converter call.
* Adds indicator entities (battery, connectivity, error, maintenance, working),
* detects and resolves duplicate entity_ids, and pushes into existingEntities.
*
* @param entities - entities produced by the converter
* @param params - conversion parameters
*/
static _processEntities(entities, params) {
var _a, _b, _c;
if (!(entities == null ? void 0 : entities.length)) {
return;
}
const { existingEntities, adapter, entityRegistry, controls } = params;
if (entityData.autoEntityIdFormat === "iobId") {
for (const entity of entities) {
const stateId = (_b = (_a = entity == null ? void 0 : entity.context) == null ? void 0 : _a.STATE) == null ? void 0 : _b.getId;
if (entity && stateId) {
entity.entity_id = (0, import_entity_id.getEntityId)(entity.entity_id.split(".")[0], null, {
_id: stateId
});
}
}
}
for (const entity of entities) {
if (!entity) {
continue;
}
const reserved = entityRegistry.getReservedEntityId(Converter._registryKey(entity));
if (reserved) {
entity.entity_id = reserved;
}
}
const mainEntity = entities.find((x) => x == null ? void 0 : x.entity_id);
if (mainEntity) {
entities.push(...Converter._generateEntitiesFromIndicators(mainEntity, params));
const electricitySensors = (0, import_indicators.generateElectricitySensors)(params, mainEntity.entity_id.split(".")[1]);
for (const sensor of electricitySensors) {
sensor.context.deviceId = mainEntity.context.id;
}
entities.push(...electricitySensors);
}
for (const entity of entities) {
if (((_c = entity == null ? void 0 : entity.context.STATE) == null ? void 0 : _c.getId) && entity.context.STATE.getId !== entity.context.id) {
entity.context.id = entity.context.STATE.getId;
}
}
for (const entity of entities) {
if (!entity) {
continue;
}
if (!entity.context.iobType) {
entity.context.iobType = controls.type;
}
const existing = existingEntities.find((e) => e.entity_id === entity.entity_id);
if (existing) {
if (entity.context.id !== existing.context.id) {
const newId = Converter._resolveCollision(entity, existingEntities);
adapter.log.debug(
`Duplicates found for ${existing.entity_id}, solved by renaming second to ${newId}`
);
entity.entity_id = newId;
} else {
const dupKey = `${entity.entity_id}|${entity.context.id}`;
if (!Converter._loggedDuplicateIobIds.has(dupKey)) {
Converter._loggedDuplicateIobIds.add(dupKey);
adapter.log.info(
`Duplicate entities for identical iob ids? ${entity.entity_id}, ${entity.context.id}, ${controls.type}, ${params.id}`
);
}
continue;
}
}
entityRegistry.reserveEntityId(Converter._registryKey(entity), entity.entity_id);
existingEntities.push(entity);
adapter.log.debug(
`[Type-Detector] Created auto device: ${entity.entity_id} - ${controls.type} - ${params.id}`
);
}
}
/**
* Build the registry composite key for an entity:
* `${entityType}.${STATE.getId ?? context.id}`.
* Works before or after the context.id rewrite step.
*
* @param entity - entity to derive the key for
*/
static _registryKey(entity) {
var _a, _b;
const type = entity.entity_id.split(".")[0];
const stableId = (_b = (_a = entity.context.STATE) == null ? void 0 : _a.getId) != null ? _b : entity.context.id;
return `${type}.${stableId}`;
}
/**
* Generate a deterministic, non-colliding entity_id for an entity that clashes
* with an existing entity_id. Uses the last segment of context.id as suffix,
* falling back to a counter if the suffix-augmented id still collides.
*
* @param entity - entity needing a new entity_id (its current entity_id collides)
* @param existingEntities - already-registered entities to check against
*/
static _resolveCollision(entity, existingEntities) {
const base = entity.entity_id;
const lastSeg = entity.context.id.split(".").pop().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
let candidate = lastSeg ? `${base}_${lastSeg}` : `${base}_2`;
let counter = 2;
while (existingEntities.some((e) => e.entity_id === candidate)) {
candidate = lastSeg ? `${base}_${lastSeg}_${counter++}` : `${base}_${counter++}`;
}
return candidate;
}
/**
* Generate indicator entities (battery, connectivity, error, maintenance, working)
* for the given device. Sets context.deviceId on each indicator to link it back
* to the main entity.
*
* @param mainEntity - the primary entity for the device
* @param parameters - conversion parameters (used to build each indicator)
*/
static _generateEntitiesFromIndicators(mainEntity, parameters) {
const entities = [];
const baseName = mainEntity.entity_id.split(".")[1];
const add = (entity) => {
if (entity) {
entity.context.deviceId = mainEntity.context.id;
entities.push(entity);
}
};
add((0, import_indicators.processBattery)({ ...parameters, forcedEntityId: `binary_sensor.${baseName}_BatteryWarning` }));
add((0, import_indicators.connectivityIndicator)({ ...parameters, forcedEntityId: `binary_sensor.${baseName}_Connectivity` }));
add((0, import_indicators.processError)({ ...parameters, forcedEntityId: `binary_sensor.${baseName}_Error` }));
add((0, import_indicators.processMaintenance)({ ...parameters, forcedEntityId: `binary_sensor.${baseName}_Maintenance` }));
add((0, import_indicators.processWorking)({ ...parameters, forcedEntityId: `binary_sensor.${baseName}_Working` }));
return entities;
}
/**
* Create manual entity - base function for creating entities that are not based on type-detector results, but are manually
* defined by the user via object-settings.
* TODO: use in server.js
*
* @param _params - conversion parameters (unused in base; subclasses may use)
*/
static processManualEntity(_params) {
}
}
var converter_default = Converter;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Converter,
Entity
});
//# sourceMappingURL=converter.js.map