lavva.exalushome
Version:
Library implementing communication and abstraction layers for ExalusHome system
973 lines • 69.8 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 { Api } from "../../Api";
import { DependencyContainer } from "../../DependencyContainer";
import { Guid } from "../../Guid";
import { Helpers } from "../../Helpers";
import { DeviceResponseType, DeviceTaskType } from "../Devices/IDevice";
import { EnergyMeasurementParameter } from "../Devices/IDeviceState";
import { DeviceControlFeature } from "../Devices/IDeviceTask";
import { LightRGBW, SetBlindMicroventilation, SetBlindOpenCloseTime, SetBlindPosition, SetBlindPositionSimple, SetFacadePosition, SetGatePositionPrecise, SetLightBrightness, SetLightBrightnessDynamicly, SetLightColor, SetLightTemperature, SetTemperature, TurnOnWithTime } from "../Devices/Tasks/Tasks";
import { UpdatesProvider } from "../Updates/UpdatesProvider";
import { ConditionInfoArgument, DeviceStateComparisonMethod, DeviceStateComparisonParams } from "./LeftArgumentTypes";
import { LockType, NotifyType } from "./SceneTaskTypes";
import { ConditionsTypes, DeviceStateType, HandledType, SceneTaskTypeNum, SupportedTaskTypes, UnsupportedScenesDeviceState } from "./Scenes";
import { ScenesService } from "./ScenesService";
export class SequenceBuilder {
constructor(sequenceName, sequenceIcon = "Cube") {
this._result = null;
this._tmp = new SequenceRequestData();
this._tmpTask = null;
this._prevSeqGuid = "";
this._currentSeqGuid = "";
this._editingExistingSequence = false;
this._rawExistingSequenceTasks = null;
//Saved in case when we remove first argument by method RemoveArgument
this._sequenceName = "";
this._sequenceIcon = "";
this._service = Api.Get(ScenesService.ServiceName);
if (sequenceName) {
this._sequenceName = sequenceName;
this._sequenceIcon = sequenceIcon;
this._tmp.Guid = Guid.NewGuid();
}
}
/**
* Sets current (new or in edit) sequence name
* @param name name
*/
SetSequenceName(name) {
const findLastArgumentAndEditNameInNotifyTask = (sequence) => {
if (sequence.RightArgumentType == ArgumentTypeNum.Null) {
sequence.Tasks.ControllerTasks.where(t => t.TaskType == SceneTaskTypeNum.NotifyTask).toArray().forEach(t => {
t.Title = name;
});
}
else
return findLastArgumentAndEditNameInNotifyTask(sequence.RightArgument);
};
this._sequenceName = name;
if (this._editingExistingSequence && this._result != null) {
this._result.Name = name;
//Find notify task and update topic (name)
findLastArgumentAndEditNameInNotifyTask(this._result);
}
}
/**
* Sets current (new or in edit) sequence icon
* @param icon icon
*/
SetSequenceIcon(icon) {
this._sequenceIcon = icon;
if (this._editingExistingSequence && this._result != null) {
this._result.Icon = icon;
}
}
/**
* Gets next sequence from sequence chain
*/
GetNext() {
if (this._result == null)
return null;
if (this._currentSeqGuid == "") {
this._currentSeqGuid = this._result.Guid;
return this._service.MapSequence(JSON.parse(JSON.stringify(this._result)), true);
}
else {
const result = this.FindArgumentWithGuid(this._result, this._currentSeqGuid);
if (result == null) {
return null;
}
else {
if (result.RightArgumentType == ArgumentTypeNum.Condition) {
this._prevSeqGuid = this._currentSeqGuid;
this._currentSeqGuid = result.RightArgument.Guid;
return this._service.MapSequence(JSON.parse(JSON.stringify(result.RightArgument)), true);
}
else
return null;
}
}
}
/**
* Method allows to clone builder with all sqeuence atributes and tasks.
* Function re-generate all guids in chain and reset navigation to first element.
* @returns cloned builder (new object)
*/
CloneCurrentBuilder() {
const regenerateArgumentsGuids = (builder) => {
const regenerateGuids = (sequence) => {
sequence.Guid = Guid.NewGuid();
if (sequence.RightArgumentType == ArgumentTypeNum.Condition) {
regenerateGuids(sequence.RightArgument);
}
};
if (builder._result != null)
regenerateGuids(builder._result);
if (this._tmp != null)
this._tmp.Guid = Guid.NewGuid();
};
var clonedBuilder = new SequenceBuilder();
clonedBuilder._currentSeqGuid = "";
clonedBuilder._prevSeqGuid = "";
clonedBuilder._editingExistingSequence = structuredClone(this._editingExistingSequence);
clonedBuilder._rawExistingSequenceTasks = structuredClone(this._rawExistingSequenceTasks);
clonedBuilder._result = structuredClone(this._result);
clonedBuilder._sequenceIcon = structuredClone(this._sequenceIcon);
clonedBuilder._sequenceName = structuredClone(this._sequenceName);
;
clonedBuilder._tmp = structuredClone(this._tmp);
regenerateArgumentsGuids(clonedBuilder);
return clonedBuilder;
}
/**
* Gets previous sequence from sequence chain
*/
GetPrevious() {
let prevGuid = "";
const findArgumentWithGuidAndReturnPrevGuid = (sequence, sequenceGuid) => {
if (sequence.Guid == sequenceGuid) {
return { sequence: sequence, prevGuid: prevGuid };
}
else if (sequence.RightArgumentType == ArgumentTypeNum.Condition) {
prevGuid = sequence.Guid;
return findArgumentWithGuidAndReturnPrevGuid(sequence.RightArgument, sequenceGuid);
}
else
return null;
};
if (this._result == null)
return null;
if (this._currentSeqGuid == "" || this._prevSeqGuid == "")
return null;
const result = findArgumentWithGuidAndReturnPrevGuid(this._result, this._prevSeqGuid);
if (result == null) {
return null;
}
else {
this._currentSeqGuid = result.sequence.Guid;
this._prevSeqGuid = result.prevGuid;
return this._service.MapSequence(JSON.parse(JSON.stringify(result.sequence)), true);
}
}
/**
* Gets sequence by guid
* @param sequenceGuid sequence guid
*/
GetByGuid(sequenceGuid) {
if (this._result == null)
return null;
const arg = this.FindArgumentWithGuid(this._result, sequenceGuid);
if (arg == null)
return null;
return this._service.MapSequence(arg);
}
EditCurrentSequence(sequence) {
const findLastArgumentAndGetRawTasks = (sequence) => {
if (sequence.RightArgumentType == ArgumentTypeNum.Null) {
this._rawExistingSequenceTasks = JSON.parse(JSON.stringify(sequence.Tasks));
}
else
return findLastArgumentAndGetRawTasks(sequence.RightArgument);
};
this._editingExistingSequence = true;
findLastArgumentAndGetRawTasks(sequence._rawRequestData);
if (Object.hasOwn(sequence._rawRequestData, "Condition")) {
this._result = sequence._rawRequestData.Condition;
}
else {
this._result = sequence._rawRequestData;
}
//Getting raw tasks from last argument
return {
GetNext: () => this.GetNext(),
GetPrevious: () => this.GetPrevious(),
GetByGuid: (sequenceGuid) => this.GetByGuid(sequenceGuid),
GetAllowedArguments: () => this.GetAllowedArguments(),
RemoveSequence: (sequenceGuid) => this.RemoveSequenceByGuid(sequenceGuid),
ArgumentAsAstronomicalClockWithOffset: (arg, atMeetCondition, comparasion) => this.ArgumentAsAstronomicalClockWithOffset(arg, atMeetCondition, comparasion),
ArgumentAsDaysOfWeek: (arg, atMeetCondition, comparison) => this.ArgumentAsDaysOfWeek(arg, atMeetCondition, comparison),
ArgumentAsDeviceState: (arg, atMeetCondition, atMeetConditionTimeout, comparison = ConditionsTypes.Equal) => this.ArgumentAsDeviceState(arg, atMeetCondition, atMeetConditionTimeout, comparison),
ArgumentAsTime: (arg, atMeetCondition, comparison = ConditionsTypes.Equal) => this.ArgumentAsTime(arg, atMeetCondition, comparison),
ArgumentAsTimeSpan: (arg, comparison) => this.ArgumentAsTimeSpan(arg, comparison),
ArgumentAsSceneExecuted: (arg) => this.ArgumentAsSceneExecuted(arg),
RemoveTask: (taskGuid) => this.RemoveTask(taskGuid),
};
}
/**
* Function creates argument of type AstronomicalClockWithOffse in the argument chain
* @param arg
* @returns function that adds argument to end of chain
*/
ArgumentAsAstronomicalClockWithOffset(arg, atMeetCondition, comparasion) {
this._tmp.Guid = Guid.NewGuid();
this._tmp.HandledType = HandledType.AstronomicalClockWithOffset;
this._tmp.LeftArgumentType = ArgumentTypeNum.ArgumentAsAstronomicalClockWithOffset;
this._tmp.AtMeetCondition = atMeetCondition;
if (atMeetCondition && (comparasion != null && comparasion != ConditionsTypes.Equal)) {
throw new BadParametersScenesBuilderException("AtmeetCondition supports only comparation type 'Equal'.");
}
if (arg.Offset < -3600 || arg.Offset > 3600)
throw new BadParametersScenesBuilderException("Offset must be in range between -3600 and 3600 seconds.");
if (atMeetCondition)
this._tmp.ConditionType = ConditionsTypes.Equal;
else if (comparasion != null)
this._tmp.ConditionType = comparasion;
else
throw new BadParametersScenesBuilderException("Comparasion type must be provided if atMeetCondition is false!");
this._tmp.LeftArgument.Argument = arg;
this._tmp.LeftArgument.HandledType = ArgumentTypeNum.ArgumentAsAstronomicalClockWithOffset;
return {
AddArgument: () => this.AddSequence(),
EditArgument: (sequenceGuid) => this.EditSequence(sequenceGuid)
};
}
ArgumentAsActionWithEmptyCondition() {
this._tmp.Guid = Guid.NewGuid();
this._tmp.HandledType = HandledType.Unknown;
this._tmp.LeftArgumentType = ArgumentTypeNum.Null;
this._tmp.ConditionType = ConditionsTypes.Equal;
this._tmp.LeftArgument.Argument = null;
this._tmp.LeftArgument.HandledType = ArgumentTypeNum.Null;
this._tmp.Name = this._sequenceName;
this._tmp.Icon = this._sequenceIcon;
this._tmp.AtMeetCondition = false;
return {
AddArgument: () => this.AddSequence(),
EditArgument: (sequenceGuid) => this.EditSequence(sequenceGuid)
};
}
/**
* Function creates argument of type DayOfWeekArgument in the argument chain
* @param arg
* @param atMeetCondition
* @param comparison
* @returns function that adds argument to end of chain
*/
ArgumentAsDaysOfWeek(arg, atMeetCondition, comparison = ConditionsTypes.Equal) {
this._tmp.Guid = Guid.NewGuid();
this._tmp.HandledType = HandledType.DaysOfWeek;
this._tmp.LeftArgumentType = ArgumentTypeNum.ArgumentAsDaysOfWeek;
this._tmp.ConditionType = comparison;
this._tmp.LeftArgument.Argument = arg;
this._tmp.LeftArgument.HandledType = ArgumentTypeNum.ArgumentAsDaysOfWeek;
this._tmp.AtMeetCondition = atMeetCondition;
return {
AddArgument: () => this.AddSequence(),
EditArgument: (sequenceGuid) => this.EditSequence(sequenceGuid)
};
}
/**
* Function creates argument of type SimpleTimeSpanArgument in the argument chain
* @param arg
* @param comparison
* @returns function that adds argument to end of chain
*/
ArgumentAsTimeSpan(arg, comparison = ConditionsTypes.Equal) {
this._tmp.Guid = Guid.NewGuid();
this._tmp.HandledType = HandledType.Timer;
this._tmp.LeftArgumentType = ArgumentTypeNum.ArgumentAsTimeSpan;
this._tmp.ConditionType = comparison;
this._tmp.AtMeetCondition = true;
this._tmp.LeftArgument.Argument = arg;
this._tmp.LeftArgument.HandledType = ArgumentTypeNum.ArgumentAsTimeSpan;
return {
AddArgument: () => this.AddSequence(),
EditArgument: (sequenceGuid) => this.EditSequence(sequenceGuid)
};
}
/**
* Function creates argument of type ArgumentAsTime in the argument chain
* @param arg
* @param atMeetCondition
* @param comparison
* @returns function that adds argument to end of chain
*/
ArgumentAsTime(arg, atMeetCondition, comparison = ConditionsTypes.Equal) {
this._tmp.Guid = Guid.NewGuid();
this._tmp.HandledType = HandledType.Time;
this._tmp.LeftArgumentType = ArgumentTypeNum.ArgumentAsTime;
this._tmp.ConditionType = comparison;
this._tmp.AtMeetCondition = atMeetCondition;
this._tmp.LeftArgument.Argument = arg;
this._tmp.LeftArgument.HandledType = ArgumentTypeNum.ArgumentAsTime;
return {
AddArgument: () => this.AddSequence(),
EditArgument: (sequenceGuid) => this.EditSequence(sequenceGuid)
};
}
/**
* Function creates argument of type DeviceStateArgument in the argument chain
* @param arg
* @param atMeetCondition
* @param atMeetConditionTimeout
* @param comparison
* @returns function that adds argument to end of chain
*/
ArgumentAsDeviceState(arg, atMeetCondition, atMeetConditionTimeout, comparison = ConditionsTypes.Equal) {
this._tmp.Guid = Guid.NewGuid();
this._tmp.HandledType = HandledType.DeviceState;
this._tmp.LeftArgumentType = ArgumentTypeNum.ArgumentAsDeviceState;
this._tmp.ConditionType = comparison;
this._tmp.AtMeetCondition = atMeetCondition;
this._tmp.ConditionTimeout = atMeetConditionTimeout;
this._tmp.LeftArgument.Argument = this.GenerateDeviceStateArgument(arg);
this._tmp.LeftArgument.HandledType = ArgumentTypeNum.ArgumentAsDeviceState;
return {
AddArgument: () => this.AddSequence(),
EditArgument: (sequenceGuid) => this.EditSequence(sequenceGuid)
};
}
/**
* Function creates argument of type ArgumentAsSceneExecuted - this argument waits until given scene will be executed, then returns 'true' and allow to execute check rest of arguments in chain.
* @param arg
*/
ArgumentAsSceneExecuted(arg) {
this._tmp.Guid = Guid.NewGuid();
this._tmp.HandledType = HandledType.SceneExecuted;
this._tmp.LeftArgumentType = ArgumentTypeNum.ArgumentAsConditionInfo;
this._tmp.ConditionType = ConditionsTypes.Equal;
this._tmp.AtMeetCondition = true;
const argumentData = new ConditionInfoArgument();
argumentData.DeviceGuid = arg.DeviceGuid;
this._tmp.LeftArgument.Argument = argumentData;
this._tmp.LeftArgument.HandledType = ArgumentTypeNum.ArgumentAsConditionInfo;
return {
AddArgument: () => this.AddSequence(),
EditArgument: (sequenceGuid) => this.EditSequence(sequenceGuid)
};
}
GenerateDeviceStateArgument(arg) {
const result = new LeftArgumentDeviceStateRequestData();
result.Channel = arg.GetCheckDeviceState().Channel;
result.ComparisonMethod = arg.ComparisonMethod;
let rawParams = {};
let paramsIterable = arg.GetComparisonParams().entries();
for (const [param, paramVal] of paramsIterable) {
rawParams = Object.assign(Object.assign({}, rawParams), { [DeviceStateComparisonParams[param]]: paramVal.Value });
}
result.ComparisonParams = rawParams;
result.DeviceGuid = arg.DeviceGuid;
result.DeviceStateType = this.MapResponseTypeToDeviceStateType(arg.Type);
switch (arg.Type) {
case DeviceResponseType.BatteryState: {
result.CheckedDeviceState.State = arg.GetCheckDeviceState().State;
result.CheckedDeviceState.Percentage = arg.GetCheckDeviceState().Percentage;
break;
}
case DeviceResponseType.BinarySensorState: {
result.CheckedDeviceState.State = arg.GetCheckDeviceState().State;
break;
}
case DeviceResponseType.BlindPosition: {
result.CheckedDeviceState.Position = arg.GetCheckDeviceState().Position;
break;
}
case DeviceResponseType.LightBrightness: {
result.CheckedDeviceState.Brightness = arg.GetCheckDeviceState().Brightness;
break;
}
case DeviceResponseType.MeasuredBrightness: {
result.CheckedDeviceState.Brightness = arg.GetCheckDeviceState().Brightness;
break;
}
case DeviceResponseType.RemoteButtonState: {
result.CheckedDeviceState.State = arg.GetCheckDeviceState().State;
break;
}
case DeviceResponseType.ChannelOnOffState: {
result.CheckedDeviceState.State = arg.GetCheckDeviceState().State;
break;
}
case DeviceResponseType.DoorBellState: {
result.CheckedDeviceState.State = arg.GetCheckDeviceState().State;
break;
}
case DeviceResponseType.MeasuredEnergy: {
let rawParams = {};
let paramsIterable = arg.GetCheckDeviceState().MeasurementParameters.entries();
for (const [param, paramVal] of paramsIterable) {
rawParams = Object.assign(Object.assign({}, rawParams), { [EnergyMeasurementParameter[param]]: paramVal });
}
result.CheckedDeviceState.MeasurementParameters = rawParams;
break;
}
case DeviceResponseType.FloodSensorState: {
result.CheckedDeviceState.State = arg.GetCheckDeviceState().State;
break;
}
case DeviceResponseType.GatePosition: {
result.CheckedDeviceState.Position = arg.GetCheckDeviceState().Position;
result.CheckedDeviceState.PositionType = arg.GetCheckDeviceState().PositionType;
break;
}
case DeviceResponseType.LightColor: {
const st = arg.GetCheckDeviceState();
result.CheckedDeviceState.R = st.R;
result.CheckedDeviceState.G = st.G;
result.CheckedDeviceState.B = st.B;
break;
}
case DeviceResponseType.LightWarmth: {
result.CheckedDeviceState.Temperature = arg.GetCheckDeviceState().Temperature;
break;
}
case DeviceResponseType.ReedState: {
result.CheckedDeviceState.State = arg.GetCheckDeviceState().State;
break;
}
case DeviceResponseType.SmokeSensorState:
throw new UnsupportedScenesDeviceState("Unsupported device state!");
case DeviceResponseType.MeasuredTemperature: {
result.CheckedDeviceState.Temperature = arg.GetCheckDeviceState().Temperature;
break;
}
case DeviceResponseType.HumiditySensorState: {
result.CheckedDeviceState.Humidity = arg.GetCheckDeviceState().Humidity;
break;
}
case DeviceResponseType.BlindRemoteButtonState: {
result.CheckedDeviceState.State = arg.GetCheckDeviceState().State;
break;
}
case DeviceResponseType.LightRGBWState: {
let st = arg.GetCheckDeviceState();
result.CheckedDeviceState.R = st.R;
result.CheckedDeviceState.G = st.G;
result.CheckedDeviceState.B = st.B;
result.CheckedDeviceState.W = st.W;
break;
}
case DeviceResponseType.FacadeRemoteButtonState: {
result.CheckedDeviceState.State = arg.GetCheckDeviceState().State;
break;
}
case DeviceResponseType.MovementSensorState: {
let st = arg.GetCheckDeviceState();
result.CheckedDeviceState.Movement = st.Movement;
result.CheckedDeviceState.Intensity = st.Intensity;
break;
}
case DeviceResponseType.PressureSensorState: {
result.CheckedDeviceState.Pressure = arg.GetCheckDeviceState().Pressure;
result.CheckedDeviceState.PressureType = arg.GetCheckDeviceState().PressureType;
break;
}
case DeviceResponseType.WindSpeedState: {
result.CheckedDeviceState.Value = arg.GetCheckDeviceState().Value;
break;
}
case DeviceResponseType.CurrentWindThreshold: {
result.CheckedDeviceState.WindThreshold = arg.GetCheckDeviceState().WindThreshold;
break;
}
case DeviceResponseType.Unknown:
result.CheckedDeviceState = {};
break;
default:
throw new UnsupportedScenesDeviceState("Unsupported device state!");
}
return result;
}
MapResponseTypeToDeviceStateType(responseType) {
switch (responseType) {
case DeviceResponseType.BatteryState:
return DeviceStateType.BatteryState;
case DeviceResponseType.BinarySensorState:
return DeviceStateType.BinarySensor;
case DeviceResponseType.BlindPosition:
return DeviceStateType.BlindPosition;
case DeviceResponseType.LightBrightness:
return DeviceStateType.LightBrightness;
case DeviceResponseType.RemoteButtonState:
return DeviceStateType.ButtonState;
case DeviceResponseType.ChannelOnOffState:
return DeviceStateType.ChannelOnOff;
case DeviceResponseType.DoorBellState:
return DeviceStateType.DoorBell;
case DeviceResponseType.MeasuredEnergy:
return DeviceStateType.Energy;
case DeviceResponseType.FloodSensorState:
return DeviceStateType.FloodSensor;
case DeviceResponseType.GatePosition:
return DeviceStateType.GatePosition;
case DeviceResponseType.MeasuredBrightness:
return DeviceStateType.Brightness;
case DeviceResponseType.LightColor:
return DeviceStateType.LightColor;
case DeviceResponseType.LightWarmth:
return DeviceStateType.LightTemperature;
case DeviceResponseType.ReedState:
return DeviceStateType.ReedState;
case DeviceResponseType.SmokeSensorState:
return DeviceStateType.SmokeSensor;
case DeviceResponseType.MeasuredTemperature:
return DeviceStateType.Temperature;
case DeviceResponseType.HumiditySensorState:
return DeviceStateType.Humidity;
case DeviceResponseType.BlindRemoteButtonState:
return DeviceStateType.BlindsControlButton;
case DeviceResponseType.FacadeRemoteButtonState:
return DeviceStateType.FacadeControlButton;
case DeviceResponseType.MovementSensorState:
return DeviceStateType.Movement;
case DeviceResponseType.PressureSensorState:
return DeviceStateType.AirPressure;
case DeviceResponseType.WindSpeedState:
return DeviceStateType.WindSpeed;
case DeviceResponseType.CurrentWindThreshold:
return DeviceStateType.WindThreshold;
default:
return DeviceStateType.Unknown;
}
}
/**
* Function adds argument to the end of argument chain
* @returns Functions that coud create another argument, function that coud commit argument chain, current argument data.
*/
AddSequence() {
const findLastRightArgumentAndAddContition = (sequence, newData) => {
if (sequence.RightArgumentType == ArgumentTypeNum.Null) {
sequence.RightArgumentType = ArgumentTypeNum.Condition;
sequence.RightArgument = newData;
if (this._editingExistingSequence) {
if (this._rawExistingSequenceTasks != null) {
newData.Tasks = JSON.parse(JSON.stringify(this._rawExistingSequenceTasks));
sequence.Tasks = new TasksRequestData();
}
}
}
else
return findLastRightArgumentAndAddContition(sequence.RightArgument, newData);
};
//result null - root sequence
if (this._result == null) {
this._tmp.Name = this._sequenceName;
this._tmp.Icon = this._sequenceIcon;
this._result = this._tmp;
this._result.AtMeetCondition = true;
}
else
findLastRightArgumentAndAddContition(this._result, this._tmp);
const sequneceData = this._service.MapSequence(JSON.parse(JSON.stringify(this._tmp)));
this._tmp = new SequenceRequestData();
return {
GetNext: () => this.GetNext(),
GetPrevious: () => this.GetPrevious(),
GetByGuid: (sequenceGuid) => this.GetByGuid(sequenceGuid),
GetAllowedArguments: () => this.GetAllowedArguments(),
RemoveSequenceByGuid: (argumentGuid) => this.RemoveSequenceByGuid(argumentGuid),
Commit: () => this.Commit(),
ArgumentAsActionWithEmptyCondition: () => this.ArgumentAsActionWithEmptyCondition(),
ArgumentAsAstronomicalClockWithOffset: (arg, atMeetCondition, comparasion) => this.ArgumentAsAstronomicalClockWithOffset(arg, atMeetCondition, comparasion),
ArgumentAsDaysOfWeek: (arg, atMeetCondition, comparison) => this.ArgumentAsDaysOfWeek(arg, atMeetCondition, comparison),
ArgumentAsDeviceState: (arg, atMeetCondition, atMeetConditionTimeout, comparison = ConditionsTypes.Equal) => this.ArgumentAsDeviceState(arg, atMeetCondition, atMeetConditionTimeout, comparison),
ArgumentAsTime: (arg, atMeetCondition, comparison = ConditionsTypes.Equal) => this.ArgumentAsTime(arg, atMeetCondition, comparison),
ArgumentAsTimeSpan: (arg, comparison) => this.ArgumentAsTimeSpan(arg, comparison),
ArgumentAsSceneExecuted: (arg) => this.ArgumentAsSceneExecuted(arg),
SequenceData: sequneceData
};
}
EditSequence(sequenceGuid) {
const findLastArgumentWithGuidAndEditCondition = (sequence, newData) => {
if (sequence.Guid == sequenceGuid && sequence.ObjectType == ArgumentTypeNum.Condition) {
//Remap properties (needs in this format to keep reference to this._result, we changing only sequence properties without deattach root) newData is reference to this._tmp
sequence.AtMeetCondition = newData.AtMeetCondition;
sequence.ConditionTimeout = newData.ConditionTimeout;
sequence.ConditionType = newData.ConditionType;
sequence.ExecuteOnce = newData.ExecuteOnce;
sequence.HandledType = newData.HandledType;
sequence.IsDisabled = newData.IsDisabled;
sequence.LeftArgument = newData.LeftArgument;
sequence.LeftArgumentType = newData.LeftArgumentType;
sequence.ObjectType = newData.ObjectType;
sequence.Tasks = newData.Tasks;
//Keep settings that are not edited in this scope
newData.Guid = sequence.Guid;
newData.Icon = sequence.Icon;
newData.Name = sequence.Name;
}
else if (sequence.RightArgumentType == ArgumentTypeNum.Condition)
return findLastArgumentWithGuidAndEditCondition(sequence.RightArgument, newData);
else
throw new SequenceNotFoundScenesBuilderException(`Cannot edit sequence with given GUID ${sequenceGuid} - sequence not foud in chain`);
};
if (this._result == null)
throw new SequenceNotFoundScenesBuilderException(`Cannot edit sequence with given GUID ${sequenceGuid} - sequence not initialized (no root element)`);
findLastArgumentWithGuidAndEditCondition(this._result, this._tmp);
const sequneceData = this._service.MapSequence(JSON.parse(JSON.stringify(this._tmp)));
this._tmp = new SequenceRequestData();
console.log(`new tmp guid: ${this._tmp.Guid}`);
if (!this._result.AtMeetCondition)
this._result.AtMeetCondition = true;
return {
GetNext: () => this.GetNext(),
GetPrevious: () => this.GetPrevious(),
GetByGuid: (sequenceGuid) => this.GetByGuid(sequenceGuid),
GetAllowedArguments: () => this.GetAllowedArguments(),
RemoveSequenceByGuid: (sequenceGuid) => this.RemoveSequenceByGuid(sequenceGuid),
Commit: () => this.Commit(),
ArgumentAsActionWithEmptyCondition: () => this.ArgumentAsActionWithEmptyCondition(),
ArgumentAsAstronomicalClockWithOffset: (arg, atMeetCondition, comparasion) => this.ArgumentAsAstronomicalClockWithOffset(arg, atMeetCondition, comparasion),
ArgumentAsDaysOfWeek: (arg, atMeetCondition, comparison) => this.ArgumentAsDaysOfWeek(arg, atMeetCondition, comparison),
ArgumentAsDeviceState: (arg, atMeetCondition, atMeetConditionTimeout, comparison = ConditionsTypes.Equal) => this.ArgumentAsDeviceState(arg, atMeetCondition, atMeetConditionTimeout, comparison),
ArgumentAsTime: (arg, atMeetCondition, comparison = ConditionsTypes.Equal) => this.ArgumentAsTime(arg, atMeetCondition, comparison),
ArgumentAsTimeSpan: (arg, comparison) => this.ArgumentAsTimeSpan(arg, comparison),
ArgumentAsSceneExecuted: (arg) => this.ArgumentAsSceneExecuted(arg),
SequenceData: sequneceData
};
}
RemoveSequenceByGuid(sequenceGuid) {
let refToHead;
const fixNavigation = (sequence, sequenceGuid) => {
//navigation never used, don't need fix
if (this._currentSeqGuid == "" && this._prevSeqGuid == "")
return;
if (this._currentSeqGuid == sequenceGuid) {
this._currentSeqGuid = sequence.RightArgumentType == ArgumentTypeNum.Condition ? sequence.RightArgument.Guid : "";
this._prevSeqGuid = refToHead != null ? refToHead.Guid : "";
}
else if (this._prevSeqGuid == sequenceGuid) {
this._prevSeqGuid = refToHead != null ? refToHead.Guid : "";
}
};
const findRightArgumentAndRemoveArg = (sequence, sequenceGuid) => {
//Argument to remove
if (sequence.Guid == sequenceGuid) {
//no ref to head - root argument
if (refToHead == null)
this._result = null;
else {
refToHead.RightArgument = sequence.RightArgument;
refToHead.RightArgumentType = sequence.RightArgumentType;
}
fixNavigation(sequence, sequenceGuid);
}
else {
refToHead = sequence;
if (sequence.RightArgumentType == ArgumentTypeNum.Null)
throw new SequenceNotFoundScenesBuilderException(`Cannot remove sequence, sequence with given guid ${sequenceGuid} not found!`);
return findRightArgumentAndRemoveArg(sequence.RightArgument, sequenceGuid);
}
};
if (this._result == null)
throw new SequenceNotFoundScenesBuilderException("Cannot remove sequence, sequence not configured!");
//Removing root argument
if (this._result.Guid == sequenceGuid && this._result.RightArgumentType != ArgumentTypeNum.Null) {
this._result.RightArgument.Name = this._result.Name;
this._result.RightArgument.Icon = this._result.Icon;
this._result.RightArgument.Guid = this._result.Guid;
this._result = this._result.RightArgument;
this._result.AtMeetCondition = true;
fixNavigation(this._result, sequenceGuid);
}
else {
//Removing nested arguments
findRightArgumentAndRemoveArg(this._result, sequenceGuid);
}
return {
GetNext: () => this.GetNext(),
GetPrevious: () => this.GetPrevious(),
GetByGuid: (sequenceGuid) => this.GetByGuid(sequenceGuid),
GetAllowedArguments: () => this.GetAllowedArguments(),
RemoveSequenceByGuid: (sequenceGuid) => this.RemoveSequenceByGuid(sequenceGuid),
Commit: () => this.Commit(),
ArgumentAsActionWithEmptyCondition: () => this.ArgumentAsActionWithEmptyCondition(),
ArgumentAsAstronomicalClockWithOffset: (arg, atMeetCondition, comparasion) => this.ArgumentAsAstronomicalClockWithOffset(arg, atMeetCondition, comparasion),
ArgumentAsDaysOfWeek: (arg, atMeetCondition, comparison) => this.ArgumentAsDaysOfWeek(arg, atMeetCondition, comparison),
ArgumentAsDeviceState: (arg, atMeetCondition, atMeetConditionTimeout, comparison = ConditionsTypes.Equal) => this.ArgumentAsDeviceState(arg, atMeetCondition, atMeetConditionTimeout, comparison),
ArgumentAsTime: (arg, atMeetCondition, comparison = ConditionsTypes.Equal) => this.ArgumentAsTime(arg, atMeetCondition, comparison),
ArgumentAsTimeSpan: (arg, comparison) => this.ArgumentAsTimeSpan(arg, comparison),
ArgumentAsSceneExecuted: (arg) => this.ArgumentAsSceneExecuted(arg),
SequenceData: null
};
}
/**
* Functions commits modifications of arguments chain
* @returns
*/
Commit() {
const findLastRightArgumentAndMoveTasks = (sequence) => {
//Last arg
if (sequence.RightArgumentType == ArgumentTypeNum.Null) {
if (this._rawExistingSequenceTasks != null)
sequence.Tasks = this._rawExistingSequenceTasks;
}
else
return findLastRightArgumentAndMoveTasks(sequence.RightArgument);
};
if (this._result == null)
throw new SequenceNotFoundScenesBuilderException("Sequence are not initialized! Not found root sequence.");
//Move tasks to last argument - required while editing (removing or adding argument)
if (this._editingExistingSequence)
findLastRightArgumentAndMoveTasks(this._result);
return {
GetSupportedTypesOfTasks: () => this.GetSupportedTaskTypesAsync(),
DeviceTask: (task) => this.DeviceTask(task),
DelayTask: (delay) => this.DelayTask(delay),
NotifyTask: (notification) => this.NotifyTask(notification),
LockExecutionTask: (lockTask) => this.LockExecutionTask(lockTask),
RemoveTask: (taskGuid) => this.RemoveTask(taskGuid),
Build: () => this.Build(),
BuildToISequence: () => this._service.MapSequence(JSON.parse(JSON.stringify(this._result))),
ValidateScene: () => this.ValidateScene(),
};
}
DeviceTask(task) {
this._tmpTask = this.ParseDeviceTask(task);
if (this._result == null)
throw new Error("No context!");
return {
AddTask: () => this.AddTask(),
EditTask: (taskId) => this.EditTask(taskId),
TaskId: Helpers.GenerateMd5(JSON.stringify(this._tmpTask)),
};
}
ParseDeviceTask(task) {
const tsk = new DeviceTaskRequestData();
tsk.Channel = task.Channel;
tsk.DeviceGuid = task.DeviceGuid;
tsk.ControlFeature = this.MapTaskTypeToControlFeature(task.TaskType);
tsk.Data = {};
tsk.Data.Channel = task.Channel;
if (task.TaskType == DeviceTaskType.SetBlindPosition || task instanceof SetBlindPosition) {
tsk.Data.Position = task.Position;
tsk.Data.Action = task.Action;
}
else if (task.TaskType == DeviceTaskType.SetBlindPositionSimple || task instanceof SetBlindPositionSimple) {
tsk.Data.Action = task.Action;
tsk.Data.Position = 0;
}
else if (task.TaskType == DeviceTaskType.SetLightColor || task instanceof SetLightColor) {
tsk.Data.R = task.R;
tsk.Data.G = task.G;
tsk.Data.B = task.B;
}
else if (task.TaskType == DeviceTaskType.SetLightTemperature || task instanceof SetLightTemperature) {
tsk.Data.Temperature = task.Temperature;
}
else if (task.TaskType == DeviceTaskType.SetLightBrightness || task instanceof SetLightBrightness) {
tsk.Data.Brightness = task.Brightness;
}
else if (task.TaskType == DeviceTaskType.SetTemperature || task instanceof SetTemperature) {
tsk.Data.Temperature = task.Temperature;
}
else if (task.TaskType == DeviceTaskType.TurnOnWithTime || task instanceof TurnOnWithTime) {
tsk.Data.SwitchOffDelaySeconds = task.SwitchOffDelaySeconds;
}
else if (task.TaskType == DeviceTaskType.SetLightBrightnessDynamicly || task instanceof SetLightBrightnessDynamicly) {
tsk.Data.Brightness = task.Brightness;
}
else if (task.TaskType == DeviceTaskType.SetBlindOpenCloseTime || task instanceof SetBlindOpenCloseTime) {
tsk.Data.CloseTime = task.Data.CloseTime;
tsk.Data.OpenTime = task.Data.OpenTime;
}
else if (task.TaskType == DeviceTaskType.SetBlindMicroventilation || task instanceof SetBlindMicroventilation) {
tsk.Data.Position = task.Position;
}
else if (task.TaskType == DeviceTaskType.SetFacadePosition || task instanceof SetFacadePosition) {
tsk.Data.FacadeAction = task.FacadeAction;
tsk.Data.Position = task.Position;
tsk.Data.Tilt = task.Tilt;
}
else if (task.TaskType == DeviceTaskType.LightRGBW || task instanceof LightRGBW) {
tsk.Data.R = task.Data.R;
tsk.Data.G = task.Data.G;
tsk.Data.B = task.Data.B;
tsk.Data.W = task.Data.W;
tsk.Data.Brightness = task.Data.Brightness;
}
else if (task.TaskType == DeviceTaskType.PreciseGateControl || task instanceof SetGatePositionPrecise) {
tsk.Data.Position = task.Position;
tsk.Data.GateControlAction = task.GateControlAction;
}
//else
// throw new Error(`Unsupported device task, task type: ${task.TaskType} task object: ${task}!`);
return tsk;
}
DelayTask(delay) {
const task = new DelayTaskRequestData();
task.Delay = delay.Delay.Value;
this._tmpTask = task;
if (this._result == null)
throw new Error("No context!");
return {
AddTask: () => this.AddTask(),
EditTask: (taskGuid) => this.EditTask(taskGuid),
TaskId: Helpers.GenerateMd5(JSON.stringify(task)),
};
}
NotifyTask(notification) {
if (notification.NotifyType == NotifyType.Email)
throw new UnsupportedArgumentScenesBuilderException("NotifyType 'Email' is not supported!");
if (notification.NotifyType == NotifyType.None)
throw new Error("NotifyType mus be set!");
if (notification.Message == "")
throw new BadParametersScenesBuilderException("Message must be set!");
if (notification.Message.length > 1000)
throw new BadParametersScenesBuilderException("Message is too long! Max length is 1000 characters.");
const task = new NotifyTaskRequestData();
task.NotifyType = notification.NotifyType;
task.Message = notification.Message;
task.NotificationClients = notification.NotificationClients;
task.Title = this._sequenceName;
this._tmpTask = task;
if (this._result == null)
throw new Error("No context!");
return {
AddTask: () => this.AddTask(),
EditTask: (taskGuid) => this.EditTask(taskGuid),
TaskId: Helpers.GenerateMd5(JSON.stringify(task)),
};
}
LockExecutionTask(lockTask) {
const task = new LockTaskTaskRequestData();
task.LockType = lockTask.LockType;
if (task.LockType == LockType.Timeout) {
if (task.LockEndHour != "00:00:00")
throw new UnsupportedArgumentScenesBuilderException("Parameter LockEndHour at lock type `Timeout` must be default!");
}
task.LockStartHour = lockTask.LockStartHour.Value;
task.LockEndHour = lockTask.LockEndHour.Value;
task.ResetLockScenesGuids = lockTask.ResetLockScenesGuids;
this._tmpTask = task;
if (this._result == null)
throw new Error("No context!");
return {
AddTask: () => this.AddTask(),
EditTask: (taskGuid) => this.EditTask(taskGuid),
TaskId: Helpers.GenerateMd5(JSON.stringify(task)),
};
}
AddTask() {
const findLastRightArgumentAndAddTask = (sequence) => {
var _a;
//Last arg
if (sequence.RightArgumentType == ArgumentTypeNum.Null) {
if (this._tmpTask == null)
throw Error("No task context!");
if (sequence.Tasks.DevicesTasks === undefined || sequence.Tasks.DevicesTasks === null)
sequence.Tasks.DevicesTasks = [];
if (this._tmpTask instanceof DeviceTaskRequestData)
sequence.Tasks.DevicesTasks.push(structuredClone(this._tmpTask));
sequence.Tasks.ControllerTasks.push(structuredClone(this._tmpTask));
this._tmpTask = null;
(_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Debug(`Task added to sequence: \n${JSON.stringify(this._tmpTask)} \ntasks on a list: \n${JSON.stringify(sequence.Tasks)}`);
}
else
return findLastRightArgumentAndAddTask(sequence.RightArgument);
};
if (this._result == null)
throw new Error("No context!");
findLastRightArgumentAndAddTask(this._result);
return {
GetSupportedTypesOfTasks: () => this.GetSupportedTaskTypesAsync(),
DeviceTask: (task) => this.DeviceTask(task),
DelayTask: (delay) => this.DelayTask(delay),
NotifyTask: (notification) => this.NotifyTask(notification),
LockExecutionTask: (lockTask) => this.LockExecutionTask(lockTask),
RemoveTask: (taskId) => this.RemoveTask(taskId),
Build: () => this.Build(),
BuildToISequence: () => this._service.MapSequence(JSON.parse(JSON.stringify(this._result))),
ValidateScene: () => this.ValidateScene(),
};
}
EditTask(taskId) {
const findLastRightArgumentAndEditTask = (sequence) => {
var _a;
//Last arg
if (sequence.RightArgumentType == ArgumentTypeNum.Null) {
if (this._tmpTask == null)
throw Error("No task context!");
if (sequence.Tasks.ControllerTasks == null || sequence.Tasks.ControllerTasks.length == 0)
throw new TaskNotFoundScenesBuilderException("Task not found, cannot edit!");
if (this._tmpTask instanceof DeviceTaskRequestData && sequence.Tasks.DevicesTasks != null)
sequence.Tasks.DevicesTasks = sequence.Tasks.DevicesTasks.map(dTask => Helpers.GenerateMd5(JSON.stringify(dTask)) == taskId ? structuredClone(this._tmpTask) : dTask);
sequence.Tasks.ControllerTasks = sequence.Tasks.ControllerTasks.map(cTask => Helpers.GenerateMd5(JSON.stringify(cTask)) == taskId ? structuredClone(this._tmpTask) : cTask);
this._tmpTask = null;
(_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Debug(`Task edited in sequence: \n${JSON.stringify(this._tmpTask)} \ntasks on a list: \n${JSON.stringify(sequence.Tasks)}`);
}
else
return findLastRightArgumentAndEditTask(sequence.RightArgument);
};
if (this._result == null)
throw new Error("No context!");
findLastRightArgumentAndEditTask(this._result);
return {
GetSupportedTypesOfTasks: () => this.GetSupportedTaskTypesAsync(),
DeviceTask: (task) => this.DeviceTask(task),
DelayTask: (delay) => this.DelayTask(delay),
NotifyTask: (notification) => this.NotifyTask(notification),
LockExecutionTask: (lockTask) => this.LockExecutionTask(lockTask),
RemoveTask: (taskGuid) => this.RemoveTask(taskGuid),
Build: () => this.Build(),
BuildToISequence: () => this._service.MapSequence(JSON.parse(JSON.stringify(this._result))),
ValidateScene: () => this.ValidateScene(),
};
}
RemoveTask(taskId) {
const findLastRightArgumentAndRemoveTask = (sequence, taskId) => {
var _a, _b;
//Last arg
if (sequence.RightArgumentType == ArgumentTypeNum.Null) {
const newTasks = sequence.Tasks.ControllerTasks.filter(t => Helpers.GenerateMd5(JSON.stringify(t)) != taskId);
if (newTasks == null)
sequence.Tasks.ControllerTasks = [];
else
sequence.Tasks.ControllerTasks = newTasks;
if ((_b = (_a = sequence.Tasks) === null || _a === void 0 ? void 0 : _a.DevicesTasks) === null || _b === void 0 ? void 0 : _b.any()) {
const newTasks = sequence.Tasks.DevicesTasks.filter(t => Helpers.GenerateMd5(JSON.stringify(t)) != taskId);
if (newTasks == null)
sequence.Tasks.DevicesTasks = [];
else
sequence.Tasks.DevicesTasks = newTasks;
}
}
else
return findLastRightArgumentAndRemoveTask(sequence.RightArgument, taskId);
};
if (this._result == null)
throw Error("Cannot remove task, sequence not configured!");
findLastRightArgumentAndRemoveTask(this._result, taskId);
}
MapTaskTypeToControlFeature(taskType) {
switch (taskType) {
case DeviceTaskType.Unknown:
throw new BadParametersScenesBuilderException("Unsupported task type!");
case DeviceTaskType.SetBlindPosition:
return DeviceControlFeature.SetBlindPosition;
case DeviceTaskType.SetBlindPositionSimple:
return DeviceControlFeature.SetBlindPosition;
case DeviceTaskType.SetBlindMicroventilation:
return DeviceControlFeature.SetBlindMicroventilation;
case DeviceTaskType.TurnOff:
return DeviceControlFeature.TurnOff;
case DeviceTaskType.TurnOn:
return DeviceControlFeature.TurnOn;
case DeviceTaskType.TurnOnWithTime:
return DeviceControlFeature.TurnOnWithTimeout;
case DeviceTaskType.TogleState:
return DeviceControlFeature.ToggleState;
case DeviceTaskType.SetLightBrightnessDynamicly:
return DeviceControlFeature.SetLightBrightnessDynamicly;
case DeviceTaskType.SetLightBrightness:
return DeviceControlFeature.SetLightBrightness;
case DeviceTaskType.SetLightColor:
return DeviceControlFeature.SetLightColor;
case DeviceTaskType.SetLightTemperature:
return DeviceControlFeature.SetLightTemperature;
case DeviceTaskType.PairDevice:
throw new BadParametersScenesBuilderException("Unsupported task type!");
case DeviceTaskType.UnpairDevice:
throw new BadParametersScenesBuilderException("Unsupported task type!");
case DeviceTaskType.IdentifyDevice:
return DeviceControlFeature.IdentifyDevice;
case DeviceTaskType.GetChannelsState:
return DeviceContr