openhab_rules_tools
Version:
Functions and classes to make writing openHAB rules in JS Scripting easier.
169 lines (156 loc) • 5.43 kB
JavaScript
/**Credit goes to Florian Hotze for the initial idea previously submitted
* to openhab_rules_tools. However, with the changes to JSScripting and
* ECMAScript 11, a complete rewrite was warranted including some
* simplification and generalization.
*
* The original is still available in the before-npm branch for reference.
*/
/**
* Utility that will return the passed in Group's members mapped with the
* passed in mapping function. An example mapping funciton would be:
*
* i => i.name
*
* which will return an array of the member's names. Supports an optional
* filterFunc to filter the members before generating the mapped list. A
* filter looks something like
*
* i => !i.isUninitialized
* @param {string} groupName
* @param {function(i)} mapFunc function called to map the Item
* @param {function(i)} filterFunc optional filtering function
* @returns {Array} the filtered Items with the mapping function applies
*/
const membersToMappedList = (groupName, mapFunc, filterFunc) => {
if(!filterFunc) filterFunc = i => i;
return items.getItem(groupName).members.filter(filterFunc).map(mapFunc);
}
/**
* Same as membersToMappingList except it works on descendents of the Group.
* @param {string} groupName
* @param {function(i)} mapFunc
* @param {function(i)} filterFunc
* @returns {Array}
*/
const descendentsToMappedList = (groupName, mapFunc, filterFunc) => {
if(!filterFunc) filterFunc = i => i;
return items.getItem(groupName).descendents.filter(filterFunc).map(mapFunc);
}
/**
* Calls membersToMappedList and joins the result into a separator
* separated string.
* @param {string} groupName
* @param {string} separator string to separate the list in the resultant string
* @param {function(i)} mapFunc
* @param {function(i)} filterFunc
* @returns {string} the mapped values concetanted to a single string
*/
const membersToString = (groupName, separator, mapFunc, filterFunc) => {
return membersToMappedList(groupName, mapFunc, filterFunc).join(separator);
}
/**
* Same as membersToString except it operates on the Group's descendents.
* @param {string} groupName
* @param {string} separator
* @param {function(i)} mapFunc
* @param {function(i)} filterFunc
* @returns {string}
*/
const descendentsToString = (groupName, separator, mapFunc, filterFunc) => {
return descendentsToMappedList(groupName, mapFunc, filterFunc).join(separator);
}
/**
* Optionally, filters the members of the group, maps the Items to rawState,
* and applies the reduce function. The function should take two values,
* a total and a value. It would look something like this for a sum.
*
* (total, value) => total += value
*
* @param {string} groupName
* @param {function(i)} reduceFunc
* @param {function(i)} filterFunc
* @returns A single reduced value calculated from all members of the group
*/
const reduceMemberStates = (groupName, reduceFunc, filterFunc) => {
return membersToMappedList(groupName, (m) => m.rawState, filterFunc)
.reduce(reduceFunc, null);
}
/**
* Same as reduceMemberStates except it does it for all descendents.
* @param {string} groupName
* @param {function(i)} reduceFunc
* @param {function(i)} filterFunc
* @returns A single reduced value calculated from all members of the group
*/
const reduceDecendentStates = (groupName, reduceFunc, filterFunc) => {
return descendentsToMappedList(groupName, (m) => m.rawState, filterFunc)
.reduce(reduceFunc, null);
}
/**
* Tests to see if i is an Item with a numeric state.
* @param {*} i
* @returns {boolean} true if i's rawState has a floatValue function
*/
const isNumber = (i) => {
return i.rawState.floatValue;
}
/**
* Sums the states of the passed in list of Items. Items with a non-numeric
* state are ignored.
* @param {Array<item>} list
* @returns {float} sum of the Items with numeric states.
*/
const sumList = (list) => {
return list.filter(isNumber)
.map(i => i.rawState.floatValue())
.reduce((total, value) => total += value);
}
/**
* Averages the states of the passed in list of Items. Items with a non-numeric
* state are completely ignored and not considered part of the calculation.
* @param {Array<item>} list
* @returns {float} average of the Item's with numberic states.
*/
const avgList = (list) => {
const filtered = list.filter(isNumber);
const sum = sumList(list);
return sum / filtered.length;
}
/**
* @param {Array<item>} list
* @returns {num} Minimum value of the Items with numeric states.
*/
const minList = (list) => {
return list.filter(isNumber)
.map(i => i.rawState.floatValue())
.reduce((total, value) => (total < value) ? total : value);
}
/**
* @param {Array<item>} list
* @returns {num} Maxiumum value of the Items with numeric states.
*/
const maxList = (list) => {
return list.filter(isNumber)
.map(i => i.rawState.floatValue())
.reduce((total, value) => (total > value) ? total : value);
}
/**
* @param {Array<item>} list
* @returns {num} the count of the Items that match the filterFunc
*/
const countList = (list, filterFunc) => {
return list.filter(filterFunc).length;
}
module.exports = {
membersToMappedList,
descendentsToMappedList,
membersToString,
descendentsToString,
reduceMemberStates,
reduceDecendentStates,
sumList,
avgList,
minList,
maxList,
countList
}