UNPKG

lavva.exalushome.extalife

Version:

Library implementing communication and abstraction layers for ExtaLife API in ExalusHome system

359 lines 20.2 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { ResponseResult, FieldChangeResultType } from "lavva.exalushome/build/js/Services/FieldChangeResult"; import { GetParamsErrorCode } from "../../../ExtaLife"; import { SbrAlarmLightDelay, SbrAlarmLightDuration, SbrAutoCloseTime } from "./ISbrConfigService"; import { Api } from "lavva.exalushome"; import { ExalusConnectionService } from "lavva.exalushome/build/js/Services/ExalusConnectionService"; import { LoggerService } from "lavva.exalushome/build/js/Services/Logging/LoggerService"; import { ControllerConfigurationService } from "lavva.exalushome/build/js/Services/Controller/ControllerConfigurationService"; import { DataFrame, Method, Status } from "lavva.exalushome/build/js/DataFrame"; import { UpdatesProvider } from "lavva.exalushome/build/js/Services/Updates/UpdatesProvider"; import { DevicesService } from "lavva.exalushome/build/js/Services/Devices/DevicesService"; export class SbrConfigService { constructor() { this._connection = Api.Get(ExalusConnectionService.ServiceName); this._logger = Api.Get(LoggerService.ServiceName); this._controllerConfigurationService = Api.Get(ControllerConfigurationService.ServiceName); } GetServiceName() { return SbrConfigService.ServiceName; } SetAutoCloseTimeAsync(deviceChannel, timeInMiliseconds, resetOnCrossToOn) { return __awaiter(this, void 0, void 0, function* () { var _a; let enteredConfigurationMode = false; try { if (timeInMiliseconds < 60000 || timeInMiliseconds > 3600000) return new ResponseResult(FieldChangeResultType.WrongData, `Cannot set auto close time - invalid value. Time must be in range from 60_000 to 3_600_000 ms.`); yield this._controllerConfigurationService.EnterConfigurationModeAsync(); enteredConfigurationMode = true; const result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new SetAutoCloseTimeRequest(deviceChannel, timeInMiliseconds, resetOnCrossToOn), 8000, false)); if (result == null || result.Status == null) return new ResponseResult(FieldChangeResultType.UnknownError, `Cannot set auto close time - unknown error.`); if (result.Status !== Status.OK) return new ResponseResult(FieldChangeResultType.UnknownError, `Cannot set auto close time - controller responded with error code: ${result.Status}.`); return new ResponseResult(FieldChangeResultType.Changed, `Auto close time set successfully.`); } catch (error) { return new ResponseResult(FieldChangeResultType.UnknownError, `Cannot get auto close time - unknown error.`); } finally { if (enteredConfigurationMode) { this._logger.Error(SbrConfigService.ServiceName, `EXIT CONFIGURATION MODE WILL BE FIRED! SetAutoCloseTimeAsync()`); yield this._controllerConfigurationService.ExitConfigurationModeAsync(); } } }); } GetAutoCloseTimeAsync(deviceChannel) { return __awaiter(this, void 0, void 0, function* () { var _a; try { const result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new GetAutoCloseTimeRequest(deviceChannel), 8000, false)); switch (result === null || result === void 0 ? void 0 : result.Status) { case Status.OK: return result.Data; default: return new ResponseResult(GetParamsErrorCode.UnknownError, `Cannot get auto close time`); } } catch (error) { return new ResponseResult(GetParamsErrorCode.UnknownError, `Cannot get auto close time error: ${error}`); } }); } SetAlarmLightDelayAsync(deviceChannel, lightDelayInMiliseconds) { return __awaiter(this, void 0, void 0, function* () { var _a; let enteredConfigurationMode = false; try { if (lightDelayInMiliseconds < 0 || lightDelayInMiliseconds > 120000) return new ResponseResult(FieldChangeResultType.WrongData, `Cannot set light delay time - invalid value. Time must be in range from 60_000 to 3_600_000 ms.`); yield this._controllerConfigurationService.EnterConfigurationModeAsync(); enteredConfigurationMode = true; const result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new SetAlarmLightDelayRequest(deviceChannel, lightDelayInMiliseconds), 8000, false)); if (result == null || result.Status == null) return new ResponseResult(FieldChangeResultType.UnknownError, `Cannot set light delay time - unknown error.`); if (result.Status !== Status.OK) return new ResponseResult(FieldChangeResultType.UnknownError, `Cannot set light delay time - controller responded with error code: ${result.Status}.`); return new ResponseResult(FieldChangeResultType.Changed, `Light delay set successfully.`); } catch (error) { return new ResponseResult(FieldChangeResultType.UnknownError, `Cannot get light delay time - unknown error.`); } finally { if (enteredConfigurationMode) { this._logger.Error(SbrConfigService.ServiceName, `EXIT CONFIGURATION MODE WILL BE FIRED! SetAlarmLightDelayAsync()`); yield this._controllerConfigurationService.ExitConfigurationModeAsync(); } } }); } GetAlarmLightDelayAsync(deviceChannel) { return __awaiter(this, void 0, void 0, function* () { var _a; try { const result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new GetAlarmLightDelayRequest(deviceChannel), 8000, false)); switch (result === null || result === void 0 ? void 0 : result.Status) { case Status.OK: return result.Data; default: return new ResponseResult(GetParamsErrorCode.UnknownError, `Cannot get light delay time`); } } catch (error) { return new ResponseResult(GetParamsErrorCode.UnknownError, `Cannot get auto light delay error: ${error}`); } }); } SetAlarmLightDurationAsync(deviceChannel, lightDurationInMiliseconds) { return __awaiter(this, void 0, void 0, function* () { var _a; let enteredConfigurationMode = false; try { if (lightDurationInMiliseconds < 0 || lightDurationInMiliseconds > 3600000) return new ResponseResult(FieldChangeResultType.WrongData, `Cannot set alarm light duration time - invalid value. Time must be in range from 60_000 to 3_600_000 ms.`); yield this._controllerConfigurationService.EnterConfigurationModeAsync(); enteredConfigurationMode = true; const result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new SetAlarmLightDurationRequest(deviceChannel, lightDurationInMiliseconds), 8000, false)); if (result == null || result.Status == null) return new ResponseResult(FieldChangeResultType.UnknownError, `Cannot set alarm light duration time - unknown error.`); if (result.Status !== Status.OK) return new ResponseResult(FieldChangeResultType.UnknownError, `Cannot set alarm light duration time - controller responded with error code: ${result.Status}.`); return new ResponseResult(FieldChangeResultType.Changed, `Alarm light duration set successfully.`); } catch (error) { return new ResponseResult(FieldChangeResultType.UnknownError, `Cannot get alarm light duration time - unknown error.`); } finally { if (enteredConfigurationMode) { this._logger.Error(SbrConfigService.ServiceName, `EXIT CONFIGURATION MODE WILL BE FIRED! SetAlarmLightDurationAsync()`); yield this._controllerConfigurationService.ExitConfigurationModeAsync(); } } }); } GetAlarmLightDurationAsync(deviceChannel) { return __awaiter(this, void 0, void 0, function* () { var _a; try { const result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new GetAlarmLightDurationRequest(deviceChannel), 8000, false)); switch (result === null || result === void 0 ? void 0 : result.Status) { case Status.OK: return result.Data; default: return new ResponseResult(GetParamsErrorCode.UnknownError, `Cannot get light delay time`); } } catch (error) { return new ResponseResult(GetParamsErrorCode.UnknownError, `Cannot get auto light delay error: ${error}`); } }); } GetServiceInfoAsync(deviceChannel) { return __awaiter(this, void 0, void 0, function* () { var _a; try { const result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new GetServiceInfoRequest(deviceChannel), 8000, false)); switch (result === null || result === void 0 ? void 0 : result.Status) { case Status.OK: return result.Data; default: return new ResponseResult(GetParamsErrorCode.UnknownError, `Cannot get service info, response status: ${result === null || result === void 0 ? void 0 : result.Status}`); } } catch (error) { return new ResponseResult(GetParamsErrorCode.UnknownError, `Cannot get service info error: ${error}`); } }); } IsPinSecureSupportedAsync(deviceChannel) { return __awaiter(this, void 0, void 0, function* () { const version = yield Api.Get(UpdatesProvider.ServiceName).GetSoftwareRuntimeInfoAsync(); const [major, minor] = version.SoftwareVersion.split(".").map(v => parseInt(v)); if ((major >= 7 && minor >= 42) && deviceChannel.Number == 1) { return true; } return false; }); } SetPinSecureAsync(deviceChannel, pinSecureEnabled, pinCode) { return __awaiter(this, void 0, void 0, function* () { try { const devicesApi = Api.Get(DevicesService.ServiceName); const channel = devicesApi.GetDeviceChannelByChannelId(deviceChannel.ChannelId); if (channel == null) return new ResponseResult(FieldChangeResultType.WrongData, `Cannot set pin secure - channel with id ${deviceChannel.ChannelId} not found.`); let customData = []; customData.push({ dataId: SecureGateControllCustomData.IsEnabledBool.toString(), data: "true" }); if (pinSecureEnabled) { if (pinCode == null || pinCode.length < 4 || !/^\d+$/.test(pinCode)) { return new ResponseResult(FieldChangeResultType.WrongData, `Cannot set pin secure - invalid pin code, pin code must be at least 4 digits long and contain only digits.`); } customData.push({ dataId: SecureGateControllCustomData.IsEnabledBool.toString(), data: "true" }); customData.push({ dataId: SecureGateControllCustomData.PinHash.toString(), data: yield this.CreatePinHashAsync(pinCode) }); } else { customData.push({ dataId: SecureGateControllCustomData.IsEnabledBool.toString(), data: "false" }); customData.push({ dataId: SecureGateControllCustomData.PinHash.toString(), data: "" }); } for (const entry of customData) { yield channel.SetCustomDataAsync(entry.dataId, entry.data); } return new ResponseResult(FieldChangeResultType.Changed, `Pin secure ${pinSecureEnabled ? "enabled" : "disabled"}.`); } catch (error) { return new ResponseResult(FieldChangeResultType.UnknownError, `Cannot set pin secure - unknown error.`); } }); } GetPinSecureStatusAsync(deviceChannel) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c; try { const devicesApi = Api.Get(DevicesService.ServiceName); const channel = devicesApi.GetDeviceChannelByChannelId(deviceChannel.ChannelId); if (channel == null) return new ResponseResult(GetParamsErrorCode.UnknownError, `Cannot get pin secure status - channel with id ${deviceChannel.ChannelId} not found.`); const enabled = ((_a = channel.CustomData) === null || _a === void 0 ? void 0 : _a[SecureGateControllCustomData.IsEnabledBool.toString()]) === "true"; // Additionally ensure that when enabled there is a hash stored if (enabled) { const hash = (_c = (_b = channel.CustomData) === null || _b === void 0 ? void 0 : _b[SecureGateControllCustomData.PinHash.toString()]) !== null && _c !== void 0 ? _c : ""; return hash.length > 0; } return false; } catch (error) { return new ResponseResult(GetParamsErrorCode.UnknownError, `Cannot get pin secure status - unknown error.`); } }); } // Generates a hash string in the format: Base64(salt):Base64(SHA256(salt || UTF8(pin))) compatible with backend VerifyHash CreatePinHashAsync(pinCode) { return __awaiter(this, void 0, void 0, function* () { const salt = this.getRandomBytes(16); const pinBytes = new TextEncoder().encode(pinCode); const input = new Uint8Array(salt.length + pinBytes.length); input.set(salt, 0); input.set(pinBytes, salt.length); const hashBytes = yield this.sha256(input); const saltB64 = this.bytesToBase64(salt); const hashB64 = this.bytesToBase64(hashBytes); return `${saltB64}:${hashB64}`; }); } getRandomBytes(length) { if (typeof globalThis !== "undefined" && globalThis.crypto && typeof globalThis.crypto.getRandomValues === "function") { const arr = new Uint8Array(length); globalThis.crypto.getRandomValues(arr); return arr; } // Fallback (non-cryptographic) only if crypto is unavailable; should not happen in supported environments const arr = new Uint8Array(length); for (let i = 0; i < length; i++) arr[i] = Math.floor(Math.random() * 256); return arr; } sha256(data) { return __awaiter(this, void 0, void 0, function* () { if (typeof globalThis !== "undefined" && globalThis.crypto && globalThis.crypto.subtle) { const digest = yield globalThis.crypto.subtle.digest("SHA-256", data); return new Uint8Array(digest); } throw new Error("Crypto.subtle not available for SHA-256 hashing"); }); } bytesToBase64(bytes) { // Prefer Node Buffer if available (e.g., in Node / Electron) const maybeBuffer = globalThis.Buffer; if (typeof maybeBuffer !== "undefined" && typeof maybeBuffer.from === "function") { return maybeBuffer.from(bytes).toString("base64"); } // Browser-safe base64 encoding using btoa let binary = ""; const chunkSize = 0x8000; for (let i = 0; i < bytes.length; i += chunkSize) { const sub = bytes.subarray(i, i + chunkSize); binary += String.fromCharCode.apply(null, Array.from(sub)); } return btoa(binary); } } SbrConfigService.ServiceName = "SbrConfigService"; var SecureGateControllCustomData; (function (SecureGateControllCustomData) { SecureGateControllCustomData["IsEnabledBool"] = "IsEnabledBool"; SecureGateControllCustomData["PinHash"] = "PinHash"; })(SecureGateControllCustomData || (SecureGateControllCustomData = {})); class GetAutoCloseTimeRequest extends DataFrame { constructor(deviceChannel) { super(); this.Resource = "/extalife/device/parameters/sbr/autoclosetime"; this.Method = Method.Get; this.Data = deviceChannel.GetDevice().Guid; } } class SetAutoCloseTimeRequest extends DataFrame { constructor(DeviceChannel, timeInMiliseconds, resetOnCrossToOn) { super(); this.Resource = "/extalife/device/parameters/sbr/autoclosetime"; this.Method = Method.Put; this.Data = new SbrAutoCloseTime(); this.Data.DeviceGuid = DeviceChannel.GetDevice().Guid; this.Data.TimeInMiliseconds = timeInMiliseconds; this.Data.ResetOnCrossToOn = resetOnCrossToOn; } } class GetAlarmLightDelayRequest extends DataFrame { constructor(deviceChannel) { super(); this.Resource = "/extalife/device/parameters/sbr/alarmlightdelay"; this.Method = Method.Get; this.Data = deviceChannel.GetDevice().Guid; } } class SetAlarmLightDelayRequest extends DataFrame { constructor(DeviceChannel, lightDelayInMiliseconds) { super(); this.Resource = "/extalife/device/parameters/sbr/alarmlightdelay"; this.Method = Method.Put; this.Data = new SbrAlarmLightDelay(); this.Data.DeviceGuid = DeviceChannel.GetDevice().Guid; this.Data.LightDelayInMiliseconds = lightDelayInMiliseconds; } } class GetAlarmLightDurationRequest extends DataFrame { constructor(deviceChannel) { super(); this.Resource = "/extalife/device/parameters/sbr/lightduration"; this.Method = Method.Get; this.Data = deviceChannel.GetDevice().Guid; } } class SetAlarmLightDurationRequest extends DataFrame { constructor(DeviceChannel, lightDurationInMiliseconds) { super(); this.Resource = "/extalife/device/parameters/sbr/lightduration"; this.Method = Method.Put; this.Data = new SbrAlarmLightDuration(); this.Data.DeviceGuid = DeviceChannel.GetDevice().Guid; this.Data.LightDurationInMiliseconds = lightDurationInMiliseconds; } } class GetServiceInfoRequest extends DataFrame { constructor(deviceChannel) { super(); this.Resource = "/extalife/device/parameters/sbr/serviceinfo"; this.Method = Method.Get; this.Data = deviceChannel.GetDevice().Guid; } } //# sourceMappingURL=SbrConfigService.js.map