mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-10 13:21:53 +01:00
Add XOR ArithmeticGroupFunction (#4386)
* #4385 add XOR ArithmeticGroupFunction (1 of n) Signed-off-by: Fabian Vollmann <surmise-metro.0c@icloud.com>
This commit is contained in:
parent
437a885d82
commit
a5c488d8c8
@ -27,7 +27,7 @@ ModelGroupItem:
|
||||
;
|
||||
|
||||
enum ModelGroupFunction:
|
||||
EQUALITY='EQUALITY' | AND='AND' | OR='OR' | NAND='NAND' | NOR='NOR' | AVG='AVG' | MEDIAN='MEDIAN' | SUM='SUM' | MAX='MAX' | MIN='MIN' | COUNT='COUNT' | LATEST='LATEST' | EARLIEST='EARLIEST'
|
||||
EQUALITY='EQUALITY' | AND='AND' | OR='OR' | NAND='NAND' | NOR='NOR' | XOR='XOR' | AVG='AVG' | MEDIAN='MEDIAN' | SUM='SUM' | MAX='MAX' | MIN='MIN' | COUNT='COUNT' | LATEST='LATEST' | EARLIEST='EARLIEST'
|
||||
;
|
||||
|
||||
ModelNormalItem:
|
||||
|
@ -140,6 +140,14 @@ public class GroupFunctionHelper {
|
||||
logger.error("Group function 'NOT OR' requires two arguments. Using Equality instead.");
|
||||
}
|
||||
break;
|
||||
case "XOR":
|
||||
args = parseStates(baseItem, function.params);
|
||||
if (args.size() == 2) {
|
||||
return new ArithmeticGroupFunction.Xor(args.get(0), args.get(1));
|
||||
} else {
|
||||
logger.error("Group function 'XOR' requires two arguments. Using Equality instead.");
|
||||
}
|
||||
break;
|
||||
case "COUNT":
|
||||
if (function.params != null && function.params.length == 1) {
|
||||
State countParam = new StringType(function.params[0]);
|
||||
|
@ -35,6 +35,7 @@ import org.openhab.core.util.Statistics;
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
* @author Thomas Eichstädt-Engelen - Added "N" functions
|
||||
* @author Gaël L'hopital - Added count function
|
||||
* @author Fabian Vollmann - Added XOR function
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface ArithmeticGroupFunction extends GroupFunction {
|
||||
@ -212,6 +213,82 @@ public interface ArithmeticGroupFunction extends GroupFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This does a logical 'xor' operation. If exactly one item is of 'activeState' this
|
||||
* is returned, otherwise the 'passiveState' is returned.
|
||||
*
|
||||
* Through the getStateAs() method, it can be determined, how many
|
||||
* items actually are in the 'activeState'.
|
||||
*/
|
||||
class Xor implements GroupFunction {
|
||||
|
||||
protected final State activeState;
|
||||
protected final State passiveState;
|
||||
|
||||
public Xor(@Nullable State activeValue, @Nullable State passiveValue) {
|
||||
if (activeValue == null || passiveValue == null) {
|
||||
throw new IllegalArgumentException("Parameters must not be null!");
|
||||
}
|
||||
this.activeState = activeValue;
|
||||
this.passiveState = passiveValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State calculate(@Nullable Set<Item> items) {
|
||||
if (items != null) {
|
||||
boolean foundOne = false;
|
||||
|
||||
for (Item item : items) {
|
||||
if (activeState.equals(item.getStateAs(activeState.getClass()))) {
|
||||
if (foundOne) {
|
||||
return passiveState;
|
||||
} else {
|
||||
foundOne = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (foundOne) {
|
||||
return activeState;
|
||||
}
|
||||
}
|
||||
|
||||
return passiveState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable <T extends State> T getStateAs(@Nullable Set<Item> items, Class<T> stateClass) {
|
||||
State state = calculate(items);
|
||||
if (stateClass.isInstance(state)) {
|
||||
return stateClass.cast(state);
|
||||
} else {
|
||||
if (stateClass == DecimalType.class) {
|
||||
if (items != null) {
|
||||
return stateClass.cast(new DecimalType(count(items, activeState)));
|
||||
} else {
|
||||
return stateClass.cast(DecimalType.ZERO);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int count(Set<Item> items, State state) {
|
||||
int count = 0;
|
||||
for (Item item : items) {
|
||||
if (state.equals(item.getStateAs(state.getClass()))) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State[] getParameters() {
|
||||
return new State[] { activeState, passiveState };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This calculates the numeric average over all item states of decimal type.
|
||||
*/
|
||||
|
@ -206,6 +206,58 @@ public class ArithmeticGroupFunctionTest {
|
||||
assertEquals(OpenClosedType.OPEN, state);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXorFunction() {
|
||||
Set<Item> items = new HashSet<>();
|
||||
items.add(new TestItem("TestItem1", OpenClosedType.OPEN));
|
||||
items.add(new TestItem("TestItem2", OpenClosedType.CLOSED));
|
||||
|
||||
GroupFunction function = new ArithmeticGroupFunction.Xor(OpenClosedType.OPEN, OpenClosedType.CLOSED);
|
||||
State state = function.calculate(items);
|
||||
|
||||
assertEquals(OpenClosedType.OPEN, state);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXorFunctionMultiple() {
|
||||
Set<Item> items = new HashSet<>();
|
||||
items.add(new TestItem("TestItem1", OpenClosedType.CLOSED));
|
||||
items.add(new TestItem("TestItem2", OpenClosedType.CLOSED));
|
||||
items.add(new TestItem("TestItem3", OpenClosedType.OPEN));
|
||||
items.add(new TestItem("TestItem4", OpenClosedType.CLOSED));
|
||||
|
||||
GroupFunction function = new ArithmeticGroupFunction.Xor(OpenClosedType.OPEN, OpenClosedType.CLOSED);
|
||||
State state = function.calculate(items);
|
||||
|
||||
assertEquals(OpenClosedType.OPEN, state);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXorFunctionNegative() {
|
||||
Set<Item> items = new HashSet<>();
|
||||
items.add(new TestItem("TestItem1", OpenClosedType.OPEN));
|
||||
items.add(new TestItem("TestItem2", OpenClosedType.OPEN));
|
||||
|
||||
GroupFunction function = new ArithmeticGroupFunction.Xor(OpenClosedType.OPEN, OpenClosedType.CLOSED);
|
||||
State state = function.calculate(items);
|
||||
|
||||
assertEquals(OpenClosedType.CLOSED, state);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXorFunctionNegativeMultiple() {
|
||||
Set<Item> items = new HashSet<>();
|
||||
items.add(new TestItem("TestItem1", OpenClosedType.CLOSED));
|
||||
items.add(new TestItem("TestItem2", OpenClosedType.OPEN));
|
||||
items.add(new TestItem("TestItem3", OpenClosedType.OPEN));
|
||||
items.add(new TestItem("TestItem4", OpenClosedType.CLOSED));
|
||||
|
||||
GroupFunction function = new ArithmeticGroupFunction.Xor(OpenClosedType.OPEN, OpenClosedType.CLOSED);
|
||||
State state = function.calculate(items);
|
||||
|
||||
assertEquals(OpenClosedType.CLOSED, state);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAvgFunction() {
|
||||
Set<Item> items = new HashSet<>();
|
||||
|
Loading…
Reference in New Issue
Block a user