iobroker.shuttercontrol
Version:
Automatic control for shutters
534 lines (439 loc) • 185 kB
JavaScript
'use strict';
const checkPendingAlarm = require('./shutterAlarm.js').checkPendingAlarm; // shutterAlarm
const setShutterState = require('./setShutter.js').setShutterState; // set Shutter State
let timerSleep = 0;
async function sleep(ms) {
return new Promise(async (resolve) => {
// @ts-ignore
timerSleep = setTimeout(async () => resolve(), ms);
});
}
// @ts-ignore
async function sunProtect(adapter, elevation, azimuth, shutterSettings) {
const driveDelayUpSleep = adapter.config.driveDelayUpAstro != 0 ? adapter.config.driveDelayUpAstro * 1000 : 20;
const vRound = adapter.config.shutterStateRound;
await sleep(2000);
if (shutterSettings) {
const result = shutterSettings.filter((d) => d.enabled === true || d.enabled === 'true'); // Filter enabled
if (elevation > adapter.config.sunProtEndElevation) {
for (const i in result) {
for (const s in shutterSettings) {
if (shutterSettings[s].shutterName == result[i].shutterName) {
let resultDirectionRangeMinus = 0;
let resultDirectionRangePlus = 0;
let convertShutter = false;
let heightDownSun = shutterSettings[s].heightDownSun;
const nameDevice = shutterSettings[s].shutterName.replace(/[.;, ]/g, '_');
if (parseFloat(shutterSettings[s].heightDown) < parseFloat(shutterSettings[s].heightUp)) {
convertShutter = false;
} else if (parseFloat(shutterSettings[s].heightDown) > parseFloat(shutterSettings[s].heightUp)) {
convertShutter = true;
}
const pendingAlarm = await checkPendingAlarm(adapter, shutterSettings[s]);
const _autoSunState = await adapter.getStateAsync(`shutters.autoSun.${nameDevice}`).catch((e) => adapter.log.warn(e));
if (_autoSunState?.val === true) {
let currentValue = '';
let _triggerState;
let mustValue = '';
let mustValueTilted = '';
switch (shutterSettings[s].type) {
// +++++++++++++++++ sunprotect with in/outside temperature and Lightsensor +++++++++++++++
case 'in- & outside temperature': // in- & outside temperature
_triggerState = shutterSettings[s].triggerID != '' ? await adapter.getForeignStateAsync(shutterSettings[s].triggerID).catch((e) => adapter.log.warn(e)) : null;
mustValue = (`${shutterSettings[s].triggerState}`);
mustValueTilted = shutterSettings[s].triggerStateTilted == 'none' ? (`${shutterSettings[s].triggerState}`) : (`${shutterSettings[s].triggerStateTilted}`);
currentValue = _triggerState?.val !== null && _triggerState?.val !== undefined ? (`${_triggerState.val}`) : '';
if ((currentValue === mustValue ||
currentValue === mustValueTilted) &&
shutterSettings[s].tempSensor != '' ||
(currentValue != mustValue &&
currentValue != mustValueTilted &&
shutterSettings[s].autoDrive != 'off' &&
shutterSettings[s].tempSensor != '') ||
(shutterSettings[s].triggerID == '' &&
shutterSettings[s].tempSensor != '')) {
let insideTemp = 0;
let outsideTemp = 0;
let sunLight = 0;
const _insideTempState = shutterSettings[s].tempSensor != '' ? await adapter.getForeignStateAsync(shutterSettings[s].tempSensor).catch((e) => adapter.log.warn(e)) : null;
insideTemp = _insideTempState?.val ? parseFloat(_insideTempState.val) : 0;
const _outsideTempState = shutterSettings[s].outsideTempSensor != '' ? await adapter.getForeignStateAsync(shutterSettings[s].outsideTempSensor).catch((e) => adapter.log.warn(e)) : null;
outsideTemp = _outsideTempState?.val ? parseFloat(_outsideTempState.val) : 0;
const _sunLight = shutterSettings[s].lightSensor != '' ? await adapter.getForeignStateAsync(shutterSettings[s].lightSensor).catch((e) => adapter.log.warn(e)) : null;
sunLight = _sunLight?.val ? parseFloat(_sunLight.val) : 0;
// heatProtection
if (shutterSettings[s].heatProtection == true &&
shutterSettings[s].tempHeatProtection < outsideTemp &&
shutterSettings[s].currentHeight != shutterSettings[s].heightDown) {
shutterSettings[s].currentAction = shutterSettings[s].currentAction == 'sunProtect' ? '' : shutterSettings[s].currentAction;
heightDownSun = shutterSettings[s].heightDown;
adapter.log.debug(`Heat Protection for ${shutterSettings[s].shutterName} is active`);
adapter.log.debug(`currentAction ${shutterSettings[s].currentAction}`);
} else {
heightDownSun = shutterSettings[s].heightDownSun;
}
if (shutterSettings[s].sunProtectEndtimerid != '' &&
shutterSettings[s].sunProtectEndtimerid != '0' &&
shutterSettings[s].lightSensor != '' &&
shutterSettings[s].valueLight < sunLight) {
adapter.log.debug(`Stopping sunprotect delay for ${shutterSettings[s].shutterName}`);
clearTimeout(shutterSettings[s].sunProtectEndtimerid);
shutterSettings[s].sunProtectEndtimerid = '';
}
if (currentValue === mustValue ||
currentValue === mustValueTilted ||
(currentValue != mustValue &&
currentValue != mustValueTilted &&
shutterSettings[s].autoDrive != 'onlyUp') ||
(shutterSettings[s].triggerID == '')) {
if (insideTemp > shutterSettings[s].tempInside) {
if (shutterSettings[s].tempOutside < outsideTemp &&
(shutterSettings[s].lightSensor != '' &&
shutterSettings[s].valueLight < sunLight ||
shutterSettings[s].lightSensor == '') &&
shutterSettings[s].currentAction != 'sunProtect' &&
shutterSettings[s].currentAction != 'OpenInSunProtect' &&
shutterSettings[s].currentAction != 'Manu_Mode') {
if (pendingAlarm == false) {
const _shutterState = await adapter.getForeignStateAsync(shutterSettings[s].name).catch((e) => adapter.log.warn(e));
if (_shutterState?.val !== null && _shutterState?.val !== undefined) {
adapter.log.debug(`${shutterSettings[s].shutterName}: Check basis for sunprotect. Height:${Math.round(_shutterState.val / vRound) * vRound} > HeightDownSun: ${heightDownSun} AND Height:${Math.round(_shutterState.val / vRound) * vRound} == currentHeight:${shutterSettings[s].currentHeight} AND currentHeight:${shutterSettings[s].currentHeight} == heightUp:${shutterSettings[s].heightUp}`);
if (((Math.round(parseFloat(_shutterState.val) / vRound) * vRound > parseFloat(heightDownSun) &&
convertShutter == false) ||
(Math.round(parseFloat(_shutterState.val) / vRound) * vRound < parseFloat(heightDownSun) &&
convertShutter == true)) &&
Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(shutterSettings[s].currentHeight) &&
(shutterSettings[s].currentHeight == shutterSettings[s].heightUp ||
(shutterSettings[s].heatProtection == true &&
shutterSettings[s].tempHeatProtection < outsideTemp))) {
shutterSettings[s].currentAction = 'sunProtect';
shutterSettings[s].lastAutoAction = 'down_Sunprotect';
shutterSettings[s].currentHeight = heightDownSun;
await setShutterState(adapter, shutterSettings, shutterSettings[s], parseFloat(heightDownSun), nameDevice, 'Sunprotect #410');
adapter.log.debug(`Sunprotect for ${shutterSettings[s].shutterName} is active`);
adapter.log.debug(`Temperature inside: ${insideTemp} > ${shutterSettings[s].tempInside} AND ( Temperatur outside: ${outsideTemp} > ${shutterSettings[s].tempOutside} AND Light: ${sunLight} > ${shutterSettings[s].valueLight} )`);
adapter.log.debug(`last automatic Action for ${shutterSettings[s].shutterName}: ${shutterSettings[s].lastAutoAction}`);
adapter.log.debug(`Sunprotect ${shutterSettings[s].shutterName} old height: ${shutterSettings[s].oldHeight}% new height: ${heightDownSun}%`);
} else if (Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(shutterSettings[s].heightDown) &&
Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(shutterSettings[s].currentHeight) &&
shutterSettings[s].currentHeight != shutterSettings[s].heightUp &&
shutterSettings[s].currentAction != 'down' &&
shutterSettings[s].currentAction != 'middle' &&
shutterSettings[s].currentAction != 'Xmas' &&
shutterSettings[s].firstCompleteUp == true) { //check currentAction!=down here. If shutter is already closed sunProtect must not be set. Otherwise shutter will be opened again when sunProtect ends!
// Shutter closed. Set currentAction = sunProtect when sunProtect starts =>
// If shutter is opened automatically it can be opened in height heightDownSun directly
shutterSettings[s].currentAction = 'OpenInSunProtect';
await adapter.setStateAsync(`shutters.autoState.${nameDevice}`, { val: shutterSettings[s].currentAction, ack: true }).catch((e) => adapter.log.warn(e));
adapter.log.debug(`Set sunprotect mode for ${shutterSettings[s].shutterName}. Currently closed. Set to sunprotect if shutter will be opened automatically`);
} else if (Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(heightDownSun) &&
Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(shutterSettings[s].currentHeight) &&
shutterSettings[s].currentHeight != shutterSettings[s].heightUp &&
shutterSettings[s].currentHeight != shutterSettings[s].heightDown &&
shutterSettings[s].currentAction == '') {
//Shutter is in position = sunProtect. Maybe restart of adapter. sunProtect not set ->
// set sunProtect again
shutterSettings[s].currentAction = 'sunProtect';
await adapter.setStateAsync(`shutters.autoState.${nameDevice}`, { val: shutterSettings[s].currentAction, ack: true }).catch((e) => adapter.log.warn(e));
adapter.log.debug(`${shutterSettings[s].shutterName}: Shutter is in position sunProtect. Reset mode sunProtect to cancel sunProtect automatically. Height:${Math.round(_shutterState.val / vRound) * vRound} HeightDownSun:${heightDownSun}`);
}
}
} else {
adapter.log.info(`SunProtect not moving down now due to active alarm: ${shutterSettings[s].shutterName} value: ${heightDownSun}%`);
shutterSettings[s].alarmTriggerLevel = parseFloat(heightDownSun);
shutterSettings[s].alarmTriggerAction = 'sunProtect';
}
}
}
}
if (currentValue != mustValue &&
currentValue != mustValueTilted &&
shutterSettings[s].driveAfterClose == true) {
if (insideTemp > shutterSettings[s].tempInside) {
if (shutterSettings[s].tempOutside < outsideTemp &&
(shutterSettings[s].lightSensor != '' &&
shutterSettings[s].valueLight < sunLight ||
shutterSettings[s].lightSensor == '') &&
shutterSettings[s].triggerAction != 'sunProtect' &&
shutterSettings[s].triggerAction != 'OpenInSunProtect' &&
shutterSettings[s].triggerAction != 'Manu_Mode') {
if (pendingAlarm == false) {
const _shutterState = await adapter.getForeignStateAsync(shutterSettings[s].name).catch((e) => adapter.log.warn(e));
if (_shutterState?.val !== null && _shutterState?.val !== undefined) {
adapter.log.debug(`${shutterSettings[s].shutterName}: Check basis for sunprotect. Height:${Math.round(_shutterState.val / vRound) * vRound} > HeightDownSun: ${heightDownSun} AND Height:${Math.round(_shutterState.val / vRound) * vRound} == currentHeight:${shutterSettings[s].currentHeight} AND currentHeight:${shutterSettings[s].currentHeight} == heightUp:${shutterSettings[s].heightUp} AND triggerAction:${shutterSettings[s].triggerAction} != down `);
if (((Math.round(parseFloat(_shutterState.val) / vRound) * vRound > parseFloat(heightDownSun) &&
convertShutter == false) ||
(Math.round(parseFloat(_shutterState.val) / vRound) * vRound < parseFloat(heightDownSun) &&
convertShutter == true)) &&
Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(shutterSettings[s].currentHeight) &&
shutterSettings[s].currentHeight == shutterSettings[s].heightUp &&
shutterSettings[s].triggerAction != 'down' &&
shutterSettings[s].currentAction != 'middle' &&
shutterSettings[s].currentAction != 'Xmas') {
shutterSettings[s].triggerHeight = parseFloat(heightDownSun);
shutterSettings[s].triggerAction = 'sunProtect';
adapter.log.info(` Will sunprotect ID: ${shutterSettings[s].shutterName} value: ${heightDownSun}%` + ` after the window has been closed `);
adapter.log.debug(`save new trigger height: ${heightDownSun}%`);
adapter.log.debug(`save new trigger action: ${shutterSettings[s].triggerAction}`);
}
}
} else {
adapter.log.info(`SunProtect not moving down now due to active alarm: ${shutterSettings[s].shutterName} value: ${heightDownSun}%`);
shutterSettings[s].alarmTriggerLevel = parseFloat(heightDownSun);
shutterSettings[s].alarmTriggerAction = 'sunProtect';
}
}
}
}
if (currentValue === mustValue ||
currentValue === mustValueTilted ||
(currentValue != mustValue &&
currentValue != mustValueTilted &&
shutterSettings[s].autoDrive != 'onlyDown') ||
(shutterSettings[s].triggerID == '')) {
const hysteresisOutside = (((100 - shutterSettings[s].hysteresisOutside) / 100) * shutterSettings[s].tempOutside).toFixed(2);
const hysteresisInside = (((100 - shutterSettings[s].hysteresisInside) / 100) * shutterSettings[s].tempInside).toFixed(2);
const hysteresisLight = (((100 - shutterSettings[s].hysteresisLight) / 100) * shutterSettings[s].valueLight).toFixed(2);
if (shutterSettings[s].sunProtectEndtimerid === '' &&
shutterSettings[s].lightSensor != '' &&
parseFloat(hysteresisLight) > sunLight &&
(shutterSettings[s].currentAction == 'sunProtect' ||
(shutterSettings[s].currentAction == 'triggered' &&
shutterSettings[s].lastAutoAction == 'down_Sunprotect')) &&
shutterSettings[s].KeepSunProtect === false) {
adapter.log.debug(`#1 Started sunprotect end delay for ${shutterSettings[s].shutterName} with ${shutterSettings[s].sunProtectEndDely} minutes`);
shutterSettings[s].sunProtectEndtimerid = setTimeout(async function () {
adapter.log.debug(`#1.1 End sunprotect delay for ${shutterSettings[s].shutterName}`);
shutterSettings[s].sunProtectEndtimerid = '0';
}, shutterSettings[s].sunProtectEndDely * 60000, s);
}
if (insideTemp < parseFloat(hysteresisInside) ||
(parseFloat(hysteresisOutside) > outsideTemp ||
shutterSettings[s].lightSensor != '' &&
parseFloat(hysteresisLight) > sunLight &&
shutterSettings[s].sunProtectEndtimerid === '0') ||
(parseFloat(hysteresisOutside) > outsideTemp &&
shutterSettings[s].lightSensor == '')) {
if (pendingAlarm == false) {
const _shutterState = await adapter.getForeignStateAsync(shutterSettings[s].name).catch((e) => adapter.log.warn(e));
if (_shutterState?.val !== null && _shutterState?.val !== undefined) {
if (shutterSettings[s].currentAction == 'sunProtect' &&
shutterSettings[s].KeepSunProtect === false &&
(Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(heightDownSun) ||
Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(shutterSettings[s].currentHeight))) {
shutterSettings[s].sunProtectEndtimerid = '';
shutterSettings[s].currentAction = 'up';
shutterSettings[s].currentHeight = shutterSettings[s].heightUp;
shutterSettings[s].lastAutoAction = 'up_Sunprotect_end';
await setShutterState(adapter, shutterSettings, shutterSettings[s], parseFloat(shutterSettings[s].heightUp), nameDevice, 'Sunprotect #411');
adapter.log.debug(`Sunprotect for ${shutterSettings[s].shutterName} is not active`);
adapter.log.debug(`Temperature inside: ${insideTemp} < ${hysteresisInside} OR ( Temperature outside: ${outsideTemp} < ${hysteresisOutside} OR Light: ${sunLight} < ${hysteresisLight} )`);
adapter.log.debug(`last automatic Action for ${shutterSettings[s].shutterName}: ${shutterSettings[s].lastAutoAction}`);
adapter.log.debug(`Sunprotect ${shutterSettings[s].shutterName} old height: ${shutterSettings[s].oldHeight}% new height: ${heightDownSun}%`)
} else if (shutterSettings[s].currentAction == 'OpenInSunProtect') {
shutterSettings[s].sunProtectEndtimerid = ''
shutterSettings[s].currentAction = 'none';
await adapter.setStateAsync(`shutters.autoState.${nameDevice}`, { val: shutterSettings[s].currentAction, ack: true }).catch((e) => adapter.log.warn(e));
adapter.log.debug(`OpenInSunProtect for ${shutterSettings[s].shutterName} is not longer active`);
}
}
} else if (shutterSettings[s].alarmTriggerAction == 'sunProtect') {
adapter.log.info(`SunProtect not moving up now due to active alarm: ${shutterSettings[s].shutterName} value: ${shutterSettings[s].heightUp}%`);
shutterSettings[s].sunProtectEndtimerid = '';
shutterSettings[s].alarmTriggerLevel = parseFloat(shutterSettings[s].heightUp);
shutterSettings[s].alarmTriggerAction = 'up';
}
}
}
if (currentValue != mustValue &&
currentValue != mustValueTilted &&
shutterSettings[s].driveAfterClose == true) {
const hysteresisOutside = (((100 - shutterSettings[s].hysteresisOutside) / 100) * shutterSettings[s].tempOutside).toFixed(2);
const hysteresisInside = (((100 - shutterSettings[s].hysteresisInside) / 100) * shutterSettings[s].tempInside).toFixed(2);
const hysteresisLight = (((100 - shutterSettings[s].hysteresisLight) / 100) * shutterSettings[s].valueLight).toFixed(2);
if (shutterSettings[s].sunProtectEndtimerid === '' &&
shutterSettings[s].lightSensor != '' &&
parseFloat(hysteresisLight) > sunLight &&
(shutterSettings[s].currentAction == 'sunProtect' ||
(shutterSettings[s].currentAction == 'triggered' &&
shutterSettings[s].lastAutoAction == 'down_Sunprotect')) &&
shutterSettings[s].KeepSunProtect === false) {
adapter.log.debug(`#2 Started sunprotect end delay for ${shutterSettings[s].shutterName} with ${shutterSettings[s].sunProtectEndDely} minutes`);
shutterSettings[s].sunProtectEndtimerid = setTimeout(async function () {
adapter.log.debug(`#2.1 End sunprotect delay for ${shutterSettings[s].shutterName}`);
shutterSettings[s].sunProtectEndtimerid = '0';
}, shutterSettings[s].sunProtectEndDely * 60000, s);
}
if (insideTemp < parseFloat(hysteresisInside) ||
(parseFloat(hysteresisOutside) > outsideTemp ||
shutterSettings[s].lightSensor != '' &&
parseFloat(hysteresisLight) > sunLight &&
shutterSettings[s].sunProtectEndtimerid === '0') ||
(parseFloat(hysteresisOutside) > outsideTemp &&
shutterSettings[s].lightSensor == '')) {
if (pendingAlarm == false) {
const _shutterState = await adapter.getForeignStateAsync(shutterSettings[s].name).catch((e) => adapter.log.warn(e));
if (_shutterState?.val !== null && _shutterState?.val !== undefined) {
if (shutterSettings[s].triggerAction == 'sunProtect' &&
shutterSettings[s].KeepSunProtect === false &&
(parseFloat(shutterSettings[s].triggerHeight) == parseFloat(heightDownSun) ||
Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(shutterSettings[s].currentHeight))) {
shutterSettings[s].triggerHeight = parseFloat(shutterSettings[s].heightUp);
shutterSettings[s].triggerAction = 'up';
adapter.log.info(` Will end sunprotect ID: ${shutterSettings[s].shutterName} value: ${heightDownSun}%` + ` after the window has been closed `);
adapter.log.debug(`Sunprotect for ${shutterSettings[s].shutterName} is not active anymore`);
adapter.log.debug(`Temperature inside: ${insideTemp} < ${hysteresisInside} OR ( Temperature outside: ${outsideTemp} < ${hysteresisOutside} OR Light: ${sunLight} < ${hysteresisLight} )`);
adapter.log.debug(`save new trigger height: ${shutterSettings[s].triggerHeight}%`);
adapter.log.debug(`save new trigger action: ${shutterSettings[s].triggerAction}`);
} else if (shutterSettings[s].triggerAction == 'sunProtect' &&
shutterSettings[s].KeepSunProtect === false &&
(parseFloat(shutterSettings[s].triggerHeight) == parseFloat(shutterSettings[s].heightUp) ||
Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(shutterSettings[s].heightUp))) {
shutterSettings[s].triggerHeight = parseFloat(shutterSettings[s].heightUp);
shutterSettings[s].triggerAction = 'up';
adapter.log.info(`#1 Will end sunprotect ID: ${shutterSettings[s].shutterName} value: ${shutterSettings[s].triggerHeight}% after is the value for up`);
adapter.log.debug(`save new trigger height: ${shutterSettings[s].triggerHeight}%`);
adapter.log.debug(`save new trigger action: ${shutterSettings[s].triggerAction}`);
} else if (shutterSettings[s].currentAction == 'OpenInSunProtect') {
shutterSettings[s].sunProtectEndtimerid = ''
shutterSettings[s].triggerAction = 'none';
adapter.log.debug(`OpenInSunProtect for ${shutterSettings[s].shutterName} is not longer active`);
}
}
} else if (shutterSettings[s].alarmTriggerAction == 'sunProtect') {
adapter.log.info(`SunProtect not moving up now due to active alarm: ${shutterSettings[s].shutterName} value: ${shutterSettings[s].heightUp}%`);
shutterSettings[s].sunProtectEndtimerid = '';
shutterSettings[s].alarmTriggerLevel = parseFloat(shutterSettings[s].heightUp);
shutterSettings[s].alarmTriggerAction = 'up';
}
}
}
}
await sleep(driveDelayUpSleep);
break;
//////////////////////////////////////////////////////////////////////////////////////////////////////
// +++++++++++++++++ sunprotect with in/outside temperature, Lightsensor and direction +++++++++++++++
case 'in- & outside temperature and direction': // in- & outside temperature and direction
resultDirectionRangeMinus = parseInt(shutterSettings[s].direction) - parseInt(shutterSettings[s].directionRange);
resultDirectionRangePlus = parseInt(shutterSettings[s].direction) + parseInt(shutterSettings[s].directionRange);
_triggerState = shutterSettings[s].triggerID != '' ? await adapter.getForeignStateAsync(shutterSettings[s].triggerID).catch((e) => adapter.log.warn(e)) : null;
mustValue = (`${shutterSettings[s].triggerState}`);
mustValueTilted = shutterSettings[s].triggerStateTilted == 'none' ? (`${shutterSettings[s].triggerState}`) : (`${shutterSettings[s].triggerStateTilted}`);
currentValue = _triggerState?.val !== null && _triggerState?.val !== undefined ? (`${_triggerState.val}`) : '';
if ((currentValue === mustValue ||
currentValue === mustValueTilted) &&
shutterSettings[s].tempSensor != '' ||
(currentValue != mustValue &&
currentValue != mustValueTilted &&
shutterSettings[s].autoDrive != 'off' &&
shutterSettings[s].tempSensor != '') ||
(shutterSettings[s].triggerID == '' &&
shutterSettings[s].tempSensor != '')) {
let insideTemp = 0;
let outsideTemp = 0;
let sunLight = 0;
const _insideTempState = shutterSettings[s].tempSensor != '' ? await adapter.getForeignStateAsync(shutterSettings[s].tempSensor).catch((e) => adapter.log.warn(e)) : null;
insideTemp = _insideTempState?.val ? parseFloat(_insideTempState.val) : 0;
const _outsideTempState = shutterSettings[s].outsideTempSensor != '' ? await adapter.getForeignStateAsync(shutterSettings[s].outsideTempSensor).catch((e) => adapter.log.warn(e)) : null;
outsideTemp = _outsideTempState?.val ? parseFloat(_outsideTempState.val) : 0;
// heatProtection
if (shutterSettings[s].heatProtection == true &&
shutterSettings[s].tempHeatProtection < outsideTemp &&
shutterSettings[s].currentHeight != shutterSettings[s].heightDown) {
shutterSettings[s].currentAction = shutterSettings[s].currentAction == 'sunProtect' ? '' : shutterSettings[s].currentAction;
heightDownSun = shutterSettings[s].heightDown;
adapter.log.debug(`Heat Protection for ${shutterSettings[s].shutterName} is active`);
} else {
heightDownSun = shutterSettings[s].heightDownSun;
}
const _sunLight = shutterSettings[s].lightSensor != '' ? await adapter.getForeignStateAsync(shutterSettings[s].lightSensor).catch((e) => adapter.log.warn(e)) : null;
sunLight = _sunLight?.val ? parseFloat(_sunLight.val) : 0;
if (shutterSettings[s].sunProtectEndtimerid != '' &&
shutterSettings[s].sunProtectEndtimerid != '0' &&
shutterSettings[s].lightSensor != '' &&
shutterSettings[s].valueLight < sunLight) {
adapter.log.debug(`Stopping sunprotect delay for ${shutterSettings[s].shutterName}`);
clearTimeout(shutterSettings[s].sunProtectEndtimerid);
shutterSettings[s].sunProtectEndtimerid = '';
}
if (currentValue === mustValue ||
currentValue === mustValueTilted ||
(currentValue != mustValue &&
currentValue != mustValueTilted &&
shutterSettings[s].autoDrive != 'onlyUp') ||
(shutterSettings[s].triggerID == '')) {
if (resultDirectionRangeMinus < azimuth &&
resultDirectionRangePlus > azimuth &&
insideTemp > shutterSettings[s].tempInside) {
if (shutterSettings[s].tempOutside < outsideTemp &&
(shutterSettings[s].lightSensor != '' &&
shutterSettings[s].valueLight < sunLight ||
shutterSettings[s].lightSensor == '') &&
shutterSettings[s].currentAction != 'sunProtect' &&
shutterSettings[s].currentAction != 'OpenInSunProtect' &&
shutterSettings[s].currentAction != 'Manu_Mode') {
if (pendingAlarm == false) {
const _shutterState = await adapter.getForeignStateAsync(shutterSettings[s].name).catch((e) => adapter.log.warn(e));
if (_shutterState?.val !== null && _shutterState?.val !== undefined) {
adapter.log.debug(`${shutterSettings[s].shutterName}: Check basis for sunprotect. Height:${Math.round(_shutterState.val / vRound) * vRound} > HeightDownSun: ${heightDownSun} AND Height:${Math.round(_shutterState.val / vRound) * vRound} == currentHeight:${shutterSettings[s].currentHeight} AND currentHeight:${shutterSettings[s].currentHeight} == heightUp:${shutterSettings[s].heightUp}`);
if (((Math.round(parseFloat(_shutterState.val) / vRound) * vRound > parseFloat(heightDownSun) &&
convertShutter == false) ||
(Math.round(parseFloat(_shutterState.val) / vRound) * vRound < parseFloat(heightDownSun) &&
convertShutter == true)) &&
Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(shutterSettings[s].currentHeight) &&
(shutterSettings[s].currentHeight == shutterSettings[s].heightUp ||
(shutterSettings[s].heatProtection == true &&
shutterSettings[s].tempHeatProtection < outsideTemp))) {
shutterSettings[s].currentAction = 'sunProtect';
shutterSettings[s].currentHeight = heightDownSun;
shutterSettings[s].lastAutoAction = 'down_Sunprotect';
await setShutterState(adapter, shutterSettings, shutterSettings[s], parseFloat(heightDownSun), nameDevice, 'Sunprotect #412');
adapter.log.debug(`Sunprotect for ${shutterSettings[s].shutterName} is active`);
adapter.log.debug(`Temperature inside: ${insideTemp} > ${shutterSettings[s].tempInside} AND ( Temperatur outside: ${outsideTemp} > ${shutterSettings[s].tempOutside} AND Light: ${sunLight} > ${shutterSettings[s].valueLight} )`);
adapter.log.debug(`Sunprotect ${shutterSettings[s].shutterName} old height: ${shutterSettings[s].oldHeight}% new height: ${heightDownSun}%`);
adapter.log.debug(`last automatic Action for ${shutterSettings[s].shutterName}: ${shutterSettings[s].lastAutoAction}`);
adapter.log.debug(`Sunprotect ${shutterSettings[s].shutterName} old height: ${shutterSettings[s].oldHeight}% new height: ${heightDownSun}%`)
} else if (Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(shutterSettings[s].heightDown) &&
Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(shutterSettings[s].currentHeight) &&
shutterSettings[s].currentHeight != shutterSettings[s].heightUp &&
shutterSettings[s].currentAction != 'down' &&
shutterSettings[s].currentAction != 'middle' &&
shutterSettings[s].currentAction != 'Xmas' &&
shutterSettings[s].firstCompleteUp == true) { //check currentAction!=down here. If shutter is already closed sunProtect must not be set. Otherwise shutter will be opened again when sunProtect ends!
// Shutter closed. Set currentAction = sunProtect when sunProtect starts =>
// If shutter is opened automatically it can be opened in height heightDownSun directly
shutterSettings[s].currentAction = 'OpenInSunProtect';
adapter.log.debug(`Set sunprotect mode for ${shutterSettings[s].shutterName}. Currently closed. Set to sunprotect if shutter will be opened automatically`);
} else if (Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(heightDownSun) &&
Math.round(parseFloat(_shutterState.val) / vRound) * vRound == parseFloat(shutterSettings[s].currentHeight) &&
shutterSettings[s].currentHeight != shutterSettings[s].heightUp &&
shutterSettings[s].currentHeight != shutterSettings[s].heightDown &&
shutterSettings[s].currentAction == '') {
// Shutter is in position = sunProtect. Maybe restart of adapter. sunProtect not set ->
// set sunProtect again
shutterSettings[s].currentAction = 'sunProtect';
await adapter.setStateAsync(`shutters.autoState.${nameDevice}`, { val: shutterSettings[s].currentAction, ack: true }).catch((e) => adapter.log.warn(e));
adapter.log.debug(`${shutterSettings[s].shutterName}: Shutter is in position sunProtect. Reset mode sunProtect to cancel sunProtect automatically. Height:${Math.round(_shutterState.val / vRound) * vRound} HeightDownSun:${heightDownSun}`);
}
}
} else {
adapter.log.info(`SunProtect not moving down now due to active alarm: ${shutterSettings[s].shutterName} value: ${heightDownSun}%`);
shutterSettings[s].alarmTriggerLevel = parseFloat(heightDownSun);
shutterSettings[s].alarmTriggerAction = 'sunProtect';
}
}
}
}
if (currentValue != mustValue &&
currentValue != mustValueTilted &&
shutterSettings[s].driveAfterClose == true) {
if (resultDirectionRangeMinus < azimuth &&
resultDirectionRangePlus > azimuth &&
insideTemp > shutterSettings[s].tempInside) {
if (shutterSettings[s].tempOutside < outsideTemp &&
(shutterSettings[s].lightSensor != '' &&
shutterSettings[s].valueLight < sunLight ||
shutterSettings[s].lightSensor == '') &&
shutterSettings[s].triggerAction != 'sunProtect' &&
shutterSettings[s].triggerAction != 'OpenInSunProtect' &&
shutterSettings[s].triggerAction != 'Manu_Mode'