Rework equipmentMgr
This commit is contained in:
268
equipmentMgr.js
268
equipmentMgr.js
@@ -2,25 +2,281 @@ console.loggerName = 'js.equipmentMgr';
|
||||
console.log('Load equipmentMgr');
|
||||
|
||||
const {
|
||||
equipment,
|
||||
lib,
|
||||
timer,
|
||||
watch
|
||||
} = require('../utils');
|
||||
|
||||
class Equipment {
|
||||
constructor(equipmentItem) {
|
||||
|
||||
// Fetch item if provided equipmentItem is a string
|
||||
if (typeof equipmentItem === 'string' || equipmentItem instanceof String) {
|
||||
this.equipmentItem = items[equipmentItem];
|
||||
} else {
|
||||
this.equipmentItem = equipmentItem;
|
||||
}
|
||||
|
||||
// Throw error if item is not existing
|
||||
if (this.equipmentItem === null) {
|
||||
throw(`Item ${equipmentItem} not existing`);
|
||||
}
|
||||
|
||||
// Throw error if item is not an equipment type
|
||||
if (this.equipmentItem.semantics.semanticType != 'Equipment') {
|
||||
throw(`Item ${this.equipmentItem.name} is not an equipment type`);
|
||||
}
|
||||
|
||||
console.info(`Initialization of equipment ${this.equipmentItem.name} with type ${this.constructor.name}`);
|
||||
|
||||
// Initialization of properties
|
||||
this.name = this.equipmentItem.name;
|
||||
|
||||
this.watch = new Object();
|
||||
this.timers = new timer.Timer();
|
||||
|
||||
// Check if equipment has state item
|
||||
if (this.hasProperty('State')) {
|
||||
this.stateItem = items[this.getPropertyItemName('State')];
|
||||
this.watch['State'] = new watch.Watch(this.stateItem);
|
||||
} else {
|
||||
console.info(`Item ${this.equipmentItem.name} has no state item`)
|
||||
}
|
||||
|
||||
// Check if equipment has LowBat item
|
||||
if (this.hasProperty('LowBat')) {
|
||||
this.watch['LowBat'] = new watch.Watch(this.getPropertyItemName('LowBat'));
|
||||
this.watch['LowBat'].add({
|
||||
targetState: 'ON',
|
||||
alertFunc: () => { this.#notifyLowBat(); },
|
||||
alertRepeat: 'PT23H'
|
||||
});
|
||||
}
|
||||
|
||||
// Check if equipment has Unreach item
|
||||
if (this.hasProperty('Unreach')) {
|
||||
this.watch['Unreach'] = new watch.Watch(this.getPropertyItemName('Unreach'));
|
||||
this.watch['Unreach'].add({
|
||||
targetState: 'ON',
|
||||
alertFunc: () => { this.#notifyUnreach(); },
|
||||
alertDelay: 'PT15M',
|
||||
alertRepeat: 'PT1H'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getValue(propertyName, defaultValue = '') {
|
||||
let valueItemName = this.name + '_' + propertyName;
|
||||
let returnValue = defaultValue;
|
||||
|
||||
if (items[valueItemName] == null) { // Return default value if item is missing
|
||||
console.warn('Item ' + valueItemName + ' is missing');
|
||||
} else if (items[valueItemName]['state'] == 'NULL') { // Return default value if item state is null
|
||||
console.warn('Item ' + valueItemName + ' is unset')
|
||||
} else { // Return value from item
|
||||
if (items[valueItemName].quantityState == null && items[valueItemName].numericState == null) {
|
||||
returnValue = items[valueItemName]['state'];
|
||||
} else if (items[valueItemName].quantityState == null) {
|
||||
returnValue = items[valueItemName]['numericState']
|
||||
} else {
|
||||
returnValue = items[valueItemName].quantityState;
|
||||
}
|
||||
}
|
||||
|
||||
console.debug(`Return value for property ${propertyName} for ${this.name}: ${returnValue}`);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
getPropertyItemName(propertyName) {
|
||||
if (this.hasProperty(propertyName)) {
|
||||
return items[this.name + '_' + propertyName].name;
|
||||
}
|
||||
}
|
||||
|
||||
hasProperty(propertyName) {
|
||||
if (items[this.name + '_' + propertyName] == null) {
|
||||
console.debug(`Eqipment ${this.name} has no property ${propertyName}`)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#notifyLowBat() {
|
||||
console.warn(`${this.name} has a low battery level.`);
|
||||
}
|
||||
|
||||
#notifyUnreach() {
|
||||
console.warn(`${this.name} is offline.`);
|
||||
}
|
||||
|
||||
gc() {
|
||||
console.log('Denitialization of eqipment ' + this.name);
|
||||
|
||||
// Delete all watchObjects
|
||||
for (let watchItem of Object.keys(this.watch)) {
|
||||
this.watch[watchItem].deleteAll();
|
||||
}
|
||||
|
||||
// Cancel all timers
|
||||
this.timers.cancelAll();
|
||||
}
|
||||
}
|
||||
|
||||
class Irrigation extends Equipment {
|
||||
constructor(equipmentItem) {
|
||||
super(equipmentItem);
|
||||
|
||||
// Initialization of properties
|
||||
this.valves = new Object();
|
||||
|
||||
// Add on/off watch rule
|
||||
this.watch['State'].add({
|
||||
targetState: 'ON',
|
||||
alertFunc: () => { this.#irrigationOn(); },
|
||||
endAlertFunc: () => { this.#irrigationOff(); },
|
||||
});
|
||||
|
||||
// Fetch irrigation valves and initialize as subequipment
|
||||
for (let valve of this.equipmentItem.members.filter(item => { return item.tags.includes('IrrigationValve'); } )) {
|
||||
try {
|
||||
this.valves[valve.name] = new IrrigationValve(valve);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
gc() {
|
||||
console.info('Deinitialization of irrigation valves for ' + this.name);
|
||||
|
||||
// Delete all watchObjects
|
||||
for (let valve of Object.keys(this.valves)) {
|
||||
this.valves[valve].gc();
|
||||
}
|
||||
|
||||
// Call function to deinitialize irrigation
|
||||
super.gc();
|
||||
}
|
||||
|
||||
#irrigationOn() {
|
||||
console.info(`Irrigation ${this.name} received command on`);
|
||||
|
||||
// Fetch valves with AutoMode enabled
|
||||
let autoValves = Object.keys(this.valves).filter(element => { return this.valves[element].getValue('AutoMode', 'OFF') == 'ON'} );
|
||||
|
||||
// Skip if no valves with AutoMode enabled are available
|
||||
if (autoValves.length == 0) {
|
||||
console.info('No valves with AutoMode enabled available');
|
||||
this.stateItem.sendCommandIfDifferent('OFF');
|
||||
return;
|
||||
}
|
||||
|
||||
let totalDuration = 0;
|
||||
|
||||
for (let i = 0; i < autoValves.length; i++) {
|
||||
let currentValve = autoValves[i];
|
||||
let nextValve = autoValves[(i + 1)];
|
||||
let duration = time.toZDT(this.valves[currentValve].getValue('Duration', 'PT30S')).getMillisFromNow();
|
||||
|
||||
// calculate start and endtimes for valve
|
||||
let startTime = time.toZDT(totalDuration)
|
||||
totalDuration = totalDuration + duration;
|
||||
let endTime = time.toZDT(totalDuration);
|
||||
|
||||
// Set timers for valve
|
||||
this.valves[currentValve].timers.create(
|
||||
'autoOn',
|
||||
startTime,
|
||||
() => {
|
||||
this.valves[currentValve].stateItem.sendCommandIfDifferent('ON');
|
||||
}
|
||||
);
|
||||
|
||||
this.valves[currentValve].timers.create(
|
||||
'autoOff',
|
||||
endTime,
|
||||
() => {
|
||||
this.valves[currentValve].stateItem.sendCommandIfDifferent('OFF');
|
||||
}
|
||||
);
|
||||
|
||||
// Stop irrigation after the last valve
|
||||
if (nextValve == undefined) {
|
||||
console.log('No further valves with autoMode enabled available');
|
||||
this.timers.create(
|
||||
'autoOff',
|
||||
endTime.plusSeconds(5),
|
||||
() => {
|
||||
console.debug(`Switch irrigation ${this.name} to off`)
|
||||
this.stateItem.sendCommandIfDifferent('OFF');
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#irrigationOff() {
|
||||
console.info(`Irrigation ${this.name} received command off`);
|
||||
|
||||
this.timers.cancel('autoOff')
|
||||
|
||||
for (let valve of Object.keys(this.valves)) {
|
||||
this.valves[valve].timers.cancel('autoOn');
|
||||
this.valves[valve].timers.cancel('autoOff');
|
||||
this.valves[valve].stateItem.sendCommandIfDifferent('OFF')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class IrrigationValve extends Equipment {
|
||||
constructor(equipmentItem) {
|
||||
super(equipmentItem);
|
||||
|
||||
this.watch['State'].add({
|
||||
targetState: 'ON',
|
||||
alertFunc: () => { this.stateItem.sendCommand('OFF'); },
|
||||
alertDelay: 'PT30M'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class TowelRadiator extends Equipment {
|
||||
constructor(equipmentItem) {
|
||||
super(equipmentItem);
|
||||
|
||||
this.watch['State'].add({
|
||||
targetState: 'ON',
|
||||
alertFunc: () => { this.stateItem.sendCommand('OFF'); },
|
||||
alertDelay: 'PT59M'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class WeatherService extends Equipment {
|
||||
constructor(equipmentItem) {
|
||||
super(equipmentItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const eMgr = new Object();
|
||||
|
||||
for (let equipmentItem of items.getItems().filter(element => { return (element.semantics.isEquipment == true) && (element.semantics.equipment == null) })) {
|
||||
// Fetch equipment type
|
||||
let equipmentType = equipmentItem.tags.filter(element => Object.keys(equipment).includes(element));
|
||||
if (equipmentType.length > 1) {
|
||||
equipmentType.splice(equipmentType.indexOf('Equipment'), 1);
|
||||
|
||||
// Get equipmentType
|
||||
var equipmentType = equipmentItem.tags.filter(element => { return !(element == 'Equipment') } );
|
||||
console.log(equipmentType);
|
||||
|
||||
// Set default equipmentType if item does not provide a type
|
||||
if (equipmentType == '') {
|
||||
equipmentType = 'Equipment';
|
||||
}
|
||||
|
||||
// Initialize equipment class
|
||||
try {
|
||||
eMgr[equipmentItem.name] = new equipment[equipmentType](equipmentItem);
|
||||
eMgr[equipmentItem.name] = eval(`new ${equipmentType}(equipmentItem)`);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
console.loggerName = 'js.equipment';
|
||||
console.log('Load equipment modules');
|
||||
|
||||
class Equipment {
|
||||
constructor(equipmentItem) {
|
||||
|
||||
// Fetch item if provided equipmentItem is a string
|
||||
if (typeof equipmentItem === 'string' || equipmentItem instanceof String) {
|
||||
this.equipmentItem = items[equipmentItem];
|
||||
} else {
|
||||
this.equipmentItem = equipmentItem;
|
||||
}
|
||||
|
||||
// Throw error if item is not existing
|
||||
if (this.equipmentItem === null) {
|
||||
throw(`Item ${equipmentItem} not existing`);
|
||||
}
|
||||
|
||||
// Throw error if item is not an equipment type
|
||||
if (this.equipmentItem.semantics.semanticType != 'Equipment') {
|
||||
throw(`Item ${this.equipmentItem.name} is not an equipment type`);
|
||||
}
|
||||
|
||||
console.info(`Initialization of equipment ${this.equipmentItem.name} with type ${this.constructor.name}`);
|
||||
|
||||
// Initialization of properties
|
||||
this.name = this.equipmentItem.name;
|
||||
|
||||
this.watch = new Object();
|
||||
this.timers = new timer.Timer();
|
||||
|
||||
// Check if equipment has state item
|
||||
if (this.hasProperty('State')) {
|
||||
this.stateItem = items[this.getPropertyItemName('State')];
|
||||
this.watch['State'] = new watch.Watch(this.stateItem);
|
||||
} else {
|
||||
console.info(`Item ${this.equipmentItem.name} has no state item`)
|
||||
}
|
||||
|
||||
// Check if equipment has LowBat item
|
||||
if (this.hasProperty('LowBat')) {
|
||||
this.watch['LowBat'] = new watch.Watch(this.getPropertyItemName('LowBat'));
|
||||
this.watch['LowBat'].add({
|
||||
targetState: 'ON',
|
||||
alertFunc: () => { this.#notifyLowBat(); },
|
||||
alertRepeat: 'PT23H'
|
||||
});
|
||||
}
|
||||
|
||||
// Check if equipment has Unreach item
|
||||
if (this.hasProperty('Unreach')) {
|
||||
this.watch['Unreach'] = new watch.Watch(this.getPropertyItemName('Unreach'));
|
||||
this.watch['Unreach'].add({
|
||||
targetState: 'ON',
|
||||
alertFunc: () => { this.#notifyUnreach(); },
|
||||
alertDelay: 'PT15M',
|
||||
alertRepeat: 'PT1H'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getValue(propertyName, defaultValue = '') {
|
||||
let valueItemName = this.name + '_' + propertyName;
|
||||
let returnValue = defaultValue;
|
||||
|
||||
if (items[valueItemName] == null) { // Return default value if item is missing
|
||||
console.warn('Item ' + valueItemName + ' is missing');
|
||||
} else if (items[valueItemName]['state'] == 'NULL') { // Return default value if item state is null
|
||||
console.warn('Item ' + valueItemName + ' is unset')
|
||||
} else { // Return value from item
|
||||
if (items[valueItemName].quantityState == null && items[valueItemName].numericState == null) {
|
||||
returnValue = items[valueItemName]['state'];
|
||||
} else if (items[valueItemName].quantityState == null) {
|
||||
returnValue = items[valueItemName]['numericState']
|
||||
} else {
|
||||
returnValue = items[valueItemName].quantityState;
|
||||
}
|
||||
}
|
||||
|
||||
console.debug(`Return value for property ${propertyName} for ${this.name}: ${returnValue}`);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
getPropertyItemName(propertyName) {
|
||||
if (this.hasProperty(propertyName)) {
|
||||
return items[this.name + '_' + propertyName].name;
|
||||
}
|
||||
}
|
||||
|
||||
hasProperty(propertyName) {
|
||||
if (items[this.name + '_' + propertyName] == null) {
|
||||
console.debug(`Eqipment ${this.name} has no property ${propertyName}`)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#notifyLowBat() {
|
||||
console.warn(`${this.name} has a low battery level.`);
|
||||
}
|
||||
|
||||
#notifyUnreach() {
|
||||
console.warn(`${this.name} is offline.`);
|
||||
}
|
||||
|
||||
gc() {
|
||||
console.log('Denitialization of eqipment ' + this.name);
|
||||
|
||||
// Delete all watchObjects
|
||||
for (let watchItem of Object.keys(this.watch)) {
|
||||
this.watch[watchItem].deleteAll();
|
||||
}
|
||||
|
||||
// Cancel all timers
|
||||
this.timers.cancelAll();
|
||||
}
|
||||
}
|
||||
|
||||
class Irrigation extends Equipment {
|
||||
constructor(equipmentItem) {
|
||||
super(equipmentItem);
|
||||
|
||||
// Initialization of properties
|
||||
this.valves = new Object();
|
||||
|
||||
// Add on/off watch rule
|
||||
this.watch['State'].add({
|
||||
targetState: 'ON',
|
||||
alertFunc: () => { this.#irrigationOn(); },
|
||||
endAlertFunc: () => { this.#irrigationOff(); },
|
||||
});
|
||||
|
||||
// Fetch irrigation valves and initialize as subequipment
|
||||
for (let valve of this.equipmentItem.members.filter(item => { return item.tags.includes('IrrigationValve'); } )) {
|
||||
try {
|
||||
this.valves[valve.name] = new IrrigationValve(valve);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
gc() {
|
||||
console.info('Deinitialization of irrigation valves for ' + this.name);
|
||||
|
||||
// Delete all watchObjects
|
||||
for (let valve of Object.keys(this.valves)) {
|
||||
this.valves[valve].gc();
|
||||
}
|
||||
|
||||
// Call function to deinitialize irrigation
|
||||
super.gc();
|
||||
}
|
||||
|
||||
#irrigationOn() {
|
||||
console.info(`Irrigation ${this.name} received command on`);
|
||||
|
||||
// Fetch valves with AutoMode enabled
|
||||
let autoValves = Object.keys(this.valves).filter(element => { return this.valves[element].getValue('AutoMode', 'OFF') == 'ON'} );
|
||||
|
||||
// Skip if no valves with AutoMode enabled are available
|
||||
if (autoValves.length == 0) {
|
||||
console.info('No valves with AutoMode enabled available');
|
||||
this.stateItem.sendCommandIfDifferent('OFF');
|
||||
return;
|
||||
}
|
||||
|
||||
let totalDuration = 0;
|
||||
|
||||
for (let i = 0; i < autoValves.length; i++) {
|
||||
let currentValve = autoValves[i];
|
||||
let nextValve = autoValves[(i + 1)];
|
||||
let duration = time.toZDT(this.valves[currentValve].getValue('Duration', 'PT30S')).getMillisFromNow();
|
||||
|
||||
// calculate start and endtimes for valve
|
||||
let startTime = time.toZDT(totalDuration)
|
||||
totalDuration = totalDuration + duration;
|
||||
let endTime = time.toZDT(totalDuration);
|
||||
|
||||
// Set timers for valve
|
||||
this.valves[currentValve].timers.create(
|
||||
'autoOn',
|
||||
startTime,
|
||||
() => {
|
||||
this.valves[currentValve].stateItem.sendCommandIfDifferent('ON');
|
||||
}
|
||||
);
|
||||
|
||||
this.valves[currentValve].timers.create(
|
||||
'autoOff',
|
||||
endTime,
|
||||
() => {
|
||||
this.valves[currentValve].stateItem.sendCommandIfDifferent('OFF');
|
||||
}
|
||||
);
|
||||
|
||||
// Stop irrigation after the last valve
|
||||
if (nextValve == undefined) {
|
||||
console.log('No further valves with autoMode enabled available');
|
||||
this.timers.create(
|
||||
'autoOff',
|
||||
endTime.plusSeconds(5),
|
||||
() => {
|
||||
console.debug(`Switch irrigation ${this.name} to off`)
|
||||
this.stateItem.sendCommandIfDifferent('OFF');
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#irrigationOff() {
|
||||
console.info(`Irrigation ${this.name} received command off`);
|
||||
|
||||
this.timers.cancel('autoOff')
|
||||
|
||||
for (let valve of Object.keys(this.valves)) {
|
||||
this.valves[valve].timers.cancel('autoOn');
|
||||
this.valves[valve].timers.cancel('autoOff');
|
||||
this.valves[valve].stateItem.sendCommandIfDifferent('OFF')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class IrrigationValve extends Equipment {
|
||||
constructor(equipmentItem) {
|
||||
super(equipmentItem);
|
||||
|
||||
this.watch['State'].add({
|
||||
targetState: 'ON',
|
||||
alertFunc: () => { this.stateItem.sendCommand('OFF'); },
|
||||
alertDelay: 'PT30M'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class TowelRadiator extends Equipment {
|
||||
constructor(equipmentItem) {
|
||||
super(equipmentItem);
|
||||
|
||||
this.watch['State'].add({
|
||||
targetState: 'ON',
|
||||
alertFunc: () => { this.stateItem.sendCommand('OFF'); },
|
||||
alertDelay: 'PT59M'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class WeatherService extends Equipment {
|
||||
constructor(equipmentItem) {
|
||||
super(equipmentItem);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Equipment,
|
||||
Irrigation,
|
||||
IrrigationValve,
|
||||
TowelRadiator,
|
||||
WeatherService
|
||||
};
|
||||
Reference in New Issue
Block a user