lavva.exalushome
Version:
Library implementing communication and abstraction layers for ExalusHome system
936 lines (935 loc) • 62.9 kB
JavaScript
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 { TypedEvent } from '../../TypedEvent';
import { DeviceState, CommunicationWay, DeviceType, DeviceTaskTypeInfo, DeviceResponseTypeInfo, DeviceTasksInfo, DeviceResponseType, IconType } from './IDevice';
import { DeviceTaskPairExecutionResult } from './IDevicesService';
import { BatteryDeviceState, BinarySensorStateDeviceState, BlindCalibrationDeviceState, BlindErrorDeviceState, BlindOpenCloseTimeDeviceState, BlindPositionDeviceState, BlindRemoteButtonDeviceState, ChannelOnOffDeviceState, ConfigurationDeviceState, CurrentLightThresholdDeviceState, CurrentWindThresholdDeviceState, DoorBellDeviceState, FacadePositionDeviceState, FacadeRemoteButtonDeviceState, FacadeTypeDeviceState, FloodSensorDeviceState, GateControllerHealthDeviceState, GatePositionDeviceState, GatewayPositionDeviceState, HumiditySensorDeviceState, LightBrightnessDeviceState, LightColorDeviceState, LightRGBWDeviceState, LightWarmthDeviceState, MeasuredBrightnessDeviceState, MeasuredDistanceDeviceState, MeasuredEnergyDeviceState, MeasuredTemperatureDeviceState, MovementSensorDeviceState, OnlineCameraState, OvercurrentProtectionDeviceState, OvercurrentProtectionThresholdDeviceState, PressureSensorDeviceState, ReedStateDeviceState, RemoteButtonDeviceState, SignalStrenghtDeviceState, StateReliability, TamperProtectionDeviceState, VibrationSensorDeviceState, WindSpeedDeviceState, ChannelHallStateState, ChannelSceneExecutedState, IntercomDeviceState } from './IDeviceState';
import { DeviceChannel } from './DeviceChannel';
import { ChannelConfigurations, TaskExecution } from './IDeviceChannel';
import { Api } from '../../Api';
import { ExalusConnectionService } from '../ExalusConnectionService';
import { DependencyContainer } from '../../DependencyContainer';
import { DataFrame, Status, Method } from '../../DataFrame';
import { Device } from './Device';
import { DeviceControlFeature } from './IDeviceTask';
import { BlindActionEnum, FacadeActionEnum, GateActionEnum } from './Tasks/Tasks';
import { SessionService } from '../Session/SessionService';
import { ControllerConfigurationService } from '../Controller/ControllerConfigurationService';
import { DeviceTaskExecutionResult } from './TaskExecutionResult';
import { ManuallyPairedDevicesService } from './ManuallyPairedDevicesService';
import { RemoteStorageDataEntry } from '../IRemoteStorageService';
import { RemoteStorageService } from '../RemoteStorageService';
import { AccessLevel } from '../Users/IUser';
import { WebApiCacheService } from '../WebApi/WebApiCacheService';
import { ScenesService } from '../Scenes/ScenesService';
import { ResponseResult } from '../FieldChangeResult';
import { ParseObjToMap } from '../../Helpers';
import { AppState } from '../IAppStateService';
import { AppStateService } from '../AppStateService';
/**
* @type Class
*/
export class DevicesService {
constructor() {
this._devices = [];
this._onDevicesTasksChangedEvent = new TypedEvent();
this._onDeviceFoundEvent = new TypedEvent();
this._onDeviceRegisteredEvent = new TypedEvent();
this._onDeviceRemovedEvent = new TypedEvent();
this._onDeviceFirmwareVersionChangedEvent = new TypedEvent();
this._onDeviceStateChangedEvent = new TypedEvent();
this._onDeviceStateRefreshedOrChangedEvent = new TypedEvent();
this._connection = null;
this._session = null;
this._controllerConfiguration = null;
this._synchronized = false;
this._synchronizedDevicesStates = false;
this._devicesChannelsStates = [];
this._synchronizationTaskCompletionSource = null;
this._deviceStatesSynchronizationTaskCompletionSource = null;
this._connection = Api.Get(ExalusConnectionService.ServiceName);
this._session = Api.Get(SessionService.ServiceName);
this._controllerConfiguration = Api.Get(ControllerConfigurationService.ServiceName);
this._onDeviceStateChangedEvent.Subscribe((args) => __awaiter(this, void 0, void 0, function* () { return this.PutDeviceStateOnList(args.Device, args.State); }));
this._synchronizationTaskCompletionSource = new Promise((resolve) => {
var _a;
(_a = this._session) === null || _a === void 0 ? void 0 : _a.OnUserLoggedInEvent().Subscribe((user) => __awaiter(this, void 0, void 0, function* () {
var _a;
try {
this._devices = yield this.GetPairedDevicesAsync(true);
}
catch (ex) {
(_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Error(DevicesService.ServiceName, `Failed to get paired devices: ${ex}`);
}
this._synchronized = true;
resolve();
}));
});
this._deviceStatesSynchronizationTaskCompletionSource = new Promise((resolve) => {
var _a;
(_a = this._session) === null || _a === void 0 ? void 0 : _a.OnUserLoggedInEvent().Subscribe((user) => __awaiter(this, void 0, void 0, function* () {
var _a;
try {
yield this.WaitForSynchronizationAsync();
yield this.SyncDevicesStatesAsync();
}
catch (ex) {
(_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Error(DevicesService.ServiceName, `Failed to sync devices states: ${ex}`);
}
this._synchronizedDevicesStates = true;
resolve();
}));
});
Api.Get(AppStateService.ServiceName).OnAppStateChanged().Subscribe((appState) => __awaiter(this, void 0, void 0, function* () {
switch (appState) {
case AppState.ReturnedFromSuspension:
if (Api.Get(ExalusConnectionService.ServiceName).IsConnected() && this._synchronizedDevicesStates == true)
this.SyncDevicesStatesAsync();
break;
case AppState.Disconnected:
break;
case AppState.Connected:
if (this._synchronizedDevicesStates == true)
this.SyncDevicesStatesAsync();
break;
}
}));
this._connection.SubscribeTo("/info/devices/tasks", (frame) => {
this.ParseDeviceTaskInfo(frame.Data);
});
this._connection.SubscribeTo("/info/devices/device/found", (frame) => {
const foundDevices = this.MapApiDevices(frame.Data);
foundDevices.forEach(device => {
var _a;
if (device.DeviceType == DeviceType.Scene)
return;
(_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Debug(DevicesService.ServiceName, `Found device: ${device.Name} guid: ${device.Guid}`);
this._onDeviceFoundEvent.Invoke(device);
});
});
this._connection.SubscribeTo("/info/devices/device/firmware/updated", (frame) => {
const deviceGuid = frame.Data.DeviceGuid;
const version = frame.Data.Version;
const dev = this._devices.find(a => a.Guid == deviceGuid);
if (dev !== undefined) {
this._onDeviceFirmwareVersionChangedEvent.Invoke({ Device: dev, FirmwareVersion: version });
dev.SoftwareVersion = version;
dev.OnDeviceFirmwareVersionChangedEvent().Invoke({ FirmwareVersion: version });
}
});
this._connection.SubscribeTo("/info/devices/device/state/changed", (frame) => {
var _a;
const state = frame.Data;
const devices = this._devices.filter(a => a.Guid == state.DeviceGuid);
if (devices.length > 0) {
const device = devices[0];
const st = this.MapApiDeviceStateToDeviceState(device, state);
if (st != null) {
this._onDeviceStateRefreshedOrChangedEvent
.Invoke({ Device: device, State: st });
if (st.TypeAsEnum == DeviceResponseType.SignalStrength) {
device.Channels.forEach(channel => {
/// object copy { ...state }
let newState = new SignalStrenghtDeviceState(Object.assign({}, state));
newState.Data.Channel = channel.Number;
this._onDeviceStateRefreshedOrChangedEvent
.Invoke({ Device: device, State: newState });
});
}
else if (st.TypeAsEnum == DeviceResponseType.BatteryState) {
device.Channels.forEach(channel => {
let newState = new BatteryDeviceState(Object.assign({}, state));
newState.Data.Channel = channel.Number;
this._onDeviceStateRefreshedOrChangedEvent
.Invoke({ Device: device, State: newState });
});
}
/// react only if state data changes, not just state time!
let channelState = device.States.find(a => a.TypeAsEnum === st.TypeAsEnum && a.Data.Channel === st.Data.Channel);
if (channelState) {
let compData = channelState.StatesComparisonData;
if (st.TypeAsEnum == DeviceResponseType.BlindErrorState) {
const errCodeNew = (_a = st.Data) === null || _a === void 0 ? void 0 : _a.ErrorCode;
const errStateCurr = channelState.Data.ErrorCode;
if (errCodeNew != errStateCurr) {
this._onDeviceStateChangedEvent
.Invoke({ Device: device, State: st });
return;
}
}
// replace old state object data with new one
channelState.Data = st.Data;
// compare old state with new one
if (compData !== st.StatesComparisonData) {
this._onDeviceStateChangedEvent
.Invoke({ Device: device, State: st });
if (st.TypeAsEnum == DeviceResponseType.SignalStrength) {
device.Channels.forEach(channel => {
/// object copy { ...state }
let newState = new SignalStrenghtDeviceState(Object.assign({}, state));
newState.Data.Channel = channel.Number;
this._onDeviceStateChangedEvent
.Invoke({ Device: device, State: newState });
});
}
else if (st.TypeAsEnum == DeviceResponseType.BatteryState) {
device.Channels.forEach(channel => {
let newState = new BatteryDeviceState(Object.assign({}, state));
newState.Data.Channel = channel.Number;
this._onDeviceStateChangedEvent
.Invoke({ Device: device, State: newState });
});
}
}
}
else {
device.States.push(st);
this._onDeviceStateChangedEvent
.Invoke({ Device: device, State: st });
if (st.TypeAsEnum == DeviceResponseType.SignalStrength) {
device.Channels.forEach(channel => {
/// object copy { ...state }
let newState = new SignalStrenghtDeviceState(Object.assign({}, state));
newState.Data.Channel = channel.Number;
this._onDeviceStateChangedEvent
.Invoke({ Device: device, State: newState });
});
}
else if (st.TypeAsEnum == DeviceResponseType.BatteryState) {
device.Channels.forEach(channel => {
let newState = new BatteryDeviceState(Object.assign({}, state));
newState.Data.Channel = channel.Number;
this._onDeviceStateChangedEvent
.Invoke({ Device: device, State: newState });
});
}
}
}
}
});
this._connection.SubscribeTo("/info/devices/devices/registered", (frame) => {
Api.Get(WebApiCacheService.ServiceName).ClearCache();
const registeredDevices = this.MapApiDevices(frame.Data);
registeredDevices.forEach(device => {
var _a;
(_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Debug(DevicesService.ServiceName, `Registered device: ${device.Name} guid: ${device.Guid}`);
this._devices.push(device);
this._onDeviceRegisteredEvent.Invoke(device);
});
});
this._connection.SubscribeTo("/info/devices/devices/removed", (frame) => {
Api.Get(WebApiCacheService.ServiceName).ClearCache();
const removedDevices = this.MapApiDevices(frame.Data);
removedDevices.forEach(device => {
var _a;
(_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Debug(DevicesService.ServiceName, `Removed device: ${device.Name} guid: ${device.Guid}`);
this._devices = this._devices.filter(a => a.Guid != device.Guid);
this._onDeviceRemovedEvent.Invoke(device);
});
});
}
ProtocolGuidToProtocolName(guid) {
switch (guid) {
case "1fca7e8a-a2dc-4883-bd94-4e9b2012f685":
return "ExtaLife";
case "cd25bdff-628c-4dbc-a16a-648c96a819d4":
return "Portos 433MHz";
case "634c2bb2-1a4f-4db6-8dd4-d5fbaf92678e":
return "Supla";
case "194aeb81-990c-4a02-9236-59e902958fda":
return "RTSP";
case "b3e4644e-ab5b-494e-b3c5-66fabe7fff64":
return "Wekta";
case "247198e1-e360-4355-9886-232ac1456eea":
return "Lavva Wi-Fi";
default:
return null;
}
}
CanDisplaySceneDevices() {
return this.CheckIfControllerSoftwareVersionIsEnough(6, 56);
}
CheckIfControllerSoftwareVersionIsEnough(requiredContainerMajor, requiredContainerMinor) {
var _a, _b, _c;
const versionString = (_c = (_b = (_a = this._session) === null || _a === void 0 ? void 0 : _a.User) === null || _b === void 0 ? void 0 : _b.SoftwareVersion) !== null && _c !== void 0 ? _c : null;
if (!versionString || !versionString.includes('.'))
return false;
const segments = versionString.split('.');
if (segments.length !== 2)
return false;
const numbers = segments.map(s => parseInt(s, 10));
if (numbers.some(n => Number.isNaN(n) || n < 0))
return false;
const [containerMajor, containerMinor] = numbers;
return (containerMajor > requiredContainerMajor) || (containerMajor === requiredContainerMajor && containerMinor >= requiredContainerMinor);
}
CheckIfDeviceUsedInScenesAsync(dev) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f;
try {
let device;
if (typeof dev == 'string') {
const result = this.GetDevice(dev);
if (result != null)
device = result;
else {
(_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Error(`Cannot check if device is used in scenes! Device with given guid not exists`);
return Status.ResourceDoesNotExists;
}
}
else {
device = dev;
}
const resp = yield ((_b = this._connection) === null || _b === void 0 ? void 0 : _b.SendAndWaitForResponseAsync(new DeviceIsUsedInScenesRequest(device.Guid), 20000, false));
if (resp == null || resp.Status == null) {
(_c = DependencyContainer.Log) === null || _c === void 0 ? void 0 : _c.Error(`Cannot check if device is used in scenes! Response or status is null!`);
return Status.FatalError;
}
if (resp.Status != Status.OK)
return resp.Status;
if (resp.Data == null) {
(_d = DependencyContainer.Log) === null || _d === void 0 ? void 0 : _d.Error(`Cannot check if device is used in scenes! No data!`);
return Status.FatalError;
}
var seqList = yield Api.Get(ScenesService.ServiceName).GetSequencesListAsync();
if (seqList instanceof ResponseResult) {
(_e = DependencyContainer.Log) === null || _e === void 0 ? void 0 : _e.Error(`Cannot check if device is used in scenes! Cannot get sequence list, ScenesServiceErrorCode: ${seqList.Type}`);
return Status.Error;
}
const result = new DeviceUsedInScenes();
result.DeviceGuid = device.Guid;
resp.Data.ConditionsAsCondition.forEach(cGuid => {
const con = seqList.find(s => s.Guid == cGuid);
if (con)
result.ConditionsAsCondition.push(con);
});
resp.Data.ConditionsAsTask.forEach(tGuid => {
const con = seqList.find(s => s.Guid == tGuid);
if (con)
result.ConditionsAsCondition.push(con);
});
return result;
}
catch (error) {
(_f = DependencyContainer.Log) === null || _f === void 0 ? void 0 : _f.Error(`Cannot check if device is used in scenes! ${error}`);
return Status.FatalError;
}
});
}
CanEditDevicesInfo() {
var _a, _b;
if (this._session === null || this._session === undefined)
return false;
if (this._session.User === null || this._session.User === undefined)
return false;
return ((_b = (_a = this._session) === null || _a === void 0 ? void 0 : _a.User) === null || _b === void 0 ? void 0 : _b.AccessLevel) >= AccessLevel.Admin;
}
CanAddAndRemoveAndConfigureDevices() {
var _a, _b;
if (this._session === null || this._session === undefined)
return false;
if (this._session.User === null || this._session.User === undefined)
return false;
return ((_b = (_a = this._session) === null || _a === void 0 ? void 0 : _a.User) === null || _b === void 0 ? void 0 : _b.AccessLevel) >= AccessLevel.Installator;
}
GetDeviceChannelByChannelId(channelId) {
return this._devices.firstOrDefault(device => device.Channels.any(channel => channel.ChannelId == channelId))
.Channels.firstOrDefault(channel => channel.ChannelId == channelId);
}
EnableFastStatesSyncAsync() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
const res = Api.Get(RemoteStorageService.ServiceName).SaveAsync("FastDevicesSync", false, true);
(_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Error(DevicesService.ServiceName, `EXIT CONFIGURATION MODE WILL BE FIRED! EnableFastStatesSyncAsync()`);
yield Api.Get(ControllerConfigurationService.ServiceName).ExitConfigurationModeAsync();
return res;
});
}
DisableFastStatesSyncAsync() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
const res = Api.Get(RemoteStorageService.ServiceName).SaveAsync("FastDevicesSync", false, false);
(_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Error(DevicesService.ServiceName, `EXIT CONFIGURATION MODE WILL BE FIRED! DisableFastStatesSyncAsync()`);
yield Api.Get(ControllerConfigurationService.ServiceName).ExitConfigurationModeAsync();
return res;
});
}
IsFastStatesSyncEnabledAsync() {
return __awaiter(this, void 0, void 0, function* () {
const res = yield Api.Get(RemoteStorageService.ServiceName).ReadAsync("FastDevicesSync", false, false);
if (res instanceof RemoteStorageDataEntry) {
return res.Data;
}
//Controller returns ResourceDoesNotExists if fastSync option was never enabled (no option in DB - default slow sync)
if (res == Status.ResourceDoesNotExists)
return false;
return res;
});
}
GetDevicesForManualPairingAsync(protocol) {
return __awaiter(this, void 0, void 0, function* () {
let service = Api.Get(ManuallyPairedDevicesService.ServiceName);
const regGuid = new RegExp("^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$");
if (Array.isArray(protocol)) {
return yield service.GetDevicesForManualPairingAsync(protocol);
}
else if (regGuid.test(protocol)) {
return yield service.GetDevicesForManualPairingAsync(protocol);
}
else {
return yield service.GetDevicesForManualPairingAsync();
}
});
}
AddManuallyPairedDevice(device) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
var res = yield Api.Get(ManuallyPairedDevicesService.ServiceName).AddManuallyPairedDeviceAsync(device);
(_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Error(DevicesService.ServiceName, `EXIT CONFIGURATION MODE WILL BE FIRED! AddManuallyPairedDevice()`);
yield Api.Get(ControllerConfigurationService.ServiceName).ExitConfigurationModeAsync();
return res;
});
}
GetDeviceChannelStates(device, channel) {
var _a, _b;
return (_b = (_a = this._devicesChannelsStates.firstOrDefault(a => a.DeviceGuid == device.Guid)) === null || _a === void 0 ? void 0 : _a.ChannelsStates.filter(a => a.Channel == channel)) !== null && _b !== void 0 ? _b : [];
}
GetDeviceStates(device) {
var _a, _b;
return (_b = (_a = this._devicesChannelsStates.firstOrDefault(a => a.DeviceGuid == device.Guid)) === null || _a === void 0 ? void 0 : _a.ChannelsStates) !== null && _b !== void 0 ? _b : [];
}
PutDeviceStateOnList(device, state) {
let deviceStatesOnList = this._devicesChannelsStates.firstOrDefault(a => a.DeviceGuid == device.Guid);
if (deviceStatesOnList == null) {
let s = new DeviceChannelStates();
s.Channel = state.Data.Channel;
s.States = [state];
deviceStatesOnList = { DeviceGuid: device.Guid, ChannelsStates: [s] };
this._devicesChannelsStates.push(deviceStatesOnList);
}
else {
let channel = deviceStatesOnList.ChannelsStates.firstOrDefault(a => a.Channel == state.Data.Channel);
if (channel == null) {
channel = new DeviceChannelStates();
channel.Channel = state.Data.Channel;
channel.States = [state];
deviceStatesOnList.ChannelsStates.push(channel);
}
else {
let currentState = channel.States.firstOrDefault(a => a.TypeAsEnum == state.TypeAsEnum);
if (currentState != null) {
if (currentState.TypeAsEnum == DeviceResponseType.BlindErrorState) {
channel.States = channel.States.where(a => a.Data.ErrorCode != state.Data.ErrorCode).toArray();
}
else {
channel.States = channel.States.where(a => a.TypeAsEnum != state.TypeAsEnum).toArray();
}
}
channel.States.push(state);
}
}
}
WaitForSynchronizationAsync() {
return this._synchronizationTaskCompletionSource;
}
WaitForDevicesStatesSynchronizationAsync() {
return this._deviceStatesSynchronizationTaskCompletionSource;
}
GetCurrentlyRunningTaksAsync() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
const result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new GetRunningDevicesTasksRequest(), 15000, false));
if ((result === null || result === void 0 ? void 0 : result.Status) == Status.OK && result.Data != null) {
this.ParseDeviceTaskInfo(result.Data);
}
});
}
ParseDeviceTaskInfo(tasks) {
const devicesTasks = [];
tasks.forEach(taskChannelPair => {
const pair = taskChannelPair.split(";");
const task = new DeviceTasksInfo();
task.DeviceGuid = pair[0];
task.Channel = Number(pair[1]);
task.Status = TaskExecution.ExecutingTasks;
devicesTasks.push(task);
if (task.Channel === 0) {
const device = this._devices.find(a => a.Guid == task.DeviceGuid);
if (device !== undefined) {
device.Channels.forEach(channel => {
const task = new DeviceTasksInfo();
task.DeviceGuid = device.Guid;
task.Channel = channel.Number;
task.Status = TaskExecution.ExecutingTasks;
devicesTasks.push(task);
});
}
}
});
this._onDevicesTasksChangedEvent.Invoke(devicesTasks);
}
MapApiDeviceStateToDeviceState(device, state) {
var _a;
const st = state.state;
switch (state.DataType) {
case "ChannelOnOff":
return new ChannelOnOffDeviceState(state);
case "DoorBell":
return new DoorBellDeviceState(state);
case "ReedPosition":
return new ReedStateDeviceState(state);
case "BlindPosition":
return new BlindPositionDeviceState(state);
case "ButtonState":
return new RemoteButtonDeviceState(state);
case "LightColor":
return new LightColorDeviceState(state);
case "LightTemperature":
return new LightWarmthDeviceState(state);
case "LightBrightness":
return new LightBrightnessDeviceState(state);
case "TemperatureSensor":
case "TemperatureState":
case "MeasuredTemperature":
return new MeasuredTemperatureDeviceState(state);
case "BatteryState":
return new BatteryDeviceState(state);
case "MeasuredBrightness":
case "DeviceBrightnessState":
return new MeasuredBrightnessDeviceState(state);
case "EnergyMeasuredPower":
break;
case "EnergyMeasuredCurrent":
break;
case "EnergyMeasuredVoltage":
break;
case "IEnergy":
case "Energy":
return new MeasuredEnergyDeviceState(state);
case "DistanceSensor":
return new MeasuredDistanceDeviceState(state);
case "MovementSensor":
return new MovementSensorDeviceState(state);
case "BlindsControlButton":
return new BlindRemoteButtonDeviceState(state);
case "FacadeControlButton":
return new FacadeRemoteButtonDeviceState(state);
case "SignalStrength":
return new SignalStrenghtDeviceState(state);
case "GatePosition":
return new GatePositionDeviceState(state);
case "GatewayPosition":
return new GatewayPositionDeviceState(state);
case "GateControllerHealth":
return new GateControllerHealthDeviceState(state);
case "IBlindCalibrationStatus":
case "BlindCalibration":
return new BlindCalibrationDeviceState(state);
case "HumiditySensor":
case "HumidityState":
return new HumiditySensorDeviceState(state);
case "VibrationSensor":
return new VibrationSensorDeviceState(state);
case "DigitalInputSensor":
return new BinarySensorStateDeviceState(state);
case "ConfigurationState":
return new ConfigurationDeviceState(state);
case "BlindOpenCloseTime":
case "IBlindOpenCloseTime":
return new BlindOpenCloseTimeDeviceState(state);
case "IOvercurrentProtection":
case "OvercurrentProtection":
return new OvercurrentProtectionDeviceState(state);
case "IOvercurrentProtectionThreshold":
case "OvercurrentProtectionThreshold":
return new OvercurrentProtectionThresholdDeviceState(state);
case "FacadePosition":
case "FacadeState":
return new FacadePositionDeviceState(state);
case "FacadeTypeState":
return new FacadeTypeDeviceState(state);
case "CurrentWindThreshold":
return new CurrentWindThresholdDeviceState(state);
case "CurrentLightThreshold":
return new CurrentLightThresholdDeviceState(state);
case "WindSpeed":
return new WindSpeedDeviceState(state);
case "FloodSensor":
return new FloodSensorDeviceState(state);
case "PressureState":
return new PressureSensorDeviceState(state);
case "ITamperProtection":
case "TamperProtection":
return new TamperProtectionDeviceState(state);
case "ILightRGBW":
case "LightRGBW":
return new LightRGBWDeviceState(state);
case "OnlineCamera":
case "IOnlineCamera":
return new OnlineCameraState(state);
case "BlindError":
case "IBlindError":
state.state.ErrorData = ParseObjToMap(state.state.ErrorData);
return new BlindErrorDeviceState(state);
case "HallState":
return new ChannelHallStateState(state);
case "SceneExecuted":
return new ChannelSceneExecutedState(state);
case "Intercom":
return new IntercomDeviceState(state);
default:
(_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Debug(DevicesService.ServiceName, `Not supported device state ${state.DataType}`);
break;
}
return null;
}
GetServiceName() {
return DevicesService.ServiceName;
}
SyncDevicesStatesAsync() {
return __awaiter(this, arguments, void 0, function* (forceSlow = false) {
var _a, _b, _c;
const result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new GetDevicesStatesRequest(), 15000, false));
if (yield this.IsFastStatesSyncEnabledAsync()) {
if (forceSlow) {
let syncStatesRequest = new SyncDevicesStatesRequest();
syncStatesRequest.Data = true;
const result = yield ((_b = this._connection) === null || _b === void 0 ? void 0 : _b.SendAndWaitForResponseAsync(syncStatesRequest, 35000, false));
return (result === null || result === void 0 ? void 0 : result.Status) == Status.OK;
}
else {
return (result === null || result === void 0 ? void 0 : result.Status) == Status.OK;
}
}
else {
let syncStatesRequest = new SyncDevicesStatesRequest();
syncStatesRequest.Data = true;
const result = yield ((_c = this._connection) === null || _c === void 0 ? void 0 : _c.SendAndWaitForResponseAsync(syncStatesRequest, 35000, false));
return (result === null || result === void 0 ? void 0 : result.Status) == Status.OK;
}
});
}
OnDevicesTasksExecutionChangeEvent() {
return this._onDevicesTasksChangedEvent;
}
OnDeviceStateChangedEvent() {
return this._onDeviceStateChangedEvent;
}
OnDeviceStateRefreshedOrChangedEvent() {
return this._onDeviceStateRefreshedOrChangedEvent;
}
OnDeviceRegisteredEvent() {
return this._onDeviceRegisteredEvent;
}
OnDeviceRemovedEvent() {
return this._onDeviceRemovedEvent;
}
OnDeviceFoundEvent() {
return this._onDeviceFoundEvent;
}
MapApiDevices(devicesObjects) {
const devices = [];
if (devicesObjects == null)
return [];
devicesObjects.forEach(element => {
var _a, _b, _c, _d;
var device = new Device();
device.Guid = element.Guid;
device.Name = element.DeviceName;
device.ChannelsAmount = element.ChannelsNumber;
device.DeviceType = element.DeviceType;
device.CommunicationWay = element.CommunicationWay;
device.DeviceState = element.DeviceState;
device.IsEnabled = element.IsEnabled;
device.IsVirtual = element.IsVirtual;
device.SerialNumber = element.DeviceSerialNumber;
device.ManufacturerGuid = element.ManufacturerGuid;
device.ModelGuid = element.DeviceModelGuid;
device.Model = element.DeviceModel;
device.Name = element.DeviceName;
device.ProtocolGuid = element.ProtocolGuid;
if (element.IconType !== undefined && element.IconType !== null)
device.IconType = element.IconType;
else
device.IconType = IconType.Unknown;
try {
(_a = element.AvailableTasks) === null || _a === void 0 ? void 0 : _a.forEach(task => {
var typeInfo = new DeviceTaskTypeInfo();
if (device.CommunicationWay == CommunicationWay.OneWay) {
switch (task) {
case "IBlindPosition":
typeInfo.InterfaceType = "IBlindPositionSimple";
break;
}
}
else
switch (task) {
case "IGatePosition":
typeInfo.InterfaceType = "IGatePulse";
break;
case "IGatewayPosition":
typeInfo.InterfaceType = "IGatewayPulse";
break;
default:
typeInfo.InterfaceType = task;
break;
}
device.AvailableTaskTypes.push(typeInfo);
});
(_b = element.AvailableResponses) === null || _b === void 0 ? void 0 : _b.forEach(response => {
var typeInfo = new DeviceResponseTypeInfo();
typeInfo.InterfaceType = response;
device.AvailableResponseTypes.push(typeInfo);
});
(_c = element.ChannelsConfiguration) === null || _c === void 0 ? void 0 : _c.forEach(configuration => {
var _a, _b, _c;
try {
var ch = new DeviceChannel();
ch.Number = configuration.Channel;
device.Channels.push(ch);
ch.SetDevice(device);
ch.Name = configuration.ChannelName;
ch.ChannelGroups = configuration.GroupsGuids;
ch.IconName = configuration.IconName;
ch.IsHidden = configuration.Hidden;
ch.Configurations = configuration.Configurations;
ch.CustomDataAndRolesSupported = configuration.CustomData !== undefined && configuration.CustomData !== null;
if (configuration.CustomData !== undefined && configuration.CustomData !== null)
ch.CustomData = configuration.CustomData;
if (configuration.Roles !== undefined && configuration.Roles !== null)
ch.Roles = configuration.Roles;
(_a = configuration.AvailableResponses) === null || _a === void 0 ? void 0 : _a.forEach(response => {
var typeInfo = new DeviceResponseTypeInfo();
typeInfo.InterfaceType = response;
ch.AvailableResponseTypes.push(typeInfo);
});
(_b = configuration.AvailableTasks) === null || _b === void 0 ? void 0 : _b.forEach(task => {
var typeInfo = new DeviceTaskTypeInfo();
if (device.AvailableTaskTypes.any(a => a.InterfaceType == "IBlindPositionSimple")) {
if (task == "IBlindPosition")
typeInfo.InterfaceType = "IBlindPositionSimple";
}
else {
typeInfo.InterfaceType = task;
}
ch.AvailableTaskTypes.push(typeInfo);
});
}
catch (ex) {
(_c = DependencyContainer.Log) === null || _c === void 0 ? void 0 : _c.Error(ex);
}
});
}
catch (ex) {
(_d = DependencyContainer.Log) === null || _d === void 0 ? void 0 : _d.Error(ex);
}
devices.push(device);
});
return devices;
}
GetPairedDevicesAsync() {
return __awaiter(this, arguments, void 0, function* (withScenes = false) {
var _a, _b, _c;
if (this._synchronized && !(yield ((_a = this._controllerConfiguration) === null || _a === void 0 ? void 0 : _a.DidCofigurationChangeAsync()))) {
if (withScenes)
return Promise.resolve(this._devices);
else
return Promise.resolve(this._devices.filter(d => d.DeviceType != DeviceType.Scene));
}
const result = yield ((_b = this._connection) === null || _b === void 0 ? void 0 : _b.SendAndWaitForResponseAsync(new GetDevicesListRequest(), 15000, true));
if (result == null || result === undefined)
return [];
if (result.Status == Status.OK && result.Data != null) {
this._devices = this.MapApiDevices(result.Data);
if (withScenes)
return this._devices;
else
return this._devices.filter(d => d.DeviceType != DeviceType.Scene);
}
else {
(_c = DependencyContainer.Log) === null || _c === void 0 ? void 0 : _c.Error(DevicesService.ServiceName, `Failed to get devices. ${result.Status} ${result.Data}`);
return [];
}
});
}
GetDevicesAsync() {
return __awaiter(this, arguments, void 0, function* (withScenes = false) {
yield this.WaitForSynchronizationAsync();
return this.GetPairedDevicesAsync(withScenes);
});
}
GetFoundDevicesAsync() {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
const result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new GetFoundDevicesRequest(), 15000, false));
if (result == null)
return [];
if (result.Status == Status.OK && result.Data != null)
return this.MapApiDevices(result.Data).where(a => a.DeviceType !== DeviceType.Scene).toArray();
else {
(_b = DependencyContainer.Log) === null || _b === void 0 ? void 0 : _b.Error(DevicesService.ServiceName, `Failed to get found devices. ${result.Status} ${result.Data}`);
return [];
}
});
}
GetDevice(guid) {
return this._devices.find(a => a.Guid === guid);
}
FindDevicesAsync() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
Api.Get(WebApiCacheService.ServiceName).ClearCache();
yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new SearchForDevicesRequest(), 35000, false));
});
}
StopSearchingForDevices() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new StopSearchingForDevicesRequest(), 20000, false));
});
}
RegisterDeviceAsync(device) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
try {
const req = new DevicePairRequest();
req.Data = device.Guid;
const res = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(req, 20000, false));
(_b = DependencyContainer.Log) === null || _b === void 0 ? void 0 : _b.Error(DevicesService.ServiceName, `EXIT CONFIGURATION MODE WILL BE FIRED! RegisterDeviceAsync()`);
Api.Get(ControllerConfigurationService.ServiceName).ExitConfigurationModeAsync();
if ((res === null || res === void 0 ? void 0 : res.Status) == Status.OK) {
if (!(this._devices.any(d => d.Guid == device.Guid)))
this._devices.push(device);
this._onDeviceRegisteredEvent.Invoke(device);
return DeviceTaskExecutionResult.Executed;
}
else
return DeviceTaskExecutionResult.Failed;
}
catch (ex) {
(_c = DependencyContainer.Log) === null || _c === void 0 ? void 0 : _c.Error(DevicesService.ServiceName, `Failed to paired devices: ${ex}`);
return DeviceTaskExecutionResult.ControllerResponseTimeout;
}
});
}
RemoveDeviceAsync(device_1) {
return __awaiter(this, arguments, void 0, function* (device, force = false) {
var _a, _b;
var req = new DeviceUnpairRequest();
if (force)
req = new ForceDeviceUnpairRequest();
req.Data = device.Guid;
const res = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(req, 35000, false));
(_b = DependencyContainer.Log) === null || _b === void 0 ? void 0 : _b.Error(DevicesService.ServiceName, `EXIT CONFIGURATION MODE WILL BE FIRED! RemoveDeviceAsync()`);
Api.Get(ControllerConfigurationService.ServiceName).ExitConfigurationModeAsync();
if ((res === null || res === void 0 ? void 0 : res.Status) == Status.OK) {
this._devices = this._devices.where(a => a.Guid != device.Guid).toArray();
this._onDeviceRemovedEvent.Invoke(device);
return DeviceTaskExecutionResult.Executed;
}
else
return DeviceTaskExecutionResult.Failed;
});
}
MapDeviceTaskToDeviceTaskInfo(device, task) {
let t = new DeviceTaskInfo();
const tsk = task;
switch (tsk.FeatureType) {
case DeviceControlFeature.SetTemperature:
t.Data = tsk.Temperature;
break;
case DeviceControlFeature.SetLightBrightness:
t.Data = tsk.Brightness;
break;
case DeviceControlFeature.SetLightColor:
t = new LightColorTaskInfo();
const ts = tsk;
t.R = ts.R;
t.G = ts.G;
t.B = ts.B;
break;
case DeviceControlFeature.SetLightTemperature:
t.Data = tsk.Temperature;
break;
case DeviceControlFeature.SetGatePositionPrecise:
switch (tsk.GateControlAction) {
case GateActionEnum.Open:
t.Data = 101;
break;
case GateActionEnum.Close:
t.Data = 102;
break;
case GateActionEnum.Stop:
t.Data = 103;
break;
case GateActionEnum.Percentage:
t.Data = tsk.Position;
break;
}
break;
case DeviceControlFeature.SetBlindPosition:
switch (tsk.Action) {
case BlindActionEnum.Open:
t.Data = 101;
break;
case BlindActionEnum.Close:
t.Data = 102;
break;
case BlindActionEnum.Stop:
t.Data = 103;
break;
case BlindActionEnum.Percentage:
t.Data = tsk.Position;
break;
}
break;
case DeviceControlFeature.SetLightBrightnessDynamicly:
t.Data = tsk.Brightness;
break;
case DeviceControlFeature.SetBlindOpenCloseTime:
t.Data = tsk.Data;
break;
case DeviceControlFeature.SetBlindMicroventilation:
t.Data = tsk.Position;
break;
case DeviceControlFeature.SetFacadePositionAndTilt:
t = new FacadePositionTaskInfo();
const fp = tsk;
t.FacadeAction = fp.FacadeAction;
t.Tilt = fp.Tilt;
t.Position = fp.Position;
break;
case DeviceControlFeature.LightRGBW:
t.Data = tsk.Data;
break;
case DeviceControlFeature.GatePulse:
case DeviceControlFeature.GatewayPulse:
t.Data = 0;
break;
case DeviceControlFeature.TurnOnWithTimeout:
t.Data = tsk.SwitchOffDelaySeconds;
break;
}
t.Channel = tsk.Channel;
t.DeviceGuid = device.Guid;
t.ControlFeature = tsk.FeatureType;
return t;
}
ExecuteDeviceTaskAsync(device, task) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g, _h;
try {
(_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Debug(DevicesService.ServiceName, `Preparing device task execution, device: ${device.Guid} task: ${task.TaskType} channel: ${task.Channel}`);
let t = this.MapDeviceTaskToDeviceTaskInfo(device, task);
try {
const req = new ExecuteDeviceTaskRequest(t);
(_b = DependencyContainer.Log) === null || _b === void 0 ? void 0 : _b.Debug(DevicesService.ServiceName, `Sending device task for execution, device: ${t.DeviceGuid} task: ${t.ControlFeature} channel: ${t.Channel} request: ${JSON.stringify(req)}`);
const result = yield ((_c = this._connection) === null || _c === void 0 ? void 0 : _c.SendAndWaitForResponseAsync(req, 15000, false));
switch (result === null || result === void 0 ? void 0 : result.Status) {