iobroker.shuttercontrol
Version:
Automatic control for shutters
791 lines (694 loc) • 106 kB
JavaScript
/* jshint -W097 */
/* jshint strict: false */
/*jslint node: true */
'use strict';
// @ts-ignore
const utils = require('@iobroker/adapter-core');
// @ts-ignore
const schedule = require('node-schedule');
// @ts-ignore
const SunCalc = require('suncalc');
const sunProtect = require('./lib/sunProtect.js'); // SunProtect
const triggerChange = require('./lib/triggerChange.js'); // triggerChange
const elevationDown = require('./lib/elevationDown.js'); // elevationDown
const shutterGoldenHour = require('./lib/shutterGoldenHour.js'); // shutterGoldenHour
const shutterUpLiving = require('./lib/shutterUpLiving.js'); // shutterUpLiving
const shutterSunriseSunset = require('./lib/shutterSunriseSunset.js'); // shutterSunriseSunset
const shutterDownLiving = require('./lib/shutterDownLiving.js'); // shutterDownLiving
const shutterUpSleep = require('./lib/shutterUpSleep.js'); // shutterUpSleep
const shutterDownLate = require('./lib/shutterDownLate.js'); // shutterDownLate
const shutterDownChildren = require('./lib/shutterDownChildren.js'); // shutterDownChildren
const shutterUpChildren = require('./lib/shutterUpChildren.js'); // shutterUpChildren
const shutterDownSleep = require('./lib/shutterDownSleep.js'); // shutterDownSleep
const buttonAction = require('./lib/buttonAction.js'); // buttonAction
const shutterState = require('./lib/shutterState.js'); // shutterState
const shutterDownComplete = require('./lib/shutterDownComplete.js'); // shutterDownComplete
const shutterBrightnessSensor = require('./lib/shutterBrightnessSensor.js').shutterBrightnessSensor; // shutterBrightnessSensor
const brightnessState = require('./lib/shutterBrightnessSensor.js').brightnessState; // brightnessState
const shutterAlarm = require('./lib/shutterAlarm.js').shutterAlarm; // ShutterAlarm
let adapter;
const adapterName = require('./package.json').name.split('.').pop();
let autoLivingStr, autoSleepStr, autoChildrenStr, delayUp, delayUpChildren, delayDown, delayDownChildren, resTriggerChange, shutterSettings;
let astroTimeLivingUp, astroTimeLivingDown, astroTimeSleepUp, astroTimeSleepDown, astroTimeChildrenUp, astroTimeChildrenDown;
let timer, timerSleep;
let resTrigger = [];
let resSunInsideTemp = [];
let resSunOutsideTemp = [];
let resSunLight = [];
let ObjautoUp = [];
let ObjautoDown = [];
let ObjautoSun = [];
let ObjautoState = [];
let ObjautoLevel = [];
let resShutterState = [];
const lastLigthSensorValue = {};
let waitTime4StateCheck = 10;
let brightnessDown = false;
// +++++++++++++++++++++++++++ Starts the adapter instance ++++++++++++++++++++++++++++++++
function startAdapter(options) {
options = options || {};
Object.assign(options, { name: adapterName });
adapter = new utils.Adapter(options);
// start here!
adapter.on('ready', () => main(adapter));
// +++++++++++++++++++++++++ is called when adapter shuts down +++++++++++++++++++++++++
adapter.on('unload', (callback) => {
try {
adapter.log.info('cleaned everything up...');
clearTimeout(timer);
clearTimeout(timerSleep);
schedule.cancelJob('shutterUpGoldenHourEnd');
schedule.cancelJob('calcTimer');
schedule.cancelJob('shutterDownGoldenHour');
schedule.cancelJob('shutterUpSunrise');
schedule.cancelJob('shutterDownSunset');
schedule.cancelJob('shutterUpLiving');
schedule.cancelJob('shutterDownLiving');
schedule.cancelJob('shutterUpSleep');
schedule.cancelJob('shutterDownLate');
schedule.cancelJob('shutterDownComplete');
schedule.cancelJob('shutterDownSleep');
schedule.cancelJob('calcPosTimer');
schedule.cancelJob('shutterUpChildren');
schedule.cancelJob('shutterDownChildren');
callback();
} catch (err) {
// @ts-ignore
callback(err);
}
});
// ++++++++++++++++++ is called if a subscribed state changes ++++++++++++++++++
adapter.on('stateChange', async (id, state) => {
if (state) {
if (adapter.config.HolidayDP !== '') {
if (id.includes(adapter.config.HolidayDP)) {
adapter.log.debug(`HolidayDP changed to: ${state.val}`);
await adapter.setStateAsync('control.Holiday', { val: state.val, ack: true })
.catch((e) => adapter.log.warn(e));
}
}
if (adapter.config.schoolfreeDP !== '') {
if (id.includes(adapter.config.schoolfreeDP)) {
adapter.log.debug(`schoolfreeDP changed to: ${state.val}`);
await adapter.setStateAsync('control.schoolfree', { val: state.val, ack: true })
.catch((e) => adapter.log.warn(e));
}
}
if (id === `${adapter.namespace}.control.Holiday`) {
HolidayStr = state.val;
shutterDriveCalc();
}
if (id === `${adapter.namespace}.control.schoolfree`) {
SchoolfreeStr = state.val;
shutterDriveCalc();
}
if (id === `${adapter.namespace}.control.autoLiving`) {
autoLivingStr = state.val;
shutterDriveCalc();
}
if (id === `${adapter.namespace}.control.autoSleep`) {
autoSleepStr = state.val;
shutterDriveCalc();
}
if (id === `${adapter.namespace}.control.autoChildren`) {
autoChildrenStr = state.val;
shutterDriveCalc();
}
if (adapter.config.publicHolidays === true) {
if (id === `${adapter.config.publicHolInstance}.heute.boolean`) {
publicHolidayStr = state.val;
shutterDriveCalc();
}
if (id === `${adapter.config.publicHolInstance}.morgen.boolean`) {
publicHolidayTomorowStr = state.val;
shutterDriveCalc();
}
}
if (adapter.config.schoolfree === true) {
if (id === `${adapter.config.schoolfreeInstance}.info.today`) {
schoolfreeStr = state.val;
shutterDriveCalc();
}
if (id === `${adapter.config.schoolfreeInstance}.info.tomorrow`) {
schoolfreeTomorowStr = state.val;
shutterDriveCalc();
}
}
if (id === adapter.config.triggerAutoLiving) {
await adapter.setStateAsync('control.autoLiving', { val: state.val, ack: true })
.catch((e) => adapter.log.warn(e));
adapter.log.debug(`Auto Living is: ${state.val}`);
}
if (id === adapter.config.triggerAutoSleep) {
await adapter.setStateAsync('control.autoSleep', { val: state.val, ack: true })
.catch((e) => adapter.log.warn(e));
adapter.log.debug(`Auto Sleep is: ${state.val}`);
}
if (id === adapter.config.triggerAutoChildren) {
await adapter.setStateAsync('control.autoChildren', { val: state.val, ack: true })
.catch((e) => adapter.log.warn(e));
adapter.log.debug(`Auto Children is: ${state.val}`);
}
if (id === adapter.config.lightsensorUpDown) {
shutterBrightnessSensor(adapter, state.val, shutterSettings, brightnessDown);
adapter.log.debug(`Brightness sensor value: ${state.val}`);
if (state.val === 0 && brightnessDown === false) {
const shutterDownBrightnessTime = adapter.config.lightsensorDownTime;
const downTime = shutterDownBrightnessTime.split(':');
schedule.cancelJob('shutterDownBrightness');
const downBrightness = schedule.scheduleJob('shutterDownBrightness', `${downTime[1]} ${downTime[0]} * * *`, async function () {
adapter.log.debug(`Brightness State Down is: ${brightnessDown}`);
adapter.log.debug(`Brightness sensor value: ${state.val}`);
shutterBrightnessSensor(adapter, state.val, shutterSettings, brightnessDown);
await sleep(10000);
brightnessDown = brightnessState(adapter, state.val, brightnessDown);
adapter.log.debug(`Brightness State Down is: ${brightnessDown}`);
});
// @ts-ignore
} else if (state.val > 0) {
schedule.cancelJob('shutterDownBrightness');
}
await sleep(10000);
brightnessDown = brightnessState(adapter, state.val, brightnessDown);
adapter.log.debug(`Brightness State Down is: ${brightnessDown}`);
}
if (id === adapter.config.alarmWind1) {
adapter.log.debug(`Alarm Wind 1 changed: ${state.val}`);
shutterAlarm(adapter, 'alarmWind1', shutterSettings);
}
if (id === adapter.config.alarmWind2) {
adapter.log.debug(`Alarm Wind 2 changed: ${state.val}`);
shutterAlarm(adapter, 'alarmWind2', shutterSettings);
}
if (id === adapter.config.alarmRain) {
adapter.log.debug(`Alarm Rain changed: ${state.val}`);
shutterAlarm(adapter, 'alarmRain', shutterSettings);
}
if (id === adapter.config.alarmFrost) {
adapter.log.debug(`Alarm Frost changed: ${state.val}`);
shutterAlarm(adapter, 'alarmFrost', shutterSettings);
}
if (id === adapter.config.alarmFire) {
adapter.log.debug(`Alarm Fire changed: ${state.val}`);
shutterAlarm(adapter, 'alarmFire', shutterSettings);
}
resTrigger.forEach(async function (resultTriggerID) {
if (id === resultTriggerID && state.ts === state.lc) {
resTriggerChange = resultTriggerID;
adapter.log.debug(`TriggerID changed: ${resultTriggerID} | Value: ${state.val}`);
triggerChange(resTriggerChange, adapter, shutterSettings);
}
});
resSunInsideTemp.forEach(async function (resSunInsideTempID) {
if (id === resSunInsideTempID && state.ts === state.lc) {
adapter.log.debug(`insidetemperature changed: ${resSunInsideTempID} | Value: ${state.val}°C`);
sunProtect(adapter, elevation, azimuth, shutterSettings);
}
});
resSunOutsideTemp.forEach(async function (resSunOutsideTempID) {
if (id === resSunOutsideTempID && state.ts === state.lc && state.val !== null) {
adapter.log.debug(`outsidetemperature changed: ${resSunOutsideTempID} | Value: ${state.val}°C`);
sunProtect(adapter, elevation, azimuth, shutterSettings);
}
});
resSunLight.forEach(async function (resSunLightID) {
if (id === resSunLightID && state.ts === state.lc) {
// @ts-ignore
if (Math.round((new Date(state.lc) - new Date(lastLigthSensorValue[`${resSunLightID}`].ts)) / 1000 / 60) > 2) {
adapter.log.debug(`Lightsensor changed: ${resSunLightID} | Value: ${state.val}lux`);
sunProtect(adapter, elevation, azimuth, shutterSettings);
lastLigthSensorValue[`${resSunLightID}`].ts = state.lc;
}
}
});
resShutterState.forEach(async function (resShutterID) {
if (id === resShutterID && state.ts === state.lc) {
const result = shutterSettings.filter((d) => d.name === resShutterID);
if (adapter.config.currentShutterState === true && adapter.config.currentShutterStateTime) {
waitTime4StateCheck = (adapter.config.currentShutterStateTime ? adapter.config.currentShutterStateTime * 1000 : 60000);
}
adapter.log.debug('#0 wait for shutter check started');
await sleep(waitTime4StateCheck);
adapter.log.debug('#0 wait for shutter check end');
for (const i in result) {
for (const s in shutterSettings) {
if (shutterSettings[s].shutterName === result[i].shutterName) {
const nameDevice = shutterSettings[s].shutterName.replace(/[.;, ]/g, '_');
const _shutterState = await adapter.getForeignStateAsync(shutterSettings[s].name).catch((e) => adapter.log.warn(e));
if (_shutterState?.val !== null && _shutterState?.val !== undefined &&
shutterSettings[s].oldHeight != Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound) {
adapter.log.debug(`Shutter state changed: ${shutterSettings[s].shutterName} old value = ${shutterSettings[s].oldHeight}% | new value = ${Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound}%`);
}
if (_shutterState?.val !== null && _shutterState?.val !== undefined &&
Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound != shutterSettings[s].currentHeight &&
Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound != shutterSettings[s].oldHeight) {
if (adapter.config.blockManuMode === true) {
switch (Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound) {
case parseFloat(shutterSettings[s].heightUp):
shutterSettings[s].currentAction = 'up';
shutterSettings[s].triggerAction = 'up';
shutterSettings[s].currentHeight = Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound;
shutterSettings[s].triggerHeight = shutterSettings[s].currentHeight;
adapter.log.debug(`${shutterSettings[s].shutterName} Old value = ${shutterSettings[s].oldHeight}% | New value = ${Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound}% | automatic is active`);
break;
case parseFloat(shutterSettings[s].heightDown):
shutterSettings[s].currentAction = 'down';
shutterSettings[s].triggerAction = 'down';
shutterSettings[s].currentHeight = Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound;
shutterSettings[s].triggerHeight = shutterSettings[s].currentHeight;
adapter.log.debug(`${shutterSettings[s].shutterName} Old value = ${shutterSettings[s].oldHeight}% | New value = ${Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound}% | automatic is active`);
break;
case parseFloat(shutterSettings[s].heightDownSun):
shutterSettings[s].currentAction = 'sunProtect';
shutterSettings[s].triggerAction = 'sunProtect';
shutterSettings[s].currentHeight = Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound;
shutterSettings[s].triggerHeight = shutterSettings[s].currentHeight;
adapter.log.debug(`${shutterSettings[s].shutterName} Old value = ${shutterSettings[s].oldHeight}% | New value = ${Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound}% | automatic is active`);
break;
default:
shutterSettings[s].currentAction = 'Manu_Mode';
shutterSettings[s].triggerAction = 'Manu_Mode';
adapter.log.debug(`${shutterSettings[s].shutterName} drived manually to ${Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound}% | Old value = ${shutterSettings[s].oldHeight}% | New value = ${Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound}%`);
adapter.log.debug(`${shutterSettings[s].shutterName} Updated trigger action to ${shutterSettings[s].triggerAction} to prevent moving after window close`);
}
} else {
if (shutterSettings[s].firstCompleteUp != true &&
shutterSettings[s].currentAction != 'none' &&
shutterSettings[s].currentAction != 'OpenInSunProtect') {
shutterSettings[s].currentAction = 'Manu_Mode';
shutterSettings[s].triggerAction = 'Manu_Mode';
adapter.log.debug(`set Manu_Mode #1 ${shutterSettings[s].shutterName}`);
} else {
/* Shutter is closed -> open manually to heightUp (should be 100% or 0%) before it has been opened automatically ->
enable possibility to activate sunprotect height if required -->
if sunprotect is required: shutter is set to sunProtect height
*/
if (shutterSettings[s].firstCompleteUp == true &&
Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound == shutterSettings[s].heightUp &&
shutterSettings[s].currentAction != 'up' &&
shutterSettings[s].currentAction != 'triggered' &&
shutterSettings[s].currentAction != 'triggered_Tilted') {
shutterSettings[s].currentHeight = Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound;
shutterSettings[s].triggerHeight = Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound;
shutterSettings[s].currentAction = 'none'; //reset mode. e.g. mode can be set to sunProtect later if window is closed
shutterSettings[s].triggerAction = 'Manu_Mode';
shutterSettings[s].firstCompleteUp = false;
adapter.log.debug(`Reset firstCompleteUp #1 for ${shutterSettings[s].shutterName}`);
adapter.log.debug(`${shutterSettings[s].shutterName} opened manually to ${shutterSettings[s].heightUp}% | Old value = ${shutterSettings[s].oldHeight}% | New value = ${Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound}% | Possibility to activate sunprotect enabled`);
await adapter.setStateAsync(`shutters.autoState.${nameDevice}`, { val: shutterSettings[s].currentAction, ack: true })
.catch((e) => adapter.log.warn(e));
await adapter.setStateAsync(`shutters.autoLevel.${nameDevice}`, { val: parseFloat(shutterSettings[s].currentHeight), ack: true })
.catch((e) => adapter.log.warn(e));
} else {
shutterSettings[s].currentAction = 'Manu_Mode';
shutterSettings[s].triggerAction = 'Manu_Mode';
adapter.log.debug(`set Manu_Mode #2 ${shutterSettings[s].shutterName}`);
}
}
adapter.log.debug(`${shutterSettings[s].shutterName} drived manually to ${Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound}% | Old value = ${shutterSettings[s].oldHeight}% | New value = ${Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound}%`);
adapter.log.debug(`${shutterSettings[s].shutterName} Updated trigger action to ${shutterSettings[s].triggerAction} to prevent moving after window close`);
}
adapter.log.debug(`#1 shutterName: ${shutterSettings[s].shutterName}`);
adapter.log.debug(`#1 shutterState: ${Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound}%`);
adapter.log.debug(`#1 currentAction: ${shutterSettings[s].currentAction}`);
adapter.log.debug(`#1 triggerAction: ${shutterSettings[s].triggerAction}`);
adapter.log.debug(`#1 currentHeight: ${shutterSettings[s].currentHeight}%`);
adapter.log.debug(`#1 oldHeight: ${shutterSettings[s].oldHeight}%`);
adapter.log.debug(`#1 currentShutterState: ${adapter.config.currentShutterState === true ? 'activated' : 'disabled'}`);
adapter.log.debug(`#1 currentShutterStateTime: ${adapter.config.currentShutterStateTime} seconds`);
await adapter.setStateAsync(`shutters.autoState.${nameDevice}`, { val: shutterSettings[s].currentAction, ack: true })
.catch((e) => adapter.log.warn(e));
await sleep(2000);
shutterSettings = await shutterState(shutterSettings[s].name, adapter, shutterSettings, false);
} else if (_shutterState?.val !== null && _shutterState?.val !== undefined && Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound === shutterSettings[s].currentHeight) {
adapter.log.debug(`${shutterSettings[s].shutterName} Old value = ${shutterSettings[s].oldHeight}% | New value = ${Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound}% | automatic is active`);
await sleep(2000);
shutterSettings = await shutterState(shutterSettings[s].name, adapter, shutterSettings, false);
}
//save old height
await sleep(2000); //already waited waitTime4StateCheck seconds.
saveCurrentStates(false);
/*
await sleep because e.g.
Shelly submits several position by MQTT and not only the last one (0% 1% ... 97% - 98% - 100%).
By this the value is set only after the final height state has been processed
*/
await sleep(5000 + waitTime4StateCheck);
shutterSettings[s].oldHeight = shutterSettings[s].currentHeight;
if (shutterSettings[s].firstCompleteUp === true) {
shutterSettings[s].firstCompleteUp = false;
adapter.log.debug(`Reset firstCompleteUp #2 for ${shutterSettings[s].shutterName}`);
}
saveCurrentStates(false);
}
}
}
}
});
if (id === `${adapter.namespace}.info.Azimut`) {
sunProtect(adapter, elevation, azimuth, shutterSettings);
}
if (id === `${adapter.namespace}.info.Elevation`) {
elevationDown(adapter, elevation, azimuth, shutterSettings);
}
if (id === `${adapter.namespace}.control.closeAll`) {
buttonAction(adapter, 'closeAll', shutterSettings);
}
if (id === `${adapter.namespace}.control.openAll`) {
buttonAction(adapter, 'openAll', shutterSettings);
}
if (id === `${adapter.namespace}.control.closeLiving`) {
buttonAction(adapter, 'closeLiving', shutterSettings);
}
if (id === `${adapter.namespace}.control.openLiving`) {
buttonAction(adapter, 'openLiving', shutterSettings);
}
if (id === `${adapter.namespace}.control.closeSleep`) {
buttonAction(adapter, 'closeSleep', shutterSettings);
}
if (id === `${adapter.namespace}.control.openSleep`) {
buttonAction(adapter, 'openSleep', shutterSettings);
}
if (id === `${adapter.namespace}.control.closeChildren`) {
buttonAction(adapter, 'closeChildren', shutterSettings);
}
if (id === `${adapter.namespace}.control.openChildren`) {
buttonAction(adapter, 'openChildren', shutterSettings);
}
if (id === `${adapter.namespace}.control.sunProtect`) {
buttonAction(adapter, 'sunProtect', shutterSettings);
}
if (id === `${adapter.namespace}.control.sunProtectSleep`) {
buttonAction(adapter, 'sunProtectSleep', shutterSettings);
}
if (id === `${adapter.namespace}.control.sunProtectChildren`) {
buttonAction(adapter, 'sunProtectChildren', shutterSettings);
}
if (id === `${adapter.namespace}.control.sunProtectLiving`) {
buttonAction(adapter, 'sunProtectLiving', shutterSettings);
}
if (id === `${adapter.namespace}.control.autoAll`) {
buttonAction(adapter, 'autoAll', shutterSettings);
}
}
});
adapter.on('message', (obj) => {
if (obj?.command === 'tab' && obj.callback) {
const shutterSettings = adapter.config.events;
for (const s in shutterSettings) {
const nameDevice = shutterSettings[s].shutterName.replace(/[.;, ]/g, '_');
shutterSettings[s].autoDown = `shutters.autoDown.${nameDevice}`;
shutterSettings[s].autoUp = `shutters.autoUp.${nameDevice}`;
shutterSettings[s].autoSun = `shutters.autoSun.${nameDevice}`;
shutterSettings[s].autoState = `shutters.autoState.${nameDevice}`;
}
try {
adapter.sendTo(obj.from, obj.command, { data: { events: shutterSettings } }, obj.callback);
} catch (e) {
adapter.log.error('Tab-Menu is not loaded');
}
}
});
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* ************************ Check all shutter valuesand set default values if values are not available ********************************* */
async function shutterConfigCheck() {
return new Promise(async (resolve) => {
let num = 0;
if (shutterSettings) {
adapter.log.debug('shutter Config Check started');
try {
for (const s in shutterSettings) {
shutterSettings[s].triggerState = shutterSettings[s].triggerState ? shutterSettings[s].triggerState : 'none';
shutterSettings[s].triggerStateTilted = shutterSettings[s].triggerStateTilted ? shutterSettings[s].triggerStateTilted : 'none';
shutterSettings[s].typeUp = shutterSettings[s].typeUp ? shutterSettings[s].typeUp : 'sunrise';
shutterSettings[s].typeDown = shutterSettings[s].typeDown ? shutterSettings[s].typeDown : 'sunset';
shutterSettings[s].heightUp = shutterSettings[s].heightUp ? shutterSettings[s].heightUp : '100';
shutterSettings[s].heightDown = shutterSettings[s].heightDown ? shutterSettings[s].heightDown : '0';
shutterSettings[s].triggerDrive = shutterSettings[s].triggerDrive ? shutterSettings[s].triggerDrive : '100';
shutterSettings[s].triggerDriveTildet = shutterSettings[s].triggerDriveTildet ? shutterSettings[s].triggerDriveTildet : shutterSettings[s].triggerDrive;
shutterSettings[s].triggerChange = shutterSettings[s].triggerChange ? shutterSettings[s].triggerChange : 'off';
shutterSettings[s].elevation = shutterSettings[s].elevation ? shutterSettings[s].elevation : '8';
shutterSettings[s].type = shutterSettings[s].type ? shutterSettings[s].type : 'in- & outside temperature and direction';
shutterSettings[s].heightDownSun = shutterSettings[s].heightDownSun ? shutterSettings[s].heightDownSun : '30';
shutterSettings[s].direction = shutterSettings[s].direction ? shutterSettings[s].direction : '120';
shutterSettings[s].directionRange = shutterSettings[s].directionRange ? shutterSettings[s].directionRange : '50';
shutterSettings[s].tempInside = shutterSettings[s].tempInside ? shutterSettings[s].tempInside : '23';
shutterSettings[s].tempOutside = shutterSettings[s].tempOutside ? shutterSettings[s].tempOutside : '23';
shutterSettings[s].valueLight = shutterSettings[s].valueLight ? shutterSettings[s].valueLight : '15';
shutterSettings[s].autoDrive = shutterSettings[s].autoDrive ? shutterSettings[s].autoDrive : 'off';
shutterSettings[s].hysteresisOutside = shutterSettings[s].hysteresisOutside ? shutterSettings[s].hysteresisOutside : '5';
shutterSettings[s].hysteresisInside = shutterSettings[s].hysteresisInside ? shutterSettings[s].hysteresisInside : '5';
shutterSettings[s].hysteresisLight = shutterSettings[s].hysteresisLight ? shutterSettings[s].hysteresisLight : '5';
shutterSettings[s].XmasLevel = shutterSettings[s].XmasLevel ? shutterSettings[s].XmasLevel : '0';
shutterSettings[s].betweenPositionLevel = shutterSettings[s].betweenPositionLevel ? shutterSettings[s].betweenPositionLevel : '50';
shutterSettings[s].trigDelyUp = shutterSettings[s].trigDelyUp ? shutterSettings[s].trigDelyUp : '0';
shutterSettings[s].trigDelyDown = shutterSettings[s].trigDelyDown ? shutterSettings[s].trigDelyDown : '0';
shutterSettings[s].sunProtectEndDely = shutterSettings[s].sunProtectEndDely ? shutterSettings[s].sunProtectEndDely : '0';
shutterSettings[s].LateDown = shutterSettings[s].LateDown != null ? shutterSettings[s].LateDown : false;
shutterSettings[s].inSummerNotDown = shutterSettings[s].inSummerNotDown != null ? shutterSettings[s].inSummerNotDown : false;
shutterSettings[s].KeepSunProtect = shutterSettings[s].KeepSunProtect != null ? shutterSettings[s].KeepSunProtect : false;
shutterSettings[s].driveAfterClose = shutterSettings[s].driveAfterClose != null ? shutterSettings[s].driveAfterClose : false;
shutterSettings[s].useXmasLevel = shutterSettings[s].useXmasLevel != null ? shutterSettings[s].useXmasLevel : false;
shutterSettings[s].betweenPosition = shutterSettings[s].betweenPosition != null ? shutterSettings[s].betweenPosition : false;
shutterSettings[s].enableAlarmWind1 = shutterSettings[s].enableAlarmWind1 != null ? shutterSettings[s].enableAlarmWind1 : false;
shutterSettings[s].enableAlarmWind2 = shutterSettings[s].enableAlarmWind2 != null ? shutterSettings[s].enableAlarmWind2 : false;
shutterSettings[s].enableAlarmRain = shutterSettings[s].enableAlarmRain != null ? shutterSettings[s].enableAlarmRain : false;
shutterSettings[s].enableAlarmFrost = shutterSettings[s].enableAlarmFrost != null ? shutterSettings[s].enableAlarmFrost : false;
shutterSettings[s].enableAlarmFire = shutterSettings[s].enableAlarmFire != null ? shutterSettings[s].enableAlarmFire : false;
if (num === parseFloat(s)) {
adapter.log.debug('shutter Config Check successfully completed');
// @ts-ignore
resolve();
} else {
num++;
}
}
} catch (e) {
adapter.log.warn(`It is not possible to check the shutter configuration: ${e}`);
// @ts-ignore
resolve();
}
}
});
}
// +++++++++++++++++ save states on start and shutter change ++++++++++++++++++++++++++++
async function saveCurrentStates(onStart) {
if (onStart) {
await shutterConfigCheck();
}
let currentStates = {};
let shutterName = [];
let num = 0;
const _currentStates = await adapter.getStateAsync('shutters.currentStates').catch((e) => adapter.log.warn(e));
if (_currentStates && _currentStates.val && _currentStates.val !== null) {
try {
currentStates = JSON.parse(_currentStates.val);
} catch (err) {
adapter.log.debug('settings cannot be read from the state');
currentStates = {};
}
}
for (const s in shutterSettings) {
const nameDevice = shutterSettings[s].shutterName.replace(/[.;, ]/g, '_');
shutterName.push(shutterSettings[s].shutterName);
num++;
if (currentStates && currentStates[`${nameDevice}`] && !onStart) {
currentStates[`${nameDevice}`].currentAction = shutterSettings[s].currentAction;
currentStates[`${nameDevice}`].currentHeight = shutterSettings[s].currentHeight;
currentStates[`${nameDevice}`].triggerAction = shutterSettings[s].triggerAction;
currentStates[`${nameDevice}`].triggerHeight = shutterSettings[s].triggerHeight;
currentStates[`${nameDevice}`].oldHeight = shutterSettings[s].oldHeight;
currentStates[`${nameDevice}`].firstCompleteUp = shutterSettings[s].firstCompleteUp;
currentStates[`${nameDevice}`].alarmTriggerAction = shutterSettings[s].alarmTriggerAction;
currentStates[`${nameDevice}`].alarmTriggerLevel = shutterSettings[s].alarmTriggerLevel;
currentStates[`${nameDevice}`].lastAutoAction = shutterSettings[s].lastAutoAction;
} else if (currentStates && currentStates[`${nameDevice}`] && onStart) {
adapter.log.debug(`${nameDevice}: save settings`);
shutterSettings[s].currentAction = currentStates[`${nameDevice}`].currentAction;
shutterSettings[s].currentHeight = currentStates[`${nameDevice}`].currentHeight;
shutterSettings[s].triggerAction = currentStates[`${nameDevice}`].triggerAction;
shutterSettings[s].triggerHeight = currentStates[`${nameDevice}`].triggerHeight;
shutterSettings[s].oldHeight = currentStates[`${nameDevice}`].oldHeight;
shutterSettings[s].firstCompleteUp = currentStates[`${nameDevice}`].firstCompleteUp;
shutterSettings[s].alarmTriggerAction = currentStates[`${nameDevice}`].alarmTriggerAction;
shutterSettings[s].alarmTriggerLevel = currentStates[`${nameDevice}`].alarmTriggerLevel;
shutterSettings[s].lastAutoAction = currentStates[`${nameDevice}`].lastAutoAction;
} else if (currentStates && !currentStates[`${nameDevice}`] && onStart) {
adapter.log.debug(`${nameDevice}: settings added`);
currentStates[`${nameDevice}`] = null;
const states = ({
shutterName: shutterSettings[s].shutterName,
currentAction: shutterSettings[s].currentAction,
currentHeight: shutterSettings[s].currentHeight,
triggerAction: shutterSettings[s].triggerAction,
triggerHeight: shutterSettings[s].triggerHeight,
oldHeight: shutterSettings[s].oldHeight,
firstCompleteUp: shutterSettings[s].firstCompleteUp,
alarmTriggerLevel: shutterSettings[s].alarmTriggerLevel,
alarmTriggerAction: shutterSettings[s].alarmTriggerAction,
lastAutoAction: shutterSettings[s].lastAutoAction
});
currentStates[`${nameDevice}`] = states;
}
if (num === shutterSettings.length && onStart) {
for (const i in currentStates) {
if (shutterName.indexOf(currentStates[i].shutterName) === -1) {
const name = currentStates[i].shutterName.replace(/[.;, ]/g, '_')
adapter.log.debug(`${name}: settings deleted`);
delete currentStates[`${name}`];
}
await sleep(2000);
await adapter.setStateAsync('shutters.currentStates', { val: JSON.stringify(currentStates), ack: true })
.catch((e) => adapter.log.warn(e));
}
} else if (num === shutterSettings.length && !onStart) {
await adapter.setStateAsync('shutters.currentStates', { val: JSON.stringify(currentStates), ack: true })
.catch((e) => adapter.log.warn(e));
}
await sleep(100);
}
}
// +++++++++++++++++ Check States of Trigger after start ++++++++++++++++++++++++++++
async function checkStates() {
const _holidayStates = await adapter.getStateAsync('control.Holiday').catch((e) => adapter.log.warn(e));
if ((_holidayStates && _holidayStates === null) || (_holidayStates && _holidayStates.val === null)) {
await adapter.setStateAsync('control.Holiday', { val: false, ack: true })
.catch((e) => adapter.log.warn(e));
}
const _schoolfreeStates = await adapter.getStateAsync('control.schoolfree').catch((e) => adapter.log.warn(e));
if ((_schoolfreeStates && _schoolfreeStates === null) || (_schoolfreeStates && _schoolfreeStates.val === null)) {
await adapter.setStateAsync('control.schoolfree', { val: false, ack: true })
.catch((e) => adapter.log.warn(e));
}
const _autoLivingStates = await adapter.getStateAsync('control.autoLiving').catch((e) => adapter.log.warn(e));
if ((_autoLivingStates && _autoLivingStates === null) || (_autoLivingStates && _autoLivingStates.val === null)) {
await adapter.setStateAsync('control.autoLiving', { val: false, ack: true })
.catch((e) => adapter.log.warn(e));
}
const _autoSleepStates = await adapter.getStateAsync('control.autoSleep').catch((e) => adapter.log.warn(e));
if ((_autoSleepStates && _autoSleepStates === null) || (_autoSleepStates && _autoSleepStates.val === null)) {
await adapter.setStateAsync('control.autoSleep', { val: false, ack: true })
.catch((e) => adapter.log.warn(e));
}
const _autoChildrenStates = await adapter.getStateAsync('control.autoChildren').catch((e) => adapter.log.warn(e));
if ((_autoChildrenStates && _autoChildrenStates === null) || (_autoChildrenStates && _autoChildrenStates.val === null)) {
await adapter.setStateAsync('control.autoChildren', { val: false, ack: true })
.catch((e) => adapter.log.warn(e));
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// +++++++++++++++++++ check all current States an changes +++++++++++++++++++++++++
async function checkActualStates() {
const _holidayStates = await adapter.getStateAsync('control.Holiday').catch((e) => adapter.log.warn(e));
if (_holidayStates?.val !== null && _holidayStates?.val !== undefined) {
HolidayStr = _holidayStates.val;
}
const _schoolfreeStates = await adapter.getStateAsync('control.schoolfree').catch((e) => adapter.log.warn(e));
if (_schoolfreeStates?.val !== null && _schoolfreeStates?.val !== undefined) {
SchoolfreeStr = _schoolfreeStates.val;
}
const _autoLivingStates = await adapter.getStateAsync('control.autoLiving').catch((e) => adapter.log.warn(e));
if (_autoLivingStates?.val !== null && _autoLivingStates?.val !== undefined) {
autoLivingStr = _autoLivingStates.val;
}
const _autoSleepStates = await adapter.getStateAsync('control.autoSleep').catch((e) => adapter.log.warn(e));
if (_autoSleepStates?.val !== null && _autoSleepStates?.val !== undefined) {
autoSleepStr = _autoSleepStates.val;
}
const _autoChildrenStates = await adapter.getStateAsync('control.autoChildren').catch((e) => adapter.log.warn(e));
if (_autoChildrenStates?.val !== null && _autoChildrenStates?.val !== undefined) {
autoChildrenStr = _autoChildrenStates.val;
}
if (adapter.config.publicHolidays === true &&
(adapter.config.publicHolInstance != 'none' ||
adapter.config.publicHolInstance != '')) {
const _publicHolidayStr = await adapter.getForeignStateAsync(`${adapter.config.publicHolInstance}.heute.boolean`).catch((e) => adapter.log.warn(e));
if (_publicHolidayStr?.val !== null && _publicHolidayStr?.val !== undefined) {
publicHolidayStr = _publicHolidayStr.val;
}
const _publicHolidayTomorowStr = await adapter.getForeignStateAsync(`${adapter.config.publicHolInstance}.morgen.boolean`).catch((e) => adapter.log.warn(e));
if (_publicHolidayTomorowStr?.val !== null && _publicHolidayTomorowStr?.val !== undefined) {
publicHolidayTomorowStr = _publicHolidayTomorowStr.val;
}
}
if (adapter.config.schoolfree === true &&
(adapter.config.schoolfreeInstance != 'none' ||
adapter.config.schoolfreeInstance != '')) {
const _schoolfreeStr = await adapter.getForeignStateAsync(`${adapter.config.schoolfreeInstance}.info.today`).catch((e) => adapter.log.warn(e));
if (_schoolfreeStr?.val !== null && _schoolfreeStr?.val !== undefined) {
schoolfreeStr = _schoolfreeStr.val;
}
const _schoolfreeTomorowStr = await adapter.getForeignStateAsync(`${adapter.config.schoolfreeInstance}.info.tomorrow`).catch((e) => adapter.log.warn(e));
if (_schoolfreeTomorowStr?.val !== null && _schoolfreeTomorowStr?.val !== undefined) {
schoolfreeTomorowStr = _schoolfreeTomorowStr.val;
}
}
if (adapter.config.HolidayDP !== '') {
adapter.log.debug('checking HolidayDP');
const _HolidayDP = await adapter.getForeignStateAsync(adapter.config.HolidayDP).catch((e) => adapter.log.warn(e));
if (_HolidayDP?.val !== null && _HolidayDP?.val !== undefined) {
adapter.log.debug(`got HolidayDP: ${_HolidayDP.val}`);
await adapter.setStateAsync('control.Holiday', { val: _HolidayDP.val, ack: true })
.catch((e) => adapter.log.warn(e));
}
}
if (adapter.config.schoolfreeDP !== '') {
adapter.log.debug('checking schoolfreeDP');
const _schoolfreeDP = await adapter.getForeignStateAsync(adapter.config.schoolfreeDP).catch((e) => adapter.log.warn(e));
if (_schoolfreeDP?.val !== null && _schoolfreeDP?.val !== undefined) {
adapter.log.debug(`got schoolfreeDP: ${_schoolfreeDP.val}`);
await adapter.setStateAsync('control.schoolfree', { val: _schoolfreeDP.val, ack: true })
.catch((e) => adapter.log.warn(e));
}
}
const _ObjautoUp = await adapter.getForeignObjectsAsync(`${adapter.namespace}.shutters.autoUp.*`, 'state').catch((e) => adapter.log.warn(e));
if (_ObjautoUp) {
ObjautoUp = _ObjautoUp;
}
const _ObjautoDown = await adapter.getForeignObjectsAsync(`${adapter.namespace}.shutters.autoDown.*`, 'state').catch((e) => adapter.log.warn(e));
if (_ObjautoDown) {
ObjautoDown = _ObjautoDown;
}
const _ObjautoSun = await adapter.getForeignObjectsAsync(`${adapter.namespace}.shutters.autoSun.*`, 'state').catch((e) => adapter.log.warn(e));
if (_ObjautoSun) {
ObjautoSun = _ObjautoSun;
}
const _ObjautoState = await adapter.getForeignObjectsAsync(`${adapter.namespace}.shutters.autoState.*`, 'state').catch((e) => adapter.log.warn(e));
if (_ObjautoState) {
ObjautoState = _ObjautoState;
}
const _ObjautoLevel = await adapter.getForeignObjectsAsync(`${adapter.namespace}.shutters.autoLevel.*`, 'state').catch((e) => adapter.log.warn(e));
if (_ObjautoLevel) {
ObjautoLevel = _ObjautoLevel;
}
await sleep(1000);
shutterDriveCalc();
createShutter();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ++++++++++++++++++ reset current Action in the night at 02:30 +++++++++++++++++++++++
const calc = schedule.scheduleJob('calcTimer', '30 2 * * *', async function () {
shutterDriveCalc();
const resultStates = shutterSettings;
if (resultStates) {
for (const i in resultStates) {
const nameDevice = resultStates[i].shutterName.replace(/[.;, ]/g, '_');
const _shutterState = await adapter.getForeignStateAsync(resultStates[i].name).catch((e) => adapter.log.warn(e));
if (_shutterState?.val !== null && _shutterState?.val !== undefined) {
// Reset Actions every night
resultStates[i].currentAction = 'none';
resultStates[i].triggerAction = 'none';
resultStates[i].firstCompleteUp = true;
resultStates[i].lastAutoAction = 'none';
resultStates[i].alarmTriggerAction = 'none';
await adapter.setStateAsync(`shutters.autoState.${nameDevice}`, { val: resultStates[i].currentAction, ack: true })
.catch((e) => adapter.log.warn(e));
adapter.log.debug(`${resultStates[i].shutterName} set currentHeight to ${Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound}%`);
if (_shutterState?.val !== null && _shutterState?.val !== undefined) {
resultStates[i].currentHeight = Math.round(_shutterState.val / adapter.config.shutterStateRound) * adapter.config.shutterStateRound;
resultStates[i].oldHeight = resultStates[i].currentHeight;
await adapter.setStateAsync(`shutters.autoLevel.${nameDevice}`, { val: parseFloat(resultStates[i].currentHeight), ack: true })
.catch((e) => adapter.log.warn(e));
if (parseFloat(resultStates[i].heightDown) < parseFloat(resultStates[i].heightUp)) {
adapter.log.d