iobroker.ems-esp
Version:
EMS-ESP and KM200 Interface
1,042 lines (948 loc) • 37.4 kB
JavaScript
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable no-empty */
/*
* ems-esp adapter main
*
*/
const utils = require('@iobroker/adapter-core');
const adapterName = require('./package.json').name.split('.').pop();
const { default: axios } = require('axios');
const K = require('./lib/km200.js');
const E = require('./lib/ems.js');
const O = require('./lib/custom.js');
const S = require('./lib/syslog.js');
const F = require('./lib/functions.js');
const datafields = [];
const adapterIntervals = {};
let adapter,
unloaded = false;
let db = 'sql.0';
// -------------------------------------------------------------------------------------------------------------------------------------------------------------------
function startAdapter(options) {
options = options || {};
Object.assign(options, {
name: adapterName,
unload: function (callback) {
K.unload(true);
E.unload(true);
O.unload(true);
unloaded = true;
try {
Object.keys(adapterIntervals).forEach(interval =>
adapter.log.debug(`Interval cleared: ${adapterIntervals[interval]}`),
);
Object.keys(adapterIntervals).forEach(interval => clearInterval(adapterIntervals[interval]));
callback();
} catch {
callback();
}
},
ready: function () {
main();
},
stateChange: (id, state) => {
if (state && !state.ack) {
try {
adapter.getObject(id, function (err, obj) {
// check if state was writable
if (obj != undefined) {
if (obj.common.write) {
if (obj.native.ems_km200 != null) {
K.state_change(id, state, obj);
}
if (obj.native.ems_api == 'raw') {
O.state_change(id, state, obj);
}
if (obj.native.ems_api != null && obj.native.ems_api != 'raw') {
E.state_change(id, state, obj);
}
if (
id == `${adapter.namespace}.controls.active` &&
(state.val == false || state.val == 0)
) {
control_reset();
}
} else {
adapter.log.warn(`state is not writable: ${id}`);
}
}
});
} catch {}
}
},
});
adapter = new utils.Adapter(options);
return adapter;
}
// If started as allInOne/compact mode => return function to create instance
if (module && module.parent) {
module.exports = startAdapter;
} else {
// or start the instance directly
startAdapter();
}
//--------- main ---------------------------------------------------------------------------------------------------------
async function main() {
// test for old db config
try {
if (
adapter.config.db.trim() != '' &&
adapter.config.db_instance.trim() != '' &&
adapter.config.db.indexOf('.') < 1
) {
const db = `${adapter.config.db.trim()}.${adapter.config.db_instance.trim()}`;
const obj = await adapter.getForeignObjectAsync(`system.adapter.${adapter.namespace}`);
obj.native.db = db;
await adapter.setForeignObjectAsync(`system.adapter.${adapter.namespace}`, obj);
adapter.log.info('old database parameters are updated to new version .... instance will restart');
}
} catch {}
if (adapter.config.states_reorg) {
await delete_states_emsesp();
}
await adapter.setObjectNotExistsAsync('info.connection', {
type: 'state',
common: {
type: 'boolean',
name: 'connected to gateways',
role: 'indicator.connected',
read: true,
write: false,
def: false,
},
native: {},
});
await adapter.setStateAsync('info.connection', false, true);
await adapter.setObjectNotExistsAsync('info.connection_km200', {
type: 'state',
common: {
type: 'boolean',
name: 'connected to km200 gateway',
role: 'indicator.connected',
read: true,
write: false,
def: false,
},
native: {},
});
await adapter.setStateAsync('info.connection_km200', null, true);
await adapter.setObjectNotExistsAsync('info.connection_ems', {
type: 'state',
common: {
type: 'boolean',
name: 'connected to ems-esp gateway',
role: 'indicator.connected',
read: true,
write: false,
def: false,
},
native: {},
});
await adapter.setStateAsync('info.connection_ems', null, true);
db = adapter.config.database_instance;
// Read own custom states
if (adapter.config.db.trim() == '') {
db = '';
if (adapter.config.statistics) {
adapter.log.info('no database instance selected for statistics - statistics partly disabled');
}
} else {
db = adapter.config.db;
// Test for InfluxDB V2 - Set warning
if (adapter.config.db.substring(0, 8) == 'influxdb') {
const obj = await adapter.getForeignObjectAsync(`system.adapter.${db}`);
//adapter.log.info(JSON.stringify(obj));
let dbversion = '';
try {
dbversion = obj.native.dbversion;
} catch {}
let retention = 0;
try {
retention = obj.native.retention;
} catch {}
let retdays;
if (retention == 0) {
retdays = 999999;
}
if (retention == -1) {
retdays = obj.native.customRetentionDuration;
} else {
retdays = retention / (24 * 60 * 60);
}
let adapterversion = '';
try {
adapterversion = obj.common.version;
} catch {}
adapter.log.info(
`InfluxDB ${dbversion} - Retention: ${retdays} days --- Adapterversion: ${adapterversion}`,
);
if (dbversion == '2.x' && adapterversion < '4.0.2' && adapter.config.recordings) {
adapter.log.warn(
'************************************************************************************************',
);
adapter.log.warn('KM200 recordings with InfluxDB require adapter version >= 4.0.2');
adapter.log.warn('Database entries for recordings will be disabled');
adapter.log.warn(
'************************************************************************************************',
);
}
}
}
if (!unloaded) {
adapterIntervals.status = adapter.setInterval(function () {
info();
}, 10000);
} // 10 sec
if (!unloaded && adapter.config.statistics && (adapter.config.km200_active || adapter.config.emsesp_active)) {
await init_statistics();
}
if (adapter.config.emsesp_active && !unloaded) {
await E.init(adapter, adapterIntervals);
}
if (adapter.config.km200_active && !unloaded) {
await K.init(adapter, utils, adapterIntervals);
}
if (adapter.config.emsesp_active && adapter.config.ems_custom && !unloaded) {
await O.init(adapter, adapterIntervals);
}
if (adapter.config.syslog && !unloaded) {
await S.init(adapter, utils);
}
if (!unloaded) {
adapter.subscribeStates('*');
}
if (!unloaded && adapter.config.statistics && (adapter.config.km200_active || adapter.config.emsesp_active)) {
if (db != '') {
await init_statistics2();
//read_statistics();
adapterIntervals.stat = adapter.setInterval(function () {
read_statistics();
}, 300000); // 300 sec
}
}
if (adapter.config.eff_active && !unloaded) {
adapterIntervals.eff = adapter.setInterval(function () {
read_efficiency();
}, 60000);
} // 60 sec
if (adapter.config.heatdemand == 1 || adapter.config.heatdemand == true) {
await init_controls();
await heatdemand();
adapter.log.info('heat demand processing: polling every minute');
adapterIntervals.heatdemand = adapter.setInterval(function () {
heatdemand();
}, 60000); // 60 sec
}
}
//--------- functions ---------------------------------------------------------------------------------------------------------
async function info() {
try {
const ems = (await adapter.getStateAsync('info.connection_ems')).val;
const km200 = (await adapter.getStateAsync('info.connection_km200')).val;
if (ems == null && km200 == true) {
adapter.setState('info.connection', true, true);
}
if (ems == true && km200 == null) {
adapter.setState('info.connection', true, true);
}
if (ems == true && km200 == true) {
adapter.setState('info.connection', true, true);
}
if (ems == false || km200 == false) {
adapter.setState('info.connection', false, true);
}
} catch {}
}
async function enable_state(stateid, retention, interval) {
const id = `${adapter.namespace}.${stateid}`;
try {
const obj = await adapter.getObjectAsync(id);
if (obj.common.custom == undefined) {
adapter.sendTo(
db,
'enableHistory',
{
id: id,
options: {
changesOnly: true,
debounce: 0,
retention: retention,
changesRelogInterval: interval,
maxLength: 3,
changesMinDelta: 0,
aliasId: '',
},
},
function (result) {
if (result.error) {
adapter.log.error(`enable history error ${stateid}`);
}
},
);
await adapter.delay(500);
const state = await adapter.getState(stateid);
if (state == null || state.val === undefined) {
await await adapter.setStateAsync(stateid, { ack: false, val: 0 });
} else {
await await adapter.setStateAsync(stateid, { ack: true, val: state.val });
}
}
} catch (e) {
adapter.log.info(`statistics state not found ${stateid} - it is recommended to disable statistics`);
}
}
async function init_controls() {
try {
await adapter.setObjectNotExistsAsync('controls.active', {
type: 'state',
common: {
type: 'boolean',
name: 'heat demand control active',
role: 'value',
read: true,
write: true,
},
native: {},
});
try {
const active = (await adapter.getStateAsync('controls.active')).val;
} catch (e) {
await adapter.setStateAsync('controls.active', { ack: true, val: true });
}
let value = 0;
for (let i = 0; i < adapter.config.heatingcircuits.length; i++) {
const state = `${adapter.config.heatingcircuits[i].hc}.`;
value = parseFloat(adapter.config.heatingcircuits[i].weighton);
control_state(`${state}weighton`, 'number', 'hc weight for switching on', value, true);
value = parseFloat(adapter.config.heatingcircuits[i].weightoff);
control_state(`${state}weightoff`, 'number', 'hc weight for switching off', value, true);
await control_state(`${state}weight`, 'number', 'hc weight actual', 99, false);
await control_state(
`${state}state`,
'string',
'state for heating control',
adapter.config.heatingcircuits[i].state,
false,
);
await control_state(`${state}on`, 'string', 'state value on', adapter.config.heatingcircuits[i].on, false);
await control_state(
`${state}off`,
'string',
'state value off',
adapter.config.heatingcircuits[i].off,
false,
);
await control_state(`${state}status`, 'boolean', 'hc control status', true, false);
if (adapter.config.heatingcircuits[i].savesettemp) {
await control_state(`${state}savesettemp`, 'number', 'saved settemp when switching off', -1, false);
}
}
for (let i = 0; i < adapter.config.thermostats.length; i++) {
const state = `${adapter.config.thermostats[i].hc}.${adapter.config.thermostats[i].room}.`;
value = 0;
try {
const state1 = await adapter.getForeignStateAsync(adapter.config.thermostats[i].settemp);
value = state1.val;
} catch (e) {
value = -99;
}
await control_state(`${state}settemp`, 'number', 'set temperature', value, false);
try {
const state1 = await adapter.getForeignStateAsync(adapter.config.thermostats[i].actualtemp);
value = state1.val;
} catch (e) {
value = -99;
}
await control_state(`${state}actualtemp`, 'number', 'actual temperature', value, false);
await control_state(`${state}actualweight`, 'number', 'actual weight', 0, false);
value = parseFloat(adapter.config.thermostats[i].weight);
await control_state(`${state}weight`, 'number', 'room weight for switching off', value, true);
value = parseFloat(adapter.config.thermostats[i].deltam);
await control_state(
`${state}deltam`,
'number',
'minimum room delta temperature for switching off',
value,
true,
);
}
} catch {}
}
async function control_state(state, type, name, value, write) {
await adapter.etObjectNotExistsAsync(`controls.${state}`, {
type: 'state',
common: { type: type, name: name, role: 'value', read: true, write: write },
native: {},
});
await adapter.setStateAsync(`controls.${state}`, { ack: true, val: value });
}
async function control_reset() {
// heat demand control switched off - reset control states for hc's
for (let i = 0; i < adapter.config.heatingcircuits.length; i++) {
const hc = adapter.config.heatingcircuits[i].hc;
const on = parseInt(adapter.config.heatingcircuits[i].on);
adapter.log.debug(`heat demand control switched off for ${hc} --> reset to on control value: ${on}`);
await adapter.setStateAsync(adapter.config.heatingcircuits[i].state, { ack: false, val: on });
await adapter.setStateAsync(`controls.${hc}.status`, { ack: true, val: true });
}
}
async function heatdemand() {
let w1 = 0,
w2 = 0,
w3 = 0,
w4 = 0;
try {
if (adapter.config.thermostats.length == 0 || adapter.config.thermostats.length == undefined) {
return;
}
} catch (e) {
return;
}
for (let i = 0; i < adapter.config.thermostats.length; i++) {
const state = `controls.${adapter.config.thermostats[i].hc}.${adapter.config.thermostats[i].room}.`;
let settemp = 0,
acttemp = 0,
savetemp = 0;
try {
const state1 = await adapter.getForeignStateAsync(adapter.config.thermostats[i].settemp);
settemp = state1.val;
} catch (e) {
adapter.log.error(`${adapter.config.thermostats[i].settemp}: heat demand thermostat wrongly defined`);
return;
}
await adapter.setStateAsync(`${state}settemp`, { ack: true, val: settemp });
const state2 = `controls.${adapter.config.thermostats[i].hc}.savesettemp`;
try {
const state3 = await adapter.getStateAsync(state2);
savetemp = state3.val;
if (savetemp > settemp) {
settemp = savetemp;
}
} catch {}
try {
const state4 = await adapter.getForeignStateAsync(adapter.config.thermostats[i].actualtemp);
acttemp = state4.val;
} catch (e) {
adapter.log.error(`${adapter.config.thermostats[i].settemp}: heat demand thermostat wrongly defined`);
return;
}
await adapter.setStateAsync(`${state}actualtemp`, { ack: true, val: acttemp });
//const deltam = parseFloat(adapter.config.thermostats[i].deltam);
let deltam = 0;
try {
deltam = parseFloat((await adapter.getStateAsync(`${state}deltam`)).val);
} catch (e) {
adapter.log.error(e);
}
const delta = settemp - acttemp;
//const weight = parseInt(adapter.config.thermostats[i].weight);
let weight = 0;
try {
weight = (await adapter.getStateAsync(`${state}weight`)).val;
} catch (e) {
adapter.log.error(e);
}
let actualweight = 0;
actualweight = (await adapter.getStateAsync(`${state}actualweight`)).val;
if (delta >= deltam) {
await adapter.setStateAsync(`${state}actualweight`, { ack: true, val: weight });
if (adapter.config.thermostats[i].hc == 'hc1') {
w1 += weight;
}
if (adapter.config.thermostats[i].hc == 'hc2') {
w2 += weight;
}
if (adapter.config.thermostats[i].hc == 'hc3') {
w3 += weight;
}
if (adapter.config.thermostats[i].hc == 'hc4') {
w4 += weight;
}
}
if (delta < deltam && delta >= 0 && actualweight > 0) {
actualweight = weight;
await adapter.setStateAsync(`${state}actualweight`, { ack: true, val: weight });
if (adapter.config.thermostats[i].hc == 'hc1') {
w1 += weight;
}
if (adapter.config.thermostats[i].hc == 'hc2') {
w2 += weight;
}
if (adapter.config.thermostats[i].hc == 'hc3') {
w3 += weight;
}
if (adapter.config.thermostats[i].hc == 'hc4') {
w4 += weight;
}
}
if (delta < 0) {
actualweight = 0;
await adapter.setStateAsync(`${state}actualweight`, { ack: true, val: 0 });
}
}
let hd = false;
try {
const active = await adapter.getStateAsync('controls.active');
if (active.val == true || active.val == 1) {
hd = true;
}
} catch {}
for (let i = 0; i < adapter.config.heatingcircuits.length; i++) {
const hc = adapter.config.heatingcircuits[i].hc;
const state = `controls.${hc}.`;
let w = 99;
if (hc == 'hc1') {
w = w1;
}
if (hc == 'hc2') {
w = w2;
}
if (hc == 'hc3') {
w = w3;
}
if (hc == 'hc4') {
w = w4;
}
await adapter.setStateAsync(`${state}weight`, { ack: true, val: w });
if (hd == true) {
let state5, v, weighton, weightoff, status, von, voff;
try {
state5 = await adapter.getForeignStateAsync(adapter.config.heatingcircuits[i].state);
v = state5.val;
weighton = (await adapter.getStateAsync(`${state}weighton`)).val;
weightoff = (await adapter.getStateAsync(`${state}weightoff`)).val;
status = (await adapter.getStateAsync(`${state}status`)).val;
} catch (e) {
adapter.log.error(
`${adapter.config.heatingcircuits[i].state}: heat demand heating circuit wrongly defined`,
);
return;
}
try {
von = parseInt(adapter.config.heatingcircuits[i].on);
voff = parseInt(adapter.config.heatingcircuits[i].off);
if (w >= weighton && v == voff) {
await adapter.setStateAsync(`${state}status`, { ack: true, val: true });
adapter.log.debug(`new heat demand for ${hc} --> switching on`);
await adapter.setStateAsync(adapter.config.heatingcircuits[i].state, { ack: false, val: von });
if (adapter.config.heatingcircuits[i].savesettemp) {
for (let ii = 0; ii < adapter.config.thermostats.length; ii++) {
if (adapter.config.thermostats[ii].hc == hc) {
await adapter.setStateAsync(`${state}savesettemp`, { ack: true, val: 0 });
}
}
}
}
if (w <= weightoff && v == von) {
await adapter.setStateAsync(`${state}status`, { ack: true, val: false });
adapter.log.debug(`no heat demand anymore for ${hc} --> switching off`);
await adapter.setStateAsync(adapter.config.heatingcircuits[i].state, { ack: false, val: voff });
if (adapter.config.heatingcircuits[i].savesettemp) {
for (let ii = 0; ii < adapter.config.thermostats.length; ii++) {
if (adapter.config.thermostats[ii].hc == hc) {
let settemp;
try {
const state6 = await adapter.getForeignStateAsync(
adapter.config.thermostats[ii].settemp,
);
settemp = state6.val;
} catch (e) {
settemp = -1;
}
await adapter.setStateAsync(`${state}savesettemp`, { ack: true, val: settemp });
}
}
}
}
} catch (e) {
adapter.log.warn(`can not process heatdemand state: ${adapter.config.heatingcircuits[i].state}`);
}
}
}
}
async function init_statistics() {
try {
await adapter.setObjectNotExistsAsync('statistics.created', {
type: 'state',
common: {
type: 'boolean',
name: 'Database (mySQL/InfluxDB) enabled for fields needed for statistics',
unit: '',
role: 'value',
read: true,
write: true,
},
native: {},
});
adapter.setObjectNotExistsAsync('statistics.ems-read', {
type: 'state',
common: {
type: 'number',
name: 'ems read time for polling',
unit: 'seconds',
role: 'value',
read: true,
write: true,
},
native: {},
});
adapter.setObjectNotExistsAsync('statistics.km200-read', {
type: 'state',
common: {
type: 'number',
name: 'km200 read time for polling',
unit: 'seconds',
role: 'value',
read: true,
write: true,
},
native: {},
});
adapter.setObjectNotExistsAsync('statistics.boiler-on-1h', {
type: 'state',
common: {
type: 'number',
name: 'percentage boiler on per hour',
unit: '%',
role: 'value',
read: true,
write: true,
},
native: {},
});
adapter.setObjectNotExistsAsync('statistics.boiler-starts-1h', {
type: 'state',
common: {
type: 'number',
name: 'boiler starts per hour',
unit: '',
role: 'value',
read: true,
write: true,
},
native: {},
});
adapter.setObjectNotExistsAsync('statistics.boiler-starts-24h', {
type: 'state',
common: {
type: 'number',
name: 'boiler starts per 24 hours',
unit: '',
role: 'value',
read: true,
write: true,
},
native: {},
});
adapter.setObjectNotExistsAsync('statistics.efficiency', {
type: 'state',
common: { type: 'number', name: 'boiler efficiency', unit: '%', role: 'value', read: true, write: true },
native: {},
});
await adapter.delay(500);
} catch {}
}
async function init_statistics2() {
if (adapter.config.db.trim() == '') {
db = '';
} else {
db = adapter.config.db;
}
if (db == '') {
adapter.log.error('no database instance selected for statistics');
} else {
try {
adapter.getState('statistics.created', function (err, state) {
if (state == null || state.val === false) {
adapter.setState('statistics.created', { ack: true, val: true });
}
});
if (adapter.config.emsesp_active && adapter.config.km200_structure) {
enable_state('heatSources.hs1.burnstarts', 86400, 60);
}
if (adapter.config.emsesp_active && adapter.config.km200_structure === false) {
enable_state('boiler.burnstarts', 86400, 60);
}
if (adapter.config.km200_active) {
enable_state('heatSources.numberOfStarts', 86400, 60);
}
if (adapter.config.emsesp_active && adapter.config.km200_structure) {
enable_state('heatSources.hs1.burngas', 86400, 15);
}
if (adapter.config.emsesp_active && adapter.config.km200_structure === false) {
enable_state('boiler.burngas', 86400, 15);
}
if (adapter.config.km200_active) {
enable_state('heatSources.hs1.flameStatus', 86400, 15);
}
await adapter.delay(500);
} catch {}
}
}
async function read_efficiency() {
if (!unloaded) {
let value = 0,
power = 0,
temp = 0,
tempr = 0,
tempavg = 0,
state;
let m = adapter.config.modulation;
let s = adapter.config.supplytemp;
let r = adapter.config.returntemp;
// re-initialize config parameters for previous km200 states - not to be used for ems-esp !
if (adapter.config.emsesp_active) {
if (m == 'heatSources.hs1.actualModulation') {
m = '';
}
if (s == 'heatSources.actualSupplyTemperature') {
s = '';
}
if (r == 'heatSources.returnTemperature') {
r = '';
}
}
if (adapter.config.emsesp_active && adapter.config.km200_structure === false) {
if (m.trim() == '') {
m = 'boiler.curburnpow';
}
if (s.trim() == '') {
s = 'boiler.curflowtemp';
}
if (r.trim() == '') {
r = 'boiler.rettemp';
}
}
if (adapter.config.emsesp_active && adapter.config.km200_structure) {
if (m.trim() == '') {
m = 'heatSources.hs1.curburnpow';
}
if (s.trim() == '') {
s = 'heatSources.hs1.curflowtemp';
}
if (r.trim() == '') {
r = 'heatSources.hs1.rettemp';
}
}
if (adapter.config.emsesp_active === false && adapter.config.km200_active) {
if (m.trim() == '') {
m = 'heatSources.hs1.actualModulation';
}
if (s.trim() == '') {
s = 'heatSources.actualSupplyTemperature';
}
if (r.trim() == '') {
r = 'heatSources.returnTemperature';
}
}
try {
state = await adapter.getStateAsync(m);
power = state.val;
} catch (e) {
power = 0;
}
if (power == 0) {
try {
state = await adapter.getForeignStateAsync(m);
power = state.val;
} catch (e) {
power = 0;
}
}
try {
state = await adapter.getStateAsync(s);
temp = state.val;
} catch (e) {
temp = 0;
}
if (temp == 0) {
try {
state = await adapter.getForeignStateAsync(s);
temp = state.val;
} catch (e) {
temp = 0;
}
}
try {
state = await adapter.getStateAsync(r);
tempr = state.val;
} catch (e) {
tempr = 0;
}
if (tempr == 0) {
try {
state = await adapter.getForeignStateAsync(r);
tempr = state.val;
} catch (e) {
tempr = 0;
}
}
if (power > 0) {
if (tempr == 0) {
tempr = temp - 10;
} // when return flow temp is not available
tempavg = (temp + tempr) / 2;
if (tempavg > 60) {
value = adapter.config.eff70;
} else {
if (tempavg > 55) {
value = adapter.config.eff60;
} else {
if (tempavg > 50) {
value = adapter.config.eff55;
} else {
if (tempavg > 45) {
value = adapter.config.eff50;
} else {
if (tempavg > 40) {
value = adapter.config.eff45;
} else {
if (tempavg > 35) {
value = adapter.config.eff40;
} else {
if (tempavg > 30) {
value = adapter.config.eff35;
} else {
if (tempavg > 25) {
value = adapter.config.eff30;
} else {
if (tempavg > 20) {
value = adapter.config.eff25;
} else {
if (tempavg <= 20) {
value = adapter.config.eff20;
}
}
}
}
}
}
}
}
}
}
}
await adapter.setObjectNotExists('statistics.efficiency', {
type: 'state',
common: { type: 'number', name: 'boiler efficiency', unit: '%', role: 'value', read: true, write: true },
native: {},
});
await adapter.setStateAsync('statistics.efficiency', { ack: true, val: value });
}
}
async function read_statistics() {
if (!unloaded) {
let id = '';
const end = Date.now();
if (adapter.config.km200_active) {
id = `${adapter.namespace}.heatSources.numberOfStarts`;
}
if (adapter.config.emsesp_active && adapter.config.km200_structure) {
id = `${adapter.namespace}.heatSources.hs1.burnstarts`;
}
if (adapter.config.emsesp_active && adapter.config.km200_structure === false) {
id = `${adapter.namespace}.boiler.burnstarts`;
}
stat(db, id, 1, 'statistics.boiler-starts-1h');
stat(db, id, 24, 'statistics.boiler-starts-24h');
/*
if (adapter.config.emsesp_active) {
id = adapter.namespace + ".boiler.wwstarts";
if (adapter.config.km200_structure) id = adapter.namespace + ".dhwCircuits.dhw1.wwstarts";
stat(db,id,1,"statistics.ww-starts-1h");
stat(db,id,24,"statistics.ww-starts-24h");
}
*/
if (adapter.config.km200_active) {
id = `${adapter.namespace}.heatSources.hs1.flameStatus`;
}
if (adapter.config.emsesp_active && adapter.config.km200_structure) {
id = `${adapter.namespace}.heatSources.hs1.burngas`;
}
if (adapter.config.emsesp_active && adapter.config.km200_structure === false) {
id = `${adapter.namespace}.boiler.burngas`;
}
try {
adapter.sendTo(
db,
'getHistory',
{
id: id,
options: { start: end - 3600000, end: end, aggregate: 'none' },
},
function (result) {
if (!unloaded) {
let count = 0;
let on = 0;
try {
count = result.result.length;
for (let i = 0; i < count; i++) {
if (Math.round(result.result[i].val) == 1) {
on += 1;
}
}
} catch {}
let value = 0;
if (count !== 0 && count != undefined) {
value = (on / count) * 100;
}
value = Math.round(value * 10) / 10;
adapter.setState('statistics.boiler-on-1h', { ack: true, val: value });
}
},
);
} catch {}
}
}
async function stat(db, id, hour, state) {
if (!unloaded && id != undefined) {
const end = Date.now();
const intervall = hour * 3600000;
try {
adapter.sendTo(
db,
'getHistory',
{
id: id,
options: { start: end - intervall, end: end, step: intervall, aggregate: 'minmax' },
},
function (result) {
if (!unloaded) {
let value = 0;
let c = 0;
try {
c = result.result.length;
} catch {}
if (c == 0 || c == 1) {
value = 0;
}
try {
let val1 = result.result[0].val;
if (val1 == 0) {
val1 = result.result[1].val;
}
value = Math.round(result.result[c - 1].val - val1);
if (value < 0) {
value = 0;
}
//adapter.log.info(id + " " +hour + ": " + c +" "+ + Math.round(val1)+" - " + Math.round(result.result[c-1].val) + " = " + value);
} catch {}
adapter.setStateAsync(state, { ack: true, val: value });
}
},
);
} catch (e) {
adapter.log.error(`error reading statistics records ${id}`);
}
}
}
async function delete_states_emsesp() {
const pattern = `${adapter.namespace}.*`;
const states = await adapter.getStatesAsync(pattern);
for (const id in states) {
const obj = await adapter.getObjectAsync(id);
if (obj.common.custom == undefined) {
await adapter.delObjectAsync(id);
}
}
}