iobroker.gree-hvac
Version:
Adapter for Gree and C&H conditioners
232 lines (231 loc) • 6.46 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 device_manager_exports = {};
__export(device_manager_exports, {
DeviceManager: () => DeviceManager
});
module.exports = __toCommonJS(device_manager_exports);
var import_node_events = require("node:events");
var import_connection = require("./connection");
var import_encryptor = require("./encryptor");
const statusKeys = [
"Pow",
"Mod",
"TemUn",
"SetTem",
"TemRec",
"WdSpd",
"Air",
"Blo",
"Health",
"SwhSlp",
"Lig",
"SwingLfRig",
"SwUpDn",
"Quiet",
"Tur",
"StHt",
"SvSt",
"TemSen",
"time"
];
const TEMPERATURE_SENSOR_OFFSET = -40;
const DeviceScanTimeoutMs = 5e3;
class DeviceManager extends import_node_events.EventEmitter {
logger;
connection;
devices = {};
/**
*
*/
constructor(devicesList, logger, requestTimeoutMs = 1e3) {
super();
this.logger = logger;
this.connection = new import_connection.Connection(devicesList, logger, requestTimeoutMs);
this.rescanDevices(devicesList);
this.connection.on("dev", this._registerDevice.bind(this));
}
/**
*
*/
rescanDevices(devicesList) {
const rescanTimeout = setTimeout(() => {
const items = devicesList.split(";");
const readyDevices = Object.keys(this.devices).map((key) => this.devices[key].address);
const rescanItems = items.filter((item) => !readyDevices.includes(item));
if (rescanItems.length === 0) {
return;
}
const addresses = rescanItems.join(";");
try {
this.connection.scan(addresses);
} catch {
}
clearTimeout(rescanTimeout);
this.rescanDevices(devicesList);
}, DeviceScanTimeoutMs);
}
/**
*
*/
async sendRegisterDevice(message, rinfo, encVersion) {
var _a;
const deviceId = message.cid || message.mac;
this.logger.info(`New device found: ${message.name} (mac: ${deviceId}), binding encVer ${encVersion}...`);
const { address, port } = rinfo;
try {
const response = await this.connection.sendRequest(
address,
port,
{
cid: "app",
tcid: deviceId,
mac: deviceId,
t: "bind",
uid: 0
},
encVersion
);
const key = response.key;
if (key) {
const device = {
...message,
mac: message.mac,
name: message.name,
address,
port,
key,
encVersion
};
this.devices[deviceId] = device;
this.connection.registerKey(rinfo.address, key);
this.connection.registerEncVersion(address, encVersion);
this.emit("device_bound", deviceId, device);
this.logger.info(
`New device bound: ${device.name} (${device.address}:${device.port}) with encryption v${encVersion}`
);
return device;
}
return null;
} catch (e) {
this.logger.error(`Failed to bind device ${deviceId}: ${e.message}`);
this.logger.error((_a = e.stack) != null ? _a : String(e));
return null;
}
}
/**
*
*/
async _registerDevice(message, rinfo) {
var _a;
let encVersion = this.connection.getEncVersion(rinfo.address);
let device;
try {
device = await this.sendRegisterDevice(message, rinfo, encVersion);
if (!device) {
this.logger.info("Registering failed, trying next encVer...");
this.connection.registerEncVersion(rinfo.address, encVersion % 2 + 1);
encVersion = this.connection.getEncVersion(rinfo.address);
if (encVersion === 1) {
this.connection.registerKey(rinfo.address, import_encryptor.defaultKey);
} else if (encVersion === 2) {
this.connection.registerKey(rinfo.address, import_encryptor.defaultKeyGCM);
}
device = await this.sendRegisterDevice(message, rinfo, encVersion);
}
} catch (e) {
this.logger.error((_a = e.stack) != null ? _a : String(e));
return void 0;
}
return device;
}
/**
*
*/
close() {
this.connection.close();
}
/**
*
*/
getDevices() {
return Object.values(this.devices);
}
/**
*
*/
async getDeviceStatus(deviceId) {
const device = this.devices[deviceId];
if (!device) {
throw new Error(`Device ${deviceId} not found`);
}
const payload = {
cols: statusKeys,
mac: device.mac,
t: "status"
};
const response = await this.connection.sendRequest(device.address, device.port, payload);
const cols = response.cols;
const dat = response.dat;
const deviceStatus = cols.reduce(
(acc, key, index) => ({
...acc,
[key]: dat[index]
}),
{}
);
if ("TemSen" in deviceStatus) {
deviceStatus.TemSen = deviceStatus.TemSen + TEMPERATURE_SENSOR_OFFSET;
}
this.emit("device_status", deviceId, deviceStatus);
return deviceStatus;
}
/**
*
*/
async setDeviceState(deviceId, state) {
const device = this.devices[deviceId];
if (!device) {
return null;
}
const payload = {
mac: device.mac,
opt: Object.keys(state),
p: Object.values(state),
t: "cmd"
};
const response = await this.connection.sendRequest(device.address, device.port, payload);
const opt = response.opt;
const p = response.p;
const deviceStatus = opt.reduce(
(acc, key, index) => ({
...acc,
[key]: p[index]
}),
{}
);
this.emit("device_status", deviceId, deviceStatus);
return deviceStatus;
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
DeviceManager
});
//# sourceMappingURL=device_manager.js.map